summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--SConstruct96
-rw-r--r--core/SCsub22
-rw-r--r--core/crypto/SCsub15
-rw-r--r--core/input/input_event.cpp21
-rw-r--r--core/io/file_access_compressed.cpp4
-rw-r--r--core/io/file_access_encrypted.cpp6
-rw-r--r--core/io/image.cpp93
-rw-r--r--core/io/image.h18
-rw-r--r--core/io/logger.cpp20
-rw-r--r--core/math/aabb.h6
-rw-r--r--core/math/camera_matrix.cpp11
-rw-r--r--core/math/camera_matrix.h2
-rw-r--r--core/math/dynamic_bvh.cpp400
-rw-r--r--core/math/dynamic_bvh.h359
-rw-r--r--core/math/rect2.h6
-rw-r--r--core/object/undo_redo.cpp25
-rw-r--r--core/object/undo_redo.h4
-rw-r--r--core/os/file_access.cpp2
-rw-r--r--core/variant/method_ptrcall.h9
-rw-r--r--core/variant/variant.h12
-rw-r--r--core/variant/variant_call.cpp4
-rw-r--r--core/variant/variant_construct.cpp134
-rw-r--r--core/variant/variant_parser.cpp9
-rw-r--r--core/variant/variant_setget.cpp224
-rw-r--r--doc/classes/AcceptDialog.xml6
-rw-r--r--doc/classes/Animation.xml6
-rw-r--r--doc/classes/AnimationPlayer.xml4
-rw-r--r--doc/classes/Area3D.xml2
-rw-r--r--doc/classes/Camera3D.xml2
-rw-r--r--doc/classes/CharFXTransform.xml31
-rw-r--r--doc/classes/ConfirmationDialog.xml2
-rw-r--r--doc/classes/Control.xml20
-rw-r--r--doc/classes/EditorPlugin.xml10
-rw-r--r--doc/classes/FontData.xml28
-rw-r--r--doc/classes/Generic6DOFJoint3D.xml2
-rw-r--r--doc/classes/Geometry2D.xml2
-rw-r--r--doc/classes/GraphEdit.xml17
-rw-r--r--doc/classes/Image.xml35
-rw-r--r--doc/classes/OS.xml8
-rw-r--r--doc/classes/ProjectSettings.xml8
-rw-r--r--doc/classes/ProximityGroup3D.xml4
-rw-r--r--doc/classes/Rect2.xml2
-rw-r--r--doc/classes/Rect2i.xml2
-rw-r--r--doc/classes/ResourceLoader.xml4
-rw-r--r--doc/classes/RichTextLabel.xml191
-rw-r--r--doc/classes/SubViewport.xml6
-rw-r--r--doc/classes/TextServer.xml42
-rw-r--r--doc/classes/TextureProgressBar.xml (renamed from doc/classes/TextureProgress.xml)4
-rw-r--r--doc/classes/Theme.xml36
-rw-r--r--doc/classes/Vector2.xml2
-rw-r--r--doc/classes/Vector3.xml2
-rw-r--r--drivers/png/SCsub19
-rw-r--r--drivers/spirv-reflect/SCsub8
-rw-r--r--drivers/unix/os_unix.h50
-rw-r--r--drivers/vulkan/SCsub29
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp39
-rw-r--r--drivers/vulkan/rendering_device_vulkan.h15
-rw-r--r--drivers/vulkan/vulkan_context.cpp2
-rw-r--r--editor/animation_track_editor.cpp200
-rw-r--r--editor/animation_track_editor.h19
-rw-r--r--editor/connections_dialog.cpp10
-rw-r--r--editor/create_dialog.cpp8
-rw-r--r--editor/dependency_editor.cpp8
-rw-r--r--editor/editor_asset_installer.cpp2
-rw-r--r--editor/editor_audio_buses.cpp8
-rw-r--r--editor/editor_audio_buses.h6
-rw-r--r--editor/editor_dir_dialog.cpp2
-rw-r--r--editor/editor_feature_profile.cpp2
-rw-r--r--editor/editor_file_dialog.cpp32
-rw-r--r--editor/editor_file_system.cpp8
-rw-r--r--editor/editor_fonts.cpp17
-rw-r--r--editor/editor_help.cpp8
-rw-r--r--editor/editor_help_search.cpp42
-rw-r--r--editor/editor_help_search.h4
-rw-r--r--editor/editor_node.cpp94
-rw-r--r--editor/editor_node.h6
-rw-r--r--editor/editor_plugin.cpp6
-rw-r--r--editor/editor_plugin.h2
-rw-r--r--editor/editor_properties.cpp4
-rw-r--r--editor/editor_settings.cpp20
-rw-r--r--editor/editor_themes.cpp43
-rw-r--r--editor/export_template_manager.cpp6
-rw-r--r--editor/filesystem_dock.cpp29
-rw-r--r--editor/filesystem_dock.h2
-rw-r--r--editor/find_in_files.cpp16
-rw-r--r--editor/groups_editor.cpp2
-rw-r--r--editor/icons/GridMinimap.svg1
-rw-r--r--editor/icons/Texture3D.svg2
-rw-r--r--editor/icons/TextureArray.svg2
-rw-r--r--editor/icons/TextureProgressBar.svg (renamed from editor/icons/TextureProgress.svg)0
-rw-r--r--editor/import/collada.h4
-rw-r--r--editor/import/editor_import_collada.cpp39
-rw-r--r--editor/import/editor_scene_importer_gltf.cpp37
-rw-r--r--editor/import/editor_scene_importer_gltf.h14
-rw-r--r--editor/import/resource_importer_obj.cpp26
-rw-r--r--editor/import/resource_importer_scene.cpp381
-rw-r--r--editor/import/resource_importer_scene.h89
-rw-r--r--editor/import/resource_importer_texture.cpp2
-rw-r--r--editor/import_dock.cpp2
-rw-r--r--editor/input_map_editor.cpp20
-rw-r--r--editor/plugin_config_dialog.cpp10
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp2
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp37
-rw-r--r--editor/plugins/animation_player_editor_plugin.h2
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp4
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp23
-rw-r--r--editor/plugins/gpu_particles_3d_editor_plugin.cpp2
-rw-r--r--editor/plugins/mesh_instance_3d_editor_plugin.cpp2
-rw-r--r--editor/plugins/mesh_library_editor_plugin.cpp2
-rw-r--r--editor/plugins/multimesh_editor_plugin.cpp4
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp60
-rw-r--r--editor/plugins/node_3d_editor_plugin.h1
-rw-r--r--editor/plugins/resource_preloader_editor_plugin.cpp4
-rw-r--r--editor/plugins/script_editor_plugin.cpp10
-rw-r--r--editor/plugins/shader_editor_plugin.cpp2
-rw-r--r--editor/plugins/sprite_2d_editor_plugin.cpp10
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp12
-rw-r--r--editor/plugins/theme_editor_plugin.cpp10
-rw-r--r--editor/plugins/version_control_editor_plugin.cpp17
-rw-r--r--editor/plugins/version_control_editor_plugin.h1
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp12
-rw-r--r--editor/project_export.cpp26
-rw-r--r--editor/project_manager.cpp76
-rw-r--r--editor/project_settings_editor.cpp2
-rw-r--r--editor/property_selector.cpp6
-rw-r--r--editor/pvrtc_compress.cpp141
-rw-r--r--editor/quick_open.cpp6
-rw-r--r--editor/rename_dialog.cpp2
-rw-r--r--editor/reparent_dialog.cpp2
-rw-r--r--editor/scene_tree_dock.cpp2
-rw-r--r--editor/script_create_dialog.cpp14
-rw-r--r--editor/settings_config_dialog.cpp6
-rw-r--r--editor/translations/af.po170
-rw-r--r--editor/translations/ar.po115
-rw-r--r--editor/translations/bg.po314
-rw-r--r--editor/translations/bn.po99
-rw-r--r--editor/translations/ca.po95
-rw-r--r--editor/translations/cs.po104
-rw-r--r--editor/translations/da.po99
-rw-r--r--editor/translations/de.po110
-rw-r--r--editor/translations/editor.pot86
-rw-r--r--editor/translations/el.po95
-rw-r--r--editor/translations/eo.po90
-rw-r--r--editor/translations/es.po114
-rw-r--r--editor/translations/es_AR.po298
-rw-r--r--editor/translations/et.po146
-rw-r--r--editor/translations/eu.po86
-rw-r--r--editor/translations/fa.po94
-rw-r--r--editor/translations/fi.po104
-rw-r--r--editor/translations/fil.po86
-rw-r--r--editor/translations/fr.po106
-rw-r--r--editor/translations/ga.po86
-rw-r--r--editor/translations/he.po141
-rw-r--r--editor/translations/hi.po88
-rw-r--r--editor/translations/hr.po88
-rw-r--r--editor/translations/hu.po394
-rw-r--r--editor/translations/id.po95
-rw-r--r--editor/translations/is.po90
-rw-r--r--editor/translations/it.po179
-rw-r--r--editor/translations/ja.po114
-rw-r--r--editor/translations/ka.po86
-rw-r--r--editor/translations/ko.po95
-rw-r--r--editor/translations/lt.po90
-rw-r--r--editor/translations/lv.po86
-rw-r--r--editor/translations/mi.po86
-rw-r--r--editor/translations/ml.po86
-rw-r--r--editor/translations/mr.po86
-rw-r--r--editor/translations/ms.po108
-rw-r--r--editor/translations/nb.po99
-rw-r--r--editor/translations/nl.po160
-rw-r--r--editor/translations/or.po86
-rw-r--r--editor/translations/pl.po107
-rw-r--r--editor/translations/pr.po88
-rw-r--r--editor/translations/pt.po104
-rw-r--r--editor/translations/pt_BR.po201
-rw-r--r--editor/translations/ro.po96
-rw-r--r--editor/translations/ru.po105
-rw-r--r--editor/translations/si.po86
-rw-r--r--editor/translations/sk.po95
-rw-r--r--editor/translations/sl.po97
-rw-r--r--editor/translations/sq.po99
-rw-r--r--editor/translations/sr_Cyrl.po99
-rw-r--r--editor/translations/sr_Latn.po86
-rw-r--r--editor/translations/sv.po101
-rw-r--r--editor/translations/ta.po90
-rw-r--r--editor/translations/te.po86
-rw-r--r--editor/translations/th.po111
-rw-r--r--editor/translations/tr.po106
-rw-r--r--editor/translations/tzm.po86
-rw-r--r--editor/translations/uk.po106
-rw-r--r--editor/translations/ur_PK.po88
-rw-r--r--editor/translations/vi.po95
-rw-r--r--editor/translations/zh_CN.po107
-rw-r--r--editor/translations/zh_HK.po97
-rw-r--r--editor/translations/zh_TW.po104
-rw-r--r--icon.pngbin7569 -> 7594 bytes
-rw-r--r--icon.svg30
-rw-r--r--logo.pngbin13142 -> 13159 bytes
-rw-r--r--logo.svg30
-rw-r--r--main/main.cpp5
-rw-r--r--methods.py2
-rw-r--r--misc/dist/document_icons/project.svg2
-rw-r--r--misc/dist/document_icons/project_extra_small.svg2
-rw-r--r--misc/dist/document_icons/project_small.svg2
-rw-r--r--misc/dist/html/logo.svg28
-rw-r--r--misc/dist/project_icon.svg2
-rw-r--r--modules/assimp/SCsub30
-rw-r--r--modules/basis_universal/SCsub17
-rw-r--r--modules/bullet/SCsub14
-rw-r--r--modules/bullet/bullet_physics_server.cpp16
-rw-r--r--modules/bullet/bullet_physics_server.h3
-rw-r--r--modules/bullet/generic_6dof_joint_bullet.cpp8
-rw-r--r--modules/bullet/generic_6dof_joint_bullet.h3
-rw-r--r--modules/bullet/rigid_body_bullet.cpp9
-rw-r--r--modules/bullet/rigid_body_bullet.h2
-rw-r--r--modules/bullet/space_bullet.cpp14
-rw-r--r--modules/cvtt/SCsub15
-rw-r--r--modules/denoise/SCsub17
-rw-r--r--modules/enet/SCsub16
-rw-r--r--modules/etc/SCsub15
-rw-r--r--modules/etc/image_compress_etc.cpp (renamed from modules/etc/image_etc.cpp)10
-rw-r--r--modules/etc/image_compress_etc.h (renamed from modules/etc/image_etc.h)8
-rw-r--r--modules/etc/register_types.cpp2
-rw-r--r--modules/freetype/SCsub14
-rw-r--r--modules/gdnative/gdnative/rect2.cpp8
-rw-r--r--modules/gdnative/gdnative_api.json4
-rw-r--r--modules/gdnative/gdnative_library_editor_plugin.cpp2
-rw-r--r--modules/gdnative/include/gdnative/rect2.h4
-rw-r--r--modules/gdnative/include/text/godot_text.h3
-rw-r--r--modules/gdnative/text/text_server_gdnative.cpp18
-rw-r--r--modules/gdnative/text/text_server_gdnative.h4
-rw-r--r--modules/gdnavigation/SCsub31
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml2
-rw-r--r--modules/gdscript/gdscript.cpp7
-rw-r--r--modules/gdscript/gdscript.h4
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp95
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp67
-rw-r--r--modules/gdscript/gdscript_byte_codegen.h32
-rw-r--r--modules/gdscript/gdscript_codegen.h5
-rw-r--r--modules/gdscript/gdscript_compiler.cpp25
-rw-r--r--modules/gdscript/gdscript_disassembler.cpp48
-rw-r--r--modules/gdscript/gdscript_editor.cpp39
-rw-r--r--modules/gdscript/gdscript_function.h11
-rw-r--r--modules/gdscript/gdscript_functions.cpp1942
-rw-r--r--modules/gdscript/gdscript_parser.cpp11
-rw-r--r--modules/gdscript/gdscript_parser.h2
-rw-r--r--modules/gdscript/gdscript_utility_functions.cpp718
-rw-r--r--modules/gdscript/gdscript_utility_functions.h (renamed from modules/gdscript/gdscript_functions.h)123
-rw-r--r--modules/gdscript/gdscript_vm.cpp89
-rw-r--r--modules/gdscript/register_types.cpp4
-rw-r--r--modules/glslang/SCsub18
-rw-r--r--modules/jpg/SCsub17
-rwxr-xr-xmodules/mbedtls/SCsub23
-rw-r--r--modules/meshoptimizer/SCsub45
-rw-r--r--modules/meshoptimizer/config.py7
-rw-r--r--modules/meshoptimizer/register_types.cpp43
-rw-r--r--modules/meshoptimizer/register_types.h37
-rw-r--r--modules/mono/build_scripts/mono_configure.py3
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs45
-rw-r--r--modules/mono/editor/bindings_generator.cpp71
-rw-r--r--modules/mono/editor/editor_internal_calls.cpp139
-rw-r--r--modules/mono/glue/base_object_glue.cpp28
-rw-r--r--modules/mono/glue/collections_glue.cpp106
-rw-r--r--modules/mono/glue/gd_glue.cpp50
-rw-r--r--modules/mono/glue/nodepath_glue.cpp22
-rw-r--r--modules/mono/glue/rid_glue.cpp6
-rw-r--r--modules/mono/glue/scene_tree_glue.cpp2
-rw-r--r--modules/mono/glue/string_glue.cpp12
-rw-r--r--modules/mono/glue/string_name_glue.cpp8
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h19
-rw-r--r--modules/mono/mono_gd/gd_mono_wasm_m2n.cpp79
-rw-r--r--modules/mono/mono_gd/gd_mono_wasm_m2n.h263
-rw-r--r--modules/mono/mono_gd/support/android_support.cpp4
-rw-r--r--modules/ogg/SCsub16
-rw-r--r--modules/opensimplex/SCsub17
-rw-r--r--modules/opus/SCsub19
-rw-r--r--modules/pvr/SCsub15
-rw-r--r--modules/pvr/image_compress_pvrtc.cpp84
-rw-r--r--modules/pvr/image_compress_pvrtc.h (renamed from editor/pvrtc_compress.h)12
-rw-r--r--modules/pvr/register_types.cpp3
-rw-r--r--modules/pvr/texture_loader_pvr.cpp58
-rw-r--r--modules/regex/SCsub18
-rw-r--r--modules/squish/SCsub16
-rw-r--r--modules/stb_vorbis/SCsub17
-rw-r--r--modules/svg/SCsub17
-rw-r--r--modules/text_server_adv/SCsub62
-rw-r--r--modules/text_server_adv/dynamic_font_adv.cpp78
-rw-r--r--modules/text_server_adv/dynamic_font_adv.h6
-rw-r--r--modules/text_server_adv/font_adv.h4
-rw-r--r--modules/text_server_adv/text_server_adv.cpp38
-rw-r--r--modules/text_server_adv/text_server_adv.h4
-rw-r--r--modules/text_server_fb/SCsub1
-rw-r--r--modules/text_server_fb/text_server_fb.cpp7
-rw-r--r--modules/theora/SCsub16
-rw-r--r--modules/tinyexr/SCsub17
-rw-r--r--modules/upnp/SCsub15
-rw-r--r--modules/vhacd/SCsub17
-rw-r--r--modules/visual_script/visual_script_editor.cpp12
-rw-r--r--modules/visual_script/visual_script_property_selector.cpp6
-rw-r--r--modules/vorbis/SCsub20
-rw-r--r--modules/webm/SCsub15
-rw-r--r--modules/webm/libvpx/SCsub2
-rw-r--r--modules/webp/SCsub16
-rw-r--r--modules/webrtc/SCsub2
-rw-r--r--modules/websocket/SCsub32
-rw-r--r--modules/xatlas_unwrap/SCsub16
-rw-r--r--platform/android/SCsub6
-rw-r--r--platform/android/detect.py2
-rw-r--r--platform/android/os_android.h42
-rw-r--r--platform/iphone/detect.py3
-rw-r--r--platform/javascript/api/javascript_tools_editor_plugin.cpp7
-rw-r--r--platform/javascript/api/javascript_tools_editor_plugin.h4
-rw-r--r--platform/javascript/detect.py14
-rw-r--r--platform/javascript/export/export.cpp23
-rw-r--r--platform/linuxbsd/detect.py3
-rw-r--r--platform/linuxbsd/display_server_x11.cpp9
-rw-r--r--platform/linuxbsd/display_server_x11.h9
-rw-r--r--platform/linuxbsd/os_linuxbsd.h34
-rw-r--r--platform/osx/detect.py4
-rw-r--r--platform/osx/os_osx.h46
-rw-r--r--platform/osx/os_osx.mm2
-rw-r--r--platform/server/detect.py2
-rw-r--r--platform/server/os_server.cpp4
-rw-r--r--platform/server/os_server.h2
-rw-r--r--platform/uwp/detect.py2
-rw-r--r--platform/uwp/os_uwp.cpp4
-rw-r--r--platform/uwp/os_uwp.h1
-rw-r--r--platform/windows/detect.py6
-rw-r--r--platform/windows/display_server_windows.cpp2
-rw-r--r--platform/windows/os_windows.cpp8
-rw-r--r--platform/windows/os_windows.h90
-rw-r--r--scene/2d/camera_2d.cpp3
-rw-r--r--scene/3d/area_3d.cpp10
-rw-r--r--scene/3d/area_3d.h4
-rw-r--r--scene/3d/audio_stream_player_3d.cpp2
-rw-r--r--scene/3d/camera_3d.cpp6
-rw-r--r--scene/3d/path_3d.cpp6
-rw-r--r--scene/3d/physics_joint_3d.cpp13
-rw-r--r--scene/3d/physics_joint_3d.h7
-rw-r--r--scene/3d/proximity_group_3d.cpp94
-rw-r--r--scene/3d/proximity_group_3d.h27
-rw-r--r--scene/3d/reflection_probe.cpp14
-rw-r--r--scene/3d/reflection_probe.h4
-rw-r--r--scene/3d/visual_instance_3d.cpp16
-rw-r--r--scene/3d/visual_instance_3d.h5
-rw-r--r--scene/SCsub18
-rw-r--r--scene/animation/SCsub21
-rw-r--r--scene/animation/animation_player.cpp84
-rw-r--r--scene/animation/animation_player.h19
-rw-r--r--scene/gui/control.cpp38
-rw-r--r--scene/gui/control.h10
-rw-r--r--scene/gui/dialogs.cpp14
-rw-r--r--scene/gui/dialogs.h6
-rw-r--r--scene/gui/file_dialog.cpp20
-rw-r--r--scene/gui/graph_edit.cpp389
-rw-r--r--scene/gui/graph_edit.h67
-rw-r--r--scene/gui/popup_menu.cpp32
-rw-r--r--scene/gui/rich_text_effect.cpp31
-rw-r--r--scene/gui/rich_text_effect.h29
-rw-r--r--scene/gui/rich_text_label.cpp2724
-rw-r--r--scene/gui/rich_text_label.h268
-rw-r--r--scene/gui/text_edit.cpp25
-rw-r--r--scene/gui/text_edit.h2
-rw-r--r--scene/gui/texture_progress_bar.cpp (renamed from scene/gui/texture_progress.cpp)114
-rw-r--r--scene/gui/texture_progress_bar.h (renamed from scene/gui/texture_progress.h)16
-rw-r--r--scene/main/scene_tree.cpp4
-rw-r--r--scene/main/viewport.cpp25
-rw-r--r--scene/main/viewport.h8
-rw-r--r--scene/register_scene_types.cpp5
-rw-r--r--scene/resources/SCsub21
-rw-r--r--scene/resources/animation.cpp8
-rw-r--r--scene/resources/animation.h4
-rw-r--r--scene/resources/bit_map.cpp6
-rw-r--r--scene/resources/default_theme/default_theme.cpp53
-rw-r--r--scene/resources/default_theme/icon_grid_minimap.pngbin0 -> 640 bytes
-rw-r--r--scene/resources/default_theme/theme_data.h4
-rw-r--r--scene/resources/font.cpp44
-rw-r--r--scene/resources/font.h4
-rw-r--r--scene/resources/mesh.cpp101
-rw-r--r--scene/resources/mesh.h18
-rw-r--r--scene/resources/surface_tool.cpp360
-rw-r--r--scene/resources/surface_tool.h28
-rw-r--r--scene/resources/texture.cpp4
-rw-r--r--scene/resources/theme.cpp112
-rw-r--r--scene/resources/theme.h14
-rw-r--r--servers/camera/SCsub2
-rw-r--r--servers/physics_2d/area_pair_2d_sw.cpp2
-rw-r--r--servers/physics_2d/body_2d_sw.cpp6
-rw-r--r--servers/physics_2d/body_2d_sw.h12
-rw-r--r--servers/physics_2d/body_pair_2d_sw.cpp4
-rw-r--r--servers/physics_2d/joints_2d_sw.cpp12
-rw-r--r--servers/physics_2d/physics_server_2d_sw.cpp2
-rw-r--r--servers/physics_2d/step_2d_sw.cpp6
-rw-r--r--servers/physics_3d/body_pair_3d_sw.cpp8
-rw-r--r--servers/physics_3d/physics_server_3d_sw.h3
-rw-r--r--servers/physics_server_3d.h3
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp4
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_forward.cpp99
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_forward.h6
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp17
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.h12
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.cpp401
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.h194
-rw-r--r--servers/rendering/renderer_rd/shaders/SCsub1
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward.glsl37
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_inc.glsl6
-rw-r--r--servers/rendering/renderer_rd/shaders/sdfgi_fields.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/skeleton.glsl199
-rw-r--r--servers/rendering/renderer_scene.h5
-rw-r--r--servers/rendering/renderer_scene_cull.cpp124
-rw-r--r--servers/rendering/renderer_scene_cull.h15
-rw-r--r--servers/rendering/renderer_scene_render.h12
-rw-r--r--servers/rendering/renderer_storage.h14
-rw-r--r--servers/rendering/renderer_viewport.cpp12
-rw-r--r--servers/rendering/renderer_viewport.h4
-rw-r--r--servers/rendering/rendering_device.cpp2
-rw-r--r--servers/rendering/rendering_device.h2
-rw-r--r--servers/rendering/rendering_server_default.h8
-rw-r--r--servers/rendering/rendering_server_wrap_mt.h10
-rw-r--r--servers/rendering_server.cpp15
-rw-r--r--servers/rendering_server.h11
-rw-r--r--servers/text_server.cpp12
-rw-r--r--servers/text_server.h20
-rw-r--r--tests/data/translations.csv3
-rw-r--r--tests/test_aabb.h8
-rw-r--r--tests/test_file_access.h64
-rw-r--r--tests/test_list.h270
-rw-r--r--tests/test_main.cpp1
-rw-r--r--tests/test_rect2.h40
-rw-r--r--thirdparty/README.md21
-rw-r--r--thirdparty/bullet/Bullet3OpenCL/NarrowphaseCollision/b3OptimizedBvh.cpp9
-rw-r--r--thirdparty/bullet/Bullet3Serialize/Bullet2FileLoader/b3File.cpp6
-rw-r--r--thirdparty/bullet/BulletCollision/BroadphaseCollision/btQuantizedBvh.cpp10
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionObject.h11
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp8
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp18
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionShapes/btCollisionShape.h13
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp6
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h10
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionShapes/btOptimizedBvh.cpp9
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionShapes/btSdfCollisionShape.cpp5
-rw-r--r--thirdparty/bullet/BulletCollision/Gimpact/btGImpactShape.h10
-rw-r--r--thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btGjkEpa2.cpp3
-rw-r--r--thirdparty/bullet/BulletDynamics/ConstraintSolver/btBatchedConstraints.cpp2
-rw-r--r--thirdparty/bullet/BulletDynamics/ConstraintSolver/btContactSolverInfo.h6
-rw-r--r--thirdparty/bullet/BulletDynamics/Dynamics/btRigidBody.h10
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBody.cpp563
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBody.h84
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp3
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraint.h23
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp14
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h2
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyFixedConstraint.cpp4
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyGearConstraint.cpp2
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp2
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.h16
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp4
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyLink.h3
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyLinkCollider.h17
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp4
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySliderConstraint.cpp4
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp2
-rw-r--r--thirdparty/bullet/BulletSoftBody/DeformableBodyInplaceSolverIslandCallback.h9
-rw-r--r--thirdparty/bullet/BulletSoftBody/btCGProjection.h146
-rw-r--r--thirdparty/bullet/BulletSoftBody/btConjugateGradient.h229
-rw-r--r--thirdparty/bullet/BulletSoftBody/btConjugateResidual.h256
-rw-r--r--thirdparty/bullet/BulletSoftBody/btDeformableBackwardEulerObjective.cpp380
-rw-r--r--thirdparty/bullet/BulletSoftBody/btDeformableBackwardEulerObjective.h299
-rw-r--r--thirdparty/bullet/BulletSoftBody/btDeformableBodySolver.cpp757
-rw-r--r--thirdparty/bullet/BulletSoftBody/btDeformableBodySolver.h250
-rw-r--r--thirdparty/bullet/BulletSoftBody/btDeformableContactConstraint.cpp979
-rw-r--r--thirdparty/bullet/BulletSoftBody/btDeformableContactConstraint.h386
-rw-r--r--thirdparty/bullet/BulletSoftBody/btDeformableContactProjection.cpp761
-rw-r--r--thirdparty/bullet/BulletSoftBody/btDeformableContactProjection.h101
-rw-r--r--thirdparty/bullet/BulletSoftBody/btDeformableCorotatedForce.h189
-rw-r--r--thirdparty/bullet/BulletSoftBody/btDeformableGravityForce.h160
-rw-r--r--thirdparty/bullet/BulletSoftBody/btDeformableLagrangianForce.h675
-rw-r--r--thirdparty/bullet/BulletSoftBody/btDeformableLinearElasticityForce.h748
-rw-r--r--thirdparty/bullet/BulletSoftBody/btDeformableMassSpringForce.h544
-rw-r--r--thirdparty/bullet/BulletSoftBody/btDeformableMousePickingForce.h255
-rw-r--r--thirdparty/bullet/BulletSoftBody/btDeformableMultiBodyConstraintSolver.cpp207
-rw-r--r--thirdparty/bullet/BulletSoftBody/btDeformableMultiBodyConstraintSolver.h46
-rw-r--r--thirdparty/bullet/BulletSoftBody/btDeformableMultiBodyDynamicsWorld.cpp1070
-rw-r--r--thirdparty/bullet/BulletSoftBody/btDeformableMultiBodyDynamicsWorld.h505
-rw-r--r--thirdparty/bullet/BulletSoftBody/btDeformableNeoHookeanForce.h703
-rw-r--r--thirdparty/bullet/BulletSoftBody/btKrylovSolver.h107
-rw-r--r--thirdparty/bullet/BulletSoftBody/btPreconditioner.h471
-rw-r--r--thirdparty/bullet/BulletSoftBody/btSoftBody.cpp1413
-rw-r--r--thirdparty/bullet/BulletSoftBody/btSoftBody.h418
-rw-r--r--thirdparty/bullet/BulletSoftBody/btSoftBodyHelpers.cpp729
-rw-r--r--thirdparty/bullet/BulletSoftBody/btSoftBodyHelpers.h30
-rw-r--r--thirdparty/bullet/BulletSoftBody/btSoftBodyInternals.h2074
-rw-r--r--thirdparty/bullet/BulletSoftBody/btSoftBodySolvers.h2
-rw-r--r--thirdparty/bullet/BulletSoftBody/btSoftMultiBodyDynamicsWorld.cpp5
-rw-r--r--thirdparty/bullet/BulletSoftBody/btSparseSDF.h68
-rw-r--r--thirdparty/bullet/BulletSoftBody/poly34.cpp742
-rw-r--r--thirdparty/bullet/BulletSoftBody/poly34.h18
-rw-r--r--thirdparty/bullet/LinearMath/btAlignedAllocator.cpp4
-rw-r--r--thirdparty/bullet/LinearMath/btAlignedAllocator.h4
-rw-r--r--thirdparty/bullet/LinearMath/btConvexHullComputer.cpp6
-rw-r--r--thirdparty/bullet/LinearMath/btConvexHullComputer.h3
-rw-r--r--thirdparty/bullet/LinearMath/btReducedVector.h2
-rw-r--r--thirdparty/bullet/LinearMath/btScalar.h2
-rw-r--r--thirdparty/bullet/LinearMath/btSerializer.h6
-rw-r--r--thirdparty/mbedtls/include/mbedtls/bignum.h4
-rw-r--r--thirdparty/mbedtls/include/mbedtls/ccm.h4
-rw-r--r--thirdparty/mbedtls/include/mbedtls/config.h2
-rw-r--r--thirdparty/mbedtls/include/mbedtls/ctr_drbg.h8
-rw-r--r--thirdparty/mbedtls/include/mbedtls/gcm.h4
-rw-r--r--thirdparty/mbedtls/include/mbedtls/hmac_drbg.h7
-rw-r--r--thirdparty/mbedtls/include/mbedtls/sha512.h4
-rw-r--r--thirdparty/mbedtls/include/mbedtls/ssl.h2
-rw-r--r--thirdparty/mbedtls/include/mbedtls/version.h8
-rw-r--r--thirdparty/mbedtls/library/aes.c193
-rw-r--r--thirdparty/mbedtls/library/bignum.c13
-rw-r--r--thirdparty/mbedtls/library/cipher_wrap.c20
-rw-r--r--thirdparty/mbedtls/library/cmac.c2
-rw-r--r--thirdparty/mbedtls/library/ctr_drbg.c11
-rw-r--r--thirdparty/mbedtls/library/ecp_curves.c2
-rw-r--r--thirdparty/mbedtls/library/entropy_poll.c2
-rw-r--r--thirdparty/mbedtls/library/error.c15
-rw-r--r--thirdparty/mbedtls/library/hmac_drbg.c11
-rw-r--r--thirdparty/mbedtls/library/md2.c3
-rw-r--r--thirdparty/mbedtls/library/md4.c154
-rw-r--r--thirdparty/mbedtls/library/md5.c196
-rw-r--r--thirdparty/mbedtls/library/pem.c4
-rw-r--r--thirdparty/mbedtls/library/pkcs5.c23
-rw-r--r--thirdparty/mbedtls/library/pkparse.c2
-rw-r--r--thirdparty/mbedtls/library/platform_util.c4
-rw-r--r--thirdparty/mbedtls/library/ripemd160.c238
-rw-r--r--thirdparty/mbedtls/library/rsa.c13
-rw-r--r--thirdparty/mbedtls/library/sha1.c228
-rw-r--r--thirdparty/mbedtls/library/sha256.c97
-rw-r--r--thirdparty/mbedtls/library/sha512.c84
-rw-r--r--thirdparty/mbedtls/library/ssl_srv.c9
-rw-r--r--thirdparty/mbedtls/library/ssl_tls.c21
-rw-r--r--thirdparty/mbedtls/library/threading.c4
-rw-r--r--thirdparty/mbedtls/library/x509_crt.c1
-rw-r--r--thirdparty/meshoptimizer/LICENSE.md21
-rw-r--r--thirdparty/meshoptimizer/allocator.cpp8
-rw-r--r--thirdparty/meshoptimizer/clusterizer.cpp351
-rw-r--r--thirdparty/meshoptimizer/indexcodec.cpp752
-rw-r--r--thirdparty/meshoptimizer/indexgenerator.cpp347
-rw-r--r--thirdparty/meshoptimizer/meshoptimizer.h951
-rw-r--r--thirdparty/meshoptimizer/overdrawanalyzer.cpp230
-rw-r--r--thirdparty/meshoptimizer/overdrawoptimizer.cpp333
-rw-r--r--thirdparty/meshoptimizer/patches/simplifier_get_resulting_error.patch96
-rw-r--r--thirdparty/meshoptimizer/simplifier.cpp1562
-rw-r--r--thirdparty/meshoptimizer/spatialorder.cpp194
-rw-r--r--thirdparty/meshoptimizer/stripifier.cpp295
-rw-r--r--thirdparty/meshoptimizer/vcacheanalyzer.cpp73
-rw-r--r--thirdparty/meshoptimizer/vcacheoptimizer.cpp473
-rw-r--r--thirdparty/meshoptimizer/vertexcodec.cpp1265
-rw-r--r--thirdparty/meshoptimizer/vertexfilter.cpp825
-rw-r--r--thirdparty/meshoptimizer/vfetchanalyzer.cpp58
-rw-r--r--thirdparty/meshoptimizer/vfetchoptimizer.cpp74
-rw-r--r--thirdparty/rvo2/API.h (renamed from thirdparty/rvo2/src/API.h)0
-rw-r--r--thirdparty/rvo2/Agent.cpp (renamed from thirdparty/rvo2/src/Agent.cpp)0
-rw-r--r--thirdparty/rvo2/Agent.h (renamed from thirdparty/rvo2/src/Agent.h)0
-rw-r--r--thirdparty/rvo2/Definitions.h (renamed from thirdparty/rvo2/src/Definitions.h)0
-rw-r--r--thirdparty/rvo2/KdTree.cpp (renamed from thirdparty/rvo2/src/KdTree.cpp)0
-rw-r--r--thirdparty/rvo2/KdTree.h (renamed from thirdparty/rvo2/src/KdTree.h)0
-rw-r--r--thirdparty/rvo2/Vector3.h (renamed from thirdparty/rvo2/src/Vector3.h)0
563 files changed, 33125 insertions, 16229 deletions
diff --git a/SConstruct b/SConstruct
index 10f961cff8..2281b8a77f 100644
--- a/SConstruct
+++ b/SConstruct
@@ -115,7 +115,6 @@ opts.Add(EnumVariable("optimize", "Optimization type", "speed", ("speed", "size"
opts.Add(BoolVariable("tools", "Build the tools (a.k.a. the Godot editor)", True))
opts.Add(BoolVariable("tests", "Build the unit tests", False))
opts.Add(BoolVariable("use_lto", "Use link-time optimization", False))
-opts.Add(BoolVariable("use_precise_math_checks", "Math checks use very precise epsilon (debug option)", False))
# Components
opts.Add(BoolVariable("deprecated", "Enable deprecated features", True))
@@ -131,14 +130,13 @@ opts.Add(BoolVariable("werror", "Treat compiler warnings as errors", False))
opts.Add(BoolVariable("dev", "If yes, alias for verbose=yes warnings=extra werror=yes", False))
opts.Add("extra_suffix", "Custom extra suffix added to the base filename of all generated binary files", "")
opts.Add(BoolVariable("vsproj", "Generate a Visual Studio solution", False))
-opts.Add(EnumVariable("macports_clang", "Build using Clang from MacPorts", "no", ("no", "5.0", "devel")))
opts.Add(BoolVariable("disable_3d", "Disable 3D nodes for a smaller executable", False))
opts.Add(BoolVariable("disable_advanced_gui", "Disable advanced GUI nodes and behaviors", False))
opts.Add(BoolVariable("no_editor_splash", "Don't use the custom splash screen for the editor", False))
opts.Add("system_certs_path", "Use this path as SSL certificates default for editor (for package maintainers)", "")
+opts.Add(BoolVariable("use_precise_math_checks", "Math checks use very precise epsilon (debug option)", False))
# Thirdparty libraries
-# opts.Add(BoolVariable('builtin_assimp', "Use the built-in Assimp library", True))
opts.Add(BoolVariable("builtin_bullet", "Use the built-in Bullet library", True))
opts.Add(BoolVariable("builtin_certs", "Use the built-in SSL certificates bundles", True))
opts.Add(BoolVariable("builtin_enet", "Use the built-in ENet library", True))
@@ -176,16 +174,54 @@ opts.Add("CFLAGS", "Custom flags for the C compiler")
opts.Add("CXXFLAGS", "Custom flags for the C++ compiler")
opts.Add("LINKFLAGS", "Custom flags for the linker")
-# add platform specific options
+# Update the environment to have all above options defined
+# in following code (especially platform and custom_modules).
+opts.Update(env_base)
+
+# Platform selection: validate input, and add options.
+
+selected_platform = ""
+
+if env_base["platform"] != "":
+ selected_platform = env_base["platform"]
+elif env_base["p"] != "":
+ selected_platform = env_base["p"]
+else:
+ # Missing `platform` argument, try to detect platform automatically
+ if sys.platform.startswith("linux"):
+ selected_platform = "linuxbsd"
+ elif sys.platform == "darwin":
+ selected_platform = "osx"
+ elif sys.platform == "win32":
+ selected_platform = "windows"
+ else:
+ print("Could not detect platform automatically. Supported platforms:")
+ for x in platform_list:
+ print("\t" + x)
+ print("\nPlease run SCons again and select a valid platform: platform=<string>")
+
+ if selected_platform != "":
+ print("Automatically detected platform: " + selected_platform)
+
+if selected_platform in ["linux", "bsd", "x11"]:
+ if selected_platform == "x11":
+ # Deprecated alias kept for compatibility.
+ print('Platform "x11" has been renamed to "linuxbsd" in Godot 4.0. Building for platform "linuxbsd".')
+ # Alias for convenience.
+ selected_platform = "linuxbsd"
+
+# Make sure to update this to the found, valid platform as it's used through the buildsystem as the reference.
+# It should always be re-set after calling `opts.Update()` otherwise it uses the original input value.
+env_base["platform"] = selected_platform
-for k in platform_opts.keys():
- opt_list = platform_opts[k]
- for o in opt_list:
- opts.Add(o)
+# Add platform-specific options.
+if selected_platform in platform_opts:
+ for opt in platform_opts[selected_platform]:
+ opts.Add(opt)
-# Update the environment now as the "custom_modules" option may be
-# defined in a file rather than specified via the command line.
+# Update the environment to take platform-specific options into account.
opts.Update(env_base)
+env_base["platform"] = selected_platform # Must always be re-set after calling opts.Update().
# Detect modules.
modules_detected = OrderedDict()
@@ -225,6 +261,7 @@ methods.write_modules(modules_detected)
# Update the environment again after all the module options are added.
opts.Update(env_base)
+env_base["platform"] = selected_platform # Must always be re-set after calling opts.Update().
Help(opts.GenerateHelpText(env_base))
# add default include paths
@@ -261,41 +298,6 @@ if env_base["no_editor_splash"]:
if not env_base["deprecated"]:
env_base.Append(CPPDEFINES=["DISABLE_DEPRECATED"])
-env_base.platforms = {}
-
-selected_platform = ""
-
-if env_base["platform"] != "":
- selected_platform = env_base["platform"]
-elif env_base["p"] != "":
- selected_platform = env_base["p"]
- env_base["platform"] = selected_platform
-else:
- # Missing `platform` argument, try to detect platform automatically
- if sys.platform.startswith("linux"):
- selected_platform = "linuxbsd"
- elif sys.platform == "darwin":
- selected_platform = "osx"
- elif sys.platform == "win32":
- selected_platform = "windows"
- else:
- print("Could not detect platform automatically. Supported platforms:")
- for x in platform_list:
- print("\t" + x)
- print("\nPlease run SCons again and select a valid platform: platform=<string>")
-
- if selected_platform != "":
- print("Automatically detected platform: " + selected_platform)
- env_base["platform"] = selected_platform
-
-if selected_platform in ["linux", "bsd", "x11"]:
- if selected_platform == "x11":
- # Deprecated alias kept for compatibility.
- print('Platform "x11" has been renamed to "linuxbsd" in Godot 4.0. Building for platform "linuxbsd".')
- # Alias for convenience.
- selected_platform = "linuxbsd"
- env_base["platform"] = selected_platform
-
if selected_platform in platform_list:
tmppath = "./platform/" + selected_platform
sys.path.insert(0, tmppath)
@@ -530,13 +532,13 @@ if selected_platform in platform_list:
doc_path = config.get_doc_path()
for c in doc_classes:
env.doc_class_path[c] = path + "/" + doc_path
- except:
+ except Exception:
pass
# Get icon paths (if present)
try:
icons_path = config.get_icons_path()
env.module_icons_paths.append(path + "/" + icons_path)
- except:
+ except Exception:
# Default path for module icons
env.module_icons_paths.append(path + "/" + "icons")
modules_enabled[name] = path
diff --git a/core/SCsub b/core/SCsub
index 78a4395619..c9f84a9a00 100644
--- a/core/SCsub
+++ b/core/SCsub
@@ -25,7 +25,7 @@ if "SCRIPT_AES256_ENCRYPTION_KEY" in os.environ:
txts = "0x" + e[i * 2 : i * 2 + 2]
try:
int(txts, 16)
- except:
+ except Exception:
ec_valid = False
txt += txts
if not ec_valid:
@@ -38,6 +38,9 @@ with open("script_encryption_key.gen.cpp", "w") as f:
# Add required thirdparty code.
+
+thirdparty_obj = []
+
env_thirdparty = env.Clone()
env_thirdparty.disable_warnings()
@@ -55,7 +58,7 @@ thirdparty_misc_sources = [
"clipper.cpp",
]
thirdparty_misc_sources = [thirdparty_misc_dir + file for file in thirdparty_misc_sources]
-env_thirdparty.add_source_files(env.core_sources, thirdparty_misc_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_misc_sources)
# Zlib library, can be unbundled
if env["builtin_zlib"]:
@@ -81,14 +84,14 @@ if env["builtin_zlib"]:
if env["target"] == "debug":
env_thirdparty.Append(CPPDEFINES=["ZLIB_DEBUG"])
- env_thirdparty.add_source_files(env.core_sources, thirdparty_zlib_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_zlib_sources)
# Minizip library, could be unbundled in theory
# However, our version has some custom modifications, so it won't compile with the system one
thirdparty_minizip_dir = "#thirdparty/minizip/"
thirdparty_minizip_sources = ["ioapi.c", "unzip.c", "zip.c"]
thirdparty_minizip_sources = [thirdparty_minizip_dir + file for file in thirdparty_minizip_sources]
-env_thirdparty.add_source_files(env.core_sources, thirdparty_minizip_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_minizip_sources)
# Zstd library, can be unbundled in theory
# though we currently use some private symbols
@@ -130,10 +133,14 @@ if env["builtin_zstd"]:
# Also needed in main env includes will trigger warnings
env.Append(CPPDEFINES=["ZSTD_STATIC_LINKING_ONLY"])
- env_thirdparty.add_source_files(env.core_sources, thirdparty_zstd_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_zstd_sources)
+
+env.core_sources += thirdparty_obj
+
+
+# Godot source files
-# Godot's own sources
env.add_source_files(env.core_sources, "*.cpp")
# Certificates
@@ -185,3 +192,6 @@ SConscript("error/SCsub")
# Build it all as a library
lib = env.add_library("core", env.core_sources)
env.Prepend(LIBS=[lib])
+
+# Needed to force rebuilding the core files when the thirdparty code is updated.
+env.Depends(lib, thirdparty_obj)
diff --git a/core/crypto/SCsub b/core/crypto/SCsub
index da4a9c9381..4f3104d84b 100644
--- a/core/crypto/SCsub
+++ b/core/crypto/SCsub
@@ -6,6 +6,7 @@ env_crypto = env.Clone()
is_builtin = env["builtin_mbedtls"]
has_module = env["module_mbedtls_enabled"]
+thirdparty_obj = []
if is_builtin or not has_module:
# Use our headers for builtin or if the module is not going to be compiled.
@@ -35,6 +36,16 @@ if not has_module:
"godot_core_mbedtls_platform.c",
]
thirdparty_mbedtls_sources = [thirdparty_mbedtls_dir + file for file in thirdparty_mbedtls_sources]
- env_thirdparty.add_source_files(env.core_sources, thirdparty_mbedtls_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_mbedtls_sources)
+ env.core_sources += thirdparty_obj
-env_crypto.add_source_files(env.core_sources, "*.cpp")
+
+# Godot source files
+
+core_obj = []
+
+env_crypto.add_source_files(core_obj, "*.cpp")
+env.core_sources += core_obj
+
+# Needed to force rebuilding the core files when the thirdparty library is updated.
+env.Depends(core_obj, thirdparty_obj)
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index e04e642f6b..82bfaa82a5 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -213,7 +213,7 @@ String InputEventWithModifiers::as_text() const {
if (!mod_names.empty()) {
return String("+").join(mod_names);
} else {
- return "None";
+ return "";
}
}
@@ -369,11 +369,19 @@ String InputEventKey::to_string() {
String p = is_pressed() ? "true" : "false";
String e = is_echo() ? "true" : "false";
+ String kc = "";
+ String physical = "false";
if (keycode == 0) {
- return vformat("InputEventKey: keycode=%s mods=%s physical=%s pressed=%s echo=%s", itos(physical_keycode) + " " + keycode_get_string(physical_keycode), InputEventWithModifiers::as_text(), "true", p, e);
+ kc = itos(physical_keycode) + " " + keycode_get_string(physical_keycode);
+ physical = "true";
} else {
- return vformat("InputEventKey: keycode=%s mods=%s physical=%s pressed=%s echo=%s", itos(keycode) + " " + keycode_get_string(keycode), InputEventWithModifiers::as_text(), "false", p, e);
+ kc = itos(keycode) + " " + keycode_get_string(keycode);
}
+
+ String mods = InputEventWithModifiers::as_text();
+ mods = mods == "" ? TTR("None") : mods;
+
+ return vformat("InputEventKey: keycode=%s mods=%s physical=%s pressed=%s echo=%s", kc, mods, physical, p, e);
}
bool InputEventKey::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const {
@@ -633,7 +641,12 @@ String InputEventMouseButton::to_string() {
break;
}
- return vformat("InputEventMouseButton: button_index=%s pressed=%s position=(%s) button_mask=%s doubleclick=%s", button_index, p, String(get_position()), itos(get_button_mask()), d);
+ String mods = InputEventWithModifiers::as_text();
+ 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);
}
void InputEventMouseButton::_bind_methods() {
diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp
index 4424192af2..b06b3c078f 100644
--- a/core/io/file_access_compressed.cpp
+++ b/core/io/file_access_compressed.cpp
@@ -327,14 +327,14 @@ Error FileAccessCompressed::get_error() const {
void FileAccessCompressed::flush() {
ERR_FAIL_COND_MSG(!f, "File must be opened before use.");
- ERR_FAIL_COND_MSG(!writing, "File has not been opened in read mode.");
+ ERR_FAIL_COND_MSG(!writing, "File has not been opened in write mode.");
// compressed files keep data in memory till close()
}
void FileAccessCompressed::store_8(uint8_t p_dest) {
ERR_FAIL_COND_MSG(!f, "File must be opened before use.");
- ERR_FAIL_COND_MSG(!writing, "File has not been opened in read mode.");
+ ERR_FAIL_COND_MSG(!writing, "File has not been opened in write mode.");
WRITE_FIT(1);
write_ptr[write_pos++] = p_dest;
diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp
index 2ac24d5169..cf5800b472 100644
--- a/core/io/file_access_encrypted.cpp
+++ b/core/io/file_access_encrypted.cpp
@@ -256,7 +256,7 @@ Error FileAccessEncrypted::get_error() const {
}
void FileAccessEncrypted::store_buffer(const uint8_t *p_src, int p_length) {
- ERR_FAIL_COND_MSG(!writing, "File has not been opened in read mode.");
+ ERR_FAIL_COND_MSG(!writing, "File has not been opened in write mode.");
if (pos < data.size()) {
for (int i = 0; i < p_length; i++) {
@@ -272,13 +272,13 @@ void FileAccessEncrypted::store_buffer(const uint8_t *p_src, int p_length) {
}
void FileAccessEncrypted::flush() {
- ERR_FAIL_COND_MSG(!writing, "File has not been opened in read mode.");
+ ERR_FAIL_COND_MSG(!writing, "File has not been opened in write mode.");
// encrypted files keep data in memory till close()
}
void FileAccessEncrypted::store_8(uint8_t p_dest) {
- ERR_FAIL_COND_MSG(!writing, "File has not been opened in read mode.");
+ ERR_FAIL_COND_MSG(!writing, "File has not been opened in write mode.");
if (pos < data.size()) {
data.write[pos] = p_dest;
diff --git a/core/io/image.cpp b/core/io/image.cpp
index 6dde25af32..56d84325b5 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -66,10 +66,10 @@ const char *Image::format_names[Image::FORMAT_MAX] = {
"BPTC_RGBA",
"BPTC_RGBF",
"BPTC_RGBFU",
- "PVRTC2", //pvrtc
- "PVRTC2A",
- "PVRTC4",
- "PVRTC4A",
+ "PVRTC1_2", //pvrtc
+ "PVRTC1_2A",
+ "PVRTC1_4",
+ "PVRTC1_4A",
"ETC", //etc1
"ETC2_R11", //etc2
"ETC2_R11S", //signed", NOT srgb.
@@ -155,13 +155,13 @@ int Image::get_format_pixel_size(Format p_format) {
return 1; //float /
case FORMAT_BPTC_RGBFU:
return 1; //unsigned float
- case FORMAT_PVRTC2:
+ case FORMAT_PVRTC1_2:
return 1; //pvrtc
- case FORMAT_PVRTC2A:
+ case FORMAT_PVRTC1_2A:
return 1;
- case FORMAT_PVRTC4:
+ case FORMAT_PVRTC1_4:
return 1;
- case FORMAT_PVRTC4A:
+ case FORMAT_PVRTC1_4A:
return 1;
case FORMAT_ETC:
return 1; //etc1
@@ -200,13 +200,13 @@ void Image::get_format_min_pixel_size(Format p_format, int &r_w, int &r_h) {
r_w = 4;
r_h = 4;
} break;
- case FORMAT_PVRTC2:
- case FORMAT_PVRTC2A: {
+ case FORMAT_PVRTC1_2:
+ case FORMAT_PVRTC1_2A: {
r_w = 16;
r_h = 8;
} break;
- case FORMAT_PVRTC4A:
- case FORMAT_PVRTC4: {
+ case FORMAT_PVRTC1_4A:
+ case FORMAT_PVRTC1_4: {
r_w = 8;
r_h = 8;
} break;
@@ -242,9 +242,9 @@ void Image::get_format_min_pixel_size(Format p_format, int &r_w, int &r_h) {
}
int Image::get_format_pixel_rshift(Format p_format) {
- if (p_format == FORMAT_DXT1 || p_format == FORMAT_RGTC_R || p_format == FORMAT_PVRTC4 || p_format == FORMAT_PVRTC4A || p_format == FORMAT_ETC || p_format == FORMAT_ETC2_R11 || p_format == FORMAT_ETC2_R11S || p_format == FORMAT_ETC2_RGB8 || p_format == FORMAT_ETC2_RGB8A1) {
+ if (p_format == FORMAT_DXT1 || p_format == FORMAT_RGTC_R || p_format == FORMAT_PVRTC1_4 || p_format == FORMAT_PVRTC1_4A || p_format == FORMAT_ETC || p_format == FORMAT_ETC2_R11 || p_format == FORMAT_ETC2_R11S || p_format == FORMAT_ETC2_RGB8 || p_format == FORMAT_ETC2_RGB8A1) {
return 1;
- } else if (p_format == FORMAT_PVRTC2 || p_format == FORMAT_PVRTC2A) {
+ } else if (p_format == FORMAT_PVRTC1_2 || p_format == FORMAT_PVRTC1_2A) {
return 2;
} else {
return 0;
@@ -261,12 +261,12 @@ int Image::get_format_block_size(Format p_format) {
return 4;
}
- case FORMAT_PVRTC2:
- case FORMAT_PVRTC2A: {
+ case FORMAT_PVRTC1_2:
+ case FORMAT_PVRTC1_2A: {
return 4;
}
- case FORMAT_PVRTC4A:
- case FORMAT_PVRTC4: {
+ case FORMAT_PVRTC1_4A:
+ case FORMAT_PVRTC1_4: {
return 4;
}
case FORMAT_ETC: {
@@ -993,7 +993,7 @@ bool Image::is_size_po2() const {
return uint32_t(width) == next_power_of_2(width) && uint32_t(height) == next_power_of_2(height);
}
-void Image::resize_to_po2(bool p_square) {
+void Image::resize_to_po2(bool p_square, Interpolation p_interpolation) {
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot resize in compressed or custom image formats.");
int w = next_power_of_2(width);
@@ -1008,7 +1008,7 @@ void Image::resize_to_po2(bool p_square) {
}
}
- resize(w, h);
+ resize(w, h, p_interpolation);
}
void Image::resize(int p_width, int p_height, Interpolation p_interpolation) {
@@ -2216,8 +2216,8 @@ bool Image::is_invisible() const {
} break;
- case FORMAT_PVRTC2A:
- case FORMAT_PVRTC4A:
+ case FORMAT_PVRTC1_2A:
+ case FORMAT_PVRTC1_4A:
case FORMAT_DXT3:
case FORMAT_DXT5: {
detected = true;
@@ -2258,8 +2258,8 @@ Image::AlphaMode Image::detect_alpha() const {
}
} break;
- case FORMAT_PVRTC2A:
- case FORMAT_PVRTC4A:
+ case FORMAT_PVRTC1_2A:
+ case FORMAT_PVRTC1_4A:
case FORMAT_DXT3:
case FORMAT_DXT5: {
detected = true;
@@ -2355,7 +2355,7 @@ Error Image::decompress() {
_image_decompress_bc(this);
} else if (format >= FORMAT_BPTC_RGBA && format <= FORMAT_BPTC_RGBFU && _image_decompress_bptc) {
_image_decompress_bptc(this);
- } else if (format >= FORMAT_PVRTC2 && format <= FORMAT_PVRTC4A && _image_decompress_pvrtc) {
+ } else if (format >= FORMAT_PVRTC1_2 && format <= FORMAT_PVRTC1_4A && _image_decompress_pvrtc) {
_image_decompress_pvrtc(this);
} else if (format == FORMAT_ETC && _image_decompress_etc1) {
_image_decompress_etc1(this);
@@ -2377,13 +2377,9 @@ Error Image::compress_from_channels(CompressMode p_mode, UsedChannels p_channels
ERR_FAIL_COND_V(!_image_compress_bc_func, ERR_UNAVAILABLE);
_image_compress_bc_func(this, p_lossy_quality, p_channels);
} break;
- case COMPRESS_PVRTC2: {
- ERR_FAIL_COND_V(!_image_compress_pvrtc2_func, ERR_UNAVAILABLE);
- _image_compress_pvrtc2_func(this);
- } break;
- case COMPRESS_PVRTC4: {
- ERR_FAIL_COND_V(!_image_compress_pvrtc4_func, ERR_UNAVAILABLE);
- _image_compress_pvrtc4_func(this);
+ case COMPRESS_PVRTC1_4: {
+ ERR_FAIL_COND_V(!_image_compress_pvrtc1_4bpp_func, ERR_UNAVAILABLE);
+ _image_compress_pvrtc1_4bpp_func(this);
} break;
case COMPRESS_ETC: {
ERR_FAIL_COND_V(!_image_compress_etc1_func, ERR_UNAVAILABLE);
@@ -2484,7 +2480,7 @@ void Image::blit_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Po
ERR_FAIL_COND(format != p_src->format);
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot blit_rect in compressed or custom image formats.");
- Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).clip(p_src_rect);
+ Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).intersection(p_src_rect);
if (p_dest.x < 0) {
clipped_src_rect.position.x = ABS(p_dest.x);
@@ -2498,7 +2494,7 @@ void Image::blit_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Po
}
Point2 src_underscan = Point2(MIN(0, p_src_rect.position.x), MIN(0, p_src_rect.position.y));
- Rect2i dest_rect = Rect2i(0, 0, width, height).clip(Rect2i(p_dest - src_underscan, clipped_src_rect.size));
+ Rect2i dest_rect = Rect2i(0, 0, width, height).intersection(Rect2i(p_dest - src_underscan, clipped_src_rect.size));
uint8_t *wp = data.ptrw();
uint8_t *dst_data_ptr = wp;
@@ -2539,7 +2535,7 @@ void Image::blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, co
ERR_FAIL_COND_MSG(p_src->height != p_mask->height, "Source image height is different from mask height.");
ERR_FAIL_COND(format != p_src->format);
- Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).clip(p_src_rect);
+ Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).intersection(p_src_rect);
if (p_dest.x < 0) {
clipped_src_rect.position.x = ABS(p_dest.x);
@@ -2553,7 +2549,7 @@ void Image::blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, co
}
Point2 src_underscan = Point2(MIN(0, p_src_rect.position.x), MIN(0, p_src_rect.position.y));
- Rect2i dest_rect = Rect2i(0, 0, width, height).clip(Rect2i(p_dest - src_underscan, clipped_src_rect.size));
+ Rect2i dest_rect = Rect2i(0, 0, width, height).intersection(Rect2i(p_dest - src_underscan, clipped_src_rect.size));
uint8_t *wp = data.ptrw();
uint8_t *dst_data_ptr = wp;
@@ -2593,7 +2589,7 @@ void Image::blend_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const P
ERR_FAIL_COND(srcdsize == 0);
ERR_FAIL_COND(format != p_src->format);
- Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).clip(p_src_rect);
+ Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).intersection(p_src_rect);
if (p_dest.x < 0) {
clipped_src_rect.position.x = ABS(p_dest.x);
@@ -2607,7 +2603,7 @@ void Image::blend_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const P
}
Point2 src_underscan = Point2(MIN(0, p_src_rect.position.x), MIN(0, p_src_rect.position.y));
- Rect2i dest_rect = Rect2i(0, 0, width, height).clip(Rect2i(p_dest - src_underscan, clipped_src_rect.size));
+ Rect2i dest_rect = Rect2i(0, 0, width, height).intersection(Rect2i(p_dest - src_underscan, clipped_src_rect.size));
Ref<Image> img = p_src;
@@ -2642,7 +2638,7 @@ void Image::blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, c
ERR_FAIL_COND_MSG(p_src->height != p_mask->height, "Source image height is different from mask height.");
ERR_FAIL_COND(format != p_src->format);
- Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).clip(p_src_rect);
+ Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).intersection(p_src_rect);
if (p_dest.x < 0) {
clipped_src_rect.position.x = ABS(p_dest.x);
@@ -2656,7 +2652,7 @@ void Image::blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, c
}
Point2 src_underscan = Point2(MIN(0, p_src_rect.position.x), MIN(0, p_src_rect.position.y));
- Rect2i dest_rect = Rect2i(0, 0, width, height).clip(Rect2i(p_dest - src_underscan, clipped_src_rect.size));
+ Rect2i dest_rect = Rect2i(0, 0, width, height).intersection(Rect2i(p_dest - src_underscan, clipped_src_rect.size));
Ref<Image> img = p_src;
Ref<Image> msk = p_mask;
@@ -2714,8 +2710,7 @@ ImageMemLoadFunc Image::_bmp_mem_loader_func = nullptr;
void (*Image::_image_compress_bc_func)(Image *, float, Image::UsedChannels) = nullptr;
void (*Image::_image_compress_bptc_func)(Image *, float, Image::UsedChannels) = nullptr;
-void (*Image::_image_compress_pvrtc2_func)(Image *) = nullptr;
-void (*Image::_image_compress_pvrtc4_func)(Image *) = nullptr;
+void (*Image::_image_compress_pvrtc1_4bpp_func)(Image *) = nullptr;
void (*Image::_image_compress_etc1_func)(Image *, float) = nullptr;
void (*Image::_image_compress_etc2_func)(Image *, float, Image::UsedChannels) = nullptr;
void (*Image::_image_decompress_pvrtc)(Image *) = nullptr;
@@ -3082,7 +3077,7 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_mipmap_offset", "mipmap"), &Image::get_mipmap_offset);
- ClassDB::bind_method(D_METHOD("resize_to_po2", "square"), &Image::resize_to_po2, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("resize_to_po2", "square", "interpolation"), &Image::resize_to_po2, DEFVAL(false), DEFVAL(INTERPOLATE_BILINEAR));
ClassDB::bind_method(D_METHOD("resize", "width", "height", "interpolation"), &Image::resize, DEFVAL(INTERPOLATE_BILINEAR));
ClassDB::bind_method(D_METHOD("shrink_x2"), &Image::shrink_x2);
@@ -3173,10 +3168,10 @@ void Image::_bind_methods() {
BIND_ENUM_CONSTANT(FORMAT_BPTC_RGBA); //btpc bc6h
BIND_ENUM_CONSTANT(FORMAT_BPTC_RGBF); //float /
BIND_ENUM_CONSTANT(FORMAT_BPTC_RGBFU); //unsigned float
- BIND_ENUM_CONSTANT(FORMAT_PVRTC2); //pvrtc
- BIND_ENUM_CONSTANT(FORMAT_PVRTC2A);
- BIND_ENUM_CONSTANT(FORMAT_PVRTC4);
- BIND_ENUM_CONSTANT(FORMAT_PVRTC4A);
+ BIND_ENUM_CONSTANT(FORMAT_PVRTC1_2); //pvrtc
+ BIND_ENUM_CONSTANT(FORMAT_PVRTC1_2A);
+ BIND_ENUM_CONSTANT(FORMAT_PVRTC1_4);
+ BIND_ENUM_CONSTANT(FORMAT_PVRTC1_4A);
BIND_ENUM_CONSTANT(FORMAT_ETC); //etc1
BIND_ENUM_CONSTANT(FORMAT_ETC2_R11); //etc2
BIND_ENUM_CONSTANT(FORMAT_ETC2_R11S); //signed ); NOT srgb.
@@ -3200,10 +3195,10 @@ void Image::_bind_methods() {
BIND_ENUM_CONSTANT(ALPHA_BLEND);
BIND_ENUM_CONSTANT(COMPRESS_S3TC);
- BIND_ENUM_CONSTANT(COMPRESS_PVRTC2);
- BIND_ENUM_CONSTANT(COMPRESS_PVRTC4);
+ BIND_ENUM_CONSTANT(COMPRESS_PVRTC1_4);
BIND_ENUM_CONSTANT(COMPRESS_ETC);
BIND_ENUM_CONSTANT(COMPRESS_ETC2);
+ BIND_ENUM_CONSTANT(COMPRESS_BPTC);
BIND_ENUM_CONSTANT(USED_CHANNELS_L);
BIND_ENUM_CONSTANT(USED_CHANNELS_LA);
diff --git a/core/io/image.h b/core/io/image.h
index c4c84589e5..6b4488bd66 100644
--- a/core/io/image.h
+++ b/core/io/image.h
@@ -91,10 +91,10 @@ public:
FORMAT_BPTC_RGBA, //btpc bc7
FORMAT_BPTC_RGBF, //float bc6h
FORMAT_BPTC_RGBFU, //unsigned float bc6hu
- FORMAT_PVRTC2, //pvrtc
- FORMAT_PVRTC2A,
- FORMAT_PVRTC4,
- FORMAT_PVRTC4A,
+ FORMAT_PVRTC1_2, //pvrtc1
+ FORMAT_PVRTC1_2A,
+ FORMAT_PVRTC1_4,
+ FORMAT_PVRTC1_4A,
FORMAT_ETC, //etc1
FORMAT_ETC2_R11, //etc2
FORMAT_ETC2_R11S, //signed, NOT srgb.
@@ -138,8 +138,7 @@ public:
static void (*_image_compress_bc_func)(Image *, float, UsedChannels p_channels);
static void (*_image_compress_bptc_func)(Image *, float p_lossy_quality, UsedChannels p_channels);
- static void (*_image_compress_pvrtc2_func)(Image *);
- static void (*_image_compress_pvrtc4_func)(Image *);
+ static void (*_image_compress_pvrtc1_4bpp_func)(Image *);
static void (*_image_compress_etc1_func)(Image *, float);
static void (*_image_compress_etc2_func)(Image *, float, UsedChannels p_channels);
@@ -245,7 +244,7 @@ public:
/**
* Resize the image, using the preferred interpolation method.
*/
- void resize_to_po2(bool p_square = false);
+ void resize_to_po2(bool p_square = false, Interpolation p_interpolation = INTERPOLATE_BILINEAR);
void resize(int p_width, int p_height, Interpolation p_interpolation = INTERPOLATE_BILINEAR);
void shrink_x2();
bool is_size_po2() const;
@@ -332,11 +331,10 @@ public:
enum CompressMode {
COMPRESS_S3TC,
- COMPRESS_PVRTC2,
- COMPRESS_PVRTC4,
+ COMPRESS_PVRTC1_4,
COMPRESS_ETC,
COMPRESS_ETC2,
- COMPRESS_BPTC
+ COMPRESS_BPTC,
};
enum CompressSource {
COMPRESS_SOURCE_GENERIC,
diff --git a/core/io/logger.cpp b/core/io/logger.cpp
index f5cea00f28..241c72d310 100644
--- a/core/io/logger.cpp
+++ b/core/io/logger.cpp
@@ -30,6 +30,7 @@
#include "logger.h"
+#include "core/config/project_settings.h"
#include "core/os/dir_access.h"
#include "core/os/os.h"
#include "core/string/print_string.h"
@@ -201,15 +202,14 @@ void RotatedFileLogger::logv(const char *p_format, va_list p_list, bool p_err) {
}
va_end(list_copy);
file->store_buffer((uint8_t *)buf, len);
+
if (len >= static_buf_size) {
Memory::free_static(buf);
}
-#ifdef DEBUG_ENABLED
- const bool need_flush = true;
-#else
- bool need_flush = p_err;
-#endif
- if (need_flush) {
+
+ if (p_err || GLOBAL_GET("application/run/flush_stdout_on_print")) {
+ // Don't always flush when printing stdout to avoid performance
+ // issues when `print()` is spammed in release builds.
file->flush();
}
}
@@ -228,9 +228,11 @@ void StdLogger::logv(const char *p_format, va_list p_list, bool p_err) {
vfprintf(stderr, p_format, p_list);
} else {
vprintf(p_format, p_list);
-#ifdef DEBUG_ENABLED
- fflush(stdout);
-#endif
+ if (GLOBAL_GET("application/run/flush_stdout_on_print")) {
+ // Don't always flush when printing stdout to avoid performance
+ // issues when `print()` is spammed in release builds.
+ fflush(stdout);
+ }
}
}
diff --git a/core/math/aabb.h b/core/math/aabb.h
index 45dcbc7f7f..474304eae2 100644
--- a/core/math/aabb.h
+++ b/core/math/aabb.h
@@ -190,9 +190,9 @@ Vector3 AABB::get_support(const Vector3 &p_normal) const {
Vector3 ofs = position + half_extents;
return Vector3(
- (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) +
+ (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) +
ofs;
}
diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp
index 5e5efb6356..f29cb7a269 100644
--- a/core/math/camera_matrix.cpp
+++ b/core/math/camera_matrix.cpp
@@ -655,6 +655,17 @@ real_t CameraMatrix::get_fov() const {
}
}
+float CameraMatrix::get_lod_multiplier() const {
+ if (is_orthogonal()) {
+ return get_viewport_half_extents().x;
+ } else {
+ float zn = get_z_near();
+ float width = get_viewport_half_extents().x * 2.0;
+ return 1.0 / (zn / width);
+ }
+
+ //usage is lod_size / (lod_distance * multiplier) < threshold
+}
void CameraMatrix::make_scale(const Vector3 &p_scale) {
set_identity();
matrix[0][0] = p_scale.x;
diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h
index c5cdd98377..f856a7b1bf 100644
--- a/core/math/camera_matrix.h
+++ b/core/math/camera_matrix.h
@@ -108,6 +108,8 @@ struct CameraMatrix {
return !(*this == p_cam);
}
+ float get_lod_multiplier() const;
+
CameraMatrix();
CameraMatrix(const Transform &p_transform);
~CameraMatrix();
diff --git a/core/math/dynamic_bvh.cpp b/core/math/dynamic_bvh.cpp
new file mode 100644
index 0000000000..8486415c81
--- /dev/null
+++ b/core/math/dynamic_bvh.cpp
@@ -0,0 +1,400 @@
+/*************************************************************************/
+/* dynamic_bvh.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "dynamic_bvh.h"
+
+void DynamicBVH::_delete_node(Node *p_node) {
+ memdelete(p_node);
+}
+
+void DynamicBVH::_recurse_delete_node(Node *p_node) {
+ if (!p_node->is_leaf()) {
+ _recurse_delete_node(p_node->childs[0]);
+ _recurse_delete_node(p_node->childs[1]);
+ }
+ if (p_node == bvh_root) {
+ bvh_root = nullptr;
+ }
+ _delete_node(p_node);
+}
+
+DynamicBVH::Node *DynamicBVH::_create_node(Node *p_parent, void *p_data) {
+ Node *node = memnew(Node);
+ node->parent = p_parent;
+ node->data = p_data;
+ node->childs[1] = 0;
+ return (node);
+}
+
+DynamicBVH::Node *DynamicBVH::_create_node_with_volume(Node *p_parent, const Volume &p_volume, void *p_data) {
+ Node *node = _create_node(p_parent, p_data);
+ node->volume = p_volume;
+ return node;
+}
+
+void DynamicBVH::_insert_leaf(Node *p_root, Node *p_leaf) {
+ if (!bvh_root) {
+ bvh_root = p_leaf;
+ p_leaf->parent = 0;
+ } else {
+ if (!p_root->is_leaf()) {
+ do {
+ p_root = p_root->childs[p_leaf->volume.select_by_proximity(
+ p_root->childs[0]->volume,
+ p_root->childs[1]->volume)];
+ } while (!p_root->is_leaf());
+ }
+ Node *prev = p_root->parent;
+ Node *node = _create_node_with_volume(prev, p_leaf->volume.merge(p_root->volume), 0);
+ if (prev) {
+ prev->childs[p_root->get_index_in_parent()] = node;
+ node->childs[0] = p_root;
+ p_root->parent = node;
+ node->childs[1] = p_leaf;
+ p_leaf->parent = node;
+ do {
+ if (!prev->volume.contains(node->volume)) {
+ prev->volume = prev->childs[0]->volume.merge(prev->childs[1]->volume);
+ } else {
+ break;
+ }
+ node = prev;
+ } while (0 != (prev = node->parent));
+ } else {
+ node->childs[0] = p_root;
+ p_root->parent = node;
+ node->childs[1] = p_leaf;
+ p_leaf->parent = node;
+ bvh_root = node;
+ }
+ }
+}
+
+DynamicBVH::Node *DynamicBVH::_remove_leaf(Node *leaf) {
+ if (leaf == bvh_root) {
+ bvh_root = 0;
+ return (0);
+ } else {
+ Node *parent = leaf->parent;
+ Node *prev = parent->parent;
+ Node *sibling = parent->childs[1 - leaf->get_index_in_parent()];
+ if (prev) {
+ prev->childs[parent->get_index_in_parent()] = sibling;
+ sibling->parent = prev;
+ _delete_node(parent);
+ while (prev) {
+ const Volume pb = prev->volume;
+ prev->volume = prev->childs[0]->volume.merge(prev->childs[1]->volume);
+ if (pb.is_not_equal_to(prev->volume)) {
+ prev = prev->parent;
+ } else
+ break;
+ }
+ return (prev ? prev : bvh_root);
+ } else {
+ bvh_root = sibling;
+ sibling->parent = 0;
+ _delete_node(parent);
+ return (bvh_root);
+ }
+ }
+}
+
+void DynamicBVH::_fetch_leaves(Node *p_root, LocalVector<Node *> &r_leaves, int p_depth) {
+ if (p_root->is_internal() && p_depth) {
+ _fetch_leaves(p_root->childs[0], r_leaves, p_depth - 1);
+ _fetch_leaves(p_root->childs[1], r_leaves, p_depth - 1);
+ _delete_node(p_root);
+ } else {
+ r_leaves.push_back(p_root);
+ }
+}
+
+// Partitions leaves such that leaves[0, n) are on the
+// left of axis, and leaves[n, count) are on the right
+// of axis. returns N.
+int DynamicBVH::_split(Node **leaves, int p_count, const Vector3 &p_org, const Vector3 &p_axis) {
+ int begin = 0;
+ int end = p_count;
+ for (;;) {
+ while (begin != end && leaves[begin]->is_left_of_axis(p_org, p_axis)) {
+ ++begin;
+ }
+
+ if (begin == end) {
+ break;
+ }
+
+ while (begin != end && !leaves[end - 1]->is_left_of_axis(p_org, p_axis)) {
+ --end;
+ }
+
+ if (begin == end) {
+ break;
+ }
+
+ // swap out of place nodes
+ --end;
+ Node *temp = leaves[begin];
+ leaves[begin] = leaves[end];
+ leaves[end] = temp;
+ ++begin;
+ }
+
+ return begin;
+}
+
+DynamicBVH::Volume DynamicBVH::_bounds(Node **leaves, int p_count) {
+ Volume volume = leaves[0]->volume;
+ for (int i = 1, ni = p_count; i < ni; ++i) {
+ volume = volume.merge(leaves[i]->volume);
+ }
+ return (volume);
+}
+
+void DynamicBVH::_bottom_up(Node **leaves, int p_count) {
+ while (p_count > 1) {
+ real_t minsize = Math_INF;
+ int minidx[2] = { -1, -1 };
+ for (int i = 0; i < p_count; ++i) {
+ for (int j = i + 1; j < p_count; ++j) {
+ const real_t sz = leaves[i]->volume.merge(leaves[j]->volume).get_size();
+ if (sz < minsize) {
+ minsize = sz;
+ minidx[0] = i;
+ minidx[1] = j;
+ }
+ }
+ }
+ Node *n[] = { leaves[minidx[0]], leaves[minidx[1]] };
+ Node *p = _create_node_with_volume(nullptr, n[0]->volume.merge(n[1]->volume), nullptr);
+ p->childs[0] = n[0];
+ p->childs[1] = n[1];
+ n[0]->parent = p;
+ n[1]->parent = p;
+ leaves[minidx[0]] = p;
+ leaves[minidx[1]] = leaves[p_count - 1];
+ --p_count;
+ }
+}
+
+DynamicBVH::Node *DynamicBVH::_top_down(Node **leaves, int p_count, int p_bu_threshold) {
+ static const Vector3 axis[] = { Vector3(1, 0, 0), Vector3(0, 1, 0), Vector3(0, 0, 1) };
+
+ ERR_FAIL_COND_V(p_bu_threshold <= 1, nullptr);
+ if (p_count > 1) {
+ if (p_count > p_bu_threshold) {
+ const Volume vol = _bounds(leaves, p_count);
+ const Vector3 org = vol.get_center();
+ int partition;
+ int bestaxis = -1;
+ int bestmidp = p_count;
+ int splitcount[3][2] = { { 0, 0 }, { 0, 0 }, { 0, 0 } };
+ int i;
+ for (i = 0; i < p_count; ++i) {
+ const Vector3 x = leaves[i]->volume.get_center() - org;
+ for (int j = 0; j < 3; ++j) {
+ ++splitcount[j][x.dot(axis[j]) > 0 ? 1 : 0];
+ }
+ }
+ for (i = 0; i < 3; ++i) {
+ if ((splitcount[i][0] > 0) && (splitcount[i][1] > 0)) {
+ const int midp = (int)Math::abs(real_t(splitcount[i][0] - splitcount[i][1]));
+ if (midp < bestmidp) {
+ bestaxis = i;
+ bestmidp = midp;
+ }
+ }
+ }
+ if (bestaxis >= 0) {
+ partition = _split(leaves, p_count, org, axis[bestaxis]);
+ ERR_FAIL_COND_V(partition == 0 || partition == p_count, nullptr);
+ } else {
+ partition = p_count / 2 + 1;
+ }
+
+ Node *node = _create_node_with_volume(nullptr, vol, nullptr);
+ node->childs[0] = _top_down(&leaves[0], partition, p_bu_threshold);
+ node->childs[1] = _top_down(&leaves[partition], p_count - partition, p_bu_threshold);
+ node->childs[0]->parent = node;
+ node->childs[1]->parent = node;
+ return (node);
+ } else {
+ _bottom_up(leaves, p_count);
+ return (leaves[0]);
+ }
+ }
+ return (leaves[0]);
+}
+
+DynamicBVH::Node *DynamicBVH::_node_sort(Node *n, Node *&r) {
+ Node *p = n->parent;
+ ERR_FAIL_COND_V(!n->is_internal(), nullptr);
+ if (p > n) {
+ const int i = n->get_index_in_parent();
+ const int j = 1 - i;
+ Node *s = p->childs[j];
+ Node *q = p->parent;
+ ERR_FAIL_COND_V(n != p->childs[i], nullptr);
+ if (q)
+ q->childs[p->get_index_in_parent()] = n;
+ else
+ r = n;
+ s->parent = n;
+ p->parent = n;
+ n->parent = q;
+ p->childs[0] = n->childs[0];
+ p->childs[1] = n->childs[1];
+ n->childs[0]->parent = p;
+ n->childs[1]->parent = p;
+ n->childs[i] = p;
+ n->childs[j] = s;
+ SWAP(p->volume, n->volume);
+ return (p);
+ }
+ return (n);
+}
+
+void DynamicBVH::clear() {
+ if (bvh_root) {
+ _recurse_delete_node(bvh_root);
+ }
+ lkhd = -1;
+ opath = 0;
+}
+
+void DynamicBVH::optimize_bottom_up() {
+ if (bvh_root) {
+ LocalVector<Node *> leaves;
+ _fetch_leaves(bvh_root, leaves);
+ _bottom_up(&leaves[0], leaves.size());
+ bvh_root = leaves[0];
+ }
+}
+
+void DynamicBVH::optimize_top_down(int bu_threshold) {
+ if (bvh_root) {
+ LocalVector<Node *> leaves;
+ _fetch_leaves(bvh_root, leaves);
+ bvh_root = _top_down(&leaves[0], leaves.size(), bu_threshold);
+ }
+}
+
+void DynamicBVH::optimize_incremental(int passes) {
+ if (passes < 0)
+ passes = total_leaves;
+ if (bvh_root && (passes > 0)) {
+ do {
+ Node *node = bvh_root;
+ unsigned bit = 0;
+ while (node->is_internal()) {
+ node = _node_sort(node, bvh_root)->childs[(opath >> bit) & 1];
+ bit = (bit + 1) & (sizeof(unsigned) * 8 - 1);
+ }
+ _update(node);
+ ++opath;
+ } while (--passes);
+ }
+}
+
+DynamicBVH::ID DynamicBVH::insert(const AABB &p_box, void *p_userdata) {
+ Volume volume;
+ volume.min = p_box.position;
+ volume.max = p_box.position + p_box.size;
+
+ Node *leaf = _create_node_with_volume(nullptr, volume, p_userdata);
+ _insert_leaf(bvh_root, leaf);
+ ++total_leaves;
+
+ ID id;
+ id.node = leaf;
+ return id;
+}
+
+void DynamicBVH::_update(Node *leaf, int lookahead) {
+ Node *root = _remove_leaf(leaf);
+ if (root) {
+ if (lookahead >= 0) {
+ for (int i = 0; (i < lookahead) && root->parent; ++i) {
+ root = root->parent;
+ }
+ } else
+ root = bvh_root;
+ }
+ _insert_leaf(root, leaf);
+}
+
+void DynamicBVH::update(const ID &p_id, const AABB &p_box) {
+ ERR_FAIL_COND(!p_id.is_valid());
+ Node *leaf = p_id.node;
+ Node *base = _remove_leaf(leaf);
+ Volume volume;
+ volume.min = p_box.position;
+ volume.max = p_box.position + p_box.size;
+ if (base) {
+ if (lkhd >= 0) {
+ for (int i = 0; (i < lkhd) && base->parent; ++i) {
+ base = base->parent;
+ }
+ } else
+ base = bvh_root;
+ }
+ leaf->volume = volume;
+ _insert_leaf(base, leaf);
+}
+
+void DynamicBVH::remove(const ID &p_id) {
+ ERR_FAIL_COND(!p_id.is_valid());
+ Node *leaf = p_id.node;
+ _remove_leaf(leaf);
+ _delete_node(leaf);
+ --total_leaves;
+}
+
+void DynamicBVH::_extract_leaves(Node *p_node, List<ID> *r_elements) {
+ if (p_node->is_internal()) {
+ _extract_leaves(p_node->childs[0], r_elements);
+ _extract_leaves(p_node->childs[1], r_elements);
+ } else {
+ ID id;
+ id.node = p_node;
+ r_elements->push_back(id);
+ }
+}
+
+void DynamicBVH::get_elements(List<ID> *r_elements) {
+ if (bvh_root) {
+ _extract_leaves(bvh_root, r_elements);
+ }
+}
+
+DynamicBVH::~DynamicBVH() {
+ clear();
+}
diff --git a/core/math/dynamic_bvh.h b/core/math/dynamic_bvh.h
new file mode 100644
index 0000000000..81d70d7469
--- /dev/null
+++ b/core/math/dynamic_bvh.h
@@ -0,0 +1,359 @@
+/*************************************************************************/
+/* dynamic_bvh.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef DYNAMICBVH_H
+#define DYNAMICBVH_H
+
+#include "core/math/aabb.h"
+#include "core/templates/list.h"
+#include "core/templates/local_vector.h"
+#include "core/typedefs.h"
+
+// Based on bullet Dbvh
+
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+
+///DynamicBVH implementation by Nathanael Presson
+// The DynamicBVH class implements a fast dynamic bounding volume tree based on axis aligned bounding boxes (aabb tree).
+
+class DynamicBVH {
+ struct Node;
+
+public:
+ struct ID {
+ Node *node;
+
+ public:
+ _FORCE_INLINE_ bool is_valid() const { return node != nullptr; }
+ _FORCE_INLINE_ ID() {
+ node = nullptr;
+ }
+ };
+
+private:
+ struct Volume {
+ Vector3 min, max;
+
+ _FORCE_INLINE_ Vector3 get_center() const { return ((min + max) / 2); }
+ _FORCE_INLINE_ Vector3 get_length() const { return (max - min); }
+
+ _FORCE_INLINE_ bool contains(const Volume &a) const {
+ return ((min.x <= a.min.x) &&
+ (min.y <= a.min.y) &&
+ (min.z <= a.min.z) &&
+ (max.x >= a.max.x) &&
+ (max.y >= a.max.y) &&
+ (max.z >= a.max.z));
+ }
+
+ _FORCE_INLINE_ Volume merge(const Volume &b) const {
+ Volume r;
+ for (int i = 0; i < 3; ++i) {
+ if (min[i] < b.min[i])
+ r.min[i] = min[i];
+ else
+ r.min[i] = b.min[i];
+ if (max[i] > b.max[i])
+ r.max[i] = max[i];
+ else
+ r.max[i] = b.max[i];
+ }
+ return r;
+ }
+
+ _FORCE_INLINE_ real_t get_size() const {
+ const Vector3 edges = get_length();
+ return (edges.x * edges.y * edges.z +
+ edges.x + edges.y + edges.z);
+ }
+
+ _FORCE_INLINE_ bool is_not_equal_to(const Volume &b) const {
+ return ((min.x != b.min.x) ||
+ (min.y != b.min.y) ||
+ (min.z != b.min.z) ||
+ (max.x != b.max.x) ||
+ (max.y != b.max.y) ||
+ (max.z != b.max.z));
+ }
+
+ _FORCE_INLINE_ real_t get_proximity_to(const Volume &b) const {
+ const Vector3 d = (min + max) - (b.min + b.max);
+ return (Math::abs(d.x) + Math::abs(d.y) + Math::abs(d.z));
+ }
+
+ _FORCE_INLINE_ int select_by_proximity(const Volume &a, const Volume &b) const {
+ return (get_proximity_to(a) < get_proximity_to(b) ? 0 : 1);
+ }
+
+ //
+ _FORCE_INLINE_ bool intersects(const Volume &b) const {
+ return ((min.x <= b.max.x) &&
+ (max.x >= b.min.x) &&
+ (min.y <= b.max.y) &&
+ (max.y >= b.min.y) &&
+ (min.z <= b.max.z) &&
+ (max.z >= b.min.z));
+ }
+ };
+
+ struct Node {
+ Volume volume;
+ Node *parent = nullptr;
+ union {
+ Node *childs[2];
+ void *data;
+ };
+
+ _FORCE_INLINE_ bool is_leaf() const { return data != nullptr; }
+ _FORCE_INLINE_ bool is_internal() const { return (!is_leaf()); }
+
+ _FORCE_INLINE_ int get_index_in_parent() const {
+ ERR_FAIL_COND_V(!parent, 0);
+ return (parent->childs[1] == this) ? 1 : 0;
+ }
+ _FORCE_INLINE_ void get_max_depth(int depth, int &maxdepth) {
+ if (is_internal()) {
+ childs[0]->get_max_depth(depth + 1, maxdepth);
+ childs[1]->get_max_depth(depth + 1, maxdepth);
+ } else {
+ maxdepth = MAX(maxdepth, depth);
+ }
+ }
+
+ //
+ int count_leaves() const {
+ if (is_internal())
+ return childs[0]->count_leaves() + childs[1]->count_leaves();
+ else
+ return (1);
+ }
+
+ bool is_left_of_axis(const Vector3 &org, const Vector3 &axis) const {
+ return axis.dot(volume.get_center() - org) <= 0;
+ }
+
+ Node() {
+ childs[0] = nullptr;
+ childs[1] = nullptr;
+ }
+ };
+
+ // Fields
+ Node *bvh_root = nullptr;
+ int lkhd = -1;
+ int total_leaves = 0;
+ uint32_t opath = 0;
+
+ enum {
+ ALLOCA_STACK_SIZE = 128
+ };
+
+ _FORCE_INLINE_ void _delete_node(Node *p_node);
+ void _recurse_delete_node(Node *p_node);
+ _FORCE_INLINE_ Node *_create_node(Node *p_parent, void *p_data);
+ _FORCE_INLINE_ DynamicBVH::Node *_create_node_with_volume(Node *p_parent, const Volume &p_volume, void *p_data);
+ _FORCE_INLINE_ void _insert_leaf(Node *p_root, Node *p_leaf);
+ _FORCE_INLINE_ Node *_remove_leaf(Node *leaf);
+ void _fetch_leaves(Node *p_root, LocalVector<Node *> &r_leaves, int p_depth = -1);
+ static int _split(Node **leaves, int p_count, const Vector3 &p_org, const Vector3 &p_axis);
+ static Volume _bounds(Node **leaves, int p_count);
+ void _bottom_up(Node **leaves, int p_count);
+ Node *_top_down(Node **leaves, int p_count, int p_bu_threshold);
+ Node *_node_sort(Node *n, Node *&r);
+
+ _FORCE_INLINE_ void _update(Node *leaf, int lookahead = -1);
+
+ void _extract_leaves(Node *p_node, List<ID> *r_elements);
+
+ _FORCE_INLINE_ bool _ray_aabb(const Vector3 &rayFrom, const Vector3 &rayInvDirection, const unsigned int raySign[3], const Vector3 bounds[2], real_t &tmin, real_t lambda_min, real_t lambda_max) {
+ real_t tmax, tymin, tymax, tzmin, tzmax;
+ tmin = (bounds[raySign[0]].x - rayFrom.x) * rayInvDirection.x;
+ tmax = (bounds[1 - raySign[0]].x - rayFrom.x) * rayInvDirection.x;
+ tymin = (bounds[raySign[1]].y - rayFrom.y) * rayInvDirection.y;
+ tymax = (bounds[1 - raySign[1]].y - rayFrom.y) * rayInvDirection.y;
+
+ if ((tmin > tymax) || (tymin > tmax))
+ return false;
+
+ if (tymin > tmin)
+ tmin = tymin;
+
+ if (tymax < tmax)
+ tmax = tymax;
+
+ tzmin = (bounds[raySign[2]].z - rayFrom.z) * rayInvDirection.z;
+ tzmax = (bounds[1 - raySign[2]].z - rayFrom.z) * rayInvDirection.z;
+
+ if ((tmin > tzmax) || (tzmin > tmax))
+ return false;
+ if (tzmin > tmin)
+ tmin = tzmin;
+ if (tzmax < tmax)
+ tmax = tzmax;
+ return ((tmin < lambda_max) && (tmax > lambda_min));
+ }
+
+public:
+ // Methods
+ void clear();
+ bool empty() const { return (0 == bvh_root); }
+ void optimize_bottom_up();
+ void optimize_top_down(int bu_threshold = 128);
+ void optimize_incremental(int passes);
+ ID insert(const AABB &p_box, void *p_userdata);
+ void update(const ID &p_id, const AABB &p_box);
+ void remove(const ID &p_id);
+ void get_elements(List<ID> *r_elements);
+
+ /* Discouraged, but works as a reference on how it must be used */
+ struct DefaultQueryResult {
+ virtual bool operator()(void *p_data) = 0; //return true whether you want to continue the query
+ virtual ~DefaultQueryResult() {}
+ };
+
+ template <class QueryResult>
+ _FORCE_INLINE_ void aabb_query(const AABB &p_aabb, QueryResult &r_result);
+ template <class QueryResult>
+ _FORCE_INLINE_ void ray_query(const Vector3 &p_from, const Vector3 &p_to, QueryResult &r_result);
+
+ DynamicBVH();
+ ~DynamicBVH();
+};
+
+template <class QueryResult>
+void DynamicBVH::aabb_query(const AABB &p_box, QueryResult &r_result) {
+ if (!bvh_root) {
+ return;
+ }
+
+ Volume volume;
+ volume.min = p_box.position;
+ volume.max = p_box.position + p_box.size;
+
+ const Node **stack = (const Node **)alloca(ALLOCA_STACK_SIZE * sizeof(const Node *));
+ stack[0] = bvh_root;
+ int32_t depth = 1;
+ int32_t threshold = ALLOCA_STACK_SIZE - 2;
+
+ LocalVector<const Node *> aux_stack; //only used in rare occasions when you run out of alloca memory because tree is too unbalanced. Should correct itself over time.
+
+ do {
+ const Node *n = stack[depth - 1];
+ depth--;
+ if (n->volume.intersects(volume)) {
+ if (n->is_internal()) {
+ if (depth > threshold) {
+ if (aux_stack.empty()) {
+ aux_stack.resize(ALLOCA_STACK_SIZE * 2);
+ copymem(aux_stack.ptr(), stack, ALLOCA_STACK_SIZE * sizeof(const Node *));
+ } else {
+ aux_stack.resize(aux_stack.size() * 2);
+ }
+ stack = aux_stack.ptr();
+ threshold = aux_stack.size() - 2;
+ }
+ stack[depth++] = n->childs[0];
+ stack[depth++] = n->childs[1];
+ } else {
+ if (r_result(n->data)) {
+ return;
+ }
+ }
+ }
+ } while (depth > 0);
+}
+
+template <class QueryResult>
+void DynamicBVH::ray_query(const Vector3 &p_from, const Vector3 &p_to, QueryResult &r_result) {
+ Vector3 ray_dir = (p_to - p_from);
+ ray_dir.normalize();
+
+ ///what about division by zero? --> just set rayDirection[i] to INF/B3_LARGE_FLOAT
+ Vector3 inv_dir;
+ inv_dir[0] = ray_dir[0] == real_t(0.0) ? real_t(1e20) : real_t(1.0) / ray_dir[0];
+ inv_dir[1] = ray_dir[1] == real_t(0.0) ? real_t(1e20) : real_t(1.0) / ray_dir[1];
+ inv_dir[2] = ray_dir[2] == real_t(0.0) ? real_t(1e20) : real_t(1.0) / ray_dir[2];
+ unsigned int signs[3] = { inv_dir[0] < 0.0, inv_dir[1] < 0.0, inv_dir[2] < 0.0 };
+
+ real_t lambda_max = ray_dir.dot(p_to - p_from);
+
+ Vector3 bounds[2];
+
+ const Node **stack = (const Node **)alloca(ALLOCA_STACK_SIZE * sizeof(const Node *));
+ stack[0] = bvh_root;
+ int32_t depth = 1;
+ int32_t threshold = ALLOCA_STACK_SIZE - 2;
+
+ LocalVector<const Node *> aux_stack; //only used in rare occasions when you run out of alloca memory because tree is too unbalanced. Should correct itself over time.
+
+ do {
+ const Node *node = stack[--depth];
+ bounds[0] = node->volume.min;
+ bounds[1] = node->volume.max;
+ real_t tmin = 1.f, lambda_min = 0.f;
+ unsigned int result1 = false;
+ result1 = _ray_aabb(p_from, inv_dir, signs, bounds, tmin, lambda_min, lambda_max);
+ if (result1) {
+ if (node->is_internal()) {
+ if (depth > threshold) {
+ if (aux_stack.empty()) {
+ aux_stack.resize(ALLOCA_STACK_SIZE * 2);
+ copymem(aux_stack.ptr(), stack, ALLOCA_STACK_SIZE * sizeof(const Node *));
+ } else {
+ aux_stack.resize(aux_stack.size() * 2);
+ }
+ stack = aux_stack.ptr();
+ threshold = aux_stack.size() - 2;
+ }
+ stack[depth++] = node->childs[0];
+ stack[depth++] = node->childs[1];
+ } else {
+ if (r_result(node->data)) {
+ return;
+ }
+ }
+ }
+ } while (depth > 0);
+}
+
+#endif // DYNAMICBVH_H
diff --git a/core/math/rect2.h b/core/math/rect2.h
index b1fe865ba5..f36084ec74 100644
--- a/core/math/rect2.h
+++ b/core/math/rect2.h
@@ -123,8 +123,9 @@ struct Rect2 {
_FORCE_INLINE_ bool has_no_area() const {
return (size.x <= 0 || size.y <= 0);
}
- inline Rect2 clip(const Rect2 &p_rect) const { /// return a clipped rect
+ // Returns the instersection between two Rect2s or an empty Rect2 if there is no intersection
+ inline Rect2 intersection(const Rect2 &p_rect) const {
Rect2 new_rect = p_rect;
if (!intersects(new_rect)) {
@@ -365,8 +366,9 @@ struct Rect2i {
_FORCE_INLINE_ bool has_no_area() const {
return (size.x <= 0 || size.y <= 0);
}
- inline Rect2i clip(const Rect2i &p_rect) const { /// return a clipped rect
+ // Returns the instersection between two Rect2is or an empty Rect2i if there is no intersection
+ inline Rect2i intersection(const Rect2i &p_rect) const {
Rect2i new_rect = p_rect;
if (!intersects(new_rect)) {
diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp
index 1dcbb0cd6b..65bae6f6e8 100644
--- a/core/object/undo_redo.cpp
+++ b/core/object/undo_redo.cpp
@@ -30,6 +30,7 @@
#include "undo_redo.h"
+#include "core/io/resource.h"
#include "core/os/os.h"
void UndoRedo::_discard_redo() {
@@ -104,8 +105,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<Resource>(p_object)) {
- do_op.resref = Ref<Resource>(Object::cast_to<Resource>(p_object));
+ if (Object::cast_to<Reference>(p_object)) {
+ do_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object));
}
do_op.type = Operation::TYPE_METHOD;
@@ -130,8 +131,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<Resource>(p_object)) {
- undo_op.resref = Ref<Resource>(Object::cast_to<Resource>(p_object));
+ if (Object::cast_to<Reference>(p_object)) {
+ undo_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object));
}
undo_op.type = Operation::TYPE_METHOD;
@@ -149,8 +150,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<Resource>(p_object)) {
- do_op.resref = Ref<Resource>(Object::cast_to<Resource>(p_object));
+ if (Object::cast_to<Reference>(p_object)) {
+ do_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object));
}
do_op.type = Operation::TYPE_PROPERTY;
@@ -171,8 +172,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<Resource>(p_object)) {
- undo_op.resref = Ref<Resource>(Object::cast_to<Resource>(p_object));
+ if (Object::cast_to<Reference>(p_object)) {
+ undo_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object));
}
undo_op.type = Operation::TYPE_PROPERTY;
@@ -187,8 +188,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<Resource>(p_object)) {
- do_op.resref = Ref<Resource>(Object::cast_to<Resource>(p_object));
+ if (Object::cast_to<Reference>(p_object)) {
+ do_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object));
}
do_op.type = Operation::TYPE_REFERENCE;
@@ -207,8 +208,8 @@ void UndoRedo::add_undo_reference(Object *p_object) {
Operation undo_op;
undo_op.object = p_object->get_instance_id();
- if (Object::cast_to<Resource>(p_object)) {
- undo_op.resref = Ref<Resource>(Object::cast_to<Resource>(p_object));
+ if (Object::cast_to<Reference>(p_object)) {
+ undo_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object));
}
undo_op.type = Operation::TYPE_REFERENCE;
diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h
index 68d78e0d7d..06c2759a65 100644
--- a/core/object/undo_redo.h
+++ b/core/object/undo_redo.h
@@ -31,8 +31,8 @@
#ifndef UNDO_REDO_H
#define UNDO_REDO_H
-#include "core/io/resource.h"
#include "core/object/class_db.h"
+#include "core/object/reference.h"
class UndoRedo : public Object {
GDCLASS(UndoRedo, Object);
@@ -61,7 +61,7 @@ private:
};
Type type;
- Ref<Resource> resref;
+ Ref<Reference> ref;
ObjectID object;
StringName name;
Variant args[VARIANT_ARG_MAX];
diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp
index b962f61e1f..aa95f06cff 100644
--- a/core/os/file_access.cpp
+++ b/core/os/file_access.cpp
@@ -349,7 +349,7 @@ Vector<String> FileAccess::get_csv_line(const String &p_delim) const {
strings.push_back(current);
current = String();
} else if (c == '"') {
- if (l[i + 1] == '"') {
+ if (l[i + 1] == '"' && in_quote) {
s[0] = '"';
current += s;
i++;
diff --git a/core/variant/method_ptrcall.h b/core/variant/method_ptrcall.h
index 40fa3543dc..b00455f8ad 100644
--- a/core/variant/method_ptrcall.h
+++ b/core/variant/method_ptrcall.h
@@ -100,6 +100,7 @@ struct PtrToArg {};
}
MAKE_PTRARG(bool);
+// Integer types.
MAKE_PTRARGCONV(uint8_t, int64_t);
MAKE_PTRARGCONV(int8_t, int64_t);
MAKE_PTRARGCONV(uint16_t, int64_t);
@@ -108,15 +109,16 @@ MAKE_PTRARGCONV(uint32_t, int64_t);
MAKE_PTRARGCONV(int32_t, int64_t);
MAKE_PTRARG(int64_t);
MAKE_PTRARG(uint64_t);
+// Float types
MAKE_PTRARGCONV(float, double);
MAKE_PTRARG(double);
MAKE_PTRARG(String);
MAKE_PTRARG(Vector2);
-MAKE_PTRARG(Rect2);
-MAKE_PTRARG_BY_REFERENCE(Vector3);
MAKE_PTRARG(Vector2i);
+MAKE_PTRARG(Rect2);
MAKE_PTRARG(Rect2i);
+MAKE_PTRARG_BY_REFERENCE(Vector3);
MAKE_PTRARG_BY_REFERENCE(Vector3i);
MAKE_PTRARG(Transform2D);
MAKE_PTRARG_BY_REFERENCE(Plane);
@@ -128,9 +130,10 @@ MAKE_PTRARG_BY_REFERENCE(Color);
MAKE_PTRARG(StringName);
MAKE_PTRARG(NodePath);
MAKE_PTRARG(RID);
-MAKE_PTRARG(Dictionary);
+// Object doesn't need this.
MAKE_PTRARG(Callable);
MAKE_PTRARG(Signal);
+MAKE_PTRARG(Dictionary);
MAKE_PTRARG(Array);
MAKE_PTRARG(PackedByteArray);
MAKE_PTRARG(PackedInt32Array);
diff --git a/core/variant/variant.h b/core/variant/variant.h
index d87078b5da..76c936a7bd 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -511,7 +511,7 @@ public:
/* Constructors */
- typedef void (*ValidatedConstructor)(Variant &r_base, const Variant **p_args);
+ typedef void (*ValidatedConstructor)(Variant *r_base, const Variant **p_args);
typedef void (*PTRConstructor)(void *base, const void **p_args);
static int get_constructor_count(Variant::Type p_type);
@@ -550,8 +550,8 @@ public:
static bool has_indexing(Variant::Type p_type);
static Variant::Type get_indexed_element_type(Variant::Type p_type);
- typedef void (*ValidatedIndexedSetter)(Variant *base, int64_t index, const Variant *value, bool &oob);
- typedef void (*ValidatedIndexedGetter)(const Variant *base, int64_t index, Variant *value, bool &oob);
+ typedef void (*ValidatedIndexedSetter)(Variant *base, int64_t index, const Variant *value, bool *oob);
+ typedef void (*ValidatedIndexedGetter)(const Variant *base, int64_t index, Variant *value, bool *oob);
static ValidatedIndexedSetter get_member_validated_indexed_setter(Variant::Type p_type);
static ValidatedIndexedGetter get_member_validated_indexed_getter(Variant::Type p_type);
@@ -571,9 +571,9 @@ public:
static bool is_keyed(Variant::Type p_type);
- typedef void (*ValidatedKeyedSetter)(Variant *base, const Variant *key, const Variant *value, bool &valid);
- typedef void (*ValidatedKeyedGetter)(const Variant *base, const Variant *key, Variant *value, bool &valid);
- typedef bool (*ValidatedKeyedChecker)(const Variant *base, const Variant *key, bool &valid);
+ typedef void (*ValidatedKeyedSetter)(Variant *base, const Variant *key, const Variant *value, bool *valid);
+ typedef void (*ValidatedKeyedGetter)(const Variant *base, const Variant *key, Variant *value, bool *valid);
+ typedef bool (*ValidatedKeyedChecker)(const Variant *base, const Variant *key, bool *valid);
static ValidatedKeyedSetter get_member_validated_keyed_setter(Variant::Type p_type);
static ValidatedKeyedGetter get_member_validated_keyed_getter(Variant::Type p_type);
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index d588c83809..55a34af723 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1021,7 +1021,7 @@ static void _register_variant_builtin_methods() {
bind_method(Rect2, is_equal_approx, sarray("rect"), varray());
bind_method(Rect2, intersects, sarray("b", "include_borders"), varray(false));
bind_method(Rect2, encloses, sarray("b"), varray());
- bind_method(Rect2, clip, sarray("b"), varray());
+ bind_method(Rect2, intersection, sarray("b"), varray());
bind_method(Rect2, merge, sarray("b"), varray());
bind_method(Rect2, expand, sarray("to"), varray());
bind_method(Rect2, grow, sarray("by"), varray());
@@ -1036,7 +1036,7 @@ static void _register_variant_builtin_methods() {
bind_method(Rect2i, has_point, sarray("point"), varray());
bind_method(Rect2i, intersects, sarray("b"), varray());
bind_method(Rect2i, encloses, sarray("b"), varray());
- bind_method(Rect2i, clip, sarray("b"), varray());
+ bind_method(Rect2i, intersection, sarray("b"), varray());
bind_method(Rect2i, merge, sarray("b"), varray());
bind_method(Rect2i, expand, sarray("to"), varray());
bind_method(Rect2i, grow, sarray("by"), varray());
diff --git a/core/variant/variant_construct.cpp b/core/variant/variant_construct.cpp
index 3bb3fa3634..732e7a26f2 100644
--- a/core/variant/variant_construct.cpp
+++ b/core/variant/variant_construct.cpp
@@ -39,6 +39,60 @@
#include "core/templates/local_vector.h"
#include "core/templates/oa_hash_map.h"
+template <class T>
+struct PtrConstruct {};
+
+#define MAKE_PTRCONSTRUCT(m_type) \
+ template <> \
+ struct PtrConstruct<m_type> { \
+ _FORCE_INLINE_ static void construct(const m_type &p_value, void *p_ptr) { \
+ memnew_placement(p_ptr, m_type(p_value)); \
+ } \
+ };
+
+MAKE_PTRCONSTRUCT(bool);
+MAKE_PTRCONSTRUCT(int64_t);
+MAKE_PTRCONSTRUCT(double);
+MAKE_PTRCONSTRUCT(String);
+MAKE_PTRCONSTRUCT(Vector2);
+MAKE_PTRCONSTRUCT(Vector2i);
+MAKE_PTRCONSTRUCT(Rect2);
+MAKE_PTRCONSTRUCT(Rect2i);
+MAKE_PTRCONSTRUCT(Vector3);
+MAKE_PTRCONSTRUCT(Vector3i);
+MAKE_PTRCONSTRUCT(Transform2D);
+MAKE_PTRCONSTRUCT(Plane);
+MAKE_PTRCONSTRUCT(Quat);
+MAKE_PTRCONSTRUCT(AABB);
+MAKE_PTRCONSTRUCT(Basis);
+MAKE_PTRCONSTRUCT(Transform);
+MAKE_PTRCONSTRUCT(Color);
+MAKE_PTRCONSTRUCT(StringName);
+MAKE_PTRCONSTRUCT(NodePath);
+MAKE_PTRCONSTRUCT(RID);
+
+template <>
+struct PtrConstruct<Object *> {
+ _FORCE_INLINE_ static void construct(Object *p_value, void *p_ptr) {
+ *((Object **)p_ptr) = p_value;
+ }
+};
+
+MAKE_PTRCONSTRUCT(Callable);
+MAKE_PTRCONSTRUCT(Signal);
+MAKE_PTRCONSTRUCT(Dictionary);
+MAKE_PTRCONSTRUCT(Array);
+MAKE_PTRCONSTRUCT(PackedByteArray);
+MAKE_PTRCONSTRUCT(PackedInt32Array);
+MAKE_PTRCONSTRUCT(PackedInt64Array);
+MAKE_PTRCONSTRUCT(PackedFloat32Array);
+MAKE_PTRCONSTRUCT(PackedFloat64Array);
+MAKE_PTRCONSTRUCT(PackedStringArray);
+MAKE_PTRCONSTRUCT(PackedVector2Array);
+MAKE_PTRCONSTRUCT(PackedVector3Array);
+MAKE_PTRCONSTRUCT(PackedColorArray);
+MAKE_PTRCONSTRUCT(Variant);
+
template <class T, class... P>
class VariantConstructor {
template <size_t... Is>
@@ -59,7 +113,7 @@ class VariantConstructor {
template <size_t... Is>
static _FORCE_INLINE_ void ptr_construct_helper(void *base, const void **p_args, IndexSequence<Is...>) {
- PtrToArg<T>::encode(T(PtrToArg<P>::convert(p_args[Is])...), base);
+ PtrConstruct<T>::construct(T(PtrToArg<P>::convert(p_args[Is])...), base);
}
public:
@@ -69,9 +123,9 @@ public:
construct_helper(*VariantGetInternalPtr<T>::get_ptr(&r_ret), p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
}
- static void validated_construct(Variant &r_ret, const Variant **p_args) {
- VariantTypeChanger<T>::change(&r_ret);
- validated_construct_helper(*VariantGetInternalPtr<T>::get_ptr(&r_ret), p_args, BuildIndexSequence<sizeof...(P)>{});
+ static void validated_construct(Variant *r_ret, const Variant **p_args) {
+ VariantTypeChanger<T>::change(r_ret);
+ validated_construct_helper(*VariantGetInternalPtr<T>::get_ptr(r_ret), p_args, BuildIndexSequence<sizeof...(P)>{});
}
static void ptr_construct(void *base, const void **p_args) {
ptr_construct_helper(base, p_args, BuildIndexSequence<sizeof...(P)>{});
@@ -107,12 +161,12 @@ public:
}
}
- static void validated_construct(Variant &r_ret, const Variant **p_args) {
- VariantInternal::clear(&r_ret);
- VariantInternal::object_assign(&r_ret, p_args[0]);
+ static void validated_construct(Variant *r_ret, const Variant **p_args) {
+ VariantInternal::clear(r_ret);
+ VariantInternal::object_assign(r_ret, p_args[0]);
}
static void ptr_construct(void *base, const void **p_args) {
- PtrToArg<Object *>::encode(PtrToArg<Object *>::convert(p_args[0]), base);
+ PtrConstruct<Object *>::construct(PtrToArg<Object *>::convert(p_args[0]), base);
}
static int get_argument_count() {
@@ -141,12 +195,12 @@ public:
VariantInternal::object_assign_null(&r_ret);
}
- static void validated_construct(Variant &r_ret, const Variant **p_args) {
- VariantInternal::clear(&r_ret);
- VariantInternal::object_assign_null(&r_ret);
+ static void validated_construct(Variant *r_ret, const Variant **p_args) {
+ VariantInternal::clear(r_ret);
+ VariantInternal::object_assign_null(r_ret);
}
static void ptr_construct(void *base, const void **p_args) {
- PtrToArg<Object *>::encode(nullptr, base);
+ PtrConstruct<Object *>::construct(nullptr, base);
}
static int get_argument_count() {
@@ -194,12 +248,12 @@ public:
*VariantGetInternalPtr<Callable>::get_ptr(&r_ret) = Callable(object_id, method);
}
- static void validated_construct(Variant &r_ret, const Variant **p_args) {
- VariantTypeChanger<Callable>::change(&r_ret);
- *VariantGetInternalPtr<Callable>::get_ptr(&r_ret) = Callable(VariantInternal::get_object_id(p_args[0]), *VariantGetInternalPtr<StringName>::get_ptr(p_args[1]));
+ static void validated_construct(Variant *r_ret, const Variant **p_args) {
+ VariantTypeChanger<Callable>::change(r_ret);
+ *VariantGetInternalPtr<Callable>::get_ptr(r_ret) = Callable(VariantInternal::get_object_id(p_args[0]), *VariantGetInternalPtr<StringName>::get_ptr(p_args[1]));
}
static void ptr_construct(void *base, const void **p_args) {
- PtrToArg<Callable>::encode(Callable(PtrToArg<Object *>::convert(p_args[0]), PtrToArg<StringName>::convert(p_args[1])), base);
+ PtrConstruct<Callable>::construct(Callable(PtrToArg<Object *>::convert(p_args[0]), PtrToArg<StringName>::convert(p_args[1])), base);
}
static int get_argument_count() {
@@ -251,12 +305,12 @@ public:
*VariantGetInternalPtr<Signal>::get_ptr(&r_ret) = Signal(object_id, method);
}
- static void validated_construct(Variant &r_ret, const Variant **p_args) {
- VariantTypeChanger<Signal>::change(&r_ret);
- *VariantGetInternalPtr<Signal>::get_ptr(&r_ret) = Signal(VariantInternal::get_object_id(p_args[0]), *VariantGetInternalPtr<StringName>::get_ptr(p_args[1]));
+ static void validated_construct(Variant *r_ret, const Variant **p_args) {
+ VariantTypeChanger<Signal>::change(r_ret);
+ *VariantGetInternalPtr<Signal>::get_ptr(r_ret) = Signal(VariantInternal::get_object_id(p_args[0]), *VariantGetInternalPtr<StringName>::get_ptr(p_args[1]));
}
static void ptr_construct(void *base, const void **p_args) {
- PtrToArg<Signal>::encode(Signal(PtrToArg<Object *>::convert(p_args[0]), PtrToArg<StringName>::convert(p_args[1])), base);
+ PtrConstruct<Signal>::construct(Signal(PtrToArg<Object *>::convert(p_args[0]), PtrToArg<StringName>::convert(p_args[1])), base);
}
static int get_argument_count() {
@@ -298,9 +352,9 @@ public:
}
}
- static void validated_construct(Variant &r_ret, const Variant **p_args) {
- VariantTypeChanger<Array>::change(&r_ret);
- Array &dst_arr = *VariantGetInternalPtr<Array>::get_ptr(&r_ret);
+ static void validated_construct(Variant *r_ret, const Variant **p_args) {
+ VariantTypeChanger<Array>::change(r_ret);
+ Array &dst_arr = *VariantGetInternalPtr<Array>::get_ptr(r_ret);
const T &src_arr = *VariantGetInternalPtr<T>::get_ptr(p_args[0]);
int size = src_arr.size();
@@ -319,7 +373,7 @@ public:
dst_arr[i] = src_arr[i];
}
- PtrToArg<Array>::encode(dst_arr, base);
+ PtrConstruct<Array>::construct(dst_arr, base);
}
static int get_argument_count() {
@@ -357,10 +411,10 @@ public:
}
}
- static void validated_construct(Variant &r_ret, const Variant **p_args) {
- VariantTypeChanger<T>::change(&r_ret);
+ static void validated_construct(Variant *r_ret, const Variant **p_args) {
+ VariantTypeChanger<T>::change(r_ret);
const Array &src_arr = *VariantGetInternalPtr<Array>::get_ptr(p_args[0]);
- T &dst_arr = *VariantGetInternalPtr<T>::get_ptr(&r_ret);
+ T &dst_arr = *VariantGetInternalPtr<T>::get_ptr(r_ret);
int size = src_arr.size();
dst_arr.resize(size);
@@ -378,7 +432,7 @@ public:
dst_arr.write[i] = src_arr[i];
}
- PtrToArg<T>::encode(dst_arr, base);
+ PtrConstruct<T>::construct(dst_arr, base);
}
static int get_argument_count() {
@@ -408,11 +462,11 @@ public:
VariantInternal::clear(&r_ret);
}
- static void validated_construct(Variant &r_ret, const Variant **p_args) {
- VariantInternal::clear(&r_ret);
+ static void validated_construct(Variant *r_ret, const Variant **p_args) {
+ VariantInternal::clear(r_ret);
}
static void ptr_construct(void *base, const void **p_args) {
- PtrToArg<Variant>::encode(Variant(), base);
+ PtrConstruct<Variant>::construct(Variant(), base);
}
static int get_argument_count() {
@@ -436,11 +490,11 @@ public:
r_error.error = Callable::CallError::CALL_OK;
}
- static void validated_construct(Variant &r_ret, const Variant **p_args) {
- VariantTypeChanger<T>::change_and_reset(&r_ret);
+ static void validated_construct(Variant *r_ret, const Variant **p_args) {
+ VariantTypeChanger<T>::change_and_reset(r_ret);
}
static void ptr_construct(void *base, const void **p_args) {
- PtrToArg<T>::encode(T(), base);
+ PtrConstruct<T>::construct(T(), base);
}
static int get_argument_count() {
@@ -463,8 +517,8 @@ public:
r_error.error = Callable::CallError::CALL_OK;
}
- static void validated_construct(Variant &r_ret, const Variant **p_args) {
- VariantInternal::clear(&r_ret);
+ static void validated_construct(Variant *r_ret, const Variant **p_args) {
+ VariantInternal::clear(r_ret);
}
static void ptr_construct(void *base, const void **p_args) {
ERR_FAIL_MSG("can't ptrcall nil constructor");
@@ -491,12 +545,12 @@ public:
r_error.error = Callable::CallError::CALL_OK;
}
- static void validated_construct(Variant &r_ret, const Variant **p_args) {
- VariantInternal::clear(&r_ret);
- VariantInternal::object_assign_null(&r_ret);
+ static void validated_construct(Variant *r_ret, const Variant **p_args) {
+ VariantInternal::clear(r_ret);
+ VariantInternal::object_assign_null(r_ret);
}
static void ptr_construct(void *base, const void **p_args) {
- PtrToArg<Object *>::encode(nullptr, base);
+ PtrConstruct<Object *>::construct(nullptr, base);
}
static int get_argument_count() {
diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp
index 5a0bbf041b..00d81f597a 100644
--- a/core/variant/variant_parser.cpp
+++ b/core/variant/variant_parser.cpp
@@ -743,6 +743,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
return ERR_PARSE_ERROR;
}
+ REF ref = REF(Object::cast_to<Reference>(obj));
+
get_token(p_stream, token, line, r_err_str);
if (token.type != TK_COMMA) {
r_err_str = "Expected ',' after object type";
@@ -767,12 +769,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
}
if (token2.type == TK_PARENTHESIS_CLOSE) {
- Reference *reference = Object::cast_to<Reference>(obj);
- if (reference) {
- value = REF(reference);
- } else {
- value = obj;
- }
+ value = ref.is_valid() ? Variant(ref) : Variant(obj);
return OK;
}
diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp
index f6a2c11830..cee7465205 100644
--- a/core/variant/variant_setget.cpp
+++ b/core/variant/variant_setget.cpp
@@ -582,18 +582,18 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
#define INDEXED_SETGET_STRUCT_TYPED(m_base_type, m_elem_type) \
struct VariantIndexedSetGet_##m_base_type { \
- static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool *oob) { \
int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
if (index < 0) { \
index += size; \
} \
if (index < 0 || index >= size) { \
- oob = true; \
+ *oob = true; \
return; \
} \
VariantTypeAdjust<m_elem_type>::adjust(value); \
*VariantGetInternalPtr<m_elem_type>::get_ptr(value) = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index]; \
- oob = false; \
+ *oob = false; \
} \
static void ptr_get(const void *base, int64_t index, void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -603,10 +603,10 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
OOB_TEST(index, v.size()); \
PtrToArg<m_elem_type>::encode(v[index], member); \
} \
- static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ static void set(Variant *base, int64_t index, const Variant *value, bool *valid, bool *oob) { \
if (value->get_type() != GetTypeInfo<m_elem_type>::VARIANT_TYPE) { \
- oob = false; \
- valid = false; \
+ *oob = false; \
+ *valid = false; \
return; \
} \
int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
@@ -614,25 +614,25 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
index += size; \
} \
if (index < 0 || index >= size) { \
- oob = true; \
- valid = false; \
+ *oob = true; \
+ *valid = false; \
return; \
} \
(*VariantGetInternalPtr<m_base_type>::get_ptr(base)).write[index] = *VariantGetInternalPtr<m_elem_type>::get_ptr(value); \
- oob = false; \
- valid = true; \
+ *oob = false; \
+ *valid = true; \
} \
- static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool *oob) { \
int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
if (index < 0) { \
index += size; \
} \
if (index < 0 || index >= size) { \
- oob = true; \
+ *oob = true; \
return; \
} \
(*VariantGetInternalPtr<m_base_type>::get_ptr(base)).write[index] = *VariantGetInternalPtr<m_elem_type>::get_ptr(value); \
- oob = false; \
+ *oob = false; \
} \
static void ptr_set(void *base, int64_t index, const void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -648,18 +648,18 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
#define INDEXED_SETGET_STRUCT_TYPED_NUMERIC(m_base_type, m_elem_type, m_assign_type) \
struct VariantIndexedSetGet_##m_base_type { \
- static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool *oob) { \
int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
if (index < 0) { \
index += size; \
} \
if (index < 0 || index >= size) { \
- oob = true; \
+ *oob = true; \
return; \
} \
VariantTypeAdjust<m_elem_type>::adjust(value); \
*VariantGetInternalPtr<m_elem_type>::get_ptr(value) = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index]; \
- oob = false; \
+ *oob = false; \
} \
static void ptr_get(const void *base, int64_t index, void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -669,14 +669,14 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
OOB_TEST(index, v.size()); \
PtrToArg<m_elem_type>::encode(v[index], member); \
} \
- static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ static void set(Variant *base, int64_t index, const Variant *value, bool *valid, bool *oob) { \
int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
if (index < 0) { \
index += size; \
} \
if (index < 0 || index >= size) { \
- oob = true; \
- valid = false; \
+ *oob = true; \
+ *valid = false; \
return; \
} \
m_assign_type num; \
@@ -685,25 +685,25 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
} else if (value->get_type() == Variant::FLOAT) { \
num = (m_assign_type)*VariantGetInternalPtr<double>::get_ptr(value); \
} else { \
- oob = false; \
- valid = false; \
+ *oob = false; \
+ *valid = false; \
return; \
} \
(*VariantGetInternalPtr<m_base_type>::get_ptr(base)).write[index] = num; \
- oob = false; \
- valid = true; \
+ *oob = false; \
+ *valid = true; \
} \
- static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool *oob) { \
int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
if (index < 0) { \
index += size; \
} \
if (index < 0 || index >= size) { \
- oob = true; \
+ *oob = true; \
return; \
} \
(*VariantGetInternalPtr<m_base_type>::get_ptr(base)).write[index] = *VariantGetInternalPtr<m_elem_type>::get_ptr(value); \
- oob = false; \
+ *oob = false; \
} \
static void ptr_set(void *base, int64_t index, const void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -719,14 +719,14 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
#define INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(m_base_type, m_elem_type, m_assign_type, m_max) \
struct VariantIndexedSetGet_##m_base_type { \
- static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool *oob) { \
if (index < 0 || index >= m_max) { \
- oob = true; \
+ *oob = true; \
return; \
} \
VariantTypeAdjust<m_elem_type>::adjust(value); \
*VariantGetInternalPtr<m_elem_type>::get_ptr(value) = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index]; \
- oob = false; \
+ *oob = false; \
} \
static void ptr_get(const void *base, int64_t index, void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -734,10 +734,10 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
OOB_TEST(index, m_max); \
PtrToArg<m_elem_type>::encode(v[index], member); \
} \
- static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ static void set(Variant *base, int64_t index, const Variant *value, bool *valid, bool *oob) { \
if (index < 0 || index >= m_max) { \
- oob = true; \
- valid = false; \
+ *oob = true; \
+ *valid = false; \
return; \
} \
m_assign_type num; \
@@ -746,21 +746,21 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
} else if (value->get_type() == Variant::FLOAT) { \
num = (m_assign_type)*VariantGetInternalPtr<double>::get_ptr(value); \
} else { \
- oob = false; \
- valid = false; \
+ *oob = false; \
+ *valid = false; \
return; \
} \
(*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = num; \
- oob = false; \
- valid = true; \
+ *oob = false; \
+ *valid = true; \
} \
- static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool *oob) { \
if (index < 0 || index >= m_max) { \
- oob = true; \
+ *oob = true; \
return; \
} \
(*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *VariantGetInternalPtr<m_elem_type>::get_ptr(value); \
- oob = false; \
+ *oob = false; \
} \
static void ptr_set(void *base, int64_t index, const void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -774,14 +774,14 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
#define INDEXED_SETGET_STRUCT_BULTIN_ACCESSOR(m_base_type, m_elem_type, m_accessor, m_max) \
struct VariantIndexedSetGet_##m_base_type { \
- static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool *oob) { \
if (index < 0 || index >= m_max) { \
- oob = true; \
+ *oob = true; \
return; \
} \
VariantTypeAdjust<m_elem_type>::adjust(value); \
*VariantGetInternalPtr<m_elem_type>::get_ptr(value) = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))m_accessor[index]; \
- oob = false; \
+ *oob = false; \
} \
static void ptr_get(const void *base, int64_t index, void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -789,27 +789,27 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
OOB_TEST(index, m_max); \
PtrToArg<m_elem_type>::encode(v m_accessor[index], member); \
} \
- static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ static void set(Variant *base, int64_t index, const Variant *value, bool *valid, bool *oob) { \
if (value->get_type() != GetTypeInfo<m_elem_type>::VARIANT_TYPE) { \
- oob = false; \
- valid = false; \
+ *oob = false; \
+ *valid = false; \
} \
if (index < 0 || index >= m_max) { \
- oob = true; \
- valid = false; \
+ *oob = true; \
+ *valid = false; \
return; \
} \
(*VariantGetInternalPtr<m_base_type>::get_ptr(base)) m_accessor[index] = *VariantGetInternalPtr<m_elem_type>::get_ptr(value); \
- oob = false; \
- valid = true; \
+ *oob = false; \
+ *valid = true; \
} \
- static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool *oob) { \
if (index < 0 || index >= m_max) { \
- oob = true; \
+ *oob = true; \
return; \
} \
(*VariantGetInternalPtr<m_base_type>::get_ptr(base)) m_accessor[index] = *VariantGetInternalPtr<m_elem_type>::get_ptr(value); \
- oob = false; \
+ *oob = false; \
} \
static void ptr_set(void *base, int64_t index, const void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -823,14 +823,14 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
#define INDEXED_SETGET_STRUCT_BULTIN_FUNC(m_base_type, m_elem_type, m_set, m_get, m_max) \
struct VariantIndexedSetGet_##m_base_type { \
- static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool *oob) { \
if (index < 0 || index >= m_max) { \
- oob = true; \
+ *oob = true; \
return; \
} \
VariantTypeAdjust<m_elem_type>::adjust(value); \
*VariantGetInternalPtr<m_elem_type>::get_ptr(value) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_get(index); \
- oob = false; \
+ *oob = false; \
} \
static void ptr_get(const void *base, int64_t index, void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -838,27 +838,27 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
OOB_TEST(index, m_max); \
PtrToArg<m_elem_type>::encode(v.m_get(index), member); \
} \
- static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ static void set(Variant *base, int64_t index, const Variant *value, bool *valid, bool *oob) { \
if (value->get_type() != GetTypeInfo<m_elem_type>::VARIANT_TYPE) { \
- oob = false; \
- valid = false; \
+ *oob = false; \
+ *valid = false; \
} \
if (index < 0 || index >= m_max) { \
- oob = true; \
- valid = false; \
+ *oob = true; \
+ *valid = false; \
return; \
} \
VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_set(index, *VariantGetInternalPtr<m_elem_type>::get_ptr(value)); \
- oob = false; \
- valid = true; \
+ *oob = false; \
+ *valid = true; \
} \
- static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool *oob) { \
if (index < 0 || index >= m_max) { \
- oob = true; \
+ *oob = true; \
return; \
} \
VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_set(index, *VariantGetInternalPtr<m_elem_type>::get_ptr(value)); \
- oob = false; \
+ *oob = false; \
} \
static void ptr_set(void *base, int64_t index, const void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -872,17 +872,17 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
#define INDEXED_SETGET_STRUCT_VARIANT(m_base_type) \
struct VariantIndexedSetGet_##m_base_type { \
- static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool *oob) { \
int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
if (index < 0) { \
index += size; \
} \
if (index < 0 || index >= size) { \
- oob = true; \
+ *oob = true; \
return; \
} \
*value = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index]; \
- oob = false; \
+ *oob = false; \
} \
static void ptr_get(const void *base, int64_t index, void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -892,31 +892,31 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
OOB_TEST(index, v.size()); \
PtrToArg<Variant>::encode(v[index], member); \
} \
- static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ static void set(Variant *base, int64_t index, const Variant *value, bool *valid, bool *oob) { \
int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
if (index < 0) { \
index += size; \
} \
if (index < 0 || index >= size) { \
- oob = true; \
- valid = false; \
+ *oob = true; \
+ *valid = false; \
return; \
} \
(*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *value; \
- oob = false; \
- valid = true; \
+ *oob = false; \
+ *valid = true; \
} \
- static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool *oob) { \
int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
if (index < 0) { \
index += size; \
} \
if (index < 0 || index >= size) { \
- oob = true; \
+ *oob = true; \
return; \
} \
(*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *value; \
- oob = false; \
+ *oob = false; \
} \
static void ptr_set(void *base, int64_t index, const void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -932,14 +932,14 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
#define INDEXED_SETGET_STRUCT_DICT(m_base_type) \
struct VariantIndexedSetGet_##m_base_type { \
- static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool *oob) { \
const Variant *ptr = VariantGetInternalPtr<m_base_type>::get_ptr(base)->getptr(index); \
if (!ptr) { \
- oob = true; \
+ *oob = true; \
return; \
} \
*value = *ptr; \
- oob = false; \
+ *oob = false; \
} \
static void ptr_get(const void *base, int64_t index, void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -948,14 +948,14 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
NULL_TEST(ptr); \
PtrToArg<Variant>::encode(*ptr, member); \
} \
- static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ static void set(Variant *base, int64_t index, const Variant *value, bool *valid, bool *oob) { \
(*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *value; \
- oob = false; \
- valid = true; \
+ *oob = false; \
+ *valid = true; \
} \
- static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool *oob) { \
(*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *value; \
- oob = false; \
+ *oob = false; \
} \
static void ptr_set(void *base, int64_t index, const void *member) { \
m_base_type &v = *reinterpret_cast<m_base_type *>(base); \
@@ -989,8 +989,8 @@ INDEXED_SETGET_STRUCT_VARIANT(Array)
INDEXED_SETGET_STRUCT_DICT(Dictionary)
struct VariantIndexedSetterGetterInfo {
- void (*setter)(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob);
- void (*getter)(const Variant *base, int64_t index, Variant *value, bool &oob);
+ void (*setter)(Variant *base, int64_t index, const Variant *value, bool *valid, bool *oob);
+ void (*getter)(const Variant *base, int64_t index, Variant *value, bool *oob);
Variant::ValidatedIndexedSetter validated_setter;
Variant::ValidatedIndexedGetter validated_getter;
@@ -1083,7 +1083,7 @@ Variant::PTRIndexedGetter Variant::get_member_ptr_indexed_getter(Variant::Type p
void Variant::set_indexed(int64_t p_index, const Variant &p_value, bool &r_valid, bool &r_oob) {
if (likely(variant_indexed_setters_getters[type].valid)) {
- variant_indexed_setters_getters[type].setter(this, p_index, &p_value, r_valid, r_oob);
+ variant_indexed_setters_getters[type].setter(this, p_index, &p_value, &r_valid, &r_oob);
} else {
r_valid = false;
r_oob = false;
@@ -1092,7 +1092,7 @@ void Variant::set_indexed(int64_t p_index, const Variant &p_value, bool &r_valid
Variant Variant::get_indexed(int64_t p_index, bool &r_valid, bool &r_oob) const {
if (likely(variant_indexed_setters_getters[type].valid)) {
Variant ret;
- variant_indexed_setters_getters[type].getter(this, p_index, &ret, r_oob);
+ variant_indexed_setters_getters[type].getter(this, p_index, &ret, &r_oob);
r_valid = !r_oob;
return ret;
} else {
@@ -1111,14 +1111,14 @@ uint64_t Variant::get_indexed_size() const {
}
struct VariantKeyedSetGetDictionary {
- static void get(const Variant *base, const Variant *key, Variant *value, bool &r_valid) {
+ static void get(const Variant *base, const Variant *key, Variant *value, bool *r_valid) {
const Variant *ptr = VariantGetInternalPtr<Dictionary>::get_ptr(base)->getptr(*key);
if (!ptr) {
- r_valid = false;
+ *r_valid = false;
return;
}
*value = *ptr;
- r_valid = true;
+ *r_valid = true;
}
static void ptr_get(const void *base, const void *key, void *value) {
/* avoid ptrconvert for performance*/
@@ -1127,17 +1127,17 @@ struct VariantKeyedSetGetDictionary {
NULL_TEST(ptr);
PtrToArg<Variant>::encode(*ptr, value);
}
- static void set(Variant *base, const Variant *key, const Variant *value, bool &r_valid) {
+ static void set(Variant *base, const Variant *key, const Variant *value, bool *r_valid) {
(*VariantGetInternalPtr<Dictionary>::get_ptr(base))[*key] = *value;
- r_valid = true;
+ *r_valid = true;
}
static void ptr_set(void *base, const void *key, const void *value) {
Dictionary &v = *reinterpret_cast<Dictionary *>(base);
v[PtrToArg<Variant>::convert(key)] = PtrToArg<Variant>::convert(value);
}
- static bool has(const Variant *base, const Variant *key, bool &r_valid) {
- r_valid = true;
+ static bool has(const Variant *base, const Variant *key, bool *r_valid) {
+ *r_valid = true;
return VariantGetInternalPtr<Dictionary>::get_ptr(base)->has(*key);
}
static bool ptr_has(const void *base, const void *key) {
@@ -1148,15 +1148,15 @@ struct VariantKeyedSetGetDictionary {
};
struct VariantKeyedSetGetObject {
- static void get(const Variant *base, const Variant *key, Variant *value, bool &r_valid) {
+ static void get(const Variant *base, const Variant *key, Variant *value, bool *r_valid) {
Object *obj = base->get_validated_object();
if (!obj) {
- r_valid = false;
+ *r_valid = false;
*value = Variant();
return;
}
- *value = obj->getvar(*key, &r_valid);
+ *value = obj->getvar(*key, r_valid);
}
static void ptr_get(const void *base, const void *key, void *value) {
const Object *obj = PtrToArg<Object *>::convert(base);
@@ -1164,14 +1164,14 @@ struct VariantKeyedSetGetObject {
Variant v = obj->getvar(PtrToArg<Variant>::convert(key));
PtrToArg<Variant>::encode(v, value);
}
- static void set(Variant *base, const Variant *key, const Variant *value, bool &r_valid) {
+ static void set(Variant *base, const Variant *key, const Variant *value, bool *r_valid) {
Object *obj = base->get_validated_object();
if (!obj) {
- r_valid = false;
+ *r_valid = false;
return;
}
- obj->setvar(*key, *value, &r_valid);
+ obj->setvar(*key, *value, r_valid);
}
static void ptr_set(void *base, const void *key, const void *value) {
Object *obj = PtrToArg<Object *>::convert(base);
@@ -1179,13 +1179,13 @@ struct VariantKeyedSetGetObject {
obj->setvar(PtrToArg<Variant>::convert(key), PtrToArg<Variant>::convert(value));
}
- static bool has(const Variant *base, const Variant *key, bool &r_valid) {
+ static bool has(const Variant *base, const Variant *key, bool *r_valid) {
Object *obj = base->get_validated_object();
- if (obj != nullptr) {
- r_valid = false;
+ if (!obj) {
+ *r_valid = false;
return false;
}
- r_valid = true;
+ *r_valid = true;
bool exists;
obj->getvar(*key, &exists);
return exists;
@@ -1199,14 +1199,6 @@ struct VariantKeyedSetGetObject {
}
};
-/*typedef void (*ValidatedKeyedSetter)(Variant *base, const Variant *key, const Variant *value);
-typedef void (*ValidatedKeyedGetter)(const Variant *base, const Variant *key, Variant *value, bool &valid);
-typedef bool (*ValidatedKeyedChecker)(const Variant *base, const Variant *key);
-
-typedef void (*PTRKeyedSetter)(void *base, const void *key, const void *value);
-typedef void (*PTRKeyedGetter)(const void *base, const void *key, void *value);
-typedef bool (*PTRKeyedChecker)(const void *base, const void *key);*/
-
struct VariantKeyedSetterGetterInfo {
Variant::ValidatedKeyedSetter validated_setter;
Variant::ValidatedKeyedGetter validated_getter;
@@ -1274,7 +1266,7 @@ Variant::PTRKeyedChecker Variant::get_member_ptr_keyed_checker(Variant::Type p_t
void Variant::set_keyed(const Variant &p_key, const Variant &p_value, bool &r_valid) {
if (likely(variant_keyed_setters_getters[type].valid)) {
- variant_keyed_setters_getters[type].validated_setter(this, &p_key, &p_value, r_valid);
+ variant_keyed_setters_getters[type].validated_setter(this, &p_key, &p_value, &r_valid);
} else {
r_valid = false;
}
@@ -1282,7 +1274,7 @@ void Variant::set_keyed(const Variant &p_key, const Variant &p_value, bool &r_va
Variant Variant::get_keyed(const Variant &p_key, bool &r_valid) const {
if (likely(variant_keyed_setters_getters[type].valid)) {
Variant ret;
- variant_keyed_setters_getters[type].validated_getter(this, &p_key, &ret, r_valid);
+ variant_keyed_setters_getters[type].validated_getter(this, &p_key, &ret, &r_valid);
return ret;
} else {
r_valid = false;
@@ -1291,7 +1283,7 @@ Variant Variant::get_keyed(const Variant &p_key, bool &r_valid) const {
}
bool Variant::has_key(const Variant &p_key, bool &r_valid) const {
if (likely(variant_keyed_setters_getters[type].valid)) {
- return variant_keyed_setters_getters[type].validated_checker(this, &p_key, r_valid);
+ return variant_keyed_setters_getters[type].validated_checker(this, &p_key, &r_valid);
} else {
r_valid = false;
return false;
diff --git a/doc/classes/AcceptDialog.xml b/doc/classes/AcceptDialog.xml
index e5eb216062..f4cf246713 100644
--- a/doc/classes/AcceptDialog.xml
+++ b/doc/classes/AcceptDialog.xml
@@ -23,7 +23,7 @@
If [code]true[/code], [code]right[/code] will place the button to the right of any sibling buttons.
</description>
</method>
- <method name="add_cancel">
+ <method name="add_cancel_button">
<return type="Button">
</return>
<argument index="0" name="name" type="String">
@@ -39,7 +39,7 @@
Returns the label used for built-in text.
</description>
</method>
- <method name="get_ok">
+ <method name="get_ok_button">
<return type="Button">
</return>
<description>
@@ -76,7 +76,7 @@
<signals>
<signal name="cancelled">
<description>
- Emitted when the dialog is closed or the button created with [method add_cancel] is pressed.
+ Emitted when the dialog is closed or the button created with [method add_cancel_button] is pressed.
</description>
</signal>
<signal name="confirmed">
diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml
index d34308501c..3e33a879b3 100644
--- a/doc/classes/Animation.xml
+++ b/doc/classes/Animation.xml
@@ -514,15 +514,15 @@
Removes a key by index in a given track.
</description>
</method>
- <method name="track_remove_key_at_position">
+ <method name="track_remove_key_at_time">
<return type="void">
</return>
<argument index="0" name="track_idx" type="int">
</argument>
- <argument index="1" name="position" type="float">
+ <argument index="1" name="time" type="float">
</argument>
<description>
- Removes a key by position (seconds) in a given track.
+ Removes a key at [code]time[/code] in a given track.
</description>
</method>
<method name="track_set_enabled">
diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml
index de2087d930..bebff61671 100644
--- a/doc/classes/AnimationPlayer.xml
+++ b/doc/classes/AnimationPlayer.xml
@@ -260,6 +260,10 @@
<member name="playback_speed" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0">
The speed scaling ratio. For instance, if this value is 1, then the animation plays at normal speed. If it's 0.5, then it plays at half speed. If it's 2, then it plays at double speed.
</member>
+ <member name="reset_on_save" type="bool" setter="set_reset_on_save_enabled" getter="is_reset_on_save_enabled" default="true">
+ This is used by the editor. If set to [code]true[/code], the scene will be saved with the effects of the reset animation applied (as if it had been seeked to time 0), then reverted after saving.
+ In other words, the saved scene file will contain the "default pose", as defined by the reset animation, if any, with the editor keeping the values that the nodes had before saving.
+ </member>
<member name="root_node" type="NodePath" setter="set_root" getter="get_root" default="NodePath(&quot;..&quot;)">
The node from which node path references will travel.
</member>
diff --git a/doc/classes/Area3D.xml b/doc/classes/Area3D.xml
index 92a8465762..2f8042bb1e 100644
--- a/doc/classes/Area3D.xml
+++ b/doc/classes/Area3D.xml
@@ -92,7 +92,7 @@
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" getter="get_audio_bus" default="@&quot;Master&quot;">
+ <member name="audio_bus_name" type="StringName" setter="set_audio_bus_name" getter="get_audio_bus_name" default="@&quot;Master&quot;">
The name of the area's audio bus.
</member>
<member name="audio_bus_override" type="bool" setter="set_audio_bus_override" getter="is_overriding_audio_bus" default="false">
diff --git a/doc/classes/Camera3D.xml b/doc/classes/Camera3D.xml
index b3fe452b12..052b23a7ab 100644
--- a/doc/classes/Camera3D.xml
+++ b/doc/classes/Camera3D.xml
@@ -189,7 +189,7 @@
<member name="environment" type="Environment" setter="set_environment" getter="get_environment">
The [Environment] to use for this camera.
</member>
- <member name="far" type="float" setter="set_zfar" getter="get_zfar" default="100.0">
+ <member name="far" type="float" setter="set_zfar" getter="get_zfar" default="4000.0">
The distance to the far culling boundary for this camera relative to its local Z axis.
</member>
<member name="fov" type="float" setter="set_fov" getter="get_fov" default="75.0">
diff --git a/doc/classes/CharFXTransform.xml b/doc/classes/CharFXTransform.xml
index d1759adf30..b4cb110337 100644
--- a/doc/classes/CharFXTransform.xml
+++ b/doc/classes/CharFXTransform.xml
@@ -13,24 +13,6 @@
<methods>
</methods>
<members>
- <member name="absolute_index" type="int" setter="set_absolute_index" getter="get_absolute_index" default="0">
- The index of the current character (starting from 0). Setting this property won't affect drawing.
- </member>
- <member name="character" type="int" setter="set_character" getter="get_character" default="0">
- The Unicode codepoint the character will use. This only affects non-whitespace characters. [method @GDScript.ord] can be useful here. For example, the following will replace all characters with asterisks:
- [codeblocks]
- [gdscript]
- # `char_fx` is the CharFXTransform parameter from `_process_custom_fx()`.
- # See the RichTextEffect documentation for details.
- char_fx.character = ord("*")
- [/gdscript]
- [csharp]
- // `char_fx` is the CharFXTransform parameter from `_process_custom_fx()`.
- // See the RichTextEffect documentation for details.
- charFx.Character = char.GetNumericValue('*');
- [/csharp]
- [/codeblocks]
- </member>
<member name="color" type="Color" setter="set_color" getter="get_color" default="Color( 0, 0, 0, 1 )">
The color the character will be drawn with.
</member>
@@ -45,11 +27,20 @@
{"foo": "hello", "bar": true, "baz": 42, "color": Color(1, 1, 1, 1)}
[/codeblock]
</member>
+ <member name="font" type="RID" setter="set_font" getter="get_font">
+ Font resource used to render glyph.
+ </member>
+ <member name="glyph_index" type="int" setter="set_glyph_index" getter="get_glyph_index" default="0">
+ Font specific glyph index.
+ </member>
<member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2( 0, 0 )">
The position offset the character will be drawn with (in pixels).
</member>
- <member name="relative_index" type="int" setter="set_relative_index" getter="get_relative_index" default="0">
- The index of the current character (starting from 0). Setting this property won't affect drawing.
+ <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.
+ </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.
</member>
<member name="visible" type="bool" setter="set_visibility" getter="is_visible" default="true">
If [code]true[/code], the character will be drawn. If [code]false[/code], the character will be hidden. Characters around hidden characters will reflow to take the space of hidden characters. If this is not desired, set their [member color] to [code]Color(1, 1, 1, 0)[/code] instead.
diff --git a/doc/classes/ConfirmationDialog.xml b/doc/classes/ConfirmationDialog.xml
index a850afdd9f..9d8977cef1 100644
--- a/doc/classes/ConfirmationDialog.xml
+++ b/doc/classes/ConfirmationDialog.xml
@@ -18,7 +18,7 @@
<tutorials>
</tutorials>
<methods>
- <method name="get_cancel">
+ <method name="get_cancel_button">
<return type="Button">
</return>
<description>
diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml
index ae1a8d86a7..14d44a2fbe 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -394,13 +394,13 @@
Returns [member margin_right] and [member margin_bottom].
</description>
</method>
- <method name="get_focus_neighbour" qualifiers="const">
+ <method name="get_focus_neighbor" qualifiers="const">
<return type="NodePath">
</return>
<argument index="0" name="margin" type="int" enum="Margin">
</argument>
<description>
- Returns the focus neighbour identified by [code]margin[/code] constant from [enum Margin] enum. A getter method for [member focus_neighbour_bottom], [member focus_neighbour_left], [member focus_neighbour_right] and [member focus_neighbour_top].
+ Returns the focus neighbor identified by [code]margin[/code] constant from [enum Margin] enum. A getter method for [member focus_neighbor_bottom], [member focus_neighbor_left], [member focus_neighbor_right] and [member focus_neighbor_top].
</description>
</method>
<method name="get_focus_owner" qualifiers="const">
@@ -920,15 +920,15 @@
Sets [member margin_right] and [member margin_bottom] at the same time.
</description>
</method>
- <method name="set_focus_neighbour">
+ <method name="set_focus_neighbor">
<return type="void">
</return>
<argument index="0" name="margin" type="int" enum="Margin">
</argument>
- <argument index="1" name="neighbour" type="NodePath">
+ <argument index="1" name="neighbor" type="NodePath">
</argument>
<description>
- Sets the anchor identified by [code]margin[/code] constant from [enum Margin] enum to [Control] at [code]neighbor[/code] node path. A setter method for [member focus_neighbour_bottom], [member focus_neighbour_left], [member focus_neighbour_right] and [member focus_neighbour_top].
+ Sets the anchor identified by [code]margin[/code] constant from [enum Margin] enum to [Control] at [code]neighbor[/code] node path. A setter method for [member focus_neighbor_bottom], [member focus_neighbor_left], [member focus_neighbor_right] and [member focus_neighbor_top].
</description>
</method>
<method name="set_global_position">
@@ -1028,16 +1028,16 @@
<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.
</member>
- <member name="focus_neighbour_bottom" type="NodePath" setter="set_focus_neighbour" getter="get_focus_neighbour" default="NodePath(&quot;&quot;)">
+ <member name="focus_neighbor_bottom" 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 down arrow on the keyboard or down on a gamepad by default. You can change the key by editing the [code]ui_down[/code] input action. The node must be a [Control]. If this property is not set, Godot will give focus to the closest [Control] to the bottom of this one.
</member>
- <member name="focus_neighbour_left" type="NodePath" setter="set_focus_neighbour" getter="get_focus_neighbour" default="NodePath(&quot;&quot;)">
+ <member name="focus_neighbor_left" 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 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_neighbour_right" type="NodePath" setter="set_focus_neighbour" getter="get_focus_neighbour" default="NodePath(&quot;&quot;)">
+ <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.
</member>
- <member name="focus_neighbour_top" type="NodePath" setter="set_focus_neighbour" getter="get_focus_neighbour" default="NodePath(&quot;&quot;)">
+ <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.
</member>
<member name="focus_next" type="NodePath" setter="set_focus_next" getter="get_focus_next" default="NodePath(&quot;&quot;)">
@@ -1132,7 +1132,7 @@
Tells the parent [Container] nodes how they should resize and place the node on the X axis. Use one of the [enum SizeFlags] constants to change the flags. See the constants to learn what each does.
</member>
<member name="size_flags_stretch_ratio" type="float" setter="set_stretch_ratio" getter="get_stretch_ratio" default="1.0">
- If the node and at least one of its neighbours uses the [constant SIZE_EXPAND] size flag, the parent [Container] will let it take more or less space depending on this property. If this node has a stretch ratio of 2 and its neighbour a ratio of 1, this node will take two thirds of the available space.
+ If the node and at least one of its neighbors uses the [constant SIZE_EXPAND] size flag, the parent [Container] will let it take more or less space depending on this property. If this node has a stretch ratio of 2 and its neighbor a ratio of 1, this node will take two thirds of the available space.
</member>
<member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" default="1">
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.
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index ca011abb36..874fe4e3de 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -130,14 +130,10 @@
</return>
<argument index="0" name="name" type="String">
</argument>
- <argument index="1" name="handler" type="Object">
- </argument>
- <argument index="2" name="callback" type="String">
- </argument>
- <argument index="3" name="ud" type="Variant" default="null">
+ <argument index="1" name="callable" type="Callable">
</argument>
<description>
- Adds a custom menu item to [b]Project &gt; Tools[/b] as [code]name[/code] that calls [code]callback[/code] on an instance of [code]handler[/code] with a parameter [code]ud[/code] when user activates it.
+ 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">
@@ -148,7 +144,7 @@
<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]. This submenu should be cleaned up using [code]remove_tool_menu_item(name)[/code].
+ 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">
diff --git a/doc/classes/FontData.xml b/doc/classes/FontData.xml
index cee424394a..e2c35f9ce7 100644
--- a/doc/classes/FontData.xml
+++ b/doc/classes/FontData.xml
@@ -179,6 +179,23 @@
Returns underline thickness in pixels.
</description>
</method>
+ <method name="get_variation" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="tag" type="String">
+ </argument>
+ <description>
+ Returns variation coordinate [code]tag[/code].
+ </description>
+ </method>
+ <method name="get_variation_list" qualifiers="const">
+ <return type="Dictionary">
+ </return>
+ <description>
+ Returns list of supported [url=https://docs.microsoft.com/en-us/typography/opentype/spec/dvaraxisreg]variation coordinates[/url], each coordinate is returned as [code]tag: Vector3i(min_value,max_value,default_value)[/code].
+ Font variations allow for continuous change of glyph characteristics along some given design axis, such as weight, width or slant.
+ </description>
+ </method>
<method name="has_char" qualifiers="const">
<return type="bool">
</return>
@@ -279,6 +296,17 @@
Adds override for [method is_script_supported].
</description>
</method>
+ <method name="set_variation">
+ <return type="void">
+ </return>
+ <argument index="0" name="tag" type="String">
+ </argument>
+ <argument index="1" name="value" type="float">
+ </argument>
+ <description>
+ Sets variation coordinate [code]tag[/code].
+ </description>
+ </method>
</methods>
<members>
<member name="antialiased" type="bool" setter="set_antialiased" getter="get_antialiased" default="false">
diff --git a/doc/classes/Generic6DOFJoint3D.xml b/doc/classes/Generic6DOFJoint3D.xml
index ae86ab7365..79b861dfb8 100644
--- a/doc/classes/Generic6DOFJoint3D.xml
+++ b/doc/classes/Generic6DOFJoint3D.xml
@@ -348,8 +348,6 @@
</member>
<member name="linear_spring_z/stiffness" type="float" setter="set_param_z" getter="get_param_z" default="0.01">
</member>
- <member name="precision" type="int" setter="set_precision" getter="get_precision" default="1">
- </member>
</members>
<constants>
<constant name="PARAM_LINEAR_LOWER_LIMIT" value="0" enum="Param">
diff --git a/doc/classes/Geometry2D.xml b/doc/classes/Geometry2D.xml
index 4ff54d15ce..2c0d9b54d1 100644
--- a/doc/classes/Geometry2D.xml
+++ b/doc/classes/Geometry2D.xml
@@ -91,7 +91,7 @@
<argument index="3" name="q2" type="Vector2">
</argument>
<description>
- Given the two 2D segments ([code]p1[/code], [code]p2[/code]) and ([code]q1[/code], [code]q2[/code]), finds those two points on the two segments that are closest to each other. Returns a [PackedVector2Array] that contains this point on ([code]p1[/code], [code]p2[/code]) as well the accompanying point on ([code]q1[/code], [code]q2[/code]).
+ Given the two 2D segments ([code]p1[/code], [code]q1[/code]) and ([code]p2[/code], [code]q2[/code]), finds those two points on the two segments that are closest to each other. Returns a [PackedVector2Array] that contains this point on ([code]p1[/code], [code]q1[/code]) as well the accompanying point on ([code]p2[/code], [code]q2[/code]).
</description>
</method>
<method name="intersect_polygons">
diff --git a/doc/classes/GraphEdit.xml b/doc/classes/GraphEdit.xml
index 77bd2c60cc..c5884aa44a 100644
--- a/doc/classes/GraphEdit.xml
+++ b/doc/classes/GraphEdit.xml
@@ -174,7 +174,22 @@
</method>
</methods>
<members>
+ <member name="connection_lines_antialiased" type="bool" setter="set_connection_lines_antialiased" getter="is_connection_lines_antialiased" default="true">
+ If [code]true[/code], the lines between nodes will use antialiasing.
+ </member>
+ <member name="connection_lines_thickness" type="float" setter="set_connection_lines_thickness" getter="get_connection_lines_thickness" default="2.0">
+ The thickness of the lines between the nodes.
+ </member>
<member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" override="true" enum="Control.FocusMode" default="2" />
+ <member name="minimap_enabled" type="bool" setter="set_minimap_enabled" getter="is_minimap_enabled" default="true">
+ If [code]true[/code], the minimap is visible.
+ </member>
+ <member name="minimap_opacity" type="float" setter="set_minimap_opacity" getter="get_minimap_opacity" default="0.65">
+ The opacity of the minimap rectangle.
+ </member>
+ <member name="minimap_size" type="Vector2" setter="set_minimap_size" getter="get_minimap_size" default="Vector2( 240, 160 )">
+ The size of the minimap rectangle. The map itself is based on the size of the grid area and is scaled to fit this rectangle.
+ </member>
<member name="rect_clip_content" type="bool" setter="set_clip_contents" getter="is_clipping_contents" override="true" default="true" />
<member name="right_disconnects" type="bool" setter="set_right_disconnects" getter="is_right_disconnects_enabled" default="false">
If [code]true[/code], enables disconnection of existing connections in the GraphEdit by dragging the right end.
@@ -317,6 +332,8 @@
<theme_item name="grid_minor" type="Color" default="Color( 1, 1, 1, 0.05 )">
Color of minor grid lines.
</theme_item>
+ <theme_item name="minimap" type="Texture2D">
+ </theme_item>
<theme_item name="minus" type="Texture2D">
The icon for the zoom out button.
</theme_item>
diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml
index b4325e822c..414249f110 100644
--- a/doc/classes/Image.xml
+++ b/doc/classes/Image.xml
@@ -422,7 +422,7 @@
<argument index="2" name="interpolation" type="int" enum="Image.Interpolation" default="1">
</argument>
<description>
- Resizes the image to the given [code]width[/code] and [code]height[/code]. New pixels are calculated using [code]interpolation[/code]. See [code]interpolation[/code] constants.
+ Resizes the image to the given [code]width[/code] and [code]height[/code]. New pixels are calculated using the [code]interpolation[/code] mode defined via [enum Interpolation] constants.
</description>
</method>
<method name="resize_to_po2">
@@ -430,8 +430,10 @@
</return>
<argument index="0" name="square" type="bool" default="false">
</argument>
+ <argument index="1" name="interpolation" type="int" enum="Image.Interpolation" default="1">
+ </argument>
<description>
- Resizes the image to the nearest power of 2 for the width and height. If [code]square[/code] is [code]true[/code] then set width and height to be the same.
+ Resizes the image to the nearest power of 2 for the width and height. If [code]square[/code] is [code]true[/code] then set width and height to be the same. New pixels are calculated using the [code]interpolation[/code] mode defined via [enum Interpolation] constants.
</description>
</method>
<method name="rgbe_to_srgb">
@@ -636,18 +638,19 @@
<constant name="FORMAT_BPTC_RGBFU" value="24" enum="Format">
Texture format that uses [url=https://www.khronos.org/opengl/wiki/BPTC_Texture_Compression]BPTC[/url] compression with unsigned floating-point RGB components.
</constant>
- <constant name="FORMAT_PVRTC2" value="25" enum="Format">
+ <constant name="FORMAT_PVRTC1_2" value="25" enum="Format">
Texture format used on PowerVR-supported mobile platforms, uses 2-bit color depth with no alpha. More information can be found [url=https://en.wikipedia.org/wiki/PVRTC]here[/url].
[b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space conversion is performed.
</constant>
- <constant name="FORMAT_PVRTC2A" value="26" enum="Format">
- Same as [url=https://en.wikipedia.org/wiki/PVRTC]PVRTC2[/url], but with an alpha component.
+ <constant name="FORMAT_PVRTC1_2A" value="26" enum="Format">
+ Same as [constant FORMAT_PVRTC1_2], but with an alpha component.
</constant>
- <constant name="FORMAT_PVRTC4" value="27" enum="Format">
- Similar to [url=https://en.wikipedia.org/wiki/PVRTC]PVRTC2[/url], but with 4-bit color depth and no alpha.
+ <constant name="FORMAT_PVRTC1_4" value="27" enum="Format">
+ Texture format used on PowerVR-supported mobile platforms, uses 4-bit color depth with no alpha. More information can be found [url=https://en.wikipedia.org/wiki/PVRTC]here[/url].
+ [b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space conversion is performed.
</constant>
- <constant name="FORMAT_PVRTC4A" value="28" enum="Format">
- Same as [url=https://en.wikipedia.org/wiki/PVRTC]PVRTC4[/url], but with an alpha component.
+ <constant name="FORMAT_PVRTC1_4A" value="28" enum="Format">
+ Same as [constant FORMAT_PVRTC1_4], but with an alpha component.
</constant>
<constant name="FORMAT_ETC" value="29" enum="Format">
[url=https://en.wikipedia.org/wiki/Ericsson_Texture_Compression#ETC1]Ericsson Texture Compression format 1[/url], also referred to as "ETC1", and is part of the OpenGL ES graphics standard. This format cannot store an alpha channel.
@@ -714,18 +717,18 @@
<constant name="COMPRESS_S3TC" value="0" enum="CompressMode">
Use S3TC compression.
</constant>
- <constant name="COMPRESS_PVRTC2" value="1" enum="CompressMode">
- Use PVRTC2 compression.
+ <constant name="COMPRESS_PVRTC1_4" value="1" enum="CompressMode">
+ Use PVRTC1 4-bpp compression.
</constant>
- <constant name="COMPRESS_PVRTC4" value="2" enum="CompressMode">
- Use PVRTC4 compression.
- </constant>
- <constant name="COMPRESS_ETC" value="3" enum="CompressMode">
+ <constant name="COMPRESS_ETC" value="2" enum="CompressMode">
Use ETC compression.
</constant>
- <constant name="COMPRESS_ETC2" value="4" enum="CompressMode">
+ <constant name="COMPRESS_ETC2" value="3" enum="CompressMode">
Use ETC2 compression.
</constant>
+ <constant name="COMPRESS_BPTC" value="4" enum="CompressMode">
+ Use BPTC compression.
+ </constant>
<constant name="USED_CHANNELS_L" value="0" enum="UsedChannels">
</constant>
<constant name="USED_CHANNELS_LA" value="1" enum="UsedChannels">
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index 1d80695798..65a815a603 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -233,7 +233,12 @@
<return type="String">
</return>
<description>
- Returns the host OS locale.
+ Returns the host OS locale as a string of the form [code]language_Script_COUNTRY_VARIANT@extra[/code].
+ [code]language[/code] - 2 or 3 letter [url=https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes]language code[/url], in lower case.
+ [code]Script[/code] - optional, 4 letter [url=https://en.wikipedia.org/wiki/ISO_15924]script code[/url], in title case.
+ [code]COUNTRY[/code] - optional, 2 or 3 letter [url=https://en.wikipedia.org/wiki/ISO_3166-1]country code[/url], in upper case.
+ [code]VARIANT[/code] - optional, language variant, region and sort order. Variant can have any number of underscored key words.
+ [code]extra[/code] - optional, semicolon separated list of additional key words. Currency, calendar, sort order and numbering system information.
</description>
</method>
<method name="get_model_name" qualifiers="const">
@@ -351,6 +356,7 @@
</return>
<description>
Returns the current UNIX epoch timestamp.
+ [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">
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index eab06f633c..d0f2a927cb 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -269,6 +269,14 @@
<member name="application/run/disable_stdout" type="bool" setter="" getter="" default="false">
If [code]true[/code], disables printing to standard output in an exported build.
</member>
+ <member name="application/run/flush_stdout_on_print" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], flushes the standard output stream every time a line is printed. This affects both terminal logging and file logging.
+ When running a project, this setting must be enabled if you want logs to be collected by service managers such as systemd/journalctl. This setting is disabled by default on release builds, since flushing on every printed line will negatively affect performance if lots of lines are printed in a rapid succession. Also, if this setting is enabled, logged files will still be written successfully if the application crashes or is otherwise killed by the user (without being closed "normally").
+ [b]Note:[/b] Regardless of this setting, the standard error stream ([code]stderr[/code]) is always flushed when a line is printed to it.
+ </member>
+ <member name="application/run/flush_stdout_on_print.debug" type="bool" setter="" getter="" default="true">
+ Debug build override for [member application/run/flush_stdout_on_print], as performance is less important during debugging.
+ </member>
<member name="application/run/frame_delay_msec" type="int" setter="" getter="" default="0">
Forces a delay between frames in the main loop (in milliseconds). This may be useful if you plan to disable vertical synchronization.
</member>
diff --git a/doc/classes/ProximityGroup3D.xml b/doc/classes/ProximityGroup3D.xml
index 1714c1ec8d..512d55c9a0 100644
--- a/doc/classes/ProximityGroup3D.xml
+++ b/doc/classes/ProximityGroup3D.xml
@@ -12,7 +12,7 @@
<method name="broadcast">
<return type="void">
</return>
- <argument index="0" name="name" type="String">
+ <argument index="0" name="method" type="String">
</argument>
<argument index="1" name="parameters" type="Variant">
</argument>
@@ -30,7 +30,7 @@
</members>
<signals>
<signal name="broadcast">
- <argument index="0" name="group_name" type="String">
+ <argument index="0" name="method" type="String">
</argument>
<argument index="1" name="parameters" type="Array">
</argument>
diff --git a/doc/classes/Rect2.xml b/doc/classes/Rect2.xml
index 02a77a0e24..5682e12b63 100644
--- a/doc/classes/Rect2.xml
+++ b/doc/classes/Rect2.xml
@@ -72,7 +72,7 @@
Returns a [Rect2] with equivalent position and area, modified so that the top-left corner is the origin and [code]width[/code] and [code]height[/code] are positive.
</description>
</method>
- <method name="clip">
+ <method name="intersection">
<return type="Rect2">
</return>
<argument index="0" name="b" type="Rect2">
diff --git a/doc/classes/Rect2i.xml b/doc/classes/Rect2i.xml
index e8b75a6ac6..ef12c8de1e 100644
--- a/doc/classes/Rect2i.xml
+++ b/doc/classes/Rect2i.xml
@@ -70,7 +70,7 @@
Returns a [Rect2i] with equivalent position and area, modified so that the top-left corner is the origin and [code]width[/code] and [code]height[/code] are positive.
</description>
</method>
- <method name="clip">
+ <method name="intersection">
<return type="Rect2i">
</return>
<argument index="0" name="b" type="Rect2i">
diff --git a/doc/classes/ResourceLoader.xml b/doc/classes/ResourceLoader.xml
index 049613fa5d..c55a51c7ae 100644
--- a/doc/classes/ResourceLoader.xml
+++ b/doc/classes/ResourceLoader.xml
@@ -20,7 +20,7 @@
</argument>
<description>
Returns whether a recognized resource exists for the given [code]path[/code].
- An optional [code]type_hint[/code] can be used to further specify the [Resource] type that should be handled by the [ResourceFormatLoader].
+ An optional [code]type_hint[/code] can be used to further specify the [Resource] type that should be handled by the [ResourceFormatLoader]. Anything that inherits from [Resource] can be used as a type hint, for example [Image].
</description>
</method>
<method name="get_dependencies">
@@ -63,7 +63,7 @@
<description>
Loads a resource at the given [code]path[/code], caching the result for further access.
The registered [ResourceFormatLoader]s are queried sequentially to find the first one which can handle the file's extension, and then attempt loading. If loading fails, the remaining ResourceFormatLoaders are also attempted.
- An optional [code]type_hint[/code] can be used to further specify the [Resource] type that should be handled by the [ResourceFormatLoader].
+ An optional [code]type_hint[/code] can be used to further specify the [Resource] type that should be handled by the [ResourceFormatLoader]. Anything that inherits from [Resource] can be used as a type hint, for example [Image].
If [code]no_cache[/code] is [code]true[/code], the resource cache will be bypassed and the resource will be loaded anew. Otherwise, the cached resource will be returned if it exists.
Returns an empty resource if no [ResourceFormatLoader] could handle the file.
GDScript has a simplified [method @GDScript.load] built-in method which can be used in most situations, leaving the use of [ResourceLoader] for more advanced scenarios.
diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml
index faf0d97766..0fd440fa75 100644
--- a/doc/classes/RichTextLabel.xml
+++ b/doc/classes/RichTextLabel.xml
@@ -25,6 +25,8 @@
</argument>
<argument index="3" name="color" type="Color" default="Color( 1, 1, 1, 1 )">
</argument>
+ <argument index="4" name="inline_align" type="int" enum="VAlign" default="0">
+ </argument>
<description>
Adds an image's opening and closing tags to the tag stack, optionally providing a [code]width[/code] and [code]height[/code] to resize the image and a [code]color[/code] to tint the image.
If [code]width[/code] or [code]height[/code] is set to 0, the image size will be adjusted in order to keep the original aspect ratio.
@@ -132,15 +134,6 @@
Terminates the current tag. Use after [code]push_*[/code] methods to close BBCodes manually. Does not need to follow [code]add_*[/code] methods.
</description>
</method>
- <method name="push_align">
- <return type="void">
- </return>
- <argument index="0" name="align" type="int" enum="RichTextLabel.Align">
- </argument>
- <description>
- Adds an [code][align][/code] tag based on the given [code]align[/code] value. See [enum Align] for possible values.
- </description>
- </method>
<method name="push_bold">
<return type="void">
</return>
@@ -180,6 +173,24 @@
Adds a [code][font][/code] tag to the tag stack. Overrides default fonts for its duration.
</description>
</method>
+ <method name="push_font_features">
+ <return type="void">
+ </return>
+ <argument index="0" name="opentype_features" type="Dictionary">
+ </argument>
+ <description>
+ Adds a [code][ot_feature][/code] tag to the tag stack. Overrides default OpenType font feature for its duration.
+ </description>
+ </method>
+ <method name="push_font_size">
+ <return type="void">
+ </return>
+ <argument index="0" name="font_size" type="int">
+ </argument>
+ <description>
+ Adds a [code][font_size][/code] tag to the tag stack. Overrides default font size for its duration.
+ </description>
+ </method>
<method name="push_indent">
<return type="void">
</return>
@@ -199,10 +210,14 @@
<method name="push_list">
<return type="void">
</return>
- <argument index="0" name="type" type="int" enum="RichTextLabel.ListType">
+ <argument index="0" name="level" type="int">
+ </argument>
+ <argument index="1" name="type" type="int" enum="RichTextLabel.ListType">
+ </argument>
+ <argument index="2" name="capitalize" type="bool">
</argument>
<description>
- Adds a [code][list][/code] tag to the tag stack. Similar to the BBCodes [code][ol][/code] or [code][ul][/code], but supports more list types. Not fully implemented!
+ Adds [code][ol][/code] or [code][ul][/code] tag to the tag stack. Multiplies [code]level[/code] by current [member tab_size] to determine new margin length.
</description>
</method>
<method name="push_meta">
@@ -228,6 +243,39 @@
Adds a [code][font][/code] tag with a normal font to the tag stack.
</description>
</method>
+ <method name="push_outline_color">
+ <return type="void">
+ </return>
+ <argument index="0" name="color" type="Color">
+ </argument>
+ <description>
+ Adds a [code][outline_color][/code] tag to the tag stack. Adds text outline for its duration.
+ </description>
+ </method>
+ <method name="push_outline_size">
+ <return type="void">
+ </return>
+ <argument index="0" name="outline_size" type="int">
+ </argument>
+ <description>
+ Adds a [code][outline_size][/code] tag to the tag stack. Overrides default text outline size for its duration.
+ </description>
+ </method>
+ <method name="push_paragraph">
+ <return type="void">
+ </return>
+ <argument index="0" name="align" type="int" enum="RichTextLabel.Align">
+ </argument>
+ <argument index="1" name="base_direction" type="int" enum="Control.TextDirection" default="0">
+ </argument>
+ <argument index="2" name="language" type="String" default="&quot;&quot;">
+ </argument>
+ <argument index="3" name="st_parser" type="int" enum="Control.StructuredTextParser" default="0">
+ </argument>
+ <description>
+ Adds a [code][p][/code] tag to the tag stack.
+ </description>
+ </method>
<method name="push_strikethrough">
<return type="void">
</return>
@@ -240,8 +288,10 @@
</return>
<argument index="0" name="columns" type="int">
</argument>
+ <argument index="1" name="inline_align" type="int" enum="VAlign" default="0">
+ </argument>
<description>
- Adds a [code][table=columns][/code] tag to the tag stack.
+ Adds a [code][table=columns,inline_align][/code] tag to the tag stack.
</description>
</method>
<method name="push_underline">
@@ -270,6 +320,46 @@
Scrolls the window's top line to match [code]line[/code].
</description>
</method>
+ <method name="set_cell_border_color">
+ <return type="void">
+ </return>
+ <argument index="0" name="color" type="Color">
+ </argument>
+ <description>
+ Sets color of a table cell border.
+ </description>
+ </method>
+ <method name="set_cell_padding">
+ <return type="void">
+ </return>
+ <argument index="0" name="padding" type="Rect2">
+ </argument>
+ <description>
+ Sets inner padding of a table cell.
+ </description>
+ </method>
+ <method name="set_cell_row_background_color">
+ <return type="void">
+ </return>
+ <argument index="0" name="odd_row_bg" type="Color">
+ </argument>
+ <argument index="1" name="even_row_bg" type="Color">
+ </argument>
+ <description>
+ Sets color of a table cell. Separate colors for alternating rows can be specified.
+ </description>
+ </method>
+ <method name="set_cell_size_override">
+ <return type="void">
+ </return>
+ <argument index="0" name="min_size" type="Vector2">
+ </argument>
+ <argument index="1" name="max_size" type="Vector2">
+ </argument>
+ <description>
+ Sets minimum and maximum size overrides for a table cell.
+ </description>
+ </method>
<method name="set_table_column_expand">
<return type="void">
</return>
@@ -302,6 +392,9 @@
If [code]true[/code], the label's height will be automatically updated to fit its content.
[b]Note:[/b] This property is used as a workaround to fix issues with [RichTextLabel] in [Container]s, but it's unreliable in some cases and will be removed in future versions.
</member>
+ <member name="language" type="String" setter="set_language" getter="get_language" default="&quot;&quot;">
+ Language code used for line-breaking and text shaping algorithms, if left empty current locale is used instead.
+ </member>
<member name="meta_underlined" type="bool" setter="set_meta_underline" getter="is_meta_underlined" default="true">
If [code]true[/code], the label underlines meta tags such as [code][url]{text}[/url][/code].
</member>
@@ -322,6 +415,12 @@
<member name="selection_enabled" type="bool" setter="set_selection_enabled" getter="is_selection_enabled" default="false">
If [code]true[/code], the label allows text selection.
</member>
+ <member name="structured_text_bidi_override" type="int" setter="set_structured_text_bidi_override" getter="get_structured_text_bidi_override" enum="Control.StructuredTextParser" default="0">
+ Set BiDi algorithm override for the structured text.
+ </member>
+ <member name="structured_text_bidi_override_options" type="Array" setter="set_structured_text_bidi_override_options" getter="get_structured_text_bidi_override_options" default="[ ]">
+ Set additional options for BiDi override.
+ </member>
<member name="tab_size" type="int" setter="set_tab_size" getter="get_tab_size" default="4">
The number of spaces associated with a single tab length. Does not affect [code]\t[/code] in text tags, only indent tags.
</member>
@@ -329,6 +428,9 @@
The raw text of the label.
When set, clears the tag stack and adds a raw text tag to the top of it. Does not parse BBCodes. Does not modify [member bbcode_text].
</member>
+ <member name="text_direction" type="int" setter="set_text_direction" getter="get_text_direction" enum="Control.TextDirection" default="0">
+ Base text writing direction.
+ </member>
<member name="visible_characters" type="int" setter="set_visible_characters" getter="get_visible_characters" default="-1">
The restricted number of characters to display in the label. If [code]-1[/code], all characters will be displayed.
</member>
@@ -375,7 +477,10 @@
<constant name="LIST_LETTERS" value="1" enum="ListType">
Each list item has a letter marker.
</constant>
- <constant name="LIST_DOTS" value="2" enum="ListType">
+ <constant name="LIST_ROMAN" value="2" enum="ListType">
+ Each list item has a roman number marker.
+ </constant>
+ <constant name="LIST_DOTS" value="3" enum="ListType">
Each list item has a filled circle marker.
</constant>
<constant name="ITEM_FRAME" value="0" enum="ItemType">
@@ -388,42 +493,56 @@
</constant>
<constant name="ITEM_FONT" value="4" enum="ItemType">
</constant>
- <constant name="ITEM_COLOR" value="5" enum="ItemType">
+ <constant name="ITEM_FONT_SIZE" value="5" enum="ItemType">
+ </constant>
+ <constant name="ITEM_FONT_FEATURES" value="6" enum="ItemType">
</constant>
- <constant name="ITEM_UNDERLINE" value="6" enum="ItemType">
+ <constant name="ITEM_COLOR" value="7" enum="ItemType">
</constant>
- <constant name="ITEM_STRIKETHROUGH" value="7" enum="ItemType">
+ <constant name="ITEM_OUTLINE_SIZE" value="8" enum="ItemType">
</constant>
- <constant name="ITEM_ALIGN" value="8" enum="ItemType">
+ <constant name="ITEM_OUTLINE_COLOR" value="9" enum="ItemType">
</constant>
- <constant name="ITEM_INDENT" value="9" enum="ItemType">
+ <constant name="ITEM_UNDERLINE" value="10" enum="ItemType">
</constant>
- <constant name="ITEM_LIST" value="10" enum="ItemType">
+ <constant name="ITEM_STRIKETHROUGH" value="11" enum="ItemType">
</constant>
- <constant name="ITEM_TABLE" value="11" enum="ItemType">
+ <constant name="ITEM_PARAGRAPH" value="12" enum="ItemType">
</constant>
- <constant name="ITEM_FADE" value="12" enum="ItemType">
+ <constant name="ITEM_INDENT" value="13" enum="ItemType">
</constant>
- <constant name="ITEM_SHAKE" value="13" enum="ItemType">
+ <constant name="ITEM_LIST" value="14" enum="ItemType">
</constant>
- <constant name="ITEM_WAVE" value="14" enum="ItemType">
+ <constant name="ITEM_TABLE" value="15" enum="ItemType">
</constant>
- <constant name="ITEM_TORNADO" value="15" enum="ItemType">
+ <constant name="ITEM_FADE" value="16" enum="ItemType">
</constant>
- <constant name="ITEM_RAINBOW" value="16" enum="ItemType">
+ <constant name="ITEM_SHAKE" value="17" enum="ItemType">
</constant>
- <constant name="ITEM_CUSTOMFX" value="18" enum="ItemType">
+ <constant name="ITEM_WAVE" value="18" enum="ItemType">
</constant>
- <constant name="ITEM_META" value="17" enum="ItemType">
+ <constant name="ITEM_TORNADO" value="19" enum="ItemType">
+ </constant>
+ <constant name="ITEM_RAINBOW" value="20" enum="ItemType">
+ </constant>
+ <constant name="ITEM_CUSTOMFX" value="22" enum="ItemType">
+ </constant>
+ <constant name="ITEM_META" value="21" enum="ItemType">
</constant>
</constants>
<theme_items>
<theme_item name="bold_font" type="Font">
The font used for bold text.
</theme_item>
+ <theme_item name="bold_font_size" type="int">
+ The font size used for bold text.
+ </theme_item>
<theme_item name="bold_italics_font" type="Font">
The font used for bold italics text.
</theme_item>
+ <theme_item name="bold_italics_font_size" type="int">
+ The font size used for bold italics text.
+ </theme_item>
<theme_item name="default_color" type="Color" default="Color( 1, 1, 1, 1 )">
The default text color.
</theme_item>
@@ -439,18 +558,27 @@
<theme_item name="italics_font" type="Font">
The font used for italics text.
</theme_item>
+ <theme_item name="italics_font_size" type="int">
+ The font size used for italics text.
+ </theme_item>
<theme_item name="line_separation" type="int" default="1">
The vertical space between lines.
</theme_item>
<theme_item name="mono_font" type="Font">
The font used for monospace text.
</theme_item>
+ <theme_item name="mono_font_size" type="int">
+ The font size used for monospace text.
+ </theme_item>
<theme_item name="normal" type="StyleBox">
The normal background for the [RichTextLabel].
</theme_item>
<theme_item name="normal_font" type="Font">
The default text font.
</theme_item>
+ <theme_item name="normal_font_size" type="int">
+ The default text font size.
+ </theme_item>
<theme_item name="selection_color" type="Color" default="Color( 0.1, 0.1, 1, 0.8 )">
The color of the selection box.
</theme_item>
@@ -463,9 +591,18 @@
<theme_item name="shadow_offset_y" type="int" default="1">
The vertical offset of the font's shadow.
</theme_item>
+ <theme_item name="table_border" type="Color" default="Color( 0, 0, 0, 0 )">
+ The default cell border color.
+ </theme_item>
+ <theme_item name="table_even_row_bg" type="Color" default="Color( 0, 0, 0, 0 )">
+ The default background color for even rows.
+ </theme_item>
<theme_item name="table_hseparation" type="int" default="3">
The horizontal separation of elements in a table.
</theme_item>
+ <theme_item name="table_odd_row_bg" type="Color" default="Color( 0, 0, 0, 0 )">
+ The default background color for odd rows.
+ </theme_item>
<theme_item name="table_vseparation" type="int" default="3">
The vertical separation of elements in a table.
</theme_item>
diff --git a/doc/classes/SubViewport.xml b/doc/classes/SubViewport.xml
index 4736401395..376082f417 100644
--- a/doc/classes/SubViewport.xml
+++ b/doc/classes/SubViewport.xml
@@ -45,8 +45,8 @@
<constant name="CLEAR_MODE_NEVER" value="1" enum="ClearMode">
Never clear the render target.
</constant>
- <constant name="CLEAR_MODE_ONLY_NEXT_FRAME" value="2" enum="ClearMode">
- Clear the render target next frame, then switch to [constant CLEAR_MODE_NEVER].
+ <constant name="CLEAR_MODE_ONCE" value="2" enum="ClearMode">
+ Clear the render target on the next frame, then switch to [constant CLEAR_MODE_NEVER].
</constant>
<constant name="UPDATE_DISABLED" value="0" enum="UpdateMode">
Do not update the render target.
@@ -58,7 +58,7 @@
Update the render target only when it is visible. This is the default value.
</constant>
<constant name="UPDATE_WHEN_PARENT_VISIBLE" value="3" enum="UpdateMode">
- Update the render target only when the its parent is visible.
+ Update the render target only when its parent is visible.
</constant>
<constant name="UPDATE_ALWAYS" value="4" enum="UpdateMode">
Always update the render target.
diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml
index 9c34c63e2f..791646000b 100644
--- a/doc/classes/TextServer.xml
+++ b/doc/classes/TextServer.xml
@@ -326,6 +326,27 @@
Returns underline thickness in pixels.
</description>
</method>
+ <method name="font_get_variation" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="font" type="RID">
+ </argument>
+ <argument index="1" name="tag" type="String">
+ </argument>
+ <description>
+ Returns variation coordinate [code]tag[/code].
+ </description>
+ </method>
+ <method name="font_get_variation_list" qualifiers="const">
+ <return type="Dictionary">
+ </return>
+ <argument index="0" name="font" type="RID">
+ </argument>
+ <description>
+ Returns list of supported [url=https://docs.microsoft.com/en-us/typography/opentype/spec/dvaraxisreg]variation coordinates[/url], each coordinate is returned as [code]tag: Vector3i(min_value,max_value,default_value)[/code].
+ Font variations allow for continuous change of glyph characteristics along some given design axis, such as weight, width or slant.
+ </description>
+ </method>
<method name="font_has_char" qualifiers="const">
<return type="bool">
</return>
@@ -469,6 +490,19 @@
Adds override for [method font_is_script_supported].
</description>
</method>
+ <method name="font_set_variation">
+ <return type="void">
+ </return>
+ <argument index="0" name="font" type="RID">
+ </argument>
+ <argument index="1" name="tag" type="String">
+ </argument>
+ <argument index="2" name="value" type="float">
+ </argument>
+ <description>
+ Sets variation coordinate [code]name[/code]. Unsupported coordinates will be silently ignored.
+ </description>
+ </method>
<method name="format_number" qualifiers="const">
<return type="String">
</return>
@@ -1133,6 +1167,9 @@
<constant name="GRAPHEME_IS_ELONGATION" value="128" enum="GraphemeFlag">
Grapheme is kashida.
</constant>
+ <constant name="GRAPHEME_IS_PUNCTUATION" value="256" enum="GraphemeFlag">
+ Grapheme is punctuation character.
+ </constant>
<constant name="HINTING_NONE" value="0" enum="Hinting">
Disables font hinting (smoother but less crisp).
</constant>
@@ -1160,7 +1197,10 @@
<constant name="FEATURE_FONT_SYSTEM" value="32" enum="Feature">
TextServer supports loading system fonts.
</constant>
- <constant name="FEATURE_USE_SUPPORT_DATA" value="64" enum="Feature">
+ <constant name="FEATURE_FONT_VARIABLE" value="64" enum="Feature">
+ TextServer supports variable fonts.
+ </constant>
+ <constant name="FEATURE_USE_SUPPORT_DATA" value="128" enum="Feature">
TextServer require external data file for some features.
</constant>
</constants>
diff --git a/doc/classes/TextureProgress.xml b/doc/classes/TextureProgressBar.xml
index 4937121ebf..56a7365855 100644
--- a/doc/classes/TextureProgress.xml
+++ b/doc/classes/TextureProgressBar.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TextureProgress" inherits="Range" version="4.0">
+<class name="TextureProgressBar" inherits="Range" version="4.0">
<brief_description>
Texture-based progress bar. Useful for loading screens and life or stamina bars.
</brief_description>
<description>
- TextureProgress works like [ProgressBar], but uses up to 3 textures instead of Godot's [Theme] resource. It can be used to create horizontal, vertical and radial progress bars.
+ TextureProgressBar works like [ProgressBar], but uses up to 3 textures instead of Godot's [Theme] resource. It can be used to create horizontal, vertical and radial progress bars.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/Theme.xml b/doc/classes/Theme.xml
index 1af6610f6f..3f7f22ebcd 100644
--- a/doc/classes/Theme.xml
+++ b/doc/classes/Theme.xml
@@ -120,6 +120,13 @@
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].
</description>
</method>
+ <method name="get_color_type_list" qualifiers="const">
+ <return type="PackedStringArray">
+ </return>
+ <description>
+ Returns all the [Color] types as a [PackedStringArray] filled with unique type names, for use in [method get_color] and/or [method get_color_list].
+ </description>
+ </method>
<method name="get_constant" qualifiers="const">
<return type="int">
</return>
@@ -140,6 +147,13 @@
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].
</description>
</method>
+ <method name="get_constant_type_list" qualifiers="const">
+ <return type="PackedStringArray">
+ </return>
+ <description>
+ Returns all the constant types as a [PackedStringArray] filled with unique type names, for use in [method get_constant] and/or [method get_constant_list].
+ </description>
+ </method>
<method name="get_font" qualifiers="const">
<return type="Font">
</return>
@@ -180,6 +194,13 @@
Returns all the font sizes as a [PackedStringArray] filled with each font size name, for use in [method get_font_size], if the theme has [code]node_type[/code].
</description>
</method>
+ <method name="get_font_type_list" qualifiers="const">
+ <return type="PackedStringArray">
+ </return>
+ <description>
+ Returns all the [Font] types as a [PackedStringArray] filled with unique type names, for use in [method get_font] and/or [method get_font_list].
+ </description>
+ </method>
<method name="get_icon" qualifiers="const">
<return type="Texture2D">
</return>
@@ -200,6 +221,13 @@
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].
</description>
</method>
+ <method name="get_icon_type_list" qualifiers="const">
+ <return type="PackedStringArray">
+ </return>
+ <description>
+ Returns all the icon types as a [PackedStringArray] filled with unique type names, for use in [method get_icon] and/or [method get_icon_list].
+ </description>
+ </method>
<method name="get_stylebox" qualifiers="const">
<return type="StyleBox">
</return>
@@ -220,20 +248,18 @@
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].
</description>
</method>
- <method name="get_stylebox_types" qualifiers="const">
+ <method name="get_stylebox_type_list" qualifiers="const">
<return type="PackedStringArray">
</return>
<description>
- Returns all the [StyleBox] types as a [PackedStringArray] filled with each [StyleBox]'s type, for use in [method get_stylebox] and/or [method get_stylebox_list], if the theme has [code]node_type[/code].
+ Returns all the [StyleBox] types as a [PackedStringArray] filled with unique type names, for use in [method get_stylebox] and/or [method get_stylebox_list].
</description>
</method>
<method name="get_type_list" qualifiers="const">
<return type="PackedStringArray">
</return>
- <argument index="0" name="node_type" type="String">
- </argument>
<description>
- Returns all the types in [code]node_type[/code] as a [PackedStringArray] for use in any of the [code]get_*[/code] functions, if the theme has [code]node_type[/code].
+ Returns all the theme types as a [PackedStringArray] filled with unique type names, for use in other [code]get_*[/code] functions of this theme.
</description>
</method>
<method name="has_color" qualifiers="const">
diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml
index 4e79560f3e..05194337db 100644
--- a/doc/classes/Vector2.xml
+++ b/doc/classes/Vector2.xml
@@ -149,7 +149,7 @@
<argument index="0" name="b" type="Vector2">
</argument>
<description>
- Returns the normalized vector pointing from this vector to [code]b[/code].
+ Returns the normalized vector pointing from this vector to [code]b[/code]. This is equivalent to using [code](b - a).normalized()[/code].
</description>
</method>
<method name="distance_squared_to">
diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml
index 2c2b30a644..14a829d7a5 100644
--- a/doc/classes/Vector3.xml
+++ b/doc/classes/Vector3.xml
@@ -117,7 +117,7 @@
<argument index="0" name="b" type="Vector3">
</argument>
<description>
- Returns the normalized vector pointing from this vector to [code]b[/code].
+ Returns the normalized vector pointing from this vector to [code]b[/code]. This is equivalent to using [code](b - a).normalized()[/code].
</description>
</method>
<method name="distance_squared_to">
diff --git a/drivers/png/SCsub b/drivers/png/SCsub
index db08be0c47..26508dc612 100644
--- a/drivers/png/SCsub
+++ b/drivers/png/SCsub
@@ -5,6 +5,9 @@ Import("env")
env_png = env.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_libpng"]:
thirdparty_dir = "#thirdparty/libpng/"
thirdparty_sources = [
@@ -41,7 +44,7 @@ if env["builtin_libpng"]:
env_thirdparty = env_png.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.drivers_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
if use_neon:
env_neon = env_thirdparty.Clone()
@@ -52,9 +55,17 @@ if env["builtin_libpng"]:
neon_sources.append(env_neon.Object(thirdparty_dir + "/arm/filter_neon_intrinsics.c"))
neon_sources.append(env_neon.Object(thirdparty_dir + "/arm/filter_neon.S"))
neon_sources.append(env_neon.Object(thirdparty_dir + "/arm/palette_neon_intrinsics.c"))
- env.drivers_sources += neon_sources
+ thirdparty_obj += neon_sources
+
+ env.drivers_sources += thirdparty_obj
+
# Godot source files
-env_png.add_source_files(env.drivers_sources, "*.cpp")
-Export("env")
+driver_obj = []
+
+env_png.add_source_files(driver_obj, "*.cpp")
+env.drivers_sources += driver_obj
+
+# Needed to force rebuilding the driver files when the thirdparty library is updated.
+env.Depends(driver_obj, thirdparty_obj)
diff --git a/drivers/spirv-reflect/SCsub b/drivers/spirv-reflect/SCsub
index d0ffaf068d..1e7b3de0e6 100644
--- a/drivers/spirv-reflect/SCsub
+++ b/drivers/spirv-reflect/SCsub
@@ -2,8 +2,7 @@
Import("env")
-env_spirv_reflect = env.Clone()
-env_spirv_reflect.disable_warnings()
+# Thirdparty source files
thirdparty_dir = "#thirdparty/spirv-reflect/"
thirdparty_sources = [
@@ -12,6 +11,7 @@ thirdparty_sources = [
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
-env_spirv_reflect.add_source_files(env.drivers_sources, thirdparty_sources)
+env_thirdparty = env.Clone()
+env_thirdparty.disable_warnings()
-Export("env")
+env_thirdparty.add_source_files(env.drivers_sources, thirdparty_sources)
diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h
index 2982e0c55c..51e5a00e36 100644
--- a/drivers/unix/os_unix.h
+++ b/drivers/unix/os_unix.h
@@ -45,7 +45,7 @@ protected:
virtual int unix_initialize_audio(int p_audio_driver);
//virtual Error initialize(int p_video_driver,int p_audio_driver);
- virtual void finalize_core();
+ virtual void finalize_core() override;
String stdin_buf;
@@ -53,7 +53,7 @@ public:
OS_Unix();
virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
- virtual String get_stdin_string(bool p_block);
+ virtual String get_stdin_string(bool p_block) override;
//virtual void set_mouse_show(bool p_show);
//virtual void set_mouse_grab(bool p_grab);
@@ -65,39 +65,39 @@ public:
//virtual VideoMode get_video_mode() const;
//virtual void get_fullscreen_mode_list(List<VideoMode> *p_list) const;
- virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false);
- virtual Error close_dynamic_library(void *p_library_handle);
- virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false);
+ virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false) override;
+ virtual Error close_dynamic_library(void *p_library_handle) override;
+ virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false) override;
- virtual Error set_cwd(const String &p_cwd);
+ virtual Error set_cwd(const String &p_cwd) override;
- virtual String get_name() const;
+ virtual String get_name() const override;
- virtual Date get_date(bool utc) const;
- virtual Time get_time(bool utc) const;
- virtual TimeZoneInfo get_time_zone_info() const;
+ virtual Date get_date(bool utc) const override;
+ virtual Time get_time(bool utc) const override;
+ virtual TimeZoneInfo get_time_zone_info() const override;
- virtual double get_unix_time() const;
+ virtual double get_unix_time() const override;
- virtual void delay_usec(uint32_t p_usec) const;
- virtual uint64_t get_ticks_usec() const;
+ virtual void delay_usec(uint32_t p_usec) const override;
+ virtual uint64_t get_ticks_usec() const override;
- virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr);
- virtual Error kill(const ProcessID &p_pid);
- virtual int get_process_id() const;
+ virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) override;
+ virtual Error kill(const ProcessID &p_pid) override;
+ virtual int get_process_id() const override;
- virtual bool has_environment(const String &p_var) const;
- virtual String get_environment(const String &p_var) const;
- virtual bool set_environment(const String &p_var, const String &p_value) const;
- virtual String get_locale() const;
+ virtual bool has_environment(const String &p_var) const override;
+ virtual String get_environment(const String &p_var) const override;
+ virtual bool set_environment(const String &p_var, const String &p_value) const override;
+ virtual String get_locale() const override;
- virtual int get_processor_count() const;
+ virtual int get_processor_count() const override;
- virtual void debug_break();
- virtual void initialize_debugging();
+ virtual void debug_break() override;
+ virtual void initialize_debugging() override;
- virtual String get_executable_path() const;
- virtual String get_user_data_dir() const;
+ virtual String get_executable_path() const override;
+ virtual String get_user_data_dir() const override;
};
class UnixTerminalLogger : public StdLogger {
diff --git a/drivers/vulkan/SCsub b/drivers/vulkan/SCsub
index 13fcaf16d2..14b9d63204 100644
--- a/drivers/vulkan/SCsub
+++ b/drivers/vulkan/SCsub
@@ -2,7 +2,7 @@
Import("env")
-env.add_source_files(env.drivers_sources, "*.cpp")
+thirdparty_obj = []
# FIXME: Refactor all this to reduce code duplication.
if env["platform"] == "android":
@@ -22,7 +22,8 @@ if env["platform"] == "android":
thirdparty_dir = "#thirdparty/vulkan"
vma_sources = [thirdparty_dir + "/android/vk_mem_alloc.cpp"]
- env_thirdparty.add_source_files(env.drivers_sources, vma_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, vma_sources)
+
elif env["platform"] == "iphone":
# Use bundled Vulkan headers
thirdparty_dir = "#thirdparty/vulkan"
@@ -33,7 +34,8 @@ elif env["platform"] == "iphone":
env_thirdparty.disable_warnings()
vma_sources = [thirdparty_dir + "/vk_mem_alloc.cpp"]
- env_thirdparty.add_source_files(env.drivers_sources, vma_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, vma_sources)
+
elif env["builtin_vulkan"]:
# Use bundled Vulkan headers
thirdparty_dir = "#thirdparty/vulkan"
@@ -98,8 +100,9 @@ elif env["builtin_vulkan"]:
env_thirdparty.AppendUnique(CPPDEFINES=["HAVE_SECURE_GETENV"])
loader_sources = [thirdparty_dir + "/loader/" + file for file in loader_sources]
- env_thirdparty.add_source_files(env.drivers_sources, loader_sources)
- env_thirdparty.add_source_files(env.drivers_sources, vma_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, loader_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, vma_sources)
+
else: # Always build VMA.
thirdparty_dir = "#thirdparty/vulkan"
env.Prepend(CPPPATH=[thirdparty_dir])
@@ -109,4 +112,18 @@ else: # Always build VMA.
env_thirdparty.disable_warnings()
vma_sources = [thirdparty_dir + "/vk_mem_alloc.cpp"]
- env_thirdparty.add_source_files(env.drivers_sources, vma_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, vma_sources)
+
+
+env.drivers_sources += thirdparty_obj
+
+
+# Godot source files
+
+driver_obj = []
+
+env.add_source_files(driver_obj, "*.cpp")
+env.drivers_sources += driver_obj
+
+# Needed to force rebuilding the driver files when the thirdparty code is updated.
+env.Depends(driver_obj, thirdparty_obj)
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index ecc689bd2b..c6d49de274 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -1362,6 +1362,7 @@ Error RenderingDeviceVulkan::_buffer_allocate(Buffer *p_buffer, uint32_t p_size,
p_buffer->buffer_info.buffer = p_buffer->buffer;
p_buffer->buffer_info.offset = 0;
p_buffer->buffer_info.range = p_size;
+ p_buffer->usage = p_usage;
return OK;
}
@@ -3485,7 +3486,7 @@ RID RenderingDeviceVulkan::sampler_create(const SamplerState &p_state) {
/**** VERTEX ARRAY ****/
/**********************/
-RID RenderingDeviceVulkan::vertex_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data) {
+RID RenderingDeviceVulkan::vertex_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data, bool p_use_as_storage) {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID());
@@ -3494,8 +3495,12 @@ RID RenderingDeviceVulkan::vertex_buffer_create(uint32_t p_size_bytes, const Vec
ERR_FAIL_COND_V_MSG(compute_list != nullptr && p_data.size(), RID(),
"Creating buffers with data is forbidden during creation of a draw list");
+ uint32_t usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
+ if (p_use_as_storage) {
+ usage |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
+ }
Buffer buffer;
- _buffer_allocate(&buffer, p_size_bytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY);
+ _buffer_allocate(&buffer, p_size_bytes, usage, VMA_MEMORY_USAGE_GPU_ONLY);
if (p_data.size()) {
uint64_t data_size = p_data.size();
const uint8_t *r = p_data.ptr();
@@ -4595,7 +4600,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
List<Vector<VkBufferView>> buffer_views;
List<Vector<VkDescriptorImageInfo>> image_infos;
//used for verification to make sure a uniform set does not use a framebuffer bound texture
- Vector<RID> attachable_textures;
+ LocalVector<UniformSet::AttachableTexture> attachable_textures;
Vector<Texture *> mutable_sampled_textures;
Vector<Texture *> mutable_storage_textures;
@@ -4688,7 +4693,10 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
img_info.imageView = texture->view;
if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT)) {
- attachable_textures.push_back(texture->owner.is_valid() ? texture->owner : uniform.ids[j + 1]);
+ UniformSet::AttachableTexture attachable_texture;
+ attachable_texture.bind = set_uniform.binding;
+ attachable_texture.texture = texture->owner.is_valid() ? texture->owner : uniform.ids[j + 1];
+ attachable_textures.push_back(attachable_texture);
}
if (texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT) {
@@ -4738,7 +4746,10 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
img_info.imageView = texture->view;
if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT)) {
- attachable_textures.push_back(texture->owner.is_valid() ? texture->owner : uniform.ids[j]);
+ UniformSet::AttachableTexture attachable_texture;
+ attachable_texture.bind = set_uniform.binding;
+ attachable_texture.texture = texture->owner.is_valid() ? texture->owner : uniform.ids[j];
+ attachable_textures.push_back(attachable_texture);
}
if (texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT) {
@@ -4911,7 +4922,15 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
ERR_FAIL_COND_V_MSG(uniform.ids.size() != 1, RID(),
"Storage buffer supplied (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.ids.size()) + " provided).");
- Buffer *buffer = storage_buffer_owner.getornull(uniform.ids[0]);
+ Buffer *buffer = nullptr;
+
+ if (storage_buffer_owner.owns(uniform.ids[0])) {
+ buffer = storage_buffer_owner.getornull(uniform.ids[0]);
+ } else if (vertex_buffer_owner.owns(uniform.ids[0])) {
+ buffer = vertex_buffer_owner.getornull(uniform.ids[0]);
+
+ ERR_FAIL_COND_V_MSG(!(buffer->usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), RID(), "Vertex buffer supplied (binding: " + itos(uniform.binding) + ") was not created with storage flag.");
+ }
ERR_FAIL_COND_V_MSG(!buffer, RID(), "Storage buffer supplied (binding: " + itos(uniform.binding) + ") is invalid.");
//if 0, then its sized on link time
@@ -6155,13 +6174,13 @@ void RenderingDeviceVulkan::draw_list_bind_uniform_set(DrawListID p_list, RID p_
#ifdef DEBUG_ENABLED
{ //validate that textures bound are not attached as framebuffer bindings
uint32_t attachable_count = uniform_set->attachable_textures.size();
- const RID *attachable_ptr = uniform_set->attachable_textures.ptr();
+ const UniformSet::AttachableTexture *attachable_ptr = uniform_set->attachable_textures.ptr();
uint32_t bound_count = draw_list_bound_textures.size();
const RID *bound_ptr = draw_list_bound_textures.ptr();
for (uint32_t i = 0; i < attachable_count; i++) {
for (uint32_t j = 0; j < bound_count; j++) {
- ERR_FAIL_COND_MSG(attachable_ptr[i] == bound_ptr[j],
- "Attempted to use the same texture in framebuffer attachment and a uniform set, this is not allowed.");
+ ERR_FAIL_COND_MSG(attachable_ptr[i].texture == bound_ptr[j],
+ "Attempted to use the same texture in framebuffer attachment and a uniform (set: " + itos(p_index) + ", binding: " + itos(attachable_ptr[i].bind) + "), this is not allowed.");
}
}
}
@@ -6365,7 +6384,7 @@ void RenderingDeviceVulkan::draw_list_enable_scissor(DrawListID p_list, const Re
Rect2i rect = p_rect;
rect.position += dl->viewport.position;
- rect = dl->viewport.clip(rect);
+ rect = dl->viewport.intersection(rect);
if (rect.get_area() == 0) {
return;
diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h
index 35fc6debdd..05c5b9c63e 100644
--- a/drivers/vulkan/rendering_device_vulkan.h
+++ b/drivers/vulkan/rendering_device_vulkan.h
@@ -32,6 +32,7 @@
#define RENDERING_DEVICE_VULKAN_H
#include "core/os/thread_safe.h"
+#include "core/templates/local_vector.h"
#include "core/templates/oa_hash_map.h"
#include "core/templates/rid_owner.h"
#include "servers/rendering/rendering_device.h"
@@ -45,11 +46,6 @@
#include <vulkan/vulkan.h>
-//todo:
-//compute
-//push constants
-//views of texture slices
-
class VulkanContext;
class RenderingDeviceVulkan : public RenderingDevice {
@@ -638,7 +634,12 @@ class RenderingDeviceVulkan : public RenderingDevice {
DescriptorPoolKey pool_key;
VkDescriptorSet descriptor_set = VK_NULL_HANDLE;
//VkPipelineLayout pipeline_layout; //not owned, inherited from shader
- Vector<RID> attachable_textures; //used for validation
+ struct AttachableTexture {
+ uint32_t bind;
+ RID texture;
+ };
+
+ LocalVector<AttachableTexture> attachable_textures; //used for validation
Vector<Texture *> mutable_sampled_textures; //used for layout change
Vector<Texture *> mutable_storage_textures; //used for layout change
};
@@ -951,7 +952,7 @@ public:
/**** VERTEX ARRAY ****/
/**********************/
- virtual RID vertex_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>());
+ virtual RID vertex_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>(), bool p_use_as_storage = false);
// Internally reference counted, this ID is warranted to be unique for the same description, but needs to be freed as many times as it was allocated
virtual VertexFormatID vertex_format_create(const Vector<VertexAttribute> &p_vertex_formats);
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index 855c8a2d68..1f4092745a 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -493,6 +493,8 @@ Error VulkanContext::_create_physical_device() {
// features based on this query
vkGetPhysicalDeviceFeatures(gpu, &physical_device_features);
+ physical_device_features.robustBufferAccess = false; //turn off robust buffer access, which can hamper performance on some hardware
+
#define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \
{ \
fp##entrypoint = (PFN_vk##entrypoint)vkGetInstanceProcAddr(inst, "vk" #entrypoint); \
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 7411af2280..ec411c6415 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -37,6 +37,7 @@
#include "editor/plugins/animation_player_editor_plugin.h"
#include "editor_node.h"
#include "editor_scale.h"
+#include "scene/animation/animation_player.h"
#include "scene/main/window.h"
#include "servers/audio/audio_stream.h"
@@ -2208,7 +2209,7 @@ void AnimationTrackEdit::draw_rect_clipped(const Rect2 &p_rect, const Color &p_c
return;
}
Rect2 clip = Rect2(clip_left, 0, clip_right - clip_left, get_size().height);
- draw_rect(clip.clip(p_rect), p_color, p_filled);
+ draw_rect(clip.intersection(p_rect), p_color, p_filled);
}
void AnimationTrackEdit::draw_bg(int p_clip_left, int p_clip_right) {
@@ -2912,7 +2913,7 @@ void AnimationTrackEdit::append_to_selection(const Rect2 &p_box, bool p_deselect
// Left Border including space occupied by keyframes on t=0.
int limit_start_hitbox = timeline->get_name_limit() - type_icon->get_width();
Rect2 select_rect(limit_start_hitbox, 0, get_size().width - timeline->get_name_limit() - timeline->get_buttons_width(), get_size().height);
- select_rect = select_rect.clip(p_box);
+ select_rect = select_rect.intersection(p_box);
// Select should happen in the opposite order of drawing for more accurate overlap select.
for (int i = animation->track_get_key_count(track) - 1; i >= 0; i--) {
@@ -3299,6 +3300,19 @@ void AnimationTrackEditor::set_anim_pos(float p_pos) {
bezier_edit->set_play_position(p_pos);
}
+static bool track_type_is_resettable(Animation::TrackType p_type) {
+ switch (p_type) {
+ case Animation::TYPE_VALUE:
+ [[fallthrough]];
+ case Animation::TYPE_BEZIER:
+ [[fallthrough]];
+ case Animation::TYPE_TRANSFORM:
+ return true;
+ default:
+ return false;
+ }
+}
+
void AnimationTrackEditor::_query_insert(const InsertData &p_id) {
if (insert_frame != Engine::get_singleton()->get_frames_drawn()) {
//clear insert list for the frame if frame changed
@@ -3319,40 +3333,58 @@ void AnimationTrackEditor::_query_insert(const InsertData &p_id) {
insert_data.push_back(p_id);
+ bool reset_allowed = true;
+ AnimationPlayer *player = AnimationPlayerEditor::singleton->get_player();
+ if (player->has_animation("RESET") && player->get_animation("RESET") == animation) {
+ // Avoid messing with the reset animation itself
+ reset_allowed = false;
+ } else {
+ bool some_resettable = false;
+ for (int i = 0; i < insert_data.size(); i++) {
+ if (track_type_is_resettable(insert_data[i].type)) {
+ some_resettable = true;
+ break;
+ }
+ }
+ if (!some_resettable) {
+ reset_allowed = false;
+ }
+ }
+
if (p_id.track_idx == -1) {
- if (bool(EDITOR_DEF("editors/animation/confirm_insert_track", true))) {
- //potential new key, does not exist
- int num_tracks = 0;
- bool all_bezier = true;
- for (int i = 0; i < insert_data.size(); i++) {
- if (insert_data[i].type != Animation::TYPE_VALUE && insert_data[i].type != Animation::TYPE_BEZIER) {
- all_bezier = false;
- }
+ int num_tracks = 0;
+ bool all_bezier = true;
+ for (int i = 0; i < insert_data.size(); i++) {
+ if (insert_data[i].type != Animation::TYPE_VALUE && insert_data[i].type != Animation::TYPE_BEZIER) {
+ all_bezier = false;
+ }
- if (insert_data[i].track_idx == -1) {
- ++num_tracks;
- }
+ if (insert_data[i].track_idx == -1) {
+ ++num_tracks;
+ }
- if (insert_data[i].type != Animation::TYPE_VALUE) {
- continue;
- }
+ if (insert_data[i].type != Animation::TYPE_VALUE) {
+ continue;
+ }
- switch (insert_data[i].value.get_type()) {
- case Variant::INT:
- case Variant::FLOAT:
- case Variant::VECTOR2:
- case Variant::VECTOR3:
- case Variant::QUAT:
- case Variant::PLANE:
- case Variant::COLOR: {
- // Valid.
- } break;
- default: {
- all_bezier = false;
- }
+ switch (insert_data[i].value.get_type()) {
+ case Variant::INT:
+ case Variant::FLOAT:
+ case Variant::VECTOR2:
+ case Variant::VECTOR3:
+ case Variant::QUAT:
+ case Variant::PLANE:
+ case Variant::COLOR: {
+ // Valid.
+ } break;
+ default: {
+ all_bezier = false;
}
}
+ }
+ if (bool(EDITOR_DEF("editors/animation/confirm_insert_track", true))) {
+ //potential new key, does not exist
if (num_tracks == 1) {
insert_confirm_text->set_text(vformat(TTR("Create new track for %s and insert key?"), p_id.query));
} else {
@@ -3360,23 +3392,26 @@ void AnimationTrackEditor::_query_insert(const InsertData &p_id) {
}
insert_confirm_bezier->set_visible(all_bezier);
- insert_confirm->get_ok()->set_text(TTR("Create"));
+ insert_confirm_reset->set_visible(reset_allowed);
+
+ insert_confirm->get_ok_button()->set_text(TTR("Create"));
insert_confirm->popup_centered();
insert_query = true;
} else {
- call_deferred("_insert_delay");
+ call_deferred("_insert_delay", reset_allowed && EDITOR_GET("editors/animation/default_create_reset_tracks"), all_bezier && EDITOR_GET("editors/animation/default_create_bezier_tracks"));
insert_queue = true;
}
} else {
if (!insert_query && !insert_queue) {
- call_deferred("_insert_delay");
+ // Create Beziers wouldn't make sense in this case, where no tracks are being created
+ call_deferred("_insert_delay", reset_allowed && EDITOR_GET("editors/animation/default_create_reset_tracks"), false);
insert_queue = true;
}
}
}
-void AnimationTrackEditor::_insert_delay() {
+void AnimationTrackEditor::_insert_delay(bool p_create_reset, bool p_create_beziers) {
if (insert_query) {
//discard since it's entered into query mode
insert_queue = false;
@@ -3385,13 +3420,18 @@ void AnimationTrackEditor::_insert_delay() {
undo_redo->create_action(TTR("Anim Insert"));
- int last_track = animation->get_track_count();
+ Ref<Animation> reset_anim;
+ if (p_create_reset) {
+ reset_anim = _create_and_get_reset_animation();
+ }
+
+ TrackIndices next_tracks(animation.ptr(), reset_anim.ptr());
bool advance = false;
while (insert_data.size()) {
if (insert_data.front()->get().advance) {
advance = true;
}
- last_track = _confirm_insert(insert_data.front()->get(), last_track);
+ next_tracks = _confirm_insert(insert_data.front()->get(), next_tracks, p_create_reset, p_create_beziers);
insert_data.pop_front();
}
@@ -3682,12 +3722,34 @@ void AnimationTrackEditor::insert_value_key(const String &p_property, const Vari
}
}
+Ref<Animation> AnimationTrackEditor::_create_and_get_reset_animation() {
+ AnimationPlayer *player = AnimationPlayerEditor::singleton->get_player();
+ if (player->has_animation("RESET")) {
+ return player->get_animation("RESET");
+ } else {
+ Ref<Animation> reset_anim;
+ reset_anim.instance();
+ reset_anim->set_length(ANIM_MIN_LENGTH);
+ undo_redo->add_do_method(player, "add_animation", "RESET", reset_anim);
+ undo_redo->add_do_method(AnimationPlayerEditor::singleton, "_animation_player_changed", player);
+ undo_redo->add_undo_method(player, "remove_animation", "RESET");
+ undo_redo->add_undo_method(AnimationPlayerEditor::singleton, "_animation_player_changed", player);
+ return reset_anim;
+ }
+}
+
void AnimationTrackEditor::_confirm_insert_list() {
undo_redo->create_action(TTR("Anim Create & Insert"));
- int last_track = animation->get_track_count();
+ bool create_reset = insert_confirm_reset->is_visible() && insert_confirm_reset->is_pressed();
+ Ref<Animation> reset_anim;
+ if (create_reset) {
+ reset_anim = _create_and_get_reset_animation();
+ }
+
+ TrackIndices next_tracks(animation.ptr(), reset_anim.ptr());
while (insert_data.size()) {
- last_track = _confirm_insert(insert_data.front()->get(), last_track, insert_confirm_bezier->is_pressed());
+ next_tracks = _confirm_insert(insert_data.front()->get(), next_tracks, create_reset, insert_confirm_bezier->is_pressed());
insert_data.pop_front();
}
@@ -3807,11 +3869,7 @@ static Vector<String> _get_bezier_subindices_for_type(Variant::Type p_type, bool
return subindices;
}
-int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, bool p_create_beziers) {
- if (p_last_track == -1) {
- p_last_track = animation->get_track_count();
- }
-
+AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertData p_id, TrackIndices p_next_tracks, bool p_create_reset, bool p_create_beziers) {
bool created = false;
if (p_id.track_idx < 0) {
if (p_create_beziers) {
@@ -3823,10 +3881,10 @@ int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, boo
id.type = Animation::TYPE_BEZIER;
id.value = p_id.value.get(subindices[i].substr(1, subindices[i].length()));
id.path = String(p_id.path) + subindices[i];
- _confirm_insert(id, p_last_track + i);
+ p_next_tracks = _confirm_insert(id, p_next_tracks, p_create_reset, false);
}
- return p_last_track + subindices.size();
+ return p_next_tracks;
}
}
created = true;
@@ -3863,7 +3921,7 @@ int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, boo
}
}
- p_id.track_idx = p_last_track;
+ p_id.track_idx = p_next_tracks.normal;
undo_redo->add_do_method(animation.ptr(), "add_track", p_id.type);
undo_redo->add_do_method(animation.ptr(), "track_set_path", p_id.track_idx, p_id.path);
@@ -3915,7 +3973,7 @@ int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, boo
// Just remove the track.
undo_redo->add_undo_method(this, "_clear_selection", false);
undo_redo->add_undo_method(animation.ptr(), "remove_track", animation->get_track_count());
- p_last_track++;
+ p_next_tracks.normal++;
} else {
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", p_id.track_idx, time);
int existing = animation->track_find_key(p_id.track_idx, time, true);
@@ -3926,9 +3984,27 @@ int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, boo
}
}
+ if (p_create_reset && track_type_is_resettable(p_id.type)) {
+ bool create_reset_track = true;
+ Animation *reset_anim = AnimationPlayerEditor::singleton->get_player()->get_animation("RESET").ptr();
+ for (int i = 0; i < reset_anim->get_track_count(); i++) {
+ if (reset_anim->track_get_path(i) == p_id.path) {
+ create_reset_track = false;
+ break;
+ }
+ }
+ if (create_reset_track) {
+ undo_redo->add_do_method(reset_anim, "add_track", p_id.type);
+ undo_redo->add_do_method(reset_anim, "track_set_path", p_next_tracks.reset, p_id.path);
+ undo_redo->add_do_method(reset_anim, "track_insert_key", p_next_tracks.reset, 0.0f, value);
+ undo_redo->add_undo_method(reset_anim, "remove_track", reset_anim->get_track_count());
+ p_next_tracks.reset++;
+ }
+ }
+
undo_redo->commit_action();
- return p_last_track;
+ return p_next_tracks;
}
void AnimationTrackEditor::show_select_node_warning(bool p_show) {
@@ -4224,6 +4300,7 @@ void AnimationTrackEditor::_notification(int p_what) {
selected_filter->set_icon(get_theme_icon("AnimationFilter", "EditorIcons"));
imported_anim_warning->set_icon(get_theme_icon("NodeWarning", "EditorIcons"));
main_panel->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree"));
+ edit->get_popup()->set_item_icon(edit->get_popup()->get_item_index(EDIT_APPLY_RESET), get_theme_icon("Reload", "EditorIcons"));
}
if (p_what == NOTIFICATION_READY) {
@@ -4947,7 +5024,7 @@ void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) {
Rect2 rect(from, to - from);
Rect2 scroll_rect = Rect2(scroll->get_global_position(), scroll->get_size());
- rect = scroll_rect.clip(rect);
+ rect = scroll_rect.intersection(rect);
box_selection->set_position(rect.position);
box_selection->set_size(rect.size);
@@ -5056,6 +5133,11 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) {
}
}
+void AnimationTrackEditor::_edit_menu_about_to_popup() {
+ AnimationPlayer *player = AnimationPlayerEditor::singleton->get_player();
+ edit->get_popup()->set_item_disabled(edit->get_popup()->get_item_index(EDIT_APPLY_RESET), !player->can_apply_reset());
+}
+
void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
last_menu_track_opt = p_option;
switch (p_option) {
@@ -5378,6 +5460,10 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
emit_signal("timeline_changed", pos, true);
} break;
+ case EDIT_APPLY_RESET: {
+ AnimationPlayerEditor::singleton->get_player()->apply_reset(true);
+
+ } break;
case EDIT_OPTIMIZE_ANIMATION: {
optimize_dialog->popup_centered(Size2(250, 180) * EDSCALE);
@@ -5710,10 +5796,13 @@ AnimationTrackEditor::AnimationTrackEditor() {
edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/goto_next_step", TTR("Go to Next Step"), KEY_MASK_CMD | KEY_RIGHT), EDIT_GOTO_NEXT_STEP);
edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/goto_prev_step", TTR("Go to Previous Step"), KEY_MASK_CMD | KEY_LEFT), EDIT_GOTO_PREV_STEP);
edit->get_popup()->add_separator();
+ edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/apply_reset", TTR("Apply Reset")), EDIT_APPLY_RESET);
+ edit->get_popup()->add_separator();
edit->get_popup()->add_item(TTR("Optimize Animation"), EDIT_OPTIMIZE_ANIMATION);
edit->get_popup()->add_item(TTR("Clean-Up Animation"), EDIT_CLEAN_UP_ANIMATION);
edit->get_popup()->connect("id_pressed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed));
+ edit->get_popup()->connect("about_to_popup", callable_mp(this, &AnimationTrackEditor::_edit_menu_about_to_popup));
pick_track = memnew(SceneTreeDialog);
add_child(pick_track);
@@ -5739,9 +5828,16 @@ AnimationTrackEditor::AnimationTrackEditor() {
insert_confirm->add_child(icvb);
insert_confirm_text = memnew(Label);
icvb->add_child(insert_confirm_text);
+ HBoxContainer *ichb = memnew(HBoxContainer);
+ icvb->add_child(ichb);
insert_confirm_bezier = memnew(CheckBox);
insert_confirm_bezier->set_text(TTR("Use Bezier Curves"));
- icvb->add_child(insert_confirm_bezier);
+ insert_confirm_bezier->set_pressed(EDITOR_GET("editors/animation/default_create_bezier_tracks"));
+ ichb->add_child(insert_confirm_bezier);
+ insert_confirm_reset = memnew(CheckBox);
+ insert_confirm_reset->set_text(TTR("Create RESET Track(s)", ""));
+ insert_confirm_reset->set_pressed(EDITOR_GET("editors/animation/default_create_reset_tracks"));
+ ichb->add_child(insert_confirm_reset);
keying = false;
moving_selection = false;
key_edit = nullptr;
@@ -5789,7 +5885,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
optimize_max_angle->set_step(0.1);
optimize_max_angle->set_value(22);
- optimize_dialog->get_ok()->set_text(TTR("Optimize"));
+ optimize_dialog->get_ok_button()->set_text(TTR("Optimize"));
optimize_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed), varray(EDIT_CLEAN_UP_ANIMATION_CONFIRM));
//
@@ -5814,7 +5910,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
cleanup_vb->add_child(cleanup_all);
cleanup_dialog->set_title(TTR("Clean-Up Animation(s) (NO UNDO!)"));
- cleanup_dialog->get_ok()->set_text(TTR("Clean-Up"));
+ cleanup_dialog->get_ok_button()->set_text(TTR("Clean-Up"));
cleanup_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed), varray(EDIT_CLEAN_UP_ANIMATION_CONFIRM));
@@ -5834,7 +5930,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
track_copy_dialog = memnew(ConfirmationDialog);
add_child(track_copy_dialog);
track_copy_dialog->set_title(TTR("Select Tracks to Copy"));
- track_copy_dialog->get_ok()->set_text(TTR("Copy"));
+ track_copy_dialog->get_ok_button()->set_text(TTR("Copy"));
VBoxContainer *track_vbox = memnew(VBoxContainer);
track_copy_dialog->add_child(track_vbox);
diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h
index 3cb31fe21e..7006959187 100644
--- a/editor/animation_track_editor.h
+++ b/editor/animation_track_editor.h
@@ -47,6 +47,8 @@
#include "scene/resources/animation.h"
#include "scene_tree_editor.h"
+class AnimationPlayer;
+
class AnimationTimelineEdit : public Range {
GDCLASS(AnimationTimelineEdit, Range);
@@ -285,6 +287,7 @@ class AnimationTrackEditor : public VBoxContainer {
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,
@@ -361,6 +364,7 @@ class AnimationTrackEditor : public VBoxContainer {
Label *insert_confirm_text;
CheckBox *insert_confirm_bezier;
+ CheckBox *insert_confirm_reset;
ConfirmationDialog *insert_confirm;
bool insert_queue;
bool inserting;
@@ -369,9 +373,19 @@ class AnimationTrackEditor : public VBoxContainer {
uint64_t insert_frame;
void _query_insert(const InsertData &p_id);
+ Ref<Animation> _create_and_get_reset_animation();
void _confirm_insert_list();
- int _confirm_insert(InsertData p_id, int p_last_track, bool p_create_beziers = false);
- void _insert_delay();
+ struct TrackIndices {
+ int normal;
+ int reset;
+
+ TrackIndices(const Animation *p_anim = nullptr, const Animation *p_reset_anim = nullptr) {
+ normal = p_anim ? p_anim->get_track_count() : 0;
+ reset = p_reset_anim ? p_reset_anim->get_track_count() : 0;
+ }
+ };
+ TrackIndices _confirm_insert(InsertData p_id, TrackIndices p_next_tracks, bool p_create_reset, bool p_create_beziers);
+ void _insert_delay(bool p_create_reset, bool p_create_beziers);
void _root_removed(Node *p_root);
@@ -447,6 +461,7 @@ class AnimationTrackEditor : public VBoxContainer {
void _select_all_tracks_for_copy();
+ void _edit_menu_about_to_popup();
void _edit_menu_pressed(int p_option);
int last_menu_track_opt;
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index 2630589912..473597b9b3 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -252,16 +252,16 @@ void ConnectDialog::_update_ok_enabled() {
Node *target = tree->get_selected();
if (target == nullptr) {
- get_ok()->set_disabled(true);
+ get_ok_button()->set_disabled(true);
return;
}
if (!advanced->is_pressed() && target->get_script().is_null()) {
- get_ok()->set_disabled(true);
+ get_ok_button()->set_disabled(true);
return;
}
- get_ok()->set_disabled(false);
+ get_ok_button()->set_disabled(false);
}
void ConnectDialog::_notification(int p_what) {
@@ -496,8 +496,8 @@ ConnectDialog::ConnectDialog() {
error = memnew(AcceptDialog);
add_child(error);
error->set_title(TTR("Cannot connect signal"));
- error->get_ok()->set_text(TTR("Close"));
- get_ok()->set_text(TTR("Connect"));
+ error->get_ok_button()->set_text(TTR("Close"));
+ get_ok_button()->set_text(TTR("Connect"));
}
ConnectDialog::~ConnectDialog() {
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index 0f9c9bde7b..75d57b040f 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -57,10 +57,10 @@ void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode, const St
if (p_replace_mode) {
set_title(vformat(TTR("Change %s Type"), base_type));
- get_ok()->set_text(TTR("Change"));
+ get_ok_button()->set_text(TTR("Change"));
} else {
set_title(vformat(TTR("Create New %s"), base_type));
- get_ok()->set_text(TTR("Create"));
+ get_ok_button()->set_text(TTR("Create"));
}
_load_favorites_and_history();
@@ -195,7 +195,7 @@ void CreateDialog::_update_search() {
} else {
favorite->set_disabled(true);
help_bit->set_text("");
- get_ok()->set_disabled(true);
+ get_ok_button()->set_disabled(true);
search_options->deselect_all();
}
}
@@ -396,7 +396,7 @@ void CreateDialog::select_type(const String &p_type) {
favorite->set_disabled(false);
favorite->set_pressed(favorite_list.find(p_type) != -1);
- get_ok()->set_disabled(false);
+ get_ok_button()->set_disabled(false);
}
String CreateDialog::get_selected_type() {
diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp
index 1a7a30ba4e..a27f196d49 100644
--- a/editor/dependency_editor.cpp
+++ b/editor/dependency_editor.cpp
@@ -553,7 +553,7 @@ void DependencyRemoveDialog::_bind_methods() {
}
DependencyRemoveDialog::DependencyRemoveDialog() {
- get_ok()->set_text(TTR("Remove"));
+ get_ok_button()->set_text(TTR("Remove"));
VBoxContainer *vb = memnew(VBoxContainer);
add_child(vb);
@@ -619,8 +619,8 @@ DependencyErrorDialog::DependencyErrorDialog() {
files->set_v_size_flags(Control::SIZE_EXPAND_FILL);
set_min_size(Size2(500, 220) * EDSCALE);
- get_ok()->set_text(TTR("Open Anyway"));
- get_cancel()->set_text(TTR("Close"));
+ get_ok_button()->set_text(TTR("Open Anyway"));
+ get_cancel_button()->set_text(TTR("Close"));
text = memnew(Label);
vb->add_child(text);
@@ -756,7 +756,7 @@ void OrphanResourcesDialog::_bind_methods() {
OrphanResourcesDialog::OrphanResourcesDialog() {
set_title(TTR("Orphan Resource Explorer"));
delete_confirm = memnew(ConfirmationDialog);
- get_ok()->set_text(TTR("Delete"));
+ get_ok_button()->set_text(TTR("Delete"));
add_child(delete_confirm);
dep_edit = memnew(DependencyEditor);
add_child(dep_edit);
diff --git a/editor/editor_asset_installer.cpp b/editor/editor_asset_installer.cpp
index 8aeeba52ed..aa6f7c8766 100644
--- a/editor/editor_asset_installer.cpp
+++ b/editor/editor_asset_installer.cpp
@@ -335,7 +335,7 @@ EditorAssetInstaller::EditorAssetInstaller() {
error = memnew(AcceptDialog);
add_child(error);
- get_ok()->set_text(TTR("Install"));
+ get_ok_button()->set_text(TTR("Install"));
set_title(TTR("Package Installer"));
updating = false;
diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp
index 0888fecc67..d81dc05a75 100644
--- a/editor/editor_audio_buses.cpp
+++ b/editor/editor_audio_buses.cpp
@@ -851,15 +851,15 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
cc = 0;
for (int i = 0; i < CHANNELS_MAX; i++) {
- channel[i].vu_l = memnew(TextureProgress);
- channel[i].vu_l->set_fill_mode(TextureProgress::FILL_BOTTOM_TO_TOP);
+ channel[i].vu_l = memnew(TextureProgressBar);
+ channel[i].vu_l->set_fill_mode(TextureProgressBar::FILL_BOTTOM_TO_TOP);
hb->add_child(channel[i].vu_l);
channel[i].vu_l->set_min(-80);
channel[i].vu_l->set_max(24);
channel[i].vu_l->set_step(0.1);
- channel[i].vu_r = memnew(TextureProgress);
- channel[i].vu_r->set_fill_mode(TextureProgress::FILL_BOTTOM_TO_TOP);
+ channel[i].vu_r = memnew(TextureProgressBar);
+ channel[i].vu_r->set_fill_mode(TextureProgressBar::FILL_BOTTOM_TO_TOP);
hb->add_child(channel[i].vu_r);
channel[i].vu_r->set_min(-80);
channel[i].vu_r->set_max(24);
diff --git a/editor/editor_audio_buses.h b/editor/editor_audio_buses.h
index f72541100d..b5f2f5af81 100644
--- a/editor/editor_audio_buses.h
+++ b/editor/editor_audio_buses.h
@@ -43,7 +43,7 @@
#include "scene/gui/panel_container.h"
#include "scene/gui/scroll_container.h"
#include "scene/gui/slider.h"
-#include "scene/gui/texture_progress.h"
+#include "scene/gui/texture_progress_bar.h"
#include "scene/gui/texture_rect.h"
#include "scene/gui/tree.h"
@@ -66,8 +66,8 @@ class EditorAudioBus : public PanelContainer {
float peak_l = 0;
float peak_r = 0;
- TextureProgress *vu_l = nullptr;
- TextureProgress *vu_r = nullptr;
+ TextureProgressBar *vu_l = nullptr;
+ TextureProgressBar *vu_r = nullptr;
} channel[CHANNELS_MAX];
OptionButton *send;
diff --git a/editor/editor_dir_dialog.cpp b/editor/editor_dir_dialog.cpp
index 206fdef7c9..17e0fd0fae 100644
--- a/editor/editor_dir_dialog.cpp
+++ b/editor/editor_dir_dialog.cpp
@@ -202,7 +202,7 @@ EditorDirDialog::EditorDirDialog() {
mkdirerr->set_text(TTR("Could not create folder."));
add_child(mkdirerr);
- get_ok()->set_text(TTR("Choose"));
+ get_ok_button()->set_text(TTR("Choose"));
must_reload = false;
}
diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp
index 7335563dd9..05bc2edefb 100644
--- a/editor/editor_feature_profile.cpp
+++ b/editor/editor_feature_profile.cpp
@@ -890,7 +890,7 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() {
add_child(new_profile_dialog);
new_profile_dialog->connect("confirmed", callable_mp(this, &EditorFeatureProfileManager::_create_new_profile));
new_profile_dialog->register_text_enter(new_profile_name);
- new_profile_dialog->get_ok()->set_text(TTR("Create"));
+ new_profile_dialog->get_ok_button()->set_text(TTR("Create"));
erase_profile_dialog = memnew(ConfirmationDialog);
add_child(erase_profile_dialog);
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index ffdd7c7fa8..8ded47605c 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -212,14 +212,14 @@ void EditorFileDialog::update_dir() {
dir->set_text(dir_access->get_current_dir(false));
// Disable "Open" button only when selecting file(s) mode.
- get_ok()->set_disabled(_is_open_should_be_disabled());
+ get_ok_button()->set_disabled(_is_open_should_be_disabled());
switch (mode) {
case FILE_MODE_OPEN_FILE:
case FILE_MODE_OPEN_FILES:
- get_ok()->set_text(TTR("Open"));
+ get_ok_button()->set_text(TTR("Open"));
break;
case FILE_MODE_OPEN_DIR:
- get_ok()->set_text(TTR("Select Current Folder"));
+ get_ok_button()->set_text(TTR("Select Current Folder"));
break;
case FILE_MODE_OPEN_ANY:
case FILE_MODE_SAVE_FILE:
@@ -476,10 +476,10 @@ void EditorFileDialog::_item_selected(int p_item) {
file->set_text(d["name"]);
_request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
} else if (mode == FILE_MODE_OPEN_DIR) {
- get_ok()->set_text(TTR("Select This Folder"));
+ get_ok_button()->set_text(TTR("Select This Folder"));
}
- get_ok()->set_disabled(_is_open_should_be_disabled());
+ get_ok_button()->set_disabled(_is_open_should_be_disabled());
}
void EditorFileDialog::_multi_selected(int p_item, bool p_selected) {
@@ -495,7 +495,7 @@ void EditorFileDialog::_multi_selected(int p_item, bool p_selected) {
_request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
}
- get_ok()->set_disabled(_is_open_should_be_disabled());
+ get_ok_button()->set_disabled(_is_open_should_be_disabled());
}
void EditorFileDialog::_items_clear_selection() {
@@ -505,13 +505,13 @@ void EditorFileDialog::_items_clear_selection() {
switch (mode) {
case FILE_MODE_OPEN_FILE:
case FILE_MODE_OPEN_FILES:
- get_ok()->set_text(TTR("Open"));
- get_ok()->set_disabled(!item_list->is_anything_selected());
+ get_ok_button()->set_text(TTR("Open"));
+ get_ok_button()->set_disabled(!item_list->is_anything_selected());
break;
case FILE_MODE_OPEN_DIR:
- get_ok()->set_disabled(false);
- get_ok()->set_text(TTR("Select Current Folder"));
+ get_ok_button()->set_disabled(false);
+ get_ok_button()->set_text(TTR("Select Current Folder"));
break;
case FILE_MODE_OPEN_ANY:
@@ -855,7 +855,7 @@ void EditorFileDialog::update_file_list() {
favorite->set_pressed(false);
fav_up->set_disabled(true);
fav_down->set_disabled(true);
- get_ok()->set_disabled(_is_open_should_be_disabled());
+ get_ok_button()->set_disabled(_is_open_should_be_disabled());
for (int i = 0; i < favorites->get_item_count(); i++) {
if (favorites->get_item_metadata(i) == cdir || favorites->get_item_metadata(i) == cdir + "/") {
favorites->select(i);
@@ -978,27 +978,27 @@ void EditorFileDialog::set_file_mode(FileMode p_mode) {
mode = p_mode;
switch (mode) {
case FILE_MODE_OPEN_FILE:
- get_ok()->set_text(TTR("Open"));
+ get_ok_button()->set_text(TTR("Open"));
set_title(TTR("Open a File"));
can_create_dir = false;
break;
case FILE_MODE_OPEN_FILES:
- get_ok()->set_text(TTR("Open"));
+ get_ok_button()->set_text(TTR("Open"));
set_title(TTR("Open File(s)"));
can_create_dir = false;
break;
case FILE_MODE_OPEN_DIR:
- get_ok()->set_text(TTR("Open"));
+ get_ok_button()->set_text(TTR("Open"));
set_title(TTR("Open a Directory"));
can_create_dir = true;
break;
case FILE_MODE_OPEN_ANY:
- get_ok()->set_text(TTR("Open"));
+ get_ok_button()->set_text(TTR("Open"));
set_title(TTR("Open a File or Directory"));
can_create_dir = true;
break;
case FILE_MODE_SAVE_FILE:
- get_ok()->set_text(TTR("Save"));
+ get_ok_button()->set_text(TTR("Save"));
set_title(TTR("Save a File"));
can_create_dir = true;
break;
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index 43f0c9e2bb..a8a7262cf0 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -1586,7 +1586,7 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector
f->store_line("importer=\"" + importer->get_importer_name() + "\"");
int version = importer->get_format_version();
if (version > 0) {
- f->store_line("importer_version=" + itos(importer->get_format_version()));
+ f->store_line("importer_version=" + itos(version));
}
if (importer->get_resource_type() != "") {
f->store_line("type=\"" + importer->get_resource_type() + "\"");
@@ -1725,7 +1725,7 @@ void EditorFileSystem::_reimport_file(const String &p_file) {
importer = ResourceFormatImporter::get_singleton()->get_importer_by_extension(p_file.get_extension());
load_default = true;
if (importer.is_null()) {
- ERR_PRINT("BUG: File queued for import, but can't be imported!");
+ ERR_PRINT("BUG: File queued for import, but can't be imported, importer for type '" + importer_name + "' not found.");
ERR_FAIL();
}
}
@@ -1772,6 +1772,10 @@ void EditorFileSystem::_reimport_file(const String &p_file) {
f->store_line("[remap]");
f->store_line("");
f->store_line("importer=\"" + importer->get_importer_name() + "\"");
+ int version = importer->get_format_version();
+ if (version > 0) {
+ f->store_line("importer_version=" + itos(version));
+ }
if (importer->get_resource_type() != "") {
f->store_line("type=\"" + importer->get_resource_type() + "\"");
}
diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp
index f5bb4921d4..23dc69af12 100644
--- a/editor/editor_fonts.cpp
+++ b/editor/editor_fonts.cpp
@@ -161,6 +161,14 @@ void editor_register_fonts(Ref<Theme> p_theme) {
CustomFontSource->load_resource(custom_font_path_source, default_font_size);
CustomFontSource->set_antialiased(font_antialiased);
CustomFontSource->set_hinting(font_hinting);
+
+ Vector<String> subtag = String(EditorSettings::get_singleton()->get("interface/editor/code_font_custom_variations")).split(",");
+ for (int i = 0; i < subtag.size(); i++) {
+ Vector<String> subtag_a = subtag[i].split("=");
+ if (subtag_a.size() == 2) {
+ CustomFontSource->set_variation(subtag_a[0], subtag_a[1].to_float());
+ }
+ }
} else {
EditorSettings::get_singleton()->set_manually("interface/editor/code_font", "");
}
@@ -282,6 +290,15 @@ void editor_register_fonts(Ref<Theme> p_theme) {
dfmono->set_antialiased(font_antialiased);
dfmono->set_hinting(font_hinting);
+ Vector<String> subtag = String(EditorSettings::get_singleton()->get("interface/editor/code_font_custom_variations")).split(",");
+ Dictionary ftrs;
+ for (int i = 0; i < subtag.size(); i++) {
+ Vector<String> subtag_a = subtag[i].split("=");
+ if (subtag_a.size() == 2) {
+ dfmono->set_variation(subtag_a[0], subtag_a[1].to_float());
+ }
+ }
+
// Default font
MAKE_DEFAULT_FONT(df);
p_theme->set_default_theme_font(df); // Default theme font
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 4c553950a7..41010b6a86 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -230,7 +230,7 @@ void EditorHelp::_add_method(const DocData::MethodDoc &p_method, bool p_overview
if (p_overview) {
class_desc->push_cell();
- class_desc->push_align(RichTextLabel::ALIGN_RIGHT);
+ class_desc->push_paragraph(RichTextLabel::ALIGN_RIGHT, Control::TEXT_DIRECTION_AUTO, "");
} else {
static const char32_t prefix[3] = { 0x25CF /* filled circle */, ' ', 0 };
class_desc->add_text(String(prefix));
@@ -528,7 +528,7 @@ void EditorHelp::_update_doc() {
property_line[cd.properties[i].name] = class_desc->get_line_count() - 2; //gets overridden if description
class_desc->push_cell();
- class_desc->push_align(RichTextLabel::ALIGN_RIGHT);
+ class_desc->push_paragraph(RichTextLabel::ALIGN_RIGHT, Control::TEXT_DIRECTION_AUTO, "");
class_desc->push_font(doc_code_font);
_add_type(cd.properties[i].type, cd.properties[i].enumeration);
class_desc->pop();
@@ -729,7 +729,7 @@ void EditorHelp::_update_doc() {
theme_property_line[cd.theme_properties[i].name] = class_desc->get_line_count() - 2; //gets overridden if description
class_desc->push_cell();
- class_desc->push_align(RichTextLabel::ALIGN_RIGHT);
+ class_desc->push_paragraph(RichTextLabel::ALIGN_RIGHT, Control::TEXT_DIRECTION_AUTO, "");
class_desc->push_font(doc_code_font);
_add_type(cd.theme_properties[i].type);
class_desc->pop();
@@ -1500,7 +1500,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
tag_stack.push_front(tag);
} else if (tag == "center") {
//align to center
- p_rt->push_align(RichTextLabel::ALIGN_CENTER);
+ p_rt->push_paragraph(RichTextLabel::ALIGN_CENTER, Control::TEXT_DIRECTION_AUTO, "");
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "br") {
diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp
index 4392538737..5e784ba051 100644
--- a/editor/editor_help_search.cpp
+++ b/editor/editor_help_search.cpp
@@ -105,7 +105,7 @@ void EditorHelpSearch::_notification(int p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
if (!is_visible()) {
results_tree->call_deferred("clear"); // Wait for the Tree's mouse event propagation.
- get_ok()->set_disabled(true);
+ get_ok_button()->set_disabled(true);
EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "search_help", Rect2(get_position(), get_size()));
}
} break;
@@ -130,7 +130,7 @@ void EditorHelpSearch::_notification(int p_what) {
old_search = false;
}
- get_ok()->set_disabled(!results_tree->get_selected());
+ get_ok_button()->set_disabled(!results_tree->get_selected());
search = Ref<Runner>();
set_process(false);
@@ -182,8 +182,8 @@ EditorHelpSearch::EditorHelpSearch() {
set_title(TTR("Search Help"));
- get_ok()->set_disabled(true);
- get_ok()->set_text(TTR("Open"));
+ get_ok_button()->set_disabled(true);
+ get_ok_button()->set_text(TTR("Open"));
// Split search and results area.
VBoxContainer *vbox = memnew(VBoxContainer);
@@ -244,7 +244,7 @@ EditorHelpSearch::EditorHelpSearch() {
results_tree->set_hide_root(true);
results_tree->set_select_mode(Tree::SELECT_ROW);
results_tree->connect("item_activated", callable_mp(this, &EditorHelpSearch::_confirmed));
- results_tree->connect("item_selected", callable_mp((BaseButton *)get_ok(), &BaseButton::set_disabled), varray(false));
+ results_tree->connect("item_selected", callable_mp((BaseButton *)get_ok_button(), &BaseButton::set_disabled), varray(false));
vbox->add_child(results_tree, true);
}
@@ -412,8 +412,20 @@ bool EditorHelpSearch::Runner::_phase_member_items() {
ClassMatch &match = iterator_match->value();
TreeItem *parent = (search_flags & SEARCH_SHOW_HIERARCHY) ? class_items[match.doc->name] : root_item;
+ bool constructor_created = false;
for (int i = 0; i < match.methods.size(); i++) {
- _create_method_item(parent, match.doc, match.methods[i]);
+ String text = match.methods[i]->name;
+ if (!constructor_created) {
+ if (match.doc->name == match.methods[i]->name) {
+ text += " " + TTR("(constructors)");
+ constructor_created = true;
+ }
+ } else {
+ if (match.doc->name == match.methods[i]->name) {
+ continue;
+ }
+ }
+ _create_method_item(parent, match.doc, text, match.methods[i]);
}
for (int i = 0; i < match.signals.size(); i++) {
_create_signal_item(parent, match.doc, match.signals[i]);
@@ -508,7 +520,7 @@ TreeItem *EditorHelpSearch::Runner::_create_class_item(TreeItem *p_parent, const
return item;
}
-TreeItem *EditorHelpSearch::Runner::_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc) {
+TreeItem *EditorHelpSearch::Runner::_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc) {
String tooltip = p_doc->return_type + " " + p_class_doc->name + "." + p_doc->name + "(";
for (int i = 0; i < p_doc->arguments.size(); i++) {
const DocData::ArgumentDoc &arg = p_doc->arguments[i];
@@ -521,7 +533,7 @@ TreeItem *EditorHelpSearch::Runner::_create_method_item(TreeItem *p_parent, cons
}
}
tooltip += ")";
- return _create_member_item(p_parent, p_class_doc->name, "MemberMethod", p_doc->name, TTRC("Method"), "method", tooltip);
+ return _create_member_item(p_parent, p_class_doc->name, "MemberMethod", p_doc->name, p_text, TTRC("Method"), "method", tooltip);
}
TreeItem *EditorHelpSearch::Runner::_create_signal_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc) {
@@ -537,32 +549,32 @@ TreeItem *EditorHelpSearch::Runner::_create_signal_item(TreeItem *p_parent, cons
}
}
tooltip += ")";
- return _create_member_item(p_parent, p_class_doc->name, "MemberSignal", p_doc->name, TTRC("Signal"), "signal", tooltip);
+ return _create_member_item(p_parent, p_class_doc->name, "MemberSignal", p_doc->name, p_doc->name, TTRC("Signal"), "signal", tooltip);
}
TreeItem *EditorHelpSearch::Runner::_create_constant_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ConstantDoc *p_doc) {
String tooltip = p_class_doc->name + "." + p_doc->name;
- return _create_member_item(p_parent, p_class_doc->name, "MemberConstant", p_doc->name, TTRC("Constant"), "constant", tooltip);
+ return _create_member_item(p_parent, p_class_doc->name, "MemberConstant", p_doc->name, p_doc->name, TTRC("Constant"), "constant", tooltip);
}
TreeItem *EditorHelpSearch::Runner::_create_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::PropertyDoc *p_doc) {
String tooltip = p_doc->type + " " + p_class_doc->name + "." + p_doc->name;
tooltip += "\n " + p_class_doc->name + "." + p_doc->setter + "(value) setter";
tooltip += "\n " + p_class_doc->name + "." + p_doc->getter + "() getter";
- return _create_member_item(p_parent, p_class_doc->name, "MemberProperty", p_doc->name, TTRC("Property"), "property", tooltip);
+ return _create_member_item(p_parent, p_class_doc->name, "MemberProperty", p_doc->name, p_doc->name, TTRC("Property"), "property", tooltip);
}
TreeItem *EditorHelpSearch::Runner::_create_theme_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::PropertyDoc *p_doc) {
String tooltip = p_doc->type + " " + p_class_doc->name + "." + p_doc->name;
- return _create_member_item(p_parent, p_class_doc->name, "MemberTheme", p_doc->name, TTRC("Theme Property"), "theme_item", tooltip);
+ return _create_member_item(p_parent, p_class_doc->name, "MemberTheme", p_doc->name, p_doc->name, TTRC("Theme Property"), "theme_item", tooltip);
}
-TreeItem *EditorHelpSearch::Runner::_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_type, const String &p_metatype, const String &p_tooltip) {
+TreeItem *EditorHelpSearch::Runner::_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip) {
Ref<Texture2D> icon;
String text;
if (search_flags & SEARCH_SHOW_HIERARCHY) {
icon = ui_service->get_theme_icon(p_icon, "EditorIcons");
- text = p_name;
+ text = p_text;
} else {
icon = ui_service->get_theme_icon(p_icon, "EditorIcons");
/*// In flat mode, show the class icon.
@@ -570,7 +582,7 @@ if (ui_service->has_icon(p_class_name, "EditorIcons"))
icon = ui_service->get_icon(p_class_name, "EditorIcons");
else if (ClassDB::is_parent_class(p_class_name, "Object"))
icon = ui_service->get_icon("Object", "EditorIcons");*/
- text = p_class_name + "." + p_name;
+ text = p_class_name + "." + p_text;
}
TreeItem *item = results_tree->create_item(p_parent);
diff --git a/editor/editor_help_search.h b/editor/editor_help_search.h
index cb52c515de..d94066308a 100644
--- a/editor/editor_help_search.h
+++ b/editor/editor_help_search.h
@@ -140,12 +140,12 @@ class EditorHelpSearch::Runner : public Reference {
void _match_item(TreeItem *p_item, const String &p_text);
TreeItem *_create_class_hierarchy(const ClassMatch &p_match);
TreeItem *_create_class_item(TreeItem *p_parent, const DocData::ClassDoc *p_doc, bool p_gray);
- TreeItem *_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc);
+ TreeItem *_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc);
TreeItem *_create_signal_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc);
TreeItem *_create_constant_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ConstantDoc *p_doc);
TreeItem *_create_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::PropertyDoc *p_doc);
TreeItem *_create_theme_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::PropertyDoc *p_doc);
- TreeItem *_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_type, const String &p_metatype, const String &p_tooltip);
+ TreeItem *_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip);
public:
bool work(uint64_t slot = 100000);
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index f3086d416b..a8dc14427d 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -57,8 +57,10 @@
#include "scene/gui/split_container.h"
#include "scene/gui/tab_container.h"
#include "scene/gui/tabs.h"
-#include "scene/gui/texture_progress.h"
+#include "scene/gui/texture_progress_bar.h"
+#include "scene/main/window.h"
#include "scene/resources/packed_scene.h"
+#include "servers/display_server.h"
#include "servers/navigation_server_2d.h"
#include "servers/navigation_server_3d.h"
#include "servers/physics_server_2d.h"
@@ -172,12 +174,10 @@
#include "editor/progress_dialog.h"
#include "editor/project_export.h"
#include "editor/project_settings_editor.h"
-#include "editor/pvrtc_compress.h"
#include "editor/quick_open.h"
#include "editor/register_exporters.h"
#include "editor/settings_config_dialog.h"
-#include "scene/main/window.h"
-#include "servers/display_server.h"
+
#include <stdio.h>
#include <stdlib.h>
@@ -525,6 +525,9 @@ void EditorNode::_notification(int p_what) {
scene_root->set_sdf_oversize(sdf_oversize);
Viewport::SDFScale sdf_scale = Viewport::SDFScale(int(GLOBAL_GET("rendering/quality/2d_sdf/scale")));
scene_root->set_sdf_scale(sdf_scale);
+
+ float lod_threshold = GLOBAL_GET("rendering/quality/mesh_lod/threshold_pixels");
+ scene_root->set_lod_threshold(lod_threshold);
}
ResourceImporterTexture::get_singleton()->update_imports();
@@ -1416,6 +1419,17 @@ int EditorNode::_save_external_resources() {
return saved;
}
+static void _reset_animation_players(Node *p_node, List<Ref<AnimatedValuesBackup>> *r_anim_backups) {
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ AnimationPlayer *player = Object::cast_to<AnimationPlayer>(p_node->get_child(i));
+ if (player && player->is_reset_on_save_enabled() && player->can_apply_reset()) {
+ Ref<AnimatedValuesBackup> old_values = player->apply_reset();
+ r_anim_backups->push_back(old_values);
+ }
+ _reset_animation_players(p_node->get_child(i), r_anim_backups);
+ }
+}
+
void EditorNode::_save_scene(String p_file, int idx) {
Node *scene = editor_data.get_edited_scene_root(idx);
@@ -1430,6 +1444,8 @@ void EditorNode::_save_scene(String p_file, int idx) {
}
editor_data.apply_changes_in_editors();
+ List<Ref<AnimatedValuesBackup>> anim_backups;
+ _reset_animation_players(scene, &anim_backups);
_save_default_environment();
_set_scene_metadata(p_file, idx);
@@ -1477,6 +1493,11 @@ void EditorNode::_save_scene(String p_file, int idx) {
_save_external_resources();
editor_data.save_editor_external_data();
+
+ for (List<Ref<AnimatedValuesBackup>>::Element *E = anim_backups.front(); E; E = E->next()) {
+ E->get()->restore();
+ }
+
if (err == OK) {
scene->set_filename(ProjectSettings::get_singleton()->localize_path(p_file));
if (idx < 0 || idx == editor_data.get_edited_scene()) {
@@ -2271,7 +2292,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
if (unsaved_cache || p_option == FILE_CLOSE_ALL_AND_QUIT || p_option == FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER) {
String scene_filename = editor_data.get_edited_scene_root(tab_closing)->get_filename();
- save_confirmation->get_ok()->set_text(TTR("Save & Close"));
+ save_confirmation->get_ok_button()->set_text(TTR("Save & Close"));
save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), scene_filename != "" ? scene_filename : "unsaved scene"));
save_confirmation->popup_centered();
break;
@@ -2362,8 +2383,8 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
} break;
case FILE_SAVE_BEFORE_RUN: {
if (!p_confirmed) {
- confirmation->get_cancel()->set_text(TTR("No"));
- confirmation->get_ok()->set_text(TTR("Yes"));
+ confirmation->get_cancel_button()->set_text(TTR("No"));
+ confirmation->get_ok_button()->set_text(TTR("Yes"));
confirmation->set_text(TTR("This scene has never been saved. Save before running?"));
confirmation->popup_centered();
break;
@@ -2427,7 +2448,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
case FILE_EXTERNAL_OPEN_SCENE: {
if (unsaved_cache && !p_confirmed) {
- confirmation->get_ok()->set_text(TTR("Open"));
+ confirmation->get_ok_button()->set_text(TTR("Open"));
confirmation->set_text(TTR("Current scene not saved. Open anyway?"));
confirmation->popup_centered();
break;
@@ -2483,7 +2504,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
}
if (unsaved_cache && !p_confirmed) {
- confirmation->get_ok()->set_text(TTR("Reload Saved Scene"));
+ confirmation->get_ok_button()->set_text(TTR("Reload Saved Scene"));
confirmation->set_text(
TTR("The current scene has unsaved changes.\nReload the saved scene anyway? This action cannot be undone."));
confirmation->popup_centered();
@@ -2587,7 +2608,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
if (_next_unsaved_scene(!save_each) == -1) {
bool confirm = EDITOR_GET("interface/editor/quit_confirmation");
if (confirm) {
- confirmation->get_ok()->set_text(p_option == FILE_QUIT ? TTR("Quit") : TTR("Yes"));
+ confirmation->get_ok_button()->set_text(p_option == FILE_QUIT ? TTR("Quit") : TTR("Yes"));
confirmation->set_text(p_option == FILE_QUIT ? TTR("Exit the editor?") : TTR("Open Project Manager?"));
confirmation->popup_centered();
} else {
@@ -2605,7 +2626,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
i = _next_unsaved_scene(true, ++i);
}
- save_confirmation->get_ok()->set_text(TTR("Save & Quit"));
+ save_confirmation->get_ok_button()->set_text(TTR("Save & Quit"));
save_confirmation->set_text((p_option == FILE_QUIT ? TTR("Save changes to the following scene(s) before quitting?") : TTR("Save changes the following scene(s) before opening Project Manager?")) + unsaved_scenes);
save_confirmation->popup_centered();
}
@@ -2743,16 +2764,13 @@ void EditorNode::_tool_menu_option(int p_idx) {
} break;
case TOOLS_CUSTOM: {
if (tool_menu->get_item_submenu(p_idx) == "") {
- Array params = tool_menu->get_item_metadata(p_idx);
-
- Object *handler = ObjectDB::get_instance(params[0]);
- String callback = params[1];
- Variant *ud = &params[2];
+ Callable callback = tool_menu->get_item_metadata(p_idx);
Callable::CallError ce;
+ Variant result;
+ callback.call(nullptr, 0, result, ce);
- handler->call(callback, (const Variant **)&ud, 1, ce);
if (ce.error != Callable::CallError::CALL_OK) {
- String err = Variant::get_call_error_text(handler, callback, (const Variant **)&ud, 1, ce);
+ String err = Variant::get_callable_error_text(callback, nullptr, 0, ce);
ERR_PRINT("Error calling function from tool menu: " + err);
}
} // else it's a submenu so don't do anything.
@@ -3654,6 +3672,9 @@ void EditorNode::register_editor_types() {
ClassDB::register_class<ScriptCreateDialog>();
ClassDB::register_class<EditorFeatureProfile>();
ClassDB::register_class<EditorSpinSlider>();
+ ClassDB::register_class<EditorSceneImporterMesh>();
+ ClassDB::register_class<EditorSceneImporterMeshNode>();
+
ClassDB::register_virtual_class<FileSystemDock>();
// FIXME: Is this stuff obsolete, or should it be ported to new APIs?
@@ -3945,7 +3966,7 @@ Error EditorNode::export_preset(const String &p_preset, const String &p_path, bo
void EditorNode::show_accept(const String &p_text, const String &p_title) {
current_option = -1;
- accept->get_ok()->set_text(p_title);
+ accept->get_ok_button()->set_text(p_title);
accept->set_text(p_text);
accept->popup_centered();
}
@@ -4644,14 +4665,14 @@ void EditorNode::_layout_menu_option(int p_id) {
case SETTINGS_LAYOUT_SAVE: {
current_option = p_id;
layout_dialog->set_title(TTR("Save Layout"));
- layout_dialog->get_ok()->set_text(TTR("Save"));
+ layout_dialog->get_ok_button()->set_text(TTR("Save"));
layout_dialog->popup_centered();
layout_dialog->set_name_line_enabled(true);
} break;
case SETTINGS_LAYOUT_DELETE: {
current_option = p_id;
layout_dialog->set_title(TTR("Delete Layout"));
- layout_dialog->get_ok()->set_text(TTR("Delete"));
+ layout_dialog->get_ok_button()->set_text(TTR("Delete"));
layout_dialog->popup_centered();
layout_dialog->set_name_line_enabled(false);
} break;
@@ -4693,7 +4714,7 @@ void EditorNode::_scene_tab_closed(int p_tab, int option) {
saved_version != editor_data.get_undo_redo().get_version() :
editor_data.get_scene_version(p_tab) != 0;
if (unsaved) {
- save_confirmation->get_ok()->set_text(TTR("Save & Close"));
+ save_confirmation->get_ok_button()->set_text(TTR("Save & Close"));
save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), scene->get_filename() != "" ? scene->get_filename() : "unsaved scene"));
save_confirmation->popup_centered();
} else {
@@ -5083,17 +5104,10 @@ Variant EditorNode::drag_files_and_dirs(const Vector<String> &p_paths, Control *
return drag_data;
}
-void EditorNode::add_tool_menu_item(const String &p_name, Object *p_handler, const String &p_callback, const Variant &p_ud) {
- ERR_FAIL_NULL(p_handler);
+void EditorNode::add_tool_menu_item(const String &p_name, const Callable &p_callback) {
int idx = tool_menu->get_item_count();
tool_menu->add_item(p_name, TOOLS_CUSTOM);
-
- Array parameters;
- parameters.push_back(p_handler->get_instance_id());
- parameters.push_back(p_callback);
- parameters.push_back(p_ud);
-
- tool_menu->set_item_metadata(idx, parameters);
+ tool_menu->set_item_metadata(idx, p_callback);
}
void EditorNode::add_tool_submenu_item(const String &p_name, PopupMenu *p_submenu) {
@@ -5472,7 +5486,7 @@ static void _execute_thread(void *p_ud) {
int EditorNode::execute_and_show_output(const String &p_title, const String &p_path, const List<String> &p_arguments, bool p_close_on_ok, bool p_close_on_errors) {
execute_output_dialog->set_title(p_title);
- execute_output_dialog->get_ok()->set_disabled(true);
+ execute_output_dialog->get_ok_button()->set_disabled(true);
execute_outputs->clear();
execute_outputs->set_scroll_follow(true);
execute_output_dialog->popup_centered_ratio();
@@ -5513,7 +5527,7 @@ int EditorNode::execute_and_show_output(const String &p_title, const String &p_p
execute_output_dialog->hide();
}
- execute_output_dialog->get_ok()->set_disabled(false);
+ execute_output_dialog->get_ok_button()->set_disabled(false);
return eta.exitcode;
}
@@ -5726,8 +5740,6 @@ EditorNode::EditorNode() {
EditorInspector::add_inspector_plugin(smp);
}
- _pvrtc_register_compressors();
-
editor_selection = memnew(EditorSelection);
EditorFileSystem *efs = memnew(EditorFileSystem);
@@ -6387,7 +6399,7 @@ EditorNode::EditorNode() {
#endif
video_restart_dialog = memnew(ConfirmationDialog);
video_restart_dialog->set_text(TTR("Changing the video driver requires restarting the editor."));
- video_restart_dialog->get_ok()->set_text(TTR("Save & Restart"));
+ video_restart_dialog->get_ok_button()->set_text(TTR("Save & Restart"));
video_restart_dialog->connect("confirmed", callable_mp(this, &EditorNode::_menu_option), varray(SET_VIDEO_DRIVER_SAVE_AND_RESTART));
gui_base->add_child(video_restart_dialog);
@@ -6534,19 +6546,19 @@ EditorNode::EditorNode() {
custom_build_manage_templates = memnew(ConfirmationDialog);
custom_build_manage_templates->set_text(TTR("Android build template is missing, please install relevant templates."));
- custom_build_manage_templates->get_ok()->set_text(TTR("Manage Templates"));
+ custom_build_manage_templates->get_ok_button()->set_text(TTR("Manage Templates"));
custom_build_manage_templates->connect("confirmed", callable_mp(this, &EditorNode::_menu_option), varray(SETTINGS_MANAGE_EXPORT_TEMPLATES));
gui_base->add_child(custom_build_manage_templates);
install_android_build_template = memnew(ConfirmationDialog);
install_android_build_template->set_text(TTR("This will set up your project for custom Android builds by installing the source template to \"res://android/build\".\nYou can then apply modifications and build your own custom APK on export (adding modules, changing the AndroidManifest.xml, etc.).\nNote 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."));
- install_android_build_template->get_ok()->set_text(TTR("Install"));
+ install_android_build_template->get_ok_button()->set_text(TTR("Install"));
install_android_build_template->connect("confirmed", callable_mp(this, &EditorNode::_menu_confirm_current));
gui_base->add_child(install_android_build_template);
remove_android_build_template = memnew(ConfirmationDialog);
remove_android_build_template->set_text(TTR("The Android build template is already installed in this project and it won't be overwritten.\nRemove the \"res://android/build\" directory manually before attempting this operation again."));
- remove_android_build_template->get_ok()->set_text(TTR("Show in File Manager"));
+ remove_android_build_template->get_ok_button()->set_text(TTR("Show in File Manager"));
remove_android_build_template->connect("confirmed", callable_mp(this, &EditorNode::_menu_option), varray(FILE_EXPLORE_ANDROID_BUILD_TEMPLATES));
gui_base->add_child(remove_android_build_template);
@@ -6749,7 +6761,7 @@ EditorNode::EditorNode() {
set_process(true);
open_imported = memnew(ConfirmationDialog);
- open_imported->get_ok()->set_text(TTR("Open Anyway"));
+ open_imported->get_ok_button()->set_text(TTR("Open Anyway"));
new_inherited_button = open_imported->add_button(TTR("New Inherited"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "inherit");
open_imported->connect("confirmed", callable_mp(this, &EditorNode::_open_imported));
open_imported->connect("custom_action", callable_mp(this, &EditorNode::_inherit_imported));
@@ -6799,7 +6811,7 @@ EditorNode::EditorNode() {
pick_main_scene = memnew(ConfirmationDialog);
gui_base->add_child(pick_main_scene);
- pick_main_scene->get_ok()->set_text(TTR("Select"));
+ pick_main_scene->get_ok_button()->set_text(TTR("Select"));
pick_main_scene->connect("confirmed", callable_mp(this, &EditorNode::_menu_option), varray(SETTINGS_PICK_MAIN_SCENE));
for (int i = 0; i < _init_callbacks.size(); i++) {
diff --git a/editor/editor_node.h b/editor/editor_node.h
index b727bce1e4..ab8d268801 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -81,7 +81,7 @@ class RunSettingsDialog;
class ScriptCreateDialog;
class TabContainer;
class Tabs;
-class TextureProgress;
+class TextureProgressBar;
class Button;
class VSplitContainer;
class Window;
@@ -271,7 +271,7 @@ private:
Button *play_scene_button;
Button *play_custom_scene_button;
Button *search_button;
- TextureProgress *audio_vu;
+ TextureProgressBar *audio_vu;
Timer *screenshot_timer;
@@ -830,7 +830,7 @@ public:
Variant drag_resource(const Ref<Resource> &p_res, Control *p_from);
Variant drag_files_and_dirs(const Vector<String> &p_paths, Control *p_from);
- void add_tool_menu_item(const String &p_name, Object *p_handler, const String &p_callback, const Variant &p_ud = Variant());
+ void add_tool_menu_item(const String &p_name, const Callable &p_callback);
void add_tool_submenu_item(const String &p_name, PopupMenu *p_submenu);
void remove_tool_menu_item(const String &p_name);
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index 49d8e58955..f974ba9998 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -489,8 +489,8 @@ void EditorPlugin::remove_control_from_container(CustomControlContainer p_locati
}
}
-void EditorPlugin::add_tool_menu_item(const String &p_name, Object *p_handler, const String &p_callback, const Variant &p_ud) {
- EditorNode::get_singleton()->add_tool_menu_item(p_name, p_handler, p_callback, p_ud);
+void EditorPlugin::add_tool_menu_item(const String &p_name, const Callable &p_callable) {
+ EditorNode::get_singleton()->add_tool_menu_item(p_name, p_callable);
}
void EditorPlugin::add_tool_submenu_item(const String &p_name, Object *p_submenu) {
@@ -826,7 +826,7 @@ void EditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("remove_control_from_docks", "control"), &EditorPlugin::remove_control_from_docks);
ClassDB::bind_method(D_METHOD("remove_control_from_bottom_panel", "control"), &EditorPlugin::remove_control_from_bottom_panel);
ClassDB::bind_method(D_METHOD("remove_control_from_container", "container", "control"), &EditorPlugin::remove_control_from_container);
- ClassDB::bind_method(D_METHOD("add_tool_menu_item", "name", "handler", "callback", "ud"), &EditorPlugin::add_tool_menu_item, DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("add_tool_menu_item", "name", "callable"), &EditorPlugin::add_tool_menu_item);
ClassDB::bind_method(D_METHOD("add_tool_submenu_item", "name", "submenu"), &EditorPlugin::add_tool_submenu_item);
ClassDB::bind_method(D_METHOD("remove_tool_menu_item", "name"), &EditorPlugin::remove_tool_menu_item);
ClassDB::bind_method(D_METHOD("add_custom_type", "type", "base", "script", "icon"), &EditorPlugin::add_custom_type);
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index 11063066d6..03908b43ca 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -174,7 +174,7 @@ public:
void remove_control_from_docks(Control *p_control);
void remove_control_from_bottom_panel(Control *p_control);
- void add_tool_menu_item(const String &p_name, Object *p_handler, const String &p_callback, const Variant &p_ud = Variant());
+ void add_tool_menu_item(const String &p_name, const Callable &p_callable);
void add_tool_submenu_item(const String &p_name, Object *p_submenu);
void remove_tool_menu_item(const String &p_name);
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 2c4e403a81..523e65babe 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -68,9 +68,9 @@ void EditorPropertyText::_text_changed(const String &p_string) {
}
if (string_name) {
- emit_changed(get_edited_property(), StringName(p_string), "", true);
+ emit_changed(get_edited_property(), StringName(p_string), "", false);
} else {
- emit_changed(get_edited_property(), p_string, "", true);
+ emit_changed(get_edited_property(), p_string, "", false);
}
}
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index cc04ea5a58..73a191d317 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -336,6 +336,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("interface/editor/code_font_contextual_ligatures", 0);
hints["interface/editor/code_font_contextual_ligatures"] = PropertyInfo(Variant::INT, "interface/editor/code_font_contextual_ligatures", PROPERTY_HINT_ENUM, "Default,Disable contextual alternates (coding ligatures),Use custom OpenType feature set", PROPERTY_USAGE_DEFAULT);
_initial_set("interface/editor/code_font_custom_opentype_features", "");
+ _initial_set("interface/editor/code_font_custom_variations", "");
_initial_set("interface/editor/font_antialiased", true);
_initial_set("interface/editor/font_hinting", 0);
hints["interface/editor/font_hinting"] = PropertyInfo(Variant::INT, "interface/editor/font_hinting", PROPERTY_HINT_ENUM, "Auto,None,Light,Normal", PROPERTY_USAGE_DEFAULT);
@@ -407,15 +408,6 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("filesystem/file_dialog/thumbnail_size", 64);
hints["filesystem/file_dialog/thumbnail_size"] = PropertyInfo(Variant::INT, "filesystem/file_dialog/thumbnail_size", PROPERTY_HINT_RANGE, "32,128,16");
- // Import
- _initial_set("filesystem/import/pvrtc_texture_tool", "");
-#ifdef WINDOWS_ENABLED
- hints["filesystem/import/pvrtc_texture_tool"] = PropertyInfo(Variant::STRING, "filesystem/import/pvrtc_texture_tool", PROPERTY_HINT_GLOBAL_FILE, "*.exe");
-#else
- hints["filesystem/import/pvrtc_texture_tool"] = PropertyInfo(Variant::STRING, "filesystem/import/pvrtc_texture_tool", PROPERTY_HINT_GLOBAL_FILE, "");
-#endif
- _initial_set("filesystem/import/pvrtc_fast_conversion", false);
-
/* Docks */
// SceneTree
@@ -557,9 +549,15 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("editors/3d/grid_xy_plane", false);
_initial_set("editors/3d/grid_yz_plane", false);
+ // Use a lower default FOV for the 3D camera compared to the
+ // Camera3D node as the 3D viewport doesn't span the whole screen.
+ // This means it's technically viewed from a further distance, which warrants a narrower FOV.
_initial_set("editors/3d/default_fov", 70.0);
+ hints["editors/3d/default_fov"] = PropertyInfo(Variant::FLOAT, "editors/3d/default_fov", PROPERTY_HINT_RANGE, "1,179,0.1");
_initial_set("editors/3d/default_z_near", 0.05);
- _initial_set("editors/3d/default_z_far", 500.0);
+ hints["editors/3d/default_z_near"] = PropertyInfo(Variant::FLOAT, "editors/3d/default_z_near", PROPERTY_HINT_RANGE, "0.01,10,0.01,or_greater");
+ _initial_set("editors/3d/default_z_far", 4000.0);
+ hints["editors/3d/default_z_far"] = PropertyInfo(Variant::FLOAT, "editors/3d/default_z_far", PROPERTY_HINT_RANGE, "0.1,4000,0.1,or_greater");
// 3D: Navigation
_initial_set("editors/3d/navigation/navigation_scheme", 0);
@@ -630,6 +628,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
// Animation
_initial_set("editors/animation/autorename_animation_tracks", true);
_initial_set("editors/animation/confirm_insert_track", true);
+ _initial_set("editors/animation/default_create_bezier_tracks", false);
+ _initial_set("editors/animation/default_create_reset_tracks", true);
_initial_set("editors/animation/onion_layers_past_color", Color(1, 0, 0));
_initial_set("editors/animation/onion_layers_future_color", Color(0, 1, 0));
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 723499ca9a..35de38fad2 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -85,6 +85,25 @@ static Ref<StyleBoxLine> make_line_stylebox(Color p_color, int p_thickness = 1,
return style;
}
+static Ref<Texture2D> flip_icon(Ref<Texture2D> p_texture, bool p_flip_y = false, bool p_flip_x = false) {
+ if (!p_flip_y && !p_flip_x) {
+ return p_texture;
+ }
+
+ Ref<ImageTexture> texture(memnew(ImageTexture));
+ Ref<Image> img = p_texture->get_data();
+
+ if (p_flip_y) {
+ img->flip_y();
+ }
+ if (p_flip_x) {
+ img->flip_x();
+ }
+
+ texture->create_from_image(img);
+ return texture;
+}
+
#ifdef MODULE_SVG_ENABLED
static Ref<ImageTexture> editor_generate_icon(int p_index, bool p_convert_color, float p_scale = EDSCALE, bool p_force_filter = false) {
Ref<ImageTexture> icon = memnew(ImageTexture);
@@ -1074,11 +1093,33 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_icon("more", "GraphEdit", theme->get_icon("ZoomMore", "EditorIcons"));
theme->set_icon("reset", "GraphEdit", theme->get_icon("ZoomReset", "EditorIcons"));
theme->set_icon("snap", "GraphEdit", theme->get_icon("SnapGrid", "EditorIcons"));
+ theme->set_icon("minimap", "GraphEdit", theme->get_icon("GridMinimap", "EditorIcons"));
theme->set_constant("bezier_len_pos", "GraphEdit", 80 * EDSCALE);
theme->set_constant("bezier_len_neg", "GraphEdit", 160 * EDSCALE);
- // GraphNode
+ // GraphEditMinimap
+ theme->set_stylebox("bg", "GraphEditMinimap", make_flat_stylebox(dark_color_1, 0, 0, 0, 0));
+ Ref<StyleBoxFlat> style_minimap_camera;
+ Ref<StyleBoxFlat> style_minimap_node;
+ if (dark_theme) {
+ style_minimap_camera = make_flat_stylebox(Color(0.65, 0.65, 0.65, 0.2), 0, 0, 0, 0);
+ style_minimap_camera->set_border_color(Color(0.65, 0.65, 0.65, 0.45));
+ style_minimap_node = make_flat_stylebox(Color(1, 1, 1), 0, 0, 0, 0);
+ } else {
+ style_minimap_camera = make_flat_stylebox(Color(0.38, 0.38, 0.38, 0.2), 0, 0, 0, 0);
+ style_minimap_camera->set_border_color(Color(0.38, 0.38, 0.38, 0.45));
+ style_minimap_node = make_flat_stylebox(Color(0, 0, 0), 0, 0, 0, 0);
+ }
+ style_minimap_camera->set_border_width_all(1);
+ style_minimap_node->set_corner_radius_all(1);
+ theme->set_stylebox("camera", "GraphEditMinimap", style_minimap_camera);
+ theme->set_stylebox("node", "GraphEditMinimap", style_minimap_node);
+
+ Ref<Texture2D> resizer_icon = theme->get_icon("GuiResizer", "EditorIcons");
+ theme->set_icon("resizer", "GraphEditMinimap", flip_icon(resizer_icon, true, true));
+ theme->set_color("resizer_color", "GraphEditMinimap", Color(1, 1, 1, 0.65));
+ // GraphNode
const float mv = dark_theme ? 0.0 : 1.0;
const float mv2 = 1.0 - mv;
const int gn_margin_side = 28;
diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp
index 84517f36ea..e9b6f6b5e9 100644
--- a/editor/export_template_manager.cpp
+++ b/editor/export_template_manager.cpp
@@ -661,8 +661,8 @@ ExportTemplateManager::ExportTemplateManager() {
installed_scroll->set_enable_h_scroll(false);
installed_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- get_cancel()->set_text(TTR("Close"));
- get_ok()->set_text(TTR("Install From File"));
+ get_cancel_button()->set_text(TTR("Close"));
+ get_ok_button()->set_text(TTR("Install From File"));
remove_confirm = memnew(ConfirmationDialog);
remove_confirm->set_title(TTR("Remove Template"));
@@ -690,7 +690,7 @@ ExportTemplateManager::ExportTemplateManager() {
template_downloader = memnew(AcceptDialog);
template_downloader->set_title(TTR("Download Templates"));
- template_downloader->get_ok()->set_text(TTR("Close"));
+ 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));
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index aa19bdf342..6c8bd1901e 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -1505,7 +1505,8 @@ void FileSystemDock::_move_with_overwrite() {
_move_operation_confirm(to_move_path, true);
}
-bool FileSystemDock::_check_existing() {
+Vector<String> FileSystemDock::_check_existing() {
+ Vector<String> conflicting_items;
String &p_to_path = to_move_path;
for (int i = 0; i < to_move.size(); i++) {
String ol_pth = to_move[i].path.ends_with("/") ? to_move[i].path.substr(0, to_move[i].path.length() - 1) : to_move[i].path;
@@ -1515,21 +1516,24 @@ bool FileSystemDock::_check_existing() {
String old_path = (p_item.is_file || p_item.path.ends_with("/")) ? p_item.path : (p_item.path + "/");
String new_path = (p_item.is_file || p_new_path.ends_with("/")) ? p_new_path : (p_new_path + "/");
- if (p_item.is_file && FileAccess::exists(new_path)) {
- return false;
- } else if (!p_item.is_file && DirAccess::exists(new_path)) {
- return false;
+ if ((p_item.is_file && FileAccess::exists(new_path)) ||
+ (!p_item.is_file && DirAccess::exists(new_path))) {
+ conflicting_items.push_back(old_path);
}
}
- return true;
+ return conflicting_items;
}
void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_overwrite) {
if (!p_overwrite) {
to_move_path = p_to_path;
- bool can_move = _check_existing();
- if (!can_move) {
+ Vector<String> conflicting_items = _check_existing();
+ if (!conflicting_items.empty()) {
// Ask to do something.
+ overwrite_dialog->set_text(vformat(
+ TTR("The following files or folders conflict with items in the target location '%s':\n\n%s\n\nDo you wish to overwrite them?"),
+ to_move_path,
+ String("\n").join(conflicting_items)));
overwrite_dialog->popup_centered();
return;
}
@@ -2833,7 +2837,7 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
add_child(remove_dialog);
move_dialog = memnew(EditorDirDialog);
- move_dialog->get_ok()->set_text(TTR("Move"));
+ move_dialog->get_ok_button()->set_text(TTR("Move"));
add_child(move_dialog);
move_dialog->connect("dir_selected", callable_mp(this, &FileSystemDock::_move_operation_confirm), make_binds(false));
@@ -2843,14 +2847,13 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
rename_dialog_text = memnew(LineEdit);
rename_dialog_vb->add_margin_child(TTR("Name:"), rename_dialog_text);
- rename_dialog->get_ok()->set_text(TTR("Rename"));
+ rename_dialog->get_ok_button()->set_text(TTR("Rename"));
add_child(rename_dialog);
rename_dialog->register_text_enter(rename_dialog_text);
rename_dialog->connect("confirmed", callable_mp(this, &FileSystemDock::_rename_operation_confirm));
overwrite_dialog = memnew(ConfirmationDialog);
- overwrite_dialog->set_text(TTR("There is already file or folder with the same name in this location."));
- overwrite_dialog->get_ok()->set_text(TTR("Overwrite"));
+ overwrite_dialog->get_ok_button()->set_text(TTR("Overwrite"));
add_child(overwrite_dialog);
overwrite_dialog->connect("confirmed", callable_mp(this, &FileSystemDock::_move_with_overwrite));
@@ -2860,7 +2863,7 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
duplicate_dialog_text = memnew(LineEdit);
duplicate_dialog_vb->add_margin_child(TTR("Name:"), duplicate_dialog_text);
- duplicate_dialog->get_ok()->set_text(TTR("Duplicate"));
+ duplicate_dialog->get_ok_button()->set_text(TTR("Duplicate"));
add_child(duplicate_dialog);
duplicate_dialog->register_text_enter(duplicate_dialog_text);
duplicate_dialog->connect("confirmed", callable_mp(this, &FileSystemDock::_duplicate_operation_confirm));
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index c01d58dfbb..4b93931ba7 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -236,7 +236,7 @@ private:
void _rename_operation_confirm();
void _duplicate_operation_confirm();
void _move_with_overwrite();
- bool _check_existing();
+ Vector<String> _check_existing();
void _move_operation_confirm(const String &p_to_path, bool p_overwrite = false);
void _tree_rmb_option(int p_option);
diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp
index abcb7bbd93..076b873eac 100644
--- a/editor/find_in_files.cpp
+++ b/editor/find_in_files.cpp
@@ -383,7 +383,7 @@ FindInFilesDialog::FindInFilesDialog() {
_replace_button = add_button(TTR("Replace..."), false, "replace");
_replace_button->set_disabled(true);
- Button *cancel_button = get_ok();
+ Button *cancel_button = get_ok_button();
cancel_button->set_text(TTR("Cancel"));
_mode = SEARCH_MODE;
@@ -779,7 +779,19 @@ void FindInFilesPanel::_on_item_edited() {
}
void FindInFilesPanel::_on_finished() {
- _status_label->set_text(TTR("Search complete"));
+ String results_text;
+ int result_count = _result_items.size();
+ int file_count = _file_items.size();
+
+ if (result_count == 1 && file_count == 1) {
+ results_text = vformat(TTR("%d match in %d file."), result_count, file_count);
+ } else if (result_count != 1 && file_count == 1) {
+ results_text = vformat(TTR("%d matches in %d file."), result_count, file_count);
+ } else {
+ results_text = vformat(TTR("%d matches in %d files."), result_count, file_count);
+ }
+
+ _status_label->set_text(results_text);
update_replace_buttons();
set_progress_visible(false);
_refresh_button->show();
diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp
index f3bad8d86d..32c50321d7 100644
--- a/editor/groups_editor.cpp
+++ b/editor/groups_editor.cpp
@@ -540,7 +540,7 @@ GroupDialog::GroupDialog() {
error = memnew(ConfirmationDialog);
add_child(error);
- error->get_ok()->set_text(TTR("Close"));
+ error->get_ok_button()->set_text(TTR("Close"));
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/editor/icons/GridMinimap.svg b/editor/icons/GridMinimap.svg
new file mode 100644
index 0000000000..72f107066d
--- /dev/null
+++ b/editor/icons/GridMinimap.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m14 2.1992188v2.6152343l-2.625 1.3125v-2.6152343zm-12 4.0644531 2.625 1.3125v2.5507811l-2.625-1.3124999zm12 0v2.5507812l-2.625 1.3124999v-2.5507811zm-8 1.4550781h4v2.640625h-4zm-4 2.560547 2.625 1.3125v2.521484l-2.625-1.3125zm12 0v2.521484l-2.625 1.3125v-2.521484zm-8 1.455078h4v2.640625h-4zm1.7014535-8.109375h2.2985465v2.734375h-4.15625s-.7487346.647119-.8746377.640625c-.1310411-.0067594-1.5097373-1.4558594-1.5097373-1.4558594l-1.459375-.7296875v-2.6152343l.068419.034223s.026411-.4573464.062111-.6760553c.0346282-.2121439.1970747-.59225724.1970747-.59225724l-1.0483078-.52372301c-.0795772-.04012218-.1668141-.06276382-.2558594-.06640625-.35427845-.01325803-.64865004.27047362-.6484375.625v12c.00021484.236623.13402736.45284.34570312.558594l3.99999998 2c.086686.043505.1823067.06624.2792969.066406h6c.09699-.000166.192611-.0229.279297-.06641l4-2c.211676-.10575.345488-.321967.345703-.55859v-12c-.000468-.46423753-.488958-.76598317-.904297-.55859375l-3.869141 1.93359375h-2.9709527s.033448.4166167.015891.625c-.029188.3464401-.1950466.625-.1950468.625z" fill="#e0e0e0"/><path d="m5 6s-2.21875-2.1616704-2.21875-3.2425057c0-1.0808352 0-2.6072392 2.21875-2.6072392s2.21875 1.526404 2.21875 2.6072392c0 1.0808353-2.21875 3.2425057-2.21875 3.2425057z" fill="#fff" fill-opacity=".68627"/></svg>
diff --git a/editor/icons/Texture3D.svg b/editor/icons/Texture3D.svg
index 6bdc599f6d..795dd62ba5 100644
--- a/editor/icons/Texture3D.svg
+++ b/editor/icons/Texture3D.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 1c-.5522847 0-1 .4477153-1 1v12c0 .552285.4477153 1 1 1h12c.552285 0 1-.447715 1-1v-12c0-.5522847-.447715-1-1-1zm1 2h10v8h-10z" fill-opacity=".99608" transform="translate(.359546 -.287637)"/><g fill-opacity=".996078" stroke-width=".203212" transform="scale(.9167105 1.0908569)"><path d="m5.8175194 8.9717502q-.2194689 0-.4633233-.032514-.2438544-.0243854-.4714519-.0731562-.2275974-.0487709-.4145524-.1056703-.1869551-.0568993-.2926253-.1056702l.2357259-1.0079315q.2113405.089413.5364797.1950835.3332677.097542.8209765.097542.5608651 0 .8209764-.2113404.2601114-.2113405.2601114-.5689936 0-.219469-.097542-.3657816-.089413-.1544415-.2519826-.2438547-.1625696-.0975418-.3901671-.1300557-.2194689-.0406424-.4714518-.0406424h-.4714519v-.9754176h.5364797q.1788266 0 .3413962-.032514.1706981-.032514.3007537-.1056703.1300557-.081285.203212-.2113404.081285-.1381842.081285-.3413962 0-.1544411-.065028-.2682398-.0650278-.1137987-.1706981-.186955-.0975417-.0731563-.2357259-.1056702-.1300557-.0406424-.2682398-.0406424-.3495247 0-.6502784.1056702-.2926253.1056703-.5364797.2601114l-.4308095-.8860043q.1300557-.0812848.3007538-.1706981.1788266-.0894133.390167-.1625696.2113405-.0731563.4470664-.1219272.2438544-.048771.5120943-.048771.4958373 0 .8534904.1219272.3657816.1137987.6015075.3332677.2357259.2113405.3495246.5039657.1137987.2844968.1137987.625893 0 .3332677-.186955.6502784-.186955.3088822-.5039657.4714518.4389379.1788266.6746638.5364797.2438544.3495246.2438544.8453619 0 .3901671-.1300557.7234347-.1300557.3251393-.406424.5689937-.2763683.235726-.7071777.3739101-.422681.1300557-1.0079316.1300557z"/><path d="m10.502445 7.817506q.08941.00813.203212.016257.121927 0 .284497 0 .951032 0 1.406227-.4795803.463323-.4795803.463323-1.3249422 0-.8860044-.438938-1.3411992-.438938-.4551949-1.38997-.4551949-.130055 0-.26824.00813-.138184 0-.260111.016257zm3.665945-1.7882655q0 .7315631-.227598 1.2761713-.227597.5446082-.650278.9022613-.414553.3576531-1.01606.5364797-.601508.1788265-1.349328.1788265-.341396 0-.796591-.032514-.4551948-.0243853-.8941328-.1137986v-5.486724q.438938-.081285.9103898-.1056702.47958-.032514.820976-.032514.723435 0 1.308686.1625696.593379.1625696 1.01606.5120943.422681.3495246.650278.8941328.227598.5446081.227598 1.3086853z"/></g></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(-.359546 .287637)"><path d="m2 1c-.5522847 0-1 .4477153-1 1v12c0 .552285.4477153 1 1 1h12c.552285 0 1-.447715 1-1v-12c0-.5522847-.447715-1-1-1zm1 2h10v8h-10z" fill-opacity=".99608" transform="translate(.359546 -.287637)"/><g fill-opacity=".996078" stroke-width=".203212" transform="scale(.9167105 1.0908569)"><path d="m5.8175194 8.9717502q-.2194689 0-.4633233-.032514-.2438544-.0243854-.4714519-.0731562-.2275974-.0487709-.4145524-.1056703-.1869551-.0568993-.2926253-.1056702l.2357259-1.0079315q.2113405.089413.5364797.1950835.3332677.097542.8209765.097542.5608651 0 .8209764-.2113404.2601114-.2113405.2601114-.5689936 0-.219469-.097542-.3657816-.089413-.1544415-.2519826-.2438547-.1625696-.0975418-.3901671-.1300557-.2194689-.0406424-.4714518-.0406424h-.4714519v-.9754176h.5364797q.1788266 0 .3413962-.032514.1706981-.032514.3007537-.1056703.1300557-.081285.203212-.2113404.081285-.1381842.081285-.3413962 0-.1544411-.065028-.2682398-.0650278-.1137987-.1706981-.186955-.0975417-.0731563-.2357259-.1056702-.1300557-.0406424-.2682398-.0406424-.3495247 0-.6502784.1056702-.2926253.1056703-.5364797.2601114l-.4308095-.8860043q.1300557-.0812848.3007538-.1706981.1788266-.0894133.390167-.1625696.2113405-.0731563.4470664-.1219272.2438544-.048771.5120943-.048771.4958373 0 .8534904.1219272.3657816.1137987.6015075.3332677.2357259.2113405.3495246.5039657.1137987.2844968.1137987.625893 0 .3332677-.186955.6502784-.186955.3088822-.5039657.4714518.4389379.1788266.6746638.5364797.2438544.3495246.2438544.8453619 0 .3901671-.1300557.7234347-.1300557.3251393-.406424.5689937-.2763683.235726-.7071777.3739101-.422681.1300557-1.0079316.1300557z"/><path d="m10.502445 7.817506q.08941.00813.203212.016257.121927 0 .284497 0 .951032 0 1.406227-.4795803.463323-.4795803.463323-1.3249422 0-.8860044-.438938-1.3411992-.438938-.4551949-1.38997-.4551949-.130055 0-.26824.00813-.138184 0-.260111.016257zm3.665945-1.7882655q0 .7315631-.227598 1.2761713-.227597.5446082-.650278.9022613-.414553.3576531-1.01606.5364797-.601508.1788265-1.349328.1788265-.341396 0-.796591-.032514-.4551948-.0243853-.8941328-.1137986v-5.486724q.438938-.081285.9103898-.1056702.47958-.032514.820976-.032514.723435 0 1.308686.1625696.593379.1625696 1.01606.5120943.422681.3495246.650278.8941328.227598.5446081.227598 1.3086853z"/></g></g></svg>
diff --git a/editor/icons/TextureArray.svg b/editor/icons/TextureArray.svg
index 86d4875e12..a71860023b 100644
--- a/editor/icons/TextureArray.svg
+++ b/editor/icons/TextureArray.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 1c-.5522847 0-1 .4477153-1 1v12c0 .552285.4477153 1 1 1h12c.552285 0 1-.447715 1-1v-12c0-.5522847-.447715-1-1-1zm1 2h10v8h-10z" fill-opacity=".99608" transform="translate(.359546 -.287637)"/><g fill-opacity=".996078" stroke-width=".207395" transform="matrix(1.6197742 0 0 .750929 -3.723153 1.832957)"><path d="m4.7302951 2.4553483h2.2481639v.9872012h-1.0701592v6.0559397h1.0701592v.9872008h-2.2481639z"/><path d="m10.138643 10.48569h-2.2481636v-.9872008h1.0701592v-6.0559397h-1.0701592v-.9872012h2.2481636z"/></g></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(-.359546 .287637)"><path d="m2 1c-.5522847 0-1 .4477153-1 1v12c0 .552285.4477153 1 1 1h12c.552285 0 1-.447715 1-1v-12c0-.5522847-.447715-1-1-1zm1 2h10v8h-10z" fill-opacity=".99608" transform="translate(.359546 -.287637)"/><g fill-opacity=".996078" stroke-width=".207395" transform="matrix(1.6197742 0 0 .750929 -3.723153 1.832957)"><path d="m4.9900159 2.5027746h1.85211v1.3316838h-.926055v5.3267353h.926055v1.3316833h-1.85211z"/><path d="m9.9289759 10.492877h-1.85211v-1.3316833h.926055v-5.3267353h-.926055v-1.3316838h1.85211z"/></g></g></svg>
diff --git a/editor/icons/TextureProgress.svg b/editor/icons/TextureProgressBar.svg
index 30d76e33b8..30d76e33b8 100644
--- a/editor/icons/TextureProgress.svg
+++ b/editor/icons/TextureProgressBar.svg
diff --git a/editor/import/collada.h b/editor/import/collada.h
index 3b6b508b28..29d49d4aa7 100644
--- a/editor/import/collada.h
+++ b/editor/import/collada.h
@@ -96,8 +96,8 @@ public:
};
float aspect = 1;
- float z_near = 0.1;
- float z_far = 100;
+ float z_near = 0.05;
+ float z_far = 4000;
CameraData() {}
};
diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp
index 270bdc3821..4e93fe6f12 100644
--- a/editor/import/editor_import_collada.cpp
+++ b/editor/import/editor_import_collada.cpp
@@ -67,7 +67,7 @@ struct ColladaImport {
Map<String, NodeMap> node_map; //map from collada node to engine node
Map<String, String> node_name_map; //map from collada node to engine node
- Map<String, Ref<ArrayMesh>> mesh_cache;
+ Map<String, Ref<EditorSceneImporterMesh>> mesh_cache;
Map<String, Ref<Curve3D>> curve_cache;
Map<String, Ref<Material>> material_cache;
Map<Collada::Node *, Skeleton3D *> skeleton_map;
@@ -83,7 +83,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<ArrayMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<ArrayMesh>> p_morph_meshes = Vector<Ref<ArrayMesh>>(), bool p_use_compression = false, bool p_use_mesh_material = false);
+ Error _create_mesh_surfaces(bool p_optimize, Ref<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 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);
@@ -278,8 +278,8 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Node3D *p_parent) {
node = memnew(Path3D);
} else {
//mesh since nothing else
- node = memnew(MeshInstance3D);
- //Object::cast_to<MeshInstance3D>(node)->set_flag(GeometryInstance3D::FLAG_USE_BAKED_LIGHT, true);
+ node = memnew(EditorSceneImporterMeshNode);
+ //Object::cast_to<EditorSceneImporterMeshNode>(node)->set_flag(GeometryInstance3D::FLAG_USE_BAKED_LIGHT, true);
}
} break;
case Collada::Node::TYPE_SKELETON: {
@@ -440,7 +440,7 @@ Error ColladaImport::_create_material(const String &p_target) {
return OK;
}
-Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<ArrayMesh>> p_morph_meshes, bool p_use_compression, bool p_use_mesh_material) {
+Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<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) {
bool local_xform_mirror = p_local_xform.basis.determinant() < 0;
if (p_morph_data) {
@@ -457,9 +457,9 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
p_mesh->add_blend_shape(name);
}
if (p_morph_data->mode == "RELATIVE") {
- p_mesh->set_blend_shape_mode(ArrayMesh::BLEND_SHAPE_MODE_RELATIVE);
+ p_mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_RELATIVE);
} else if (p_morph_data->mode == "NORMALIZED") {
- p_mesh->set_blend_shape_mode(ArrayMesh::BLEND_SHAPE_MODE_NORMALIZED);
+ p_mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED);
}
}
@@ -897,7 +897,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
////////////////////////////
for (int mi = 0; mi < p_morph_meshes.size(); mi++) {
- Array a = p_morph_meshes[mi]->surface_get_arrays(surface);
+ Array a = p_morph_meshes[mi]->get_surface_arrays(surface);
//add valid weight and bone arrays if they exist, TODO check if they are unique to shape (generally not)
if (has_weights) {
@@ -910,14 +910,15 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
mr.push_back(a);
}
- p_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, d, mr, Dictionary(), 0);
-
+ String surface_name;
+ Ref<Material> mat;
if (material.is_valid()) {
if (p_use_mesh_material) {
- p_mesh->surface_set_material(surface, material);
+ mat = material;
}
- p_mesh->surface_set_name(surface, material->get_name());
+ surface_name = material->get_name();
}
+ p_mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, d, mr, Dictionary(), mat, surface_name);
}
/*****************/
@@ -1002,10 +1003,10 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
}
}
- if (Object::cast_to<MeshInstance3D>(node)) {
+ if (Object::cast_to<EditorSceneImporterMeshNode>(node)) {
Collada::NodeGeometry *ng2 = static_cast<Collada::NodeGeometry *>(p_node);
- MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(node);
+ EditorSceneImporterMeshNode *mi = Object::cast_to<EditorSceneImporterMeshNode>(node);
ERR_FAIL_COND_V(!mi, ERR_BUG);
@@ -1014,7 +1015,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
String meshid;
Transform apply_xform;
Vector<int> bone_remap;
- Vector<Ref<ArrayMesh>> morphs;
+ Vector<Ref<EditorSceneImporterMesh>> morphs;
if (ng2->controller) {
String ngsource = ng2->source;
@@ -1083,10 +1084,10 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
for (int i = 0; i < names.size(); i++) {
String meshid2 = names[i];
if (collada.state.mesh_data_map.has(meshid2)) {
- Ref<ArrayMesh> mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
+ Ref<EditorSceneImporterMesh> mesh = Ref<EditorSceneImporterMesh>(memnew(EditorSceneImporterMesh));
const Collada::MeshData &meshdata = collada.state.mesh_data_map[meshid2];
mesh->set_name(meshdata.name);
- Error err = _create_mesh_surfaces(false, mesh, ng2->material_map, meshdata, apply_xform, bone_remap, skin, nullptr, Vector<Ref<ArrayMesh>>(), false);
+ Error err = _create_mesh_surfaces(false, mesh, ng2->material_map, meshdata, apply_xform, bone_remap, skin, nullptr, Vector<Ref<EditorSceneImporterMesh>>(), false);
ERR_FAIL_COND_V(err, err);
morphs.push_back(mesh);
@@ -1109,7 +1110,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
meshid = ng2->source;
}
- Ref<ArrayMesh> mesh;
+ Ref<EditorSceneImporterMesh> mesh;
if (mesh_cache.has(meshid)) {
mesh = mesh_cache[meshid];
} else {
@@ -1117,7 +1118,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
//bleh, must ignore invalid
ERR_FAIL_COND_V(!collada.state.mesh_data_map.has(meshid), ERR_INVALID_DATA);
- mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
+ mesh = Ref<EditorSceneImporterMesh>(memnew(EditorSceneImporterMesh));
const Collada::MeshData &meshdata = collada.state.mesh_data_map[meshid];
mesh->set_name(meshdata.name);
Error err = _create_mesh_surfaces(morphs.size() == 0, mesh, ng2->material_map, meshdata, apply_xform, bone_remap, skin, morph, morphs, p_use_compression, use_mesh_builtin_materials);
diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp
index ac76f67ef9..1059692ca0 100644
--- a/editor/import/editor_scene_importer_gltf.cpp
+++ b/editor/import/editor_scene_importer_gltf.cpp
@@ -970,8 +970,6 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) {
return OK;
}
- uint32_t mesh_flags = 0;
-
Array meshes = state.json["meshes"];
for (GLTFMeshIndex i = 0; i < meshes.size(); i++) {
print_verbose("glTF: Parsing mesh: " + itos(i));
@@ -979,6 +977,7 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) {
GLTFMesh mesh;
mesh.mesh.instance();
+ bool has_vertex_color = false;
ERR_FAIL_COND_V(!d.has("primitives"), ERR_PARSE_ERROR);
@@ -1034,6 +1033,7 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) {
}
if (a.has("COLOR_0")) {
array[Mesh::ARRAY_COLOR] = _decode_accessor_as_color(state, a["COLOR_0"], true);
+ has_vertex_color = true;
}
if (a.has("JOINTS_0")) {
array[Mesh::ARRAY_BONES] = _decode_accessor_as_ints(state, a["JOINTS_0"], true);
@@ -1112,7 +1112,7 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) {
//ideally BLEND_SHAPE_MODE_RELATIVE since gltf2 stores in displacement
//but it could require a larger refactor?
- mesh.mesh->set_blend_shape_mode(ArrayMesh::BLEND_SHAPE_MODE_NORMALIZED);
+ mesh.mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED);
if (j == 0) {
const Array &target_names = extras.has("targetNames") ? (Array)extras["targetNames"] : Array();
@@ -1226,21 +1226,25 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) {
}
//just add it
- mesh.mesh->add_surface_from_arrays(primitive, array, morphs, Dictionary(), mesh_flags);
+ Ref<Material> mat;
if (p.has("material")) {
const int material = p["material"];
ERR_FAIL_INDEX_V(material, state.materials.size(), ERR_FILE_CORRUPT);
- const Ref<Material> &mat = state.materials[material];
-
- mesh.mesh->surface_set_material(mesh.mesh->get_surface_count() - 1, mat);
- } else {
- Ref<StandardMaterial3D> mat;
- mat.instance();
- mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ Ref<StandardMaterial3D> mat3d = state.materials[material];
+ if (has_vertex_color) {
+ mat3d->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ }
+ mat = mat3d;
- mesh.mesh->surface_set_material(mesh.mesh->get_surface_count() - 1, mat);
+ } else if (has_vertex_color) {
+ Ref<StandardMaterial3D> mat3d;
+ mat3d.instance();
+ mat3d->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ mat = mat3d;
}
+
+ mesh.mesh->add_surface(primitive, array, morphs, Dictionary(), mat);
}
mesh.blend_weights.resize(mesh.mesh->get_blend_shape_count());
@@ -1440,7 +1444,8 @@ Error EditorSceneImporterGLTF::_parse_materials(GLTFState &state) {
if (d.has("name")) {
material->set_name(d["name"]);
}
- material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ //don't do this here only if vertex color exists
+ //material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
if (d.has("pbrMetallicRoughness")) {
const Dictionary &mr = d["pbrMetallicRoughness"];
@@ -2586,12 +2591,12 @@ BoneAttachment3D *EditorSceneImporterGLTF::_generate_bone_attachment(GLTFState &
return bone_attachment;
}
-MeshInstance3D *EditorSceneImporterGLTF::_generate_mesh_instance(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) {
+EditorSceneImporterMeshNode *EditorSceneImporterGLTF::_generate_mesh_instance(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) {
const GLTFNode *gltf_node = state.nodes[node_index];
ERR_FAIL_INDEX_V(gltf_node->mesh, state.meshes.size(), nullptr);
- MeshInstance3D *mi = memnew(MeshInstance3D);
+ EditorSceneImporterMeshNode *mi = memnew(EditorSceneImporterMeshNode);
print_verbose("glTF: Creating mesh for: " + gltf_node->name);
GLTFMesh &mesh = state.meshes.write[gltf_node->mesh];
@@ -3058,7 +3063,7 @@ void EditorSceneImporterGLTF::_process_mesh_instances(GLTFState &state, Node3D *
const GLTFSkinIndex skin_i = node->skin;
Map<GLTFNodeIndex, Node *>::Element *mi_element = state.scene_nodes.find(node_i);
- MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(mi_element->get());
+ EditorSceneImporterMeshNode *mi = Object::cast_to<EditorSceneImporterMeshNode>(mi_element->get());
ERR_FAIL_COND(mi == nullptr);
const GLTFSkeletonIndex skel_i = state.skins[node->skin].skeleton;
diff --git a/editor/import/editor_scene_importer_gltf.h b/editor/import/editor_scene_importer_gltf.h
index 5ea8bf17b8..e6163a46be 100644
--- a/editor/import/editor_scene_importer_gltf.h
+++ b/editor/import/editor_scene_importer_gltf.h
@@ -38,7 +38,7 @@
class AnimationPlayer;
class BoneAttachment3D;
-class MeshInstance3D;
+class EditorSceneImporterMeshNode;
class EditorSceneImporterGLTF : public EditorSceneImporter {
GDCLASS(EditorSceneImporterGLTF, EditorSceneImporter);
@@ -199,15 +199,15 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
};
struct GLTFMesh {
- Ref<ArrayMesh> mesh;
+ Ref<EditorSceneImporterMesh> mesh;
Vector<float> blend_weights;
};
struct GLTFCamera {
bool perspective = true;
- float fov_size = 64;
- float zfar = 500;
- float znear = 0.1;
+ float fov_size = 75;
+ float zfar = 4000;
+ float znear = 0.05;
};
struct GLTFLight {
@@ -262,7 +262,7 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
Vector<GLTFAccessor> accessors;
Vector<GLTFMesh> meshes; //meshes are loaded directly, no reason not to.
- Vector<Ref<Material>> materials;
+ Vector<Ref<StandardMaterial3D>> materials;
String scene_name;
Vector<int> root_nodes;
@@ -355,7 +355,7 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
Error _parse_animations(GLTFState &state);
BoneAttachment3D *_generate_bone_attachment(GLTFState &state, Skeleton3D *skeleton, const GLTFNodeIndex node_index);
- MeshInstance3D *_generate_mesh_instance(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index);
+ EditorSceneImporterMeshNode *_generate_mesh_instance(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index);
Camera3D *_generate_camera(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index);
Light3D *_generate_light(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index);
Node3D *_generate_spatial(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index);
diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp
index d4560a2984..30c7b2920a 100644
--- a/editor/import/resource_importer_obj.cpp
+++ b/editor/import/resource_importer_obj.cpp
@@ -225,6 +225,8 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
String current_material_library;
String current_material;
String current_group;
+ uint32_t smooth_group = 0;
+ bool smoothing = true;
while (true) {
String l = f->get_line().strip_edges();
@@ -315,6 +317,10 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
Vector3 vertex = vertices[vtx];
//if (weld_vertices)
// vertex.snap(Vector3(weld_tolerance, weld_tolerance, weld_tolerance));
+ if (!smoothing) {
+ smooth_group++;
+ }
+ surf_tool->set_smooth_group(smooth_group);
surf_tool->add_vertex(vertex);
}
@@ -322,10 +328,15 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
}
} else if (l.begins_with("s ")) { //smoothing
String what = l.substr(2, l.length()).strip_edges();
+ bool do_smooth;
if (what == "off") {
- surf_tool->add_smooth_group(false);
+ do_smooth = false;
} else {
- surf_tool->add_smooth_group(true);
+ do_smooth = true;
+ }
+ if (do_smooth != smoothing) {
+ smooth_group++;
+ smoothing = do_smooth;
}
} else if (/*l.begins_with("g ") ||*/ l.begins_with("usemtl ") || (l.begins_with("o ") || f->eof_reached())) { //commit group to mesh
//groups are too annoying
@@ -426,8 +437,15 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, in
Node3D *scene = memnew(Node3D);
for (List<Ref<Mesh>>::Element *E = meshes.front(); E; E = E->next()) {
- MeshInstance3D *mi = memnew(MeshInstance3D);
- mi->set_mesh(E->get());
+ Ref<EditorSceneImporterMesh> mesh;
+ mesh.instance();
+ Ref<Mesh> m = E->get();
+ for (int i = 0; i < m->get_surface_count(); i++) {
+ mesh->add_surface(m->surface_get_primitive_type(i), m->surface_get_arrays(i), Array(), Dictionary(), m->surface_get_material(i));
+ }
+
+ EditorSceneImporterMeshNode *mi = memnew(EditorSceneImporterMeshNode);
+ mi->set_mesh(mesh);
mi->set_name(E->get()->get_name());
scene->add_child(mi);
mi->set_owner(scene);
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index fc4f673ec4..b591627660 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -44,6 +44,7 @@
#include "scene/resources/ray_shape_3d.h"
#include "scene/resources/resource_format_text.h"
#include "scene/resources/sphere_shape_3d.h"
+#include "scene/resources/surface_tool.h"
#include "scene/resources/world_margin_shape_3d.h"
uint32_t EditorSceneImporter::get_import_flags() const {
@@ -119,6 +120,345 @@ void EditorSceneImporter::_bind_methods() {
BIND_CONSTANT(IMPORT_USE_COMPRESSION);
}
+////////////////////////////////////////////////
+
+void EditorSceneImporterMesh::add_blend_shape(const String &p_name) {
+ ERR_FAIL_COND(surfaces.size() > 0);
+ blend_shapes.push_back(p_name);
+}
+
+int EditorSceneImporterMesh::get_blend_shape_count() const {
+ return blend_shapes.size();
+}
+
+String EditorSceneImporterMesh::get_blend_shape_name(int p_blend_shape) const {
+ ERR_FAIL_INDEX_V(p_blend_shape, blend_shapes.size(), String());
+ return blend_shapes[p_blend_shape];
+}
+
+void EditorSceneImporterMesh::set_blend_shape_mode(Mesh::BlendShapeMode p_blend_shape_mode) {
+ blend_shape_mode = p_blend_shape_mode;
+}
+Mesh::BlendShapeMode EditorSceneImporterMesh::get_blend_shape_mode() const {
+ return blend_shape_mode;
+}
+
+void EditorSceneImporterMesh::add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, const Ref<Material> &p_material, const String &p_name) {
+ ERR_FAIL_COND(p_blend_shapes.size() != blend_shapes.size());
+ ERR_FAIL_COND(p_arrays.size() != Mesh::ARRAY_MAX);
+ Surface s;
+ s.primitive = p_primitive;
+ s.arrays = p_arrays;
+ s.name = p_name;
+
+ for (int i = 0; i < blend_shapes.size(); i++) {
+ Array bsdata = p_blend_shapes[i];
+ ERR_FAIL_COND(bsdata.size() != Mesh::ARRAY_MAX);
+ Surface::BlendShape bs;
+ bs.arrays = bsdata;
+ s.blend_shape_data.push_back(bs);
+ }
+
+ List<Variant> lods;
+ p_lods.get_key_list(&lods);
+ for (List<Variant>::Element *E = lods.front(); E; E = E->next()) {
+ ERR_CONTINUE(!E->get().is_num());
+ Surface::LOD lod;
+ lod.distance = E->get();
+ lod.indices = p_lods[E->get()];
+ ERR_CONTINUE(lod.indices.size() == 0);
+ s.lods.push_back(lod);
+ }
+
+ s.material = p_material;
+
+ surfaces.push_back(s);
+ mesh.unref();
+}
+int EditorSceneImporterMesh::get_surface_count() const {
+ return surfaces.size();
+}
+
+Mesh::PrimitiveType EditorSceneImporterMesh::get_surface_primitive_type(int p_surface) {
+ ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Mesh::PRIMITIVE_MAX);
+ return surfaces[p_surface].primitive;
+}
+Array EditorSceneImporterMesh::get_surface_arrays(int p_surface) const {
+ ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Array());
+ return surfaces[p_surface].arrays;
+}
+String EditorSceneImporterMesh::get_surface_name(int p_surface) const {
+ ERR_FAIL_INDEX_V(p_surface, surfaces.size(), String());
+ return surfaces[p_surface].name;
+}
+Array EditorSceneImporterMesh::get_surface_blend_shape_arrays(int p_surface, int p_blend_shape) const {
+ ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Array());
+ ERR_FAIL_INDEX_V(p_blend_shape, surfaces[p_surface].blend_shape_data.size(), Array());
+ return surfaces[p_surface].blend_shape_data[p_blend_shape].arrays;
+}
+int EditorSceneImporterMesh::get_surface_lod_count(int p_surface) const {
+ ERR_FAIL_INDEX_V(p_surface, surfaces.size(), 0);
+ return surfaces[p_surface].lods.size();
+}
+Vector<int> EditorSceneImporterMesh::get_surface_lod_indices(int p_surface, int p_lod) const {
+ ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Vector<int>());
+ ERR_FAIL_INDEX_V(p_lod, surfaces[p_surface].lods.size(), Vector<int>());
+
+ return surfaces[p_surface].lods[p_lod].indices;
+}
+
+float EditorSceneImporterMesh::get_surface_lod_size(int p_surface, int p_lod) const {
+ ERR_FAIL_INDEX_V(p_surface, surfaces.size(), 0);
+ ERR_FAIL_INDEX_V(p_lod, surfaces[p_surface].lods.size(), 0);
+ return surfaces[p_surface].lods[p_lod].distance;
+}
+
+Ref<Material> EditorSceneImporterMesh::get_surface_material(int p_surface) const {
+ ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Ref<Material>());
+ return surfaces[p_surface].material;
+}
+
+void EditorSceneImporterMesh::generate_lods() {
+ if (!SurfaceTool::simplify_func) {
+ return;
+ }
+
+ for (int i = 0; i < surfaces.size(); i++) {
+ if (surfaces[i].primitive != Mesh::PRIMITIVE_TRIANGLES) {
+ continue;
+ }
+
+ surfaces.write[i].lods.clear();
+ Vector<Vector3> vertices = surfaces[i].arrays[RS::ARRAY_VERTEX];
+ Vector<int> indices = surfaces[i].arrays[RS::ARRAY_INDEX];
+ if (indices.size() == 0) {
+ continue; //no lods if no indices
+ }
+ 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: " + itos(indices.size()));
+ 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, 1e20, &error);
+ print_line("shoot for " + itos(index_target) + ", got " + itos(new_len) + " distance " + rtos(error));
+ if ((int)new_len > (index_target * 120 / 100)) {
+ break; // 20 percent tolerance
+ }
+ new_indices.resize(new_len);
+ Surface::LOD lod;
+ lod.distance = error;
+ lod.indices = new_indices;
+ surfaces.write[i].lods.push_back(lod);
+ index_target /= 2;
+ }
+ }
+}
+
+bool EditorSceneImporterMesh::has_mesh() const {
+ return mesh.is_valid();
+}
+
+Ref<ArrayMesh> EditorSceneImporterMesh::get_mesh() {
+ ERR_FAIL_COND_V(surfaces.size() == 0, Ref<ArrayMesh>());
+
+ if (mesh.is_null()) {
+ mesh.instance();
+ for (int i = 0; i < blend_shapes.size(); i++) {
+ mesh->add_blend_shape(blend_shapes[i]);
+ }
+ mesh->set_blend_shape_mode(blend_shape_mode);
+ for (int i = 0; i < surfaces.size(); i++) {
+ Array bs_data;
+ if (surfaces[i].blend_shape_data.size()) {
+ for (int j = 0; j < surfaces[i].blend_shape_data.size(); j++) {
+ bs_data.push_back(surfaces[i].blend_shape_data[j].arrays);
+ }
+ }
+ Dictionary lods;
+ if (surfaces[i].lods.size()) {
+ for (int j = 0; j < surfaces[i].lods.size(); j++) {
+ lods[surfaces[i].lods[j].distance] = surfaces[i].lods[j].indices;
+ }
+ }
+
+ mesh->add_surface_from_arrays(surfaces[i].primitive, surfaces[i].arrays, bs_data, lods);
+ if (surfaces[i].material.is_valid()) {
+ mesh->surface_set_material(mesh->get_surface_count() - 1, surfaces[i].material);
+ }
+ if (surfaces[i].name != String()) {
+ mesh->surface_set_name(mesh->get_surface_count() - 1, surfaces[i].name);
+ }
+ }
+ }
+
+ return mesh;
+}
+
+void EditorSceneImporterMesh::clear() {
+ surfaces.clear();
+ blend_shapes.clear();
+ mesh.unref();
+}
+
+void EditorSceneImporterMesh::_set_data(const Dictionary &p_data) {
+ clear();
+ if (p_data.has("blend_shape_names")) {
+ blend_shapes = p_data["blend_shape_names"];
+ }
+ if (p_data.has("surfaces")) {
+ Array surface_arr = p_data["surfaces"];
+ for (int i = 0; i < surface_arr.size(); i++) {
+ Dictionary s = surface_arr[i];
+ ERR_CONTINUE(!s.has("primitive"));
+ ERR_CONTINUE(!s.has("arrays"));
+ Mesh::PrimitiveType prim = Mesh::PrimitiveType(int(s["primitive"]));
+ ERR_CONTINUE(prim >= Mesh::PRIMITIVE_MAX);
+ Array arr = s["arrays"];
+ Dictionary lods;
+ String name;
+ if (s.has("name")) {
+ name = s["name"];
+ }
+ if (s.has("lods")) {
+ lods = s["lods"];
+ }
+ Array blend_shapes;
+ if (s.has("blend_shapes")) {
+ blend_shapes = s["blend_shapes"];
+ }
+ Ref<Material> material;
+ if (s.has("material")) {
+ material = s["material"];
+ }
+ add_surface(prim, arr, blend_shapes, lods, material, name);
+ }
+ }
+}
+Dictionary EditorSceneImporterMesh::_get_data() const {
+ Dictionary data;
+ if (blend_shapes.size()) {
+ data["blend_shape_names"] = blend_shapes;
+ }
+ Array surface_arr;
+ for (int i = 0; i < surfaces.size(); i++) {
+ Dictionary d;
+ d["primitive"] = surfaces[i].primitive;
+ d["arrays"] = surfaces[i].arrays;
+ if (surfaces[i].blend_shape_data.size()) {
+ Array bs_data;
+ for (int j = 0; j < surfaces[i].blend_shape_data.size(); j++) {
+ bs_data.push_back(surfaces[i].blend_shape_data[j].arrays);
+ }
+ d["blend_shapes"] = bs_data;
+ }
+ if (surfaces[i].lods.size()) {
+ Dictionary lods;
+ for (int j = 0; j < surfaces[i].lods.size(); j++) {
+ lods[surfaces[i].lods[j].distance] = surfaces[i].lods[j].indices;
+ }
+ d["lods"] = lods;
+ }
+
+ if (surfaces[i].material.is_valid()) {
+ d["material"] = surfaces[i].material;
+ }
+
+ if (surfaces[i].name != String()) {
+ d["name"] = surfaces[i].name;
+ }
+
+ surface_arr.push_back(d);
+ }
+ data["surfaces"] = surface_arr;
+ return data;
+}
+
+void EditorSceneImporterMesh::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("add_blend_shape", "name"), &EditorSceneImporterMesh::add_blend_shape);
+ ClassDB::bind_method(D_METHOD("get_blend_shape_count"), &EditorSceneImporterMesh::get_blend_shape_count);
+ ClassDB::bind_method(D_METHOD("get_blend_shape_name", "blend_shape_idx"), &EditorSceneImporterMesh::get_blend_shape_name);
+
+ ClassDB::bind_method(D_METHOD("set_blend_shape_mode", "mode"), &EditorSceneImporterMesh::set_blend_shape_mode);
+ ClassDB::bind_method(D_METHOD("get_blend_shape_mode"), &EditorSceneImporterMesh::get_blend_shape_mode);
+
+ ClassDB::bind_method(D_METHOD("add_surface", "primitive", "arrays", "blend_shapes", "lods", "material"), &EditorSceneImporterMesh::add_surface, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(Ref<Material>()), DEFVAL(String()));
+
+ ClassDB::bind_method(D_METHOD("get_surface_count"), &EditorSceneImporterMesh::get_surface_count);
+ ClassDB::bind_method(D_METHOD("get_surface_primitive_type", "surface_idx"), &EditorSceneImporterMesh::get_surface_primitive_type);
+ ClassDB::bind_method(D_METHOD("get_surface_name", "surface_idx"), &EditorSceneImporterMesh::get_surface_name);
+ ClassDB::bind_method(D_METHOD("get_surface_arrays", "surface_idx"), &EditorSceneImporterMesh::get_surface_arrays);
+ ClassDB::bind_method(D_METHOD("get_surface_blend_shape_arrays", "surface_idx", "blend_shape_idx"), &EditorSceneImporterMesh::get_surface_blend_shape_arrays);
+ ClassDB::bind_method(D_METHOD("get_surface_lod_count", "surface_idx"), &EditorSceneImporterMesh::get_surface_lod_count);
+ ClassDB::bind_method(D_METHOD("get_surface_lod_size", "surface_idx", "lod_idx"), &EditorSceneImporterMesh::get_surface_lod_size);
+ ClassDB::bind_method(D_METHOD("get_surface_lod_indices", "surface_idx", "lod_idx"), &EditorSceneImporterMesh::get_surface_lod_indices);
+ ClassDB::bind_method(D_METHOD("get_surface_material", "surface_idx"), &EditorSceneImporterMesh::get_surface_material);
+
+ ClassDB::bind_method(D_METHOD("get_mesh"), &EditorSceneImporterMesh::get_mesh);
+ ClassDB::bind_method(D_METHOD("clear"), &EditorSceneImporterMesh::clear);
+
+ ClassDB::bind_method(D_METHOD("_set_data", "data"), &EditorSceneImporterMesh::_set_data);
+ ClassDB::bind_method(D_METHOD("_get_data"), &EditorSceneImporterMesh::_get_data);
+
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data");
+}
+
+void EditorSceneImporterMeshNode::set_mesh(const Ref<EditorSceneImporterMesh> &p_mesh) {
+ mesh = p_mesh;
+}
+Ref<EditorSceneImporterMesh> EditorSceneImporterMeshNode::get_mesh() const {
+ return mesh;
+}
+
+void EditorSceneImporterMeshNode::set_skin(const Ref<Skin> &p_skin) {
+ skin = p_skin;
+}
+Ref<Skin> EditorSceneImporterMeshNode::get_skin() const {
+ return skin;
+}
+
+void EditorSceneImporterMeshNode::set_surface_material(int p_idx, const Ref<Material> &p_material) {
+ ERR_FAIL_COND(p_idx < 0);
+ if (p_idx >= surface_materials.size()) {
+ surface_materials.resize(p_idx + 1);
+ }
+
+ surface_materials.write[p_idx] = p_material;
+}
+Ref<Material> EditorSceneImporterMeshNode::get_surface_material(int p_idx) const {
+ ERR_FAIL_COND_V(p_idx < 0, Ref<Material>());
+ if (p_idx >= surface_materials.size()) {
+ return Ref<Material>();
+ }
+ return surface_materials[p_idx];
+}
+
+void EditorSceneImporterMeshNode::set_skeleton_path(const NodePath &p_path) {
+ skeleton_path = p_path;
+}
+NodePath EditorSceneImporterMeshNode::get_skeleton_path() const {
+ return skeleton_path;
+}
+
+void EditorSceneImporterMeshNode::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &EditorSceneImporterMeshNode::set_mesh);
+ ClassDB::bind_method(D_METHOD("get_mesh"), &EditorSceneImporterMeshNode::get_mesh);
+
+ ClassDB::bind_method(D_METHOD("set_skin", "skin"), &EditorSceneImporterMeshNode::set_skin);
+ ClassDB::bind_method(D_METHOD("get_skin"), &EditorSceneImporterMeshNode::get_skin);
+
+ ClassDB::bind_method(D_METHOD("set_skeleton_path", "skeleton_path"), &EditorSceneImporterMeshNode::set_skeleton_path);
+ ClassDB::bind_method(D_METHOD("get_skeleton_path"), &EditorSceneImporterMeshNode::get_skeleton_path);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "EditorSceneImporterMesh"), "set_mesh", "get_mesh");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "skin", PROPERTY_HINT_RESOURCE_TYPE, "Skin"), "set_skin", "get_skin");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton"), "set_skeleton_path", "get_skeleton_path");
+}
+
/////////////////////////////////
void EditorScenePostImport::_bind_methods() {
BIND_VMETHOD(MethodInfo(Variant::OBJECT, "post_import", PropertyInfo(Variant::OBJECT, "scene")));
@@ -1124,9 +1464,9 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "materials/location", PROPERTY_HINT_ENUM, "Node,Mesh"), (meshes_out || materials_out) ? 1 : 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "materials/storage", PROPERTY_HINT_ENUM, "Built-In,Files (.material),Files (.tres)", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), materials_out ? 1 : 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "materials/keep_on_reimport"), materials_out));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/compress"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/ensure_tangents"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/storage", PROPERTY_HINT_ENUM, "Built-In,Files (.mesh),Files (.tres)"), meshes_out ? 1 : 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/generate_lods"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Enable,Gen Lightmaps", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "meshes/lightmap_texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.1));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "skins/use_named_skins"), true));
@@ -1219,6 +1559,37 @@ Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(Edito
return importer->import_animation(p_path, p_flags, p_bake_fps);
}
+void ResourceImporterScene::_generate_meshes(Node *p_node, bool p_generate_lods) {
+ EditorSceneImporterMeshNode *src_mesh = Object::cast_to<EditorSceneImporterMeshNode>(p_node);
+ if (src_mesh != nullptr) {
+ //is mesh
+ MeshInstance3D *mesh_node = memnew(MeshInstance3D);
+ mesh_node->set_transform(src_mesh->get_transform());
+ mesh_node->set_skin(src_mesh->get_skin());
+ mesh_node->set_skeleton_path(src_mesh->get_skeleton_path());
+
+ Ref<ArrayMesh> mesh;
+ if (!src_mesh->get_mesh()->has_mesh()) {
+ if (p_generate_lods) {
+ src_mesh->get_mesh()->generate_lods();
+ }
+ //do mesh processing
+ }
+ mesh = src_mesh->get_mesh()->get_mesh();
+ mesh_node->set_mesh(mesh);
+ for (int i = 0; i < mesh->get_surface_count(); i++) {
+ mesh_node->set_surface_material(i, src_mesh->get_surface_material(i));
+ }
+
+ p_node->replace_by(mesh_node);
+ memdelete(p_node);
+ p_node = mesh_node;
+ }
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ _generate_meshes(p_node->get_child(i), p_generate_lods);
+ }
+}
Error ResourceImporterScene::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
const String &src_path = p_source_file;
@@ -1257,10 +1628,6 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
import_flags |= EditorSceneImporter::IMPORT_ANIMATION;
}
- if (int(p_options["meshes/compress"])) {
- import_flags |= EditorSceneImporter::IMPORT_USE_COMPRESSION;
- }
-
if (bool(p_options["meshes/ensure_tangents"])) {
import_flags |= EditorSceneImporter::IMPORT_GENERATE_TANGENT_ARRAYS;
}
@@ -1315,6 +1682,10 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
scene->set_name(p_save_path.get_file().get_basename());
}
+ bool gen_lods = bool(p_options["meshes/generate_lods"]);
+
+ _generate_meshes(scene, gen_lods);
+
err = OK;
String animation_filter = String(p_options["animation/filter_script"]).strip_edges();
diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h
index cd61ec01f2..aef6c0ac50 100644
--- a/editor/import/resource_importer_scene.h
+++ b/editor/import/resource_importer_scene.h
@@ -32,9 +32,11 @@
#define RESOURCEIMPORTERSCENE_H
#include "core/io/resource_importer.h"
+#include "scene/3d/node_3d.h"
#include "scene/resources/animation.h"
#include "scene/resources/mesh.h"
#include "scene/resources/shape_3d.h"
+#include "scene/resources/skin.h"
class Material;
@@ -88,6 +90,92 @@ public:
EditorScenePostImport();
};
+// The following classes are used by importers instead of ArrayMesh and MeshInstance3D
+// so the data is not reginstered (hence, quality loss), importing happens faster and
+// its easier to modify before saving
+
+class EditorSceneImporterMesh : public Resource {
+ GDCLASS(EditorSceneImporterMesh, Resource)
+
+ struct Surface {
+ Mesh::PrimitiveType primitive;
+ Array arrays;
+ struct BlendShape {
+ Array arrays;
+ };
+ Vector<BlendShape> blend_shape_data;
+ struct LOD {
+ Vector<int> indices;
+ float distance;
+ };
+ Vector<LOD> lods;
+ Ref<Material> material;
+ String name;
+ };
+ Vector<Surface> surfaces;
+ Vector<String> blend_shapes;
+ Mesh::BlendShapeMode blend_shape_mode = Mesh::BLEND_SHAPE_MODE_NORMALIZED;
+
+ Ref<ArrayMesh> mesh;
+
+protected:
+ void _set_data(const Dictionary &p_data);
+ Dictionary _get_data() const;
+
+ static void _bind_methods();
+
+public:
+ void add_blend_shape(const String &p_name);
+ int get_blend_shape_count() const;
+ String get_blend_shape_name(int p_blend_shape) const;
+
+ void add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), const Ref<Material> &p_material = Ref<Material>(), const String &p_name = String());
+ int get_surface_count() const;
+
+ void set_blend_shape_mode(Mesh::BlendShapeMode p_blend_shape_mode);
+ Mesh::BlendShapeMode get_blend_shape_mode() const;
+
+ Mesh::PrimitiveType get_surface_primitive_type(int p_surface);
+ String get_surface_name(int p_surface) const;
+ Array get_surface_arrays(int p_surface) const;
+ Array get_surface_blend_shape_arrays(int p_surface, int p_blend_shape) const;
+ int get_surface_lod_count(int p_surface) const;
+ Vector<int> get_surface_lod_indices(int p_surface, int p_lod) const;
+ float get_surface_lod_size(int p_surface, int p_lod) const;
+ Ref<Material> get_surface_material(int p_surface) const;
+
+ void generate_lods();
+
+ bool has_mesh() const;
+ Ref<ArrayMesh> get_mesh();
+ void clear();
+};
+
+class EditorSceneImporterMeshNode : public Node3D {
+ GDCLASS(EditorSceneImporterMeshNode, Node3D)
+
+ Ref<EditorSceneImporterMesh> mesh;
+ Ref<Skin> skin;
+ NodePath skeleton_path;
+ Vector<Ref<Material>> surface_materials;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_mesh(const Ref<EditorSceneImporterMesh> &p_mesh);
+ Ref<EditorSceneImporterMesh> get_mesh() const;
+
+ void set_skin(const Ref<Skin> &p_skin);
+ Ref<Skin> get_skin() const;
+
+ void set_surface_material(int p_idx, const Ref<Material> &p_material);
+ Ref<Material> get_surface_material(int p_idx) const;
+
+ void set_skeleton_path(const NodePath &p_path);
+ NodePath get_skeleton_path() const;
+};
+
class ResourceImporterScene : public ResourceImporter {
GDCLASS(ResourceImporterScene, ResourceImporter);
@@ -119,6 +207,7 @@ class ResourceImporterScene : public ResourceImporter {
};
void _replace_owner(Node *p_node, Node *p_scene, Node *p_new_owner);
+ void _generate_meshes(Node *p_node, bool p_generate_lods);
public:
static ResourceImporterScene *get_singleton() { return singleton; }
diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp
index ac2485fe31..c8dae53722 100644
--- a/editor/import/resource_importer_texture.cpp
+++ b/editor/import/resource_importer_texture.cpp
@@ -537,7 +537,7 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
}
if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_pvrtc")) {
- _save_stex(image, p_save_path + ".pvrtc.stex", compress_mode, lossy, Image::COMPRESS_PVRTC4, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, true, mipmap_limit, normal_image, roughness_channel);
+ _save_stex(image, p_save_path + ".pvrtc.stex", compress_mode, lossy, Image::COMPRESS_PVRTC1_4, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, true, mipmap_limit, normal_image, roughness_channel);
r_platform_variants->push_back("pvrtc");
formats_imported.push_back("pvrtc");
}
diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp
index 8ab2e0aef1..5582f9f5f0 100644
--- a/editor/import_dock.cpp
+++ b/editor/import_dock.cpp
@@ -536,7 +536,7 @@ ImportDock::ImportDock() {
hb->add_spacer();
reimport_confirm = memnew(ConfirmationDialog);
- reimport_confirm->get_ok()->set_text(TTR("Save Scenes, Re-Import, and Restart"));
+ reimport_confirm->get_ok_button()->set_text(TTR("Save Scenes, Re-Import, and Restart"));
add_child(reimport_confirm);
reimport_confirm->connect("confirmed", callable_mp(this, &ImportDock::_reimport_and_restart));
diff --git a/editor/input_map_editor.cpp b/editor/input_map_editor.cpp
index 686fd4c08b..83adccb752 100644
--- a/editor/input_map_editor.cpp
+++ b/editor/input_map_editor.cpp
@@ -398,7 +398,7 @@ void InputMapEditor::_wait_for_key(const Ref<InputEvent> &p_event) {
const String str = (press_a_key_physical) ? keycode_get_string(k->get_physical_keycode_with_modifiers()) + TTR(" (Physical)") : keycode_get_string(k->get_keycode_with_modifiers());
press_a_key_label->set_text(str);
- press_a_key->get_ok()->set_disabled(false);
+ press_a_key->get_ok_button()->set_disabled(false);
press_a_key->set_input_as_handled();
}
}
@@ -432,7 +432,7 @@ void InputMapEditor::_add_item(int p_item, Ref<InputEvent> p_exiting_event) {
case INPUT_KEY: {
press_a_key_physical = false;
press_a_key_label->set_text(TTR("Press a Key..."));
- press_a_key->get_ok()->set_disabled(true);
+ press_a_key->get_ok_button()->set_disabled(true);
last_wait_for_key = Ref<InputEvent>();
press_a_key->popup_centered(Size2(250, 80) * EDSCALE);
//press_a_key->grab_focus();
@@ -465,10 +465,10 @@ void InputMapEditor::_add_item(int p_item, Ref<InputEvent> p_exiting_event) {
if (mb.is_valid()) {
device_index->select(mb->get_button_index() - 1);
_set_current_device(mb->get_device());
- device_input->get_ok()->set_text(TTR("Change"));
+ device_input->get_ok_button()->set_text(TTR("Change"));
} else {
_set_current_device(0);
- device_input->get_ok()->set_text(TTR("Add"));
+ device_input->get_ok_button()->set_text(TTR("Add"));
}
} break;
@@ -488,10 +488,10 @@ void InputMapEditor::_add_item(int p_item, Ref<InputEvent> p_exiting_event) {
if (jm.is_valid()) {
device_index->select(jm->get_axis() * 2 + (jm->get_axis_value() > 0 ? 1 : 0));
_set_current_device(jm->get_device());
- device_input->get_ok()->set_text(TTR("Change"));
+ device_input->get_ok_button()->set_text(TTR("Change"));
} else {
_set_current_device(0);
- device_input->get_ok()->set_text(TTR("Add"));
+ device_input->get_ok_button()->set_text(TTR("Add"));
}
} break;
@@ -510,10 +510,10 @@ void InputMapEditor::_add_item(int p_item, Ref<InputEvent> p_exiting_event) {
if (jb.is_valid()) {
device_index->select(jb->get_button_index());
_set_current_device(jb->get_device());
- device_input->get_ok()->set_text(TTR("Change"));
+ device_input->get_ok_button()->set_text(TTR("Change"));
} else {
_set_current_device(0);
- device_input->get_ok()->set_text(TTR("Add"));
+ device_input->get_ok_button()->set_text(TTR("Add"));
}
} break;
@@ -978,7 +978,7 @@ InputMapEditor::InputMapEditor() {
add_child(popup_add);
press_a_key = memnew(ConfirmationDialog);
- press_a_key->get_ok()->set_disabled(true);
+ press_a_key->get_ok_button()->set_disabled(true);
//press_a_key->set_focus_mode(Control::FOCUS_ALL);
press_a_key->connect("window_input", callable_mp(this, &InputMapEditor::_wait_for_key));
press_a_key->connect("confirmed", callable_mp(this, &InputMapEditor::_press_a_key_confirm));
@@ -994,7 +994,7 @@ InputMapEditor::InputMapEditor() {
press_a_key_label = l;
device_input = memnew(ConfirmationDialog);
- device_input->get_ok()->set_text(TTR("Add"));
+ device_input->get_ok_button()->set_text(TTR("Add"));
device_input->connect("confirmed", callable_mp(this, &InputMapEditor::_device_input_add));
add_child(device_input);
diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp
index 3ad6938498..a780750633 100644
--- a/editor/plugin_config_dialog.cpp
+++ b/editor/plugin_config_dialog.cpp
@@ -126,7 +126,7 @@ void PluginConfigDialog::_on_cancelled() {
void PluginConfigDialog::_on_required_text_changed(const String &) {
int lang_idx = script_option_edit->get_selected();
String ext = ScriptServer::get_language(lang_idx)->get_extension();
- get_ok()->set_disabled(script_edit->get_text().get_basename().empty() || script_edit->get_text().get_extension() != ext || name_edit->get_text().empty());
+ get_ok_button()->set_disabled(script_edit->get_text().get_basename().empty() || script_edit->get_text().get_extension() != ext || name_edit->get_text().empty());
}
void PluginConfigDialog::_notification(int p_what) {
@@ -138,7 +138,7 @@ void PluginConfigDialog::_notification(int p_what) {
} break;
case NOTIFICATION_READY: {
connect("confirmed", callable_mp(this, &PluginConfigDialog::_on_confirmed));
- get_cancel()->connect("pressed", callable_mp(this, &PluginConfigDialog::_on_cancelled));
+ get_cancel_button()->connect("pressed", callable_mp(this, &PluginConfigDialog::_on_cancelled));
} break;
}
}
@@ -171,8 +171,8 @@ void PluginConfigDialog::config(const String &p_config_path) {
Object::cast_to<Label>(subfolder_edit->get_parent()->get_child(subfolder_edit->get_index() - 1))->show();
set_title(TTR("Create a Plugin"));
}
- get_ok()->set_disabled(!_edit_mode);
- get_ok()->set_text(_edit_mode ? TTR("Update") : TTR("Create"));
+ get_ok_button()->set_disabled(!_edit_mode);
+ get_ok_button()->set_text(_edit_mode ? TTR("Update") : TTR("Create"));
}
void PluginConfigDialog::_bind_methods() {
@@ -180,7 +180,7 @@ void PluginConfigDialog::_bind_methods() {
}
PluginConfigDialog::PluginConfigDialog() {
- get_ok()->set_disabled(true);
+ get_ok_button()->set_disabled(true);
set_hide_on_ok(true);
GridContainer *grid = memnew(GridContainer);
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index 0b61db6835..281b1d79af 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -724,7 +724,7 @@ AbstractPolygon2DEditor::AbstractPolygon2DEditor(EditorNode *p_editor, bool p_wi
create_resource = memnew(ConfirmationDialog);
add_child(create_resource);
- create_resource->get_ok()->set_text(TTR("Create"));
+ create_resource->get_ok_button()->set_text(TTR("Create"));
mode = MODE_EDIT;
}
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index 17cfb5f5f3..4b97dacbc1 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -116,6 +116,19 @@ void AnimationPlayerEditor::_notification(int p_what) {
play_bw_from->set_icon(get_theme_icon("PlayBackwards", "EditorIcons"));
autoplay_icon = get_theme_icon("AutoPlay", "EditorIcons");
+ reset_icon = get_theme_icon("Reload", "EditorIcons");
+ {
+ Ref<Image> autoplay_img = autoplay_icon->get_data();
+ Ref<Image> reset_img = reset_icon->get_data();
+ Ref<Image> autoplay_reset_img;
+ Size2 icon_size = Size2(autoplay_img->get_width(), autoplay_img->get_height());
+ autoplay_reset_img.instance();
+ autoplay_reset_img->create(icon_size.x * 2, icon_size.y, false, autoplay_img->get_format());
+ autoplay_reset_img->blit_rect(autoplay_img, Rect2(Point2(), icon_size), Point2());
+ autoplay_reset_img->blit_rect(reset_img, Rect2(Point2(), icon_size), Point2(icon_size.x, 0));
+ autoplay_reset_icon.instance();
+ autoplay_reset_icon->create_from_image(autoplay_reset_img);
+ }
stop->set_icon(get_theme_icon("Stop", "EditorIcons"));
onion_toggle->set_icon(get_theme_icon("Onion", "EditorIcons"));
@@ -817,11 +830,17 @@ void AnimationPlayerEditor::_update_player() {
int active_idx = -1;
for (List<StringName>::Element *E = animlist.front(); E; E = E->next()) {
- if (player->get_autoplay() == E->get()) {
- animation->add_icon_item(autoplay_icon, E->get());
- } else {
- animation->add_item(E->get());
+ Ref<Texture2D> icon;
+ if (E->get() == player->get_autoplay()) {
+ if (E->get() == "RESET") {
+ icon = autoplay_reset_icon;
+ } else {
+ icon = autoplay_icon;
+ }
+ } else if (E->get() == "RESET") {
+ icon = reset_icon;
}
+ animation->add_icon_item(icon, E->get());
if (player->get_assigned_animation() == E->get()) {
active_idx = animation->get_item_count() - 1;
@@ -1375,7 +1394,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() {
}
// Backup current animation state.
- AnimatedValuesBackup values_backup = player->backup_animated_values();
+ Ref<AnimatedValuesBackup> values_backup = player->backup_animated_values();
float cpos = player->get_current_animation_position();
// Render every past/future step with the capture shader.
@@ -1405,7 +1424,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() {
if (valid) {
player->seek(pos, true);
get_tree()->flush_transform_notifications(); // Needed for transforms of Node3Ds.
- values_backup.update_skeletons(); // Needed for Skeletons (2D & 3D).
+ values_backup->update_skeletons(); // Needed for Skeletons (2D & 3D).
RS::get_singleton()->viewport_set_active(onion.captures[cidx], true);
RS::get_singleton()->viewport_set_parent_viewport(root_vp, onion.captures[cidx]);
@@ -1425,7 +1444,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() {
// (Seeking with update=true wouldn't do the trick because the current value of the properties
// may not match their value for the current point in the animation).
player->seek(cpos, false);
- player->restore_animated_values(values_backup);
+ values_backup->restore();
// Restore state of main editors.
if (Node3DEditor::get_singleton()->is_visible()) {
@@ -1642,7 +1661,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay
name_dialog->register_text_enter(name);
error_dialog = memnew(ConfirmationDialog);
- error_dialog->get_ok()->set_text(TTR("Close"));
+ error_dialog->get_ok_button()->set_text(TTR("Close"));
error_dialog->set_title(TTR("Error!"));
add_child(error_dialog);
@@ -1650,7 +1669,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay
blend_editor.dialog = memnew(AcceptDialog);
add_child(blend_editor.dialog);
- blend_editor.dialog->get_ok()->set_text(TTR("Close"));
+ blend_editor.dialog->get_ok_button()->set_text(TTR("Close"));
blend_editor.dialog->set_hide_on_ok(true);
VBoxContainer *blend_vb = memnew(VBoxContainer);
blend_editor.dialog->add_child(blend_vb);
diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h
index 17e554ee0d..ab3feb115f 100644
--- a/editor/plugins/animation_player_editor_plugin.h
+++ b/editor/plugins/animation_player_editor_plugin.h
@@ -105,6 +105,8 @@ class AnimationPlayerEditor : public VBoxContainer {
Label *name_title;
UndoRedo *undo_redo;
Ref<Texture2D> autoplay_icon;
+ Ref<Texture2D> reset_icon;
+ Ref<ImageTexture> autoplay_reset_icon;
bool last_active;
float timeline_position;
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index f3aa11317e..ba798a7826 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -295,8 +295,8 @@ EditorAssetLibraryItemDescription::EditorAssetLibraryItemDescription() {
preview_hb->set_v_size_flags(Control::SIZE_EXPAND_FILL);
previews->add_child(preview_hb);
- get_ok()->set_text(TTR("Download"));
- get_cancel()->set_text(TTR("Close"));
+ get_ok_button()->set_text(TTR("Download"));
+ get_cancel_button()->set_text(TTR("Close"));
}
///////////////////////////////////////////////////////////////////////////////////
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 4227482ccc..2a4cc691c3 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -3074,15 +3074,18 @@ void CanvasItemEditor::_draw_ruler_tool() {
int font_size = get_theme_font_size("bold_size", "EditorFonts");
Color font_color = get_theme_color("font_color", "Editor");
Color font_secondary_color = font_color;
- font_secondary_color.a = 0.5;
+ font_secondary_color.set_v(font_secondary_color.get_v() > 0.5 ? 0.7 : 0.3);
+ Color outline_color = font_color.inverted();
float text_height = font->get_height(font_size);
+
+ const float outline_size = 2;
const float text_width = 76;
const float angle_text_width = 54;
Point2 text_pos = (begin + end) / 2 - Vector2(text_width / 2, text_height / 2);
text_pos.x = CLAMP(text_pos.x, text_width / 2, viewport->get_rect().size.x - text_width * 1.5);
text_pos.y = CLAMP(text_pos.y, text_height * 1.5, viewport->get_rect().size.y - text_height * 1.5);
- viewport->draw_string(font, text_pos, TS->format_number(vformat("%.2f " + TTR("px"), length_vector.length())), HALIGN_LEFT, -1, font_size, font_color);
+ viewport->draw_string(font, text_pos, TS->format_number(vformat("%.2f " + TTR("px"), length_vector.length())), HALIGN_LEFT, -1, font_size, font_color, outline_size, outline_color);
if (draw_secondary_lines) {
const float horizontal_angle_rad = atan2(length_vector.y, length_vector.x);
@@ -3092,16 +3095,16 @@ void CanvasItemEditor::_draw_ruler_tool() {
Point2 text_pos2 = text_pos;
text_pos2.x = begin.x < text_pos.x ? MIN(text_pos.x - text_width, begin.x - text_width / 2) : MAX(text_pos.x + text_width, begin.x - text_width / 2);
- viewport->draw_string(font, text_pos2, TS->format_number(vformat("%.2f " + TTR("px"), length_vector.y)), HALIGN_LEFT, -1, font_size, font_secondary_color);
+ viewport->draw_string(font, text_pos2, TS->format_number(vformat("%.2f " + TTR("px"), length_vector.y)), HALIGN_LEFT, -1, font_size, font_secondary_color, outline_size, outline_color);
Point2 v_angle_text_pos = Point2();
v_angle_text_pos.x = CLAMP(begin.x - angle_text_width / 2, angle_text_width / 2, viewport->get_rect().size.x - angle_text_width);
v_angle_text_pos.y = begin.y < end.y ? MIN(text_pos2.y - 2 * text_height, begin.y - text_height * 0.5) : MAX(text_pos2.y + text_height * 3, begin.y + text_height * 1.5);
- viewport->draw_string(font, v_angle_text_pos, TS->format_number(vformat("%d " + TTR("deg"), vertical_angle)), HALIGN_LEFT, -1, font_size, font_secondary_color);
+ viewport->draw_string(font, v_angle_text_pos, TS->format_number(vformat("%d " + TTR("deg"), vertical_angle)), HALIGN_LEFT, -1, font_size, font_secondary_color, outline_size, outline_color);
text_pos2 = text_pos;
text_pos2.y = end.y < text_pos.y ? MIN(text_pos.y - text_height * 2, end.y - text_height / 2) : MAX(text_pos.y + text_height * 2, end.y - text_height / 2);
- viewport->draw_string(font, text_pos2, TS->format_number(vformat("%.2f " + TTR("px"), length_vector.x)), HALIGN_LEFT, -1, font_size, font_secondary_color);
+ viewport->draw_string(font, text_pos2, TS->format_number(vformat("%.2f " + TTR("px"), length_vector.x)), HALIGN_LEFT, -1, font_size, font_secondary_color, outline_size, outline_color);
Point2 h_angle_text_pos = Point2();
h_angle_text_pos.x = CLAMP(end.x - angle_text_width / 2, angle_text_width / 2, viewport->get_rect().size.x - angle_text_width);
@@ -3118,7 +3121,7 @@ void CanvasItemEditor::_draw_ruler_tool() {
h_angle_text_pos.y = MIN(text_pos.y - height_multiplier * text_height, MIN(end.y - text_height * 0.5, text_pos2.y - height_multiplier * text_height));
}
}
- viewport->draw_string(font, h_angle_text_pos, TS->format_number(vformat("%d " + TTR("deg"), horizontal_angle)), HALIGN_LEFT, -1, font_size, font_secondary_color);
+ viewport->draw_string(font, h_angle_text_pos, TS->format_number(vformat("%d " + TTR("deg"), horizontal_angle)), HALIGN_LEFT, -1, font_size, font_secondary_color, outline_size, outline_color);
// Angle arcs
int arc_point_count = 8;
@@ -3155,17 +3158,17 @@ void CanvasItemEditor::_draw_ruler_tool() {
text_pos.y = CLAMP(text_pos.y, text_height * 2.5, viewport->get_rect().size.y - text_height / 2);
if (draw_secondary_lines) {
- viewport->draw_string(font, text_pos, TS->format_number(vformat("%.2f " + TTR("units"), (length_vector / grid_step).length())), HALIGN_LEFT, -1, font_size, font_color);
+ viewport->draw_string(font, text_pos, TS->format_number(vformat("%.2f " + TTR("units"), (length_vector / grid_step).length())), HALIGN_LEFT, -1, font_size, font_color, outline_size, outline_color);
Point2 text_pos2 = text_pos;
text_pos2.x = begin.x < text_pos.x ? MIN(text_pos.x - text_width, begin.x - text_width / 2) : MAX(text_pos.x + text_width, begin.x - text_width / 2);
- viewport->draw_string(font, text_pos2, TS->format_number(vformat("%d " + TTR("units"), roundf(length_vector.y / grid_step.y))), HALIGN_LEFT, -1, font_size, font_secondary_color);
+ viewport->draw_string(font, text_pos2, TS->format_number(vformat("%d " + TTR("units"), roundf(length_vector.y / grid_step.y))), HALIGN_LEFT, -1, font_size, font_secondary_color, outline_size, outline_color);
text_pos2 = text_pos;
text_pos2.y = end.y < text_pos.y ? MIN(text_pos.y - text_height * 2, end.y + text_height / 2) : MAX(text_pos.y + text_height * 2, end.y + text_height / 2);
- viewport->draw_string(font, text_pos2, TS->format_number(vformat("%d " + TTR("units"), roundf(length_vector.x / grid_step.x))), HALIGN_LEFT, -1, font_size, font_secondary_color);
+ viewport->draw_string(font, text_pos2, TS->format_number(vformat("%d " + TTR("units"), roundf(length_vector.x / grid_step.x))), HALIGN_LEFT, -1, font_size, font_secondary_color, outline_size, outline_color);
} else {
- viewport->draw_string(font, text_pos, TS->format_number(vformat("%d " + TTR("units"), roundf((length_vector / grid_step).length()))), HALIGN_LEFT, -1, font_size, font_color);
+ viewport->draw_string(font, text_pos, TS->format_number(vformat("%d " + TTR("units"), roundf((length_vector / grid_step).length()))), HALIGN_LEFT, -1, font_size, font_color, outline_size, outline_color);
}
}
} else {
diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
index c98ba25db5..0de52b3930 100644
--- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
@@ -213,7 +213,7 @@ GPUParticles3DEditorBase::GPUParticles3DEditorBase() {
emission_fill->add_item(TTR("Volume"));
emd_vb->add_margin_child(TTR("Emission Source: "), emission_fill);
- emission_dialog->get_ok()->set_text(TTR("Create"));
+ emission_dialog->get_ok_button()->set_text(TTR("Create"));
emission_dialog->connect("confirmed", callable_mp(this, &GPUParticles3DEditorBase::_generate_emission_points));
emission_tree_dialog = memnew(SceneTreeDialog);
diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
index 5b241deab0..2a08e3a8b5 100644
--- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp
+++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
@@ -457,7 +457,7 @@ MeshInstance3DEditor::MeshInstance3DEditor() {
outline_dialog = memnew(ConfirmationDialog);
outline_dialog->set_title(TTR("Create Outline Mesh"));
- outline_dialog->get_ok()->set_text(TTR("Create"));
+ outline_dialog->get_ok_button()->set_text(TTR("Create"));
VBoxContainer *outline_dialog_vbc = memnew(VBoxContainer);
outline_dialog->add_child(outline_dialog_vbc);
diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp
index 9d3498efa1..b11a07365c 100644
--- a/editor/plugins/mesh_library_editor_plugin.cpp
+++ b/editor/plugins/mesh_library_editor_plugin.cpp
@@ -267,7 +267,7 @@ MeshLibraryEditor::MeshLibraryEditor(EditorNode *p_editor) {
editor = p_editor;
cd = memnew(ConfirmationDialog);
add_child(cd);
- cd->get_ok()->connect("pressed", callable_mp(this, &MeshLibraryEditor::_menu_confirm));
+ cd->get_ok_button()->connect("pressed", callable_mp(this, &MeshLibraryEditor::_menu_confirm));
}
void MeshLibraryEditorPlugin::edit(Object *p_node) {
diff --git a/editor/plugins/multimesh_editor_plugin.cpp b/editor/plugins/multimesh_editor_plugin.cpp
index bd1384967f..b8a4f7bc5a 100644
--- a/editor/plugins/multimesh_editor_plugin.cpp
+++ b/editor/plugins/multimesh_editor_plugin.cpp
@@ -345,9 +345,9 @@ MultiMeshEditor::MultiMeshEditor() {
populate_amount->set_value(128);
vbc->add_margin_child(TTR("Amount:"), populate_amount);
- populate_dialog->get_ok()->set_text(TTR("Populate"));
+ populate_dialog->get_ok_button()->set_text(TTR("Populate"));
- populate_dialog->get_ok()->connect("pressed", callable_mp(this, &MultiMeshEditor::_populate));
+ populate_dialog->get_ok_button()->connect("pressed", callable_mp(this, &MultiMeshEditor::_populate));
std = memnew(SceneTreeDialog);
populate_dialog->add_child(std);
std->connect("selected", callable_mp(this, &MultiMeshEditor::_browsed));
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 6493e0f953..4d7be66180 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -2657,11 +2657,30 @@ void Node3DEditorViewport::_draw() {
if (_edit.mode == TRANSFORM_ROTATE) {
Point2 center = _point_to_screen(_edit.center);
+
+ Color handle_color;
+ switch (_edit.plane) {
+ case TRANSFORM_X_AXIS:
+ handle_color = get_theme_color("axis_x_color", "Editor");
+ break;
+ case TRANSFORM_Y_AXIS:
+ handle_color = get_theme_color("axis_y_color", "Editor");
+ break;
+ case TRANSFORM_Z_AXIS:
+ handle_color = get_theme_color("axis_z_color", "Editor");
+ break;
+ default:
+ handle_color = get_theme_color("accent_color", "Editor");
+ break;
+ }
+ handle_color.a = 1.0;
+ handle_color *= Color(1.3, 1.3, 1.3, 1.0);
+
RenderingServer::get_singleton()->canvas_item_add_line(
ci,
_edit.mouse_pos,
center,
- get_theme_color("accent_color", "Editor") * Color(1, 1, 1, 0.6),
+ handle_color,
Math::round(2 * EDSCALE));
}
if (previewing) {
@@ -2686,7 +2705,7 @@ void Node3DEditorViewport::_draw() {
} break;
}
- draw_rect = Rect2(Vector2(), s).clip(draw_rect);
+ draw_rect = Rect2(Vector2(), s).intersection(draw_rect);
surface->draw_rect(draw_rect, Color(0.6, 0.6, 0.1, 0.5), false, Math::round(2 * EDSCALE));
@@ -2998,7 +3017,8 @@ void Node3DEditorViewport::_menu_option(int p_option) {
case VIEW_DISPLAY_DEBUG_DECAL_ATLAS:
case VIEW_DISPLAY_DEBUG_SDFGI:
case VIEW_DISPLAY_DEBUG_SDFGI_PROBES:
- case VIEW_DISPLAY_DEBUG_GI_BUFFER: {
+ case VIEW_DISPLAY_DEBUG_GI_BUFFER:
+ case VIEW_DISPLAY_DEBUG_DISABLE_LOD: {
static const int display_options[] = {
VIEW_DISPLAY_NORMAL,
VIEW_DISPLAY_WIREFRAME,
@@ -3015,6 +3035,7 @@ void Node3DEditorViewport::_menu_option(int p_option) {
VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE,
VIEW_DISPLAY_DEBUG_SSAO,
VIEW_DISPLAY_DEBUG_GI_BUFFER,
+ VIEW_DISPLAY_DEBUG_DISABLE_LOD,
VIEW_DISPLAY_DEBUG_PSSM_SPLITS,
VIEW_DISPLAY_DEBUG_DECAL_ATLAS,
VIEW_DISPLAY_DEBUG_SDFGI,
@@ -3037,6 +3058,7 @@ void Node3DEditorViewport::_menu_option(int p_option) {
Viewport::DEBUG_DRAW_SCENE_LUMINANCE,
Viewport::DEBUG_DRAW_SSAO,
Viewport::DEBUG_DRAW_GI_BUFFER,
+ Viewport::DEBUG_DRAW_DISABLE_LOD,
Viewport::DEBUG_DRAW_PSSM_SPLITS,
Viewport::DEBUG_DRAW_DECAL_ATLAS,
Viewport::DEBUG_DRAW_SDFGI,
@@ -3940,6 +3962,8 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
display_submenu->add_radio_check_item(TTR("SSAO"), VIEW_DISPLAY_DEBUG_SSAO);
display_submenu->add_separator();
display_submenu->add_radio_check_item(TTR("GI Buffer"), VIEW_DISPLAY_DEBUG_GI_BUFFER);
+ display_submenu->add_separator();
+ display_submenu->add_radio_check_item(TTR("Disable LOD"), VIEW_DISPLAY_DEBUG_DISABLE_LOD);
display_submenu->set_name("display_advanced");
view_menu->get_popup()->add_submenu_item(TTR("Display Advanced..."), "display_advanced", VIEW_DISPLAY_ADVANCED);
view_menu->get_popup()->add_separator();
@@ -5228,7 +5252,7 @@ void Node3DEditor::_init_indicators() {
gizmo_color[i] = mat;
Ref<StandardMaterial3D> mat_hl = mat->duplicate();
- mat_hl->set_albedo(Color(col.r, col.g, col.b, 1.0));
+ mat_hl->set_albedo(Color(col.r * 1.3, col.g * 1.3, col.b * 1.3, 1.0));
gizmo_color_hl[i] = mat_hl;
Vector3 ivec;
@@ -5323,7 +5347,7 @@ void Node3DEditor::_init_indicators() {
surftool->commit(move_plane_gizmo[i]);
Ref<StandardMaterial3D> plane_mat_hl = plane_mat->duplicate();
- plane_mat_hl->set_albedo(Color(col.r, col.g, col.b, 1.0));
+ plane_mat_hl->set_albedo(Color(col.r * 1.3, col.g * 1.3, col.b * 1.3, 1.0));
plane_gizmo_color_hl[i] = plane_mat_hl; // needed, so we can draw planes from both sides
}
@@ -5406,7 +5430,7 @@ void Node3DEditor::_init_indicators() {
rotate_gizmo[i]->surface_set_material(0, rotate_mat);
Ref<ShaderMaterial> rotate_mat_hl = rotate_mat->duplicate();
- rotate_mat_hl->set_shader_param("albedo", Color(col.r, col.g, col.b, 1.0));
+ rotate_mat_hl->set_shader_param("albedo", Color(col.r * 1.3, col.g * 1.3, col.b * 1.3, 1.0));
rotate_gizmo_color_hl[i] = rotate_mat_hl;
if (i == 2) { // Rotation white outline
@@ -5533,7 +5557,7 @@ void Node3DEditor::_init_indicators() {
surftool->commit(scale_plane_gizmo[i]);
Ref<StandardMaterial3D> plane_mat_hl = plane_mat->duplicate();
- plane_mat_hl->set_albedo(Color(col.r, col.g, col.b, 1.0));
+ plane_mat_hl->set_albedo(Color(col.r * 1.3, col.g * 1.3, col.b * 1.3, 1.0));
plane_gizmo_color_hl[i] = plane_mat_hl; // needed, so we can draw planes from both sides
}
}
@@ -6157,9 +6181,9 @@ void Node3DEditor::_bind_methods() {
}
void Node3DEditor::clear() {
- settings_fov->set_value(EDITOR_DEF("editors/3d/default_fov", 70.0));
- settings_znear->set_value(EDITOR_DEF("editors/3d/default_z_near", 0.05));
- settings_zfar->set_value(EDITOR_DEF("editors/3d/default_z_far", 1500.0));
+ settings_fov->set_value(EDITOR_GET("editors/3d/default_fov"));
+ settings_znear->set_value(EDITOR_GET("editors/3d/default_z_near"));
+ settings_zfar->set_value(EDITOR_GET("editors/3d/default_z_far"));
for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
viewports[i]->reset();
@@ -6423,7 +6447,7 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
snap_dialog->set_title(TTR("Snap Settings"));
add_child(snap_dialog);
snap_dialog->connect("confirmed", callable_mp(this, &Node3DEditor::_snap_changed));
- snap_dialog->get_cancel()->connect("pressed", callable_mp(this, &Node3DEditor::_snap_update));
+ snap_dialog->get_cancel_button()->connect("pressed", callable_mp(this, &Node3DEditor::_snap_update));
VBoxContainer *snap_dialog_vbc = memnew(VBoxContainer);
snap_dialog->add_child(snap_dialog_vbc);
@@ -6451,22 +6475,22 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
settings_fov = memnew(SpinBox);
settings_fov->set_max(MAX_FOV);
settings_fov->set_min(MIN_FOV);
- settings_fov->set_step(0.01);
- settings_fov->set_value(EDITOR_DEF("editors/3d/default_fov", 70.0));
+ settings_fov->set_step(0.1);
+ settings_fov->set_value(EDITOR_GET("editors/3d/default_fov"));
settings_vbc->add_margin_child(TTR("Perspective FOV (deg.):"), settings_fov);
settings_znear = memnew(SpinBox);
settings_znear->set_max(MAX_Z);
settings_znear->set_min(MIN_Z);
settings_znear->set_step(0.01);
- settings_znear->set_value(EDITOR_DEF("editors/3d/default_z_near", 0.05));
+ settings_znear->set_value(EDITOR_GET("editors/3d/default_z_near"));
settings_vbc->add_margin_child(TTR("View Z-Near:"), settings_znear);
settings_zfar = memnew(SpinBox);
settings_zfar->set_max(MAX_Z);
settings_zfar->set_min(MIN_Z);
- settings_zfar->set_step(0.01);
- settings_zfar->set_value(EDITOR_DEF("editors/3d/default_z_far", 1500));
+ settings_zfar->set_step(0.1);
+ settings_zfar->set_value(EDITOR_GET("editors/3d/default_z_far"));
settings_vbc->add_margin_child(TTR("View Z-Far:"), settings_zfar);
for (uint32_t i = 0; i < VIEWPORTS_COUNT; ++i) {
@@ -6541,8 +6565,8 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
add_to_group("_spatial_editor_group");
EDITOR_DEF("editors/3d/manipulator_gizmo_size", 80);
- EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "editors/3d/manipulator_gizmo_size", PROPERTY_HINT_RANGE, "16,1024,1"));
- EDITOR_DEF("editors/3d/manipulator_gizmo_opacity", 0.4);
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "editors/3d/manipulator_gizmo_size", PROPERTY_HINT_RANGE, "16,160,1"));
+ EDITOR_DEF("editors/3d/manipulator_gizmo_opacity", 0.9);
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::FLOAT, "editors/3d/manipulator_gizmo_opacity", PROPERTY_HINT_RANGE, "0,1,0.01"));
EDITOR_DEF("editors/3d/navigation/show_viewport_rotation_gizmo", true);
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index 66ee678154..079c86ceb4 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -212,6 +212,7 @@ class Node3DEditorViewport : public Control {
VIEW_DISPLAY_DEBUG_SDFGI,
VIEW_DISPLAY_DEBUG_SDFGI_PROBES,
VIEW_DISPLAY_DEBUG_GI_BUFFER,
+ VIEW_DISPLAY_DEBUG_DISABLE_LOD,
VIEW_LOCK_ROTATION,
VIEW_CINEMATIC_PREVIEW,
VIEW_AUTO_ORTHOGONAL,
diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp
index f317aebe74..684d43e963 100644
--- a/editor/plugins/resource_preloader_editor_plugin.cpp
+++ b/editor/plugins/resource_preloader_editor_plugin.cpp
@@ -62,7 +62,7 @@ void ResourcePreloaderEditor::_files_load_request(const Vector<String> &p_paths)
dialog->set_text(TTR("ERROR: Couldn't load resource!"));
dialog->set_title(TTR("Error!"));
//dialog->get_cancel()->set_text("Close");
- dialog->get_ok()->set_text(TTR("Close"));
+ dialog->get_ok_button()->set_text(TTR("Close"));
dialog->popup_centered();
return; ///beh should show an error i guess
}
@@ -144,7 +144,7 @@ void ResourcePreloaderEditor::_paste_pressed() {
if (!r.is_valid()) {
dialog->set_text(TTR("Resource clipboard is empty!"));
dialog->set_title(TTR("Error!"));
- dialog->get_ok()->set_text(TTR("Close"));
+ dialog->get_ok_button()->set_text(TTR("Close"));
dialog->popup_centered();
return; ///beh should show an error i guess
}
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 5982074750..e0a6fe16f7 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -338,7 +338,7 @@ void ScriptEditorQuickOpen::_update_search() {
}
}
- get_ok()->set_disabled(root->get_children() == nullptr);
+ get_ok_button()->set_disabled(root->get_children() == nullptr);
}
void ScriptEditorQuickOpen::_confirmed() {
@@ -382,8 +382,8 @@ ScriptEditorQuickOpen::ScriptEditorQuickOpen() {
search_box->connect("gui_input", callable_mp(this, &ScriptEditorQuickOpen::_sbox_input));
search_options = memnew(Tree);
vbc->add_margin_child(TTR("Matches:"), search_options, true);
- get_ok()->set_text(TTR("Open"));
- get_ok()->set_disabled(true);
+ get_ok_button()->set_text(TTR("Open"));
+ get_ok_button()->set_disabled(true);
register_text_enter(search_box);
set_hide_on_ok(false);
search_options->connect("item_activated", callable_mp(this, &ScriptEditorQuickOpen::_confirmed));
@@ -3482,7 +3482,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
tab_container->connect("tab_changed", callable_mp(this, &ScriptEditor::_tab_changed));
erase_tab_confirm = memnew(ConfirmationDialog);
- erase_tab_confirm->get_ok()->set_text(TTR("Save"));
+ erase_tab_confirm->get_ok_button()->set_text(TTR("Save"));
erase_tab_confirm->add_button(TTR("Discard"), DisplayServer::get_singleton()->get_swap_cancel_ok(), "discard");
erase_tab_confirm->connect("confirmed", callable_mp(this, &ScriptEditor::_close_current_tab));
erase_tab_confirm->connect("custom_action", callable_mp(this, &ScriptEditor::_close_discard_current_tab));
@@ -3515,7 +3515,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
disk_changed_list->set_v_size_flags(SIZE_EXPAND_FILL);
disk_changed->connect("confirmed", callable_mp(this, &ScriptEditor::_reload_scripts));
- disk_changed->get_ok()->set_text(TTR("Reload"));
+ disk_changed->get_ok_button()->set_text(TTR("Reload"));
disk_changed->add_button(TTR("Resave"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "resave");
disk_changed->connect("custom_action", callable_mp(this, &ScriptEditor::_resave_scripts));
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index 6e174653f6..d24dcdef83 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -661,7 +661,7 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) {
vbc->add_child(dl);
disk_changed->connect("confirmed", callable_mp(this, &ShaderEditor::_reload_shader_from_disk));
- disk_changed->get_ok()->set_text(TTR("Reload"));
+ disk_changed->get_ok_button()->set_text(TTR("Reload"));
disk_changed->add_button(TTR("Resave"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "resave");
disk_changed->connect("custom_action", callable_mp(this, &ShaderEditor::save_external_data));
diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp
index f5fafb68a5..1be6b979b1 100644
--- a/editor/plugins/sprite_2d_editor_plugin.cpp
+++ b/editor/plugins/sprite_2d_editor_plugin.cpp
@@ -120,7 +120,7 @@ void Sprite2DEditor::_menu_option(int p_option) {
switch (p_option) {
case MENU_OPTION_CONVERT_TO_MESH_2D: {
- debug_uv_dialog->get_ok()->set_text(TTR("Create Mesh2D"));
+ debug_uv_dialog->get_ok_button()->set_text(TTR("Create Mesh2D"));
debug_uv_dialog->set_title(TTR("Mesh2D Preview"));
_update_mesh_data();
@@ -129,7 +129,7 @@ void Sprite2DEditor::_menu_option(int p_option) {
} break;
case MENU_OPTION_CONVERT_TO_POLYGON_2D: {
- debug_uv_dialog->get_ok()->set_text(TTR("Create Polygon2D"));
+ debug_uv_dialog->get_ok_button()->set_text(TTR("Create Polygon2D"));
debug_uv_dialog->set_title(TTR("Polygon2D Preview"));
_update_mesh_data();
@@ -137,7 +137,7 @@ void Sprite2DEditor::_menu_option(int p_option) {
debug_uv->update();
} break;
case MENU_OPTION_CREATE_COLLISION_POLY_2D: {
- debug_uv_dialog->get_ok()->set_text(TTR("Create CollisionPolygon2D"));
+ debug_uv_dialog->get_ok_button()->set_text(TTR("Create CollisionPolygon2D"));
debug_uv_dialog->set_title(TTR("CollisionPolygon2D Preview"));
_update_mesh_data();
@@ -146,7 +146,7 @@ void Sprite2DEditor::_menu_option(int p_option) {
} break;
case MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D: {
- debug_uv_dialog->get_ok()->set_text(TTR("Create LightOccluder2D"));
+ debug_uv_dialog->get_ok_button()->set_text(TTR("Create LightOccluder2D"));
debug_uv_dialog->set_title(TTR("LightOccluder2D Preview"));
_update_mesh_data();
@@ -515,7 +515,7 @@ Sprite2DEditor::Sprite2DEditor() {
add_child(err_dialog);
debug_uv_dialog = memnew(ConfirmationDialog);
- debug_uv_dialog->get_ok()->set_text(TTR("Create Mesh2D"));
+ debug_uv_dialog->get_ok_button()->set_text(TTR("Create Mesh2D"));
debug_uv_dialog->set_title("Mesh 2D Preview");
VBoxContainer *vb = memnew(VBoxContainer);
debug_uv_dialog->add_child(vb);
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index 69a8a8d92c..b79d829c34 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -74,8 +74,8 @@ void SpriteFramesEditor::_sheet_preview_draw() {
}
if (frames_selected.size() == 0) {
- split_sheet_dialog->get_ok()->set_disabled(true);
- split_sheet_dialog->get_ok()->set_text(TTR("No Frames Selected"));
+ split_sheet_dialog->get_ok_button()->set_disabled(true);
+ split_sheet_dialog->get_ok_button()->set_text(TTR("No Frames Selected"));
return;
}
@@ -97,8 +97,8 @@ void SpriteFramesEditor::_sheet_preview_draw() {
split_sheet_preview->draw_rect(Rect2(x + 5, y + 5, width - 10, height - 10), Color(0, 0, 0, 1), false);
}
- split_sheet_dialog->get_ok()->set_disabled(false);
- split_sheet_dialog->get_ok()->set_text(vformat(TTR("Add %d Frame(s)"), frames_selected.size()));
+ split_sheet_dialog->get_ok_button()->set_disabled(false);
+ split_sheet_dialog->get_ok_button()->set_text(vformat(TTR("Add %d Frame(s)"), frames_selected.size()));
}
void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) {
@@ -310,7 +310,7 @@ void SpriteFramesEditor::_file_load_request(const Vector<String> &p_path, int p_
dialog->set_title(TTR("Error!"));
//dialog->get_cancel()->set_text("Close");
- dialog->get_ok()->set_text(TTR("Close"));
+ dialog->get_ok_button()->set_text(TTR("Close"));
dialog->popup_centered();
return; ///beh should show an error i guess
}
@@ -361,7 +361,7 @@ void SpriteFramesEditor::_paste_pressed() {
dialog->set_text(TTR("Resource clipboard is empty or not a texture!"));
dialog->set_title(TTR("Error!"));
//dialog->get_cancel()->set_text("Close");
- dialog->get_ok()->set_text(TTR("Close"));
+ dialog->get_ok_button()->set_text(TTR("Close"));
dialog->popup_centered();
return; ///beh should show an error i guess
}
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index dd53f60014..e6fb6ba22a 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -556,7 +556,7 @@ void ThemeEditor::_theme_menu_cbk(int p_option) {
if (p_option == POPUP_ADD) { // Add.
add_del_dialog->set_title(TTR("Add Item"));
- add_del_dialog->get_ok()->set_text(TTR("Add"));
+ add_del_dialog->get_ok_button()->set_text(TTR("Add"));
add_del_dialog->popup_centered(Size2(490, 85) * EDSCALE);
base_theme = Theme::get_default();
@@ -564,7 +564,7 @@ void ThemeEditor::_theme_menu_cbk(int p_option) {
} else if (p_option == POPUP_CLASS_ADD) { // Add.
add_del_dialog->set_title(TTR("Add All Items"));
- add_del_dialog->get_ok()->set_text(TTR("Add All"));
+ add_del_dialog->get_ok_button()->set_text(TTR("Add All"));
add_del_dialog->popup_centered(Size2(240, 85) * EDSCALE);
base_theme = Theme::get_default();
@@ -576,14 +576,14 @@ void ThemeEditor::_theme_menu_cbk(int p_option) {
} else if (p_option == POPUP_REMOVE) {
add_del_dialog->set_title(TTR("Remove Item"));
- add_del_dialog->get_ok()->set_text(TTR("Remove"));
+ add_del_dialog->get_ok_button()->set_text(TTR("Remove"));
add_del_dialog->popup_centered(Size2(490, 85) * EDSCALE);
base_theme = theme;
} else if (p_option == POPUP_CLASS_REMOVE) {
add_del_dialog->set_title(TTR("Remove All Items"));
- add_del_dialog->get_ok()->set_text(TTR("Remove All"));
+ add_del_dialog->get_ok_button()->set_text(TTR("Remove All"));
add_del_dialog->popup_centered(Size2(240, 85) * EDSCALE);
base_theme = Theme::get_default();
@@ -908,7 +908,7 @@ ThemeEditor::ThemeEditor() {
dialog_vbc->add_child(type_select);
- add_del_dialog->get_ok()->connect("pressed", callable_mp(this, &ThemeEditor::_dialog_cbk));
+ 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"));
diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp
index 5e98b2d98b..7747c740df 100644
--- a/editor/plugins/version_control_editor_plugin.cpp
+++ b/editor/plugins/version_control_editor_plugin.cpp
@@ -119,19 +119,13 @@ void VersionControlEditorPlugin::_initialize_vcs() {
}
void VersionControlEditorPlugin::_send_commit_msg() {
- String msg = commit_message->get_text();
- if (msg == "") {
- commit_status->set_text(TTR("No commit message was provided"));
- return;
- }
-
if (EditorVCSInterface::get_singleton()) {
if (staged_files_count == 0) {
commit_status->set_text(TTR("No files added to stage"));
return;
}
- EditorVCSInterface::get_singleton()->commit(msg);
+ EditorVCSInterface::get_singleton()->commit(commit_message->get_text());
commit_message->set_text("");
version_control_dock_button->set_pressed(false);
@@ -294,6 +288,10 @@ void VersionControlEditorPlugin::_update_commit_status() {
staged_files_count = 0;
}
+void VersionControlEditorPlugin::_update_commit_button() {
+ commit_button->set_disabled(commit_message->get_text().strip_edges() == "");
+}
+
void VersionControlEditorPlugin::register_editor() {
if (!EditorVCSInterface::get_singleton()) {
EditorNode::get_singleton()->add_control_to_dock(EditorNode::DOCK_SLOT_RIGHT_UL, version_commit_dock);
@@ -357,7 +355,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
set_up_dialog->set_min_size(Size2(400, 100));
version_control_actions->add_child(set_up_dialog);
- set_up_ok_button = set_up_dialog->get_ok();
+ set_up_ok_button = set_up_dialog->get_ok_button();
set_up_ok_button->set_text(TTR("Close"));
set_up_vbc = memnew(VBoxContainer);
@@ -463,11 +461,12 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
commit_message->set_v_grow_direction(Control::GrowDirection::GROW_DIRECTION_END);
commit_message->set_custom_minimum_size(Size2(200, 100));
commit_message->set_wrap_enabled(true);
- commit_message->set_text(TTR("Add a commit message"));
+ commit_message->connect("text_changed", callable_mp(this, &VersionControlEditorPlugin::_update_commit_button));
commit_box_vbc->add_child(commit_message);
commit_button = memnew(Button);
commit_button->set_text(TTR("Commit Changes"));
+ commit_button->set_disabled(true);
commit_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_send_commit_msg));
commit_box_vbc->add_child(commit_button);
diff --git a/editor/plugins/version_control_editor_plugin.h b/editor/plugins/version_control_editor_plugin.h
index 34643e85e4..3f107ddffb 100644
--- a/editor/plugins/version_control_editor_plugin.h
+++ b/editor/plugins/version_control_editor_plugin.h
@@ -110,6 +110,7 @@ private:
void _clear_file_diff();
void _update_stage_status();
void _update_commit_status();
+ void _update_commit_button();
friend class EditorVCSInterface;
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 07061a4bc5..da664109dc 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -1009,7 +1009,7 @@ String VisualShaderEditor::_get_description(int p_idx) {
void VisualShaderEditor::_update_options_menu() {
node_desc->set_text("");
- members_dialog->get_ok()->set_disabled(true);
+ members_dialog->get_ok_button()->set_disabled(true);
members->clear();
TreeItem *root = members->create_item();
@@ -2613,12 +2613,12 @@ void VisualShaderEditor::_member_selected() {
TreeItem *item = members->get_selected();
if (item != nullptr && item->has_meta("id")) {
- members_dialog->get_ok()->set_disabled(false);
+ members_dialog->get_ok_button()->set_disabled(false);
highend_label->set_visible(add_options[item->get_meta("id")].highend);
node_desc->set_text(_get_description(item->get_meta("id")));
} else {
highend_label->set_visible(false);
- members_dialog->get_ok()->set_disabled(true);
+ members_dialog->get_ok_button()->set_disabled(true);
node_desc->set_text("");
}
}
@@ -3068,9 +3068,9 @@ VisualShaderEditor::VisualShaderEditor() {
members_dialog->set_title(TTR("Create Shader Node"));
members_dialog->set_exclusive(false);
members_dialog->add_child(members_vb);
- members_dialog->get_ok()->set_text(TTR("Create"));
- members_dialog->get_ok()->connect("pressed", callable_mp(this, &VisualShaderEditor::_member_create));
- members_dialog->get_ok()->set_disabled(true);
+ members_dialog->get_ok_button()->set_text(TTR("Create"));
+ members_dialog->get_ok_button()->connect("pressed", callable_mp(this, &VisualShaderEditor::_member_create));
+ members_dialog->get_ok_button()->set_disabled(true);
members_dialog->connect("cancelled", callable_mp(this, &VisualShaderEditor::_member_cancel));
add_child(members_dialog);
diff --git a/editor/project_export.cpp b/editor/project_export.cpp
index 8435dccf4a..68710920a5 100644
--- a/editor/project_export.cpp
+++ b/editor/project_export.cpp
@@ -262,13 +262,13 @@ void ProjectExportDialog::_edit_preset(int p_index) {
}
export_button->set_disabled(true);
- get_ok()->set_disabled(true);
+ get_ok_button()->set_disabled(true);
} else {
export_error->hide();
export_templates_error->hide();
export_button->set_disabled(false);
- get_ok()->set_disabled(false);
+ get_ok_button()->set_disabled(false);
}
custom_features->set_text(current->get_custom_features());
@@ -586,7 +586,7 @@ void ProjectExportDialog::_delete_preset_confirm() {
int idx = presets->get_current();
_edit_preset(-1);
export_button->set_disabled(true);
- get_ok()->set_disabled(true);
+ get_ok_button()->set_disabled(true);
EditorExport::get_singleton()->remove_export_preset(idx);
_update_presets();
}
@@ -856,18 +856,18 @@ void ProjectExportDialog::_validate_export_path(const String &p_path) {
bool invalid_path = (p_path.get_file().get_basename() == "");
// Check if state change before needlessly messing with signals
- if (invalid_path && export_project->get_ok()->is_disabled()) {
+ if (invalid_path && export_project->get_ok_button()->is_disabled()) {
return;
}
- if (!invalid_path && !export_project->get_ok()->is_disabled()) {
+ if (!invalid_path && !export_project->get_ok_button()->is_disabled()) {
return;
}
if (invalid_path) {
- export_project->get_ok()->set_disabled(true);
+ export_project->get_ok_button()->set_disabled(true);
export_project->get_line_edit()->disconnect("text_entered", Callable(export_project, "_file_entered"));
} else {
- export_project->get_ok()->set_disabled(false);
+ export_project->get_ok_button()->set_disabled(false);
export_project->get_line_edit()->connect("text_entered", Callable(export_project, "_file_entered"));
}
}
@@ -901,7 +901,7 @@ void ProjectExportDialog::_export_project() {
// 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"))) {
- export_project->get_ok()->set_disabled(false);
+ export_project->get_ok_button()->set_disabled(false);
export_project->get_line_edit()->connect("text_entered", Callable(export_project, "_file_entered"));
}
@@ -1184,26 +1184,26 @@ ProjectExportDialog::ProjectExportDialog() {
delete_confirm = memnew(ConfirmationDialog);
add_child(delete_confirm);
- delete_confirm->get_ok()->set_text(TTR("Delete"));
+ delete_confirm->get_ok_button()->set_text(TTR("Delete"));
delete_confirm->connect("confirmed", callable_mp(this, &ProjectExportDialog::_delete_preset_confirm));
// Export buttons, dialogs and errors.
updating = false;
- get_cancel()->set_text(TTR("Close"));
- get_ok()->set_text(TTR("Export PCK/Zip"));
+ get_cancel_button()->set_text(TTR("Close"));
+ get_ok_button()->set_text(TTR("Export PCK/Zip"));
export_button = add_button(TTR("Export Project"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "export");
export_button->connect("pressed", callable_mp(this, &ProjectExportDialog::_export_project));
// Disable initially before we select a valid preset
export_button->set_disabled(true);
- get_ok()->set_disabled(true);
+ get_ok_button()->set_disabled(true);
export_all_dialog = memnew(ConfirmationDialog);
add_child(export_all_dialog);
export_all_dialog->set_title("Export All");
export_all_dialog->set_text(TTR("Export mode?"));
- export_all_dialog->get_ok()->hide();
+ export_all_dialog->get_ok_button()->hide();
export_all_dialog->add_button(TTR("Debug"), true, "debug");
export_all_dialog->add_button(TTR("Release"), true, "release");
export_all_dialog->connect("custom_action", callable_mp(this, &ProjectExportDialog::_export_all_dialog_action));
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 3ec0c5a6a4..ad0c9532d8 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -160,7 +160,7 @@ private:
if (valid_path == "") {
set_message(TTR("The path specified doesn't exist."), MESSAGE_ERROR);
memdelete(d);
- get_ok()->set_disabled(true);
+ get_ok_button()->set_disabled(true);
return "";
}
@@ -174,7 +174,7 @@ private:
if (valid_install_path == "") {
set_message(TTR("The path specified doesn't exist."), MESSAGE_ERROR, INSTALL_PATH);
memdelete(d);
- get_ok()->set_disabled(true);
+ get_ok_button()->set_disabled(true);
return "";
}
}
@@ -189,7 +189,7 @@ private:
if (!pkg) {
set_message(TTR("Error opening package file (it's not in ZIP format)."), MESSAGE_ERROR);
memdelete(d);
- get_ok()->set_disabled(true);
+ get_ok_button()->set_disabled(true);
unzClose(pkg);
return "";
}
@@ -210,7 +210,7 @@ private:
if (ret == UNZ_END_OF_LIST_OF_FILE) {
set_message(TTR("Invalid \".zip\" project file; it doesn't contain a \"project.godot\" file."), MESSAGE_ERROR);
memdelete(d);
- get_ok()->set_disabled(true);
+ get_ok_button()->set_disabled(true);
unzClose(pkg);
return "";
}
@@ -237,7 +237,7 @@ private:
if (!is_folder_empty) {
set_message(TTR("Please choose an empty folder."), MESSAGE_WARNING, INSTALL_PATH);
memdelete(d);
- get_ok()->set_disabled(true);
+ get_ok_button()->set_disabled(true);
return "";
}
@@ -245,14 +245,14 @@ private:
set_message(TTR("Please choose a \"project.godot\" or \".zip\" file."), MESSAGE_ERROR);
memdelete(d);
install_path_container->hide();
- get_ok()->set_disabled(true);
+ get_ok_button()->set_disabled(true);
return "";
}
} else if (valid_path.ends_with("zip")) {
set_message(TTR("This directory already contains a Godot project."), MESSAGE_ERROR, INSTALL_PATH);
memdelete(d);
- get_ok()->set_disabled(true);
+ get_ok_button()->set_disabled(true);
return "";
}
@@ -277,7 +277,7 @@ private:
if (!is_folder_empty) {
set_message(TTR("The selected path is not empty. Choosing an empty folder is highly recommended."), MESSAGE_WARNING);
memdelete(d);
- get_ok()->set_disabled(false);
+ get_ok_button()->set_disabled(false);
return valid_path;
}
}
@@ -285,7 +285,7 @@ private:
set_message("");
set_message("", MESSAGE_SUCCESS, INSTALL_PATH);
memdelete(d);
- get_ok()->set_disabled(false);
+ get_ok_button()->set_disabled(false);
return valid_path;
}
@@ -320,14 +320,14 @@ private:
if (p.ends_with("project.godot")) {
p = p.get_base_dir();
install_path_container->hide();
- get_ok()->set_disabled(false);
+ get_ok_button()->set_disabled(false);
} else if (p.ends_with(".zip")) {
install_path->set_text(p.get_base_dir());
install_path_container->show();
- get_ok()->set_disabled(false);
+ get_ok_button()->set_disabled(false);
} else {
set_message(TTR("Please choose a \"project.godot\" or \".zip\" file."), MESSAGE_ERROR);
- get_ok()->set_disabled(true);
+ get_ok_button()->set_disabled(true);
return;
}
}
@@ -338,7 +338,7 @@ private:
if (p.ends_with(".zip")) {
install_path->call_deferred("grab_focus");
} else {
- get_ok()->call_deferred("grab_focus");
+ get_ok_button()->call_deferred("grab_focus");
}
}
@@ -346,14 +346,14 @@ private:
String sp = p_path.simplify_path();
project_path->set_text(sp);
_path_text_changed(sp);
- get_ok()->call_deferred("grab_focus");
+ get_ok_button()->call_deferred("grab_focus");
}
void _install_path_selected(const String &p_path) {
String sp = p_path.simplify_path();
install_path->set_text(sp);
_path_text_changed(sp);
- get_ok()->call_deferred("grab_focus");
+ get_ok_button()->call_deferred("grab_focus");
}
void _browse_path() {
@@ -466,7 +466,7 @@ private:
ConfirmationDialog *cd = memnew(ConfirmationDialog);
cd->set_title(TTR("Warning: This folder is not empty"));
cd->set_text(TTR("You are about to create a Godot project in a non-empty folder.\nThe entire contents of this folder will be imported as project resources!\n\nAre you sure you wish to continue?"));
- cd->get_ok()->connect("pressed", callable_mp(this, &ProjectDialog::_nonempty_confirmation_ok_pressed));
+ cd->get_ok_button()->connect("pressed", callable_mp(this, &ProjectDialog::_nonempty_confirmation_ok_pressed));
get_parent()->add_child(cd);
cd->popup_centered();
cd->grab_focus();
@@ -684,14 +684,14 @@ public:
install_browse->hide();
set_title(TTR("Rename Project"));
- get_ok()->set_text(TTR("Rename"));
+ get_ok_button()->set_text(TTR("Rename"));
name_container->show();
status_rect->hide();
msg->hide();
install_path_container->hide();
install_status_rect->hide();
rasterizer_container->hide();
- get_ok()->set_disabled(false);
+ get_ok_button()->set_disabled(false);
ProjectSettings *current = memnew(ProjectSettings);
@@ -700,7 +700,7 @@ public:
set_message(vformat(TTR("Couldn't load project.godot in project path (error %d). It may be missing or corrupted."), err), MESSAGE_ERROR);
status_rect->show();
msg->show();
- get_ok()->set_disabled(true);
+ get_ok_button()->set_disabled(true);
} else if (current->has_setting("application/config/name")) {
String proj = current->get("application/config/name");
project_name->set_text(proj);
@@ -738,7 +738,7 @@ public:
if (mode == MODE_IMPORT) {
set_title(TTR("Import Existing Project"));
- get_ok()->set_text(TTR("Import & Edit"));
+ get_ok_button()->set_text(TTR("Import & Edit"));
name_container->hide();
install_path_container->hide();
rasterizer_container->hide();
@@ -746,7 +746,7 @@ public:
} else if (mode == MODE_NEW) {
set_title(TTR("Create New Project"));
- get_ok()->set_text(TTR("Create & Edit"));
+ get_ok_button()->set_text(TTR("Create & Edit"));
name_container->show();
install_path_container->hide();
rasterizer_container->show();
@@ -755,7 +755,7 @@ public:
} else if (mode == MODE_INSTALL) {
set_title(TTR("Install Project:") + " " + zip_title);
- get_ok()->set_text(TTR("Install & Edit"));
+ get_ok_button()->set_text(TTR("Install & Edit"));
project_name->set_text(zip_title);
name_container->show();
install_path_container->hide();
@@ -2321,8 +2321,8 @@ void ProjectManager::_files_dropped(PackedStringArray p_files, int p_screen) {
memdelete(dir);
}
if (confirm) {
- multi_scan_ask->get_ok()->disconnect("pressed", callable_mp(this, &ProjectManager::_scan_multiple_folders));
- multi_scan_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_scan_multiple_folders), varray(folders));
+ multi_scan_ask->get_ok_button()->disconnect("pressed", callable_mp(this, &ProjectManager::_scan_multiple_folders));
+ multi_scan_ask->get_ok_button()->connect("pressed", callable_mp(this, &ProjectManager::_scan_multiple_folders), varray(folders));
multi_scan_ask->set_text(
vformat(TTR("Are you sure to scan %s folders for existing Godot projects?\nThis could take a while."), folders.size()));
multi_scan_ask->popup_centered();
@@ -2629,9 +2629,9 @@ ProjectManager::ProjectManager() {
{
// Dialogs
language_restart_ask = memnew(ConfirmationDialog);
- language_restart_ask->get_ok()->set_text(TTR("Restart Now"));
- language_restart_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_restart_confirm));
- language_restart_ask->get_cancel()->set_text(TTR("Continue"));
+ language_restart_ask->get_ok_button()->set_text(TTR("Restart Now"));
+ language_restart_ask->get_ok_button()->connect("pressed", callable_mp(this, &ProjectManager::_restart_confirm));
+ language_restart_ask->get_cancel_button()->set_text(TTR("Continue"));
add_child(language_restart_ask);
scan_dir = memnew(FileDialog);
@@ -2643,31 +2643,31 @@ ProjectManager::ProjectManager() {
scan_dir->connect("dir_selected", callable_mp(this, &ProjectManager::_scan_begin));
erase_missing_ask = memnew(ConfirmationDialog);
- erase_missing_ask->get_ok()->set_text(TTR("Remove All"));
- erase_missing_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_erase_missing_projects_confirm));
+ erase_missing_ask->get_ok_button()->set_text(TTR("Remove All"));
+ erase_missing_ask->get_ok_button()->connect("pressed", callable_mp(this, &ProjectManager::_erase_missing_projects_confirm));
add_child(erase_missing_ask);
erase_ask = memnew(ConfirmationDialog);
- erase_ask->get_ok()->set_text(TTR("Remove"));
- erase_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_erase_project_confirm));
+ erase_ask->get_ok_button()->set_text(TTR("Remove"));
+ erase_ask->get_ok_button()->connect("pressed", callable_mp(this, &ProjectManager::_erase_project_confirm));
add_child(erase_ask);
multi_open_ask = memnew(ConfirmationDialog);
- multi_open_ask->get_ok()->set_text(TTR("Edit"));
- multi_open_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_open_selected_projects));
+ multi_open_ask->get_ok_button()->set_text(TTR("Edit"));
+ multi_open_ask->get_ok_button()->connect("pressed", callable_mp(this, &ProjectManager::_open_selected_projects));
add_child(multi_open_ask);
multi_run_ask = memnew(ConfirmationDialog);
- multi_run_ask->get_ok()->set_text(TTR("Run"));
- multi_run_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_run_project_confirm));
+ multi_run_ask->get_ok_button()->set_text(TTR("Run"));
+ multi_run_ask->get_ok_button()->connect("pressed", callable_mp(this, &ProjectManager::_run_project_confirm));
add_child(multi_run_ask);
multi_scan_ask = memnew(ConfirmationDialog);
- multi_scan_ask->get_ok()->set_text(TTR("Scan"));
+ multi_scan_ask->get_ok_button()->set_text(TTR("Scan"));
add_child(multi_scan_ask);
ask_update_settings = memnew(ConfirmationDialog);
- ask_update_settings->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_confirm_update_settings));
+ ask_update_settings->get_ok_button()->connect("pressed", callable_mp(this, &ProjectManager::_confirm_update_settings));
add_child(ask_update_settings);
npdialog = memnew(ProjectDialog);
@@ -2684,7 +2684,7 @@ ProjectManager::ProjectManager() {
open_templates = memnew(ConfirmationDialog);
open_templates->set_text(TTR("You currently don't have any projects.\nWould you like to explore official example projects in the Asset Library?"));
- open_templates->get_ok()->set_text(TTR("Open Asset Library"));
+ open_templates->get_ok_button()->set_text(TTR("Open Asset Library"));
open_templates->connect("confirmed", callable_mp(this, &ProjectManager::_open_asset_library));
add_child(open_templates);
}
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index 55d80021c8..9995c6ad65 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -478,6 +478,6 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
del_confirmation->connect("confirmed", callable_mp(this, &ProjectSettingsEditor::_delete_setting), varray(true));
add_child(del_confirmation);
- get_ok()->set_text(TTR("Close"));
+ get_ok_button()->set_text(TTR("Close"));
set_hide_on_ok(true);
}
diff --git a/editor/property_selector.cpp b/editor/property_selector.cpp
index 1ff73f25c5..220031d2dc 100644
--- a/editor/property_selector.cpp
+++ b/editor/property_selector.cpp
@@ -321,7 +321,7 @@ void PropertySelector::_update_search() {
}
}
- get_ok()->set_disabled(root->get_children() == nullptr);
+ get_ok_button()->set_disabled(root->get_children() == nullptr);
}
void PropertySelector::_confirmed() {
@@ -553,8 +553,8 @@ PropertySelector::PropertySelector() {
search_box->connect("gui_input", callable_mp(this, &PropertySelector::_sbox_input));
search_options = memnew(Tree);
vbc->add_margin_child(TTR("Matches:"), search_options, true);
- get_ok()->set_text(TTR("Open"));
- get_ok()->set_disabled(true);
+ get_ok_button()->set_text(TTR("Open"));
+ get_ok_button()->set_disabled(true);
register_text_enter(search_box);
set_hide_on_ok(false);
search_options->connect("item_activated", callable_mp(this, &PropertySelector::_confirmed));
diff --git a/editor/pvrtc_compress.cpp b/editor/pvrtc_compress.cpp
deleted file mode 100644
index 23bcf9540e..0000000000
--- a/editor/pvrtc_compress.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-/*************************************************************************/
-/* pvrtc_compress.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "pvrtc_compress.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 "editor_settings.h"
-#include "scene/resources/texture.h"
-
-static void (*_base_image_compress_pvrtc2_func)(Image *) = nullptr;
-static void (*_base_image_compress_pvrtc4_func)(Image *) = nullptr;
-
-static void _compress_image(Image::CompressMode p_mode, Image *p_image) {
- String ttpath = EditorSettings::get_singleton()->get("filesystem/import/pvrtc_texture_tool");
-
- if (ttpath.strip_edges() == "" || !FileAccess::exists(ttpath)) {
- switch (p_mode) {
- case Image::COMPRESS_PVRTC2:
- if (_base_image_compress_pvrtc2_func) {
- _base_image_compress_pvrtc2_func(p_image);
- } else if (_base_image_compress_pvrtc4_func) {
- _base_image_compress_pvrtc4_func(p_image);
- }
- break;
- case Image::COMPRESS_PVRTC4:
- if (_base_image_compress_pvrtc4_func) {
- _base_image_compress_pvrtc4_func(p_image);
- }
- break;
- default:
- ERR_FAIL_MSG("Unsupported Image compress mode used in PVRTC module.");
- }
- return;
- }
-
- String tmppath = EditorSettings::get_singleton()->get_cache_dir();
- String src_img = tmppath.plus_file("_tmp_src_img.png");
- String dst_img = tmppath.plus_file("_tmp_dst_img.pvr");
-
- List<String> args;
- args.push_back("-i");
- args.push_back(src_img);
- args.push_back("-o");
- args.push_back(dst_img);
- args.push_back("-f");
-
- switch (p_mode) {
- case Image::COMPRESS_PVRTC2:
- args.push_back("PVRTC2");
- break;
- case Image::COMPRESS_PVRTC4:
- args.push_back("PVRTC4");
- break;
- case Image::COMPRESS_ETC:
- args.push_back("ETC");
- break;
- default:
- ERR_FAIL_MSG("Unsupported Image compress mode used in PVRTC module.");
- }
-
- if (EditorSettings::get_singleton()->get("filesystem/import/pvrtc_fast_conversion").operator bool()) {
- args.push_back("-pvrtcfast");
- }
- if (p_image->has_mipmaps()) {
- args.push_back("-m");
- }
-
- // Save source PNG.
- Ref<ImageTexture> t = memnew(ImageTexture);
- t->create_from_image(Ref<Image>(p_image));
- ResourceSaver::save(src_img, t);
-
- Error err = OS::get_singleton()->execute(ttpath, args, true);
- if (err != OK) {
- // Clean up generated files.
- DirAccess::remove_file_or_error(src_img);
- DirAccess::remove_file_or_error(dst_img);
- ERR_FAIL_MSG("Could not execute PVRTC tool: " + ttpath);
- }
-
- t = ResourceLoader::load(dst_img, "Texture2D");
- if (t.is_null()) {
- // Clean up generated files.
- DirAccess::remove_file_or_error(src_img);
- DirAccess::remove_file_or_error(dst_img);
- ERR_FAIL_MSG("Can't load back converted image using PVRTC tool.");
- }
-
- p_image->copy_internals_from(t->get_data());
-
- // Clean up generated files.
- DirAccess::remove_file_or_error(src_img);
- DirAccess::remove_file_or_error(dst_img);
-}
-
-static void _compress_pvrtc2(Image *p_image) {
- _compress_image(Image::COMPRESS_PVRTC2, p_image);
-}
-
-static void _compress_pvrtc4(Image *p_image) {
- _compress_image(Image::COMPRESS_PVRTC4, p_image);
-}
-
-void _pvrtc_register_compressors() {
- _base_image_compress_pvrtc2_func = Image::_image_compress_pvrtc2_func;
- _base_image_compress_pvrtc4_func = Image::_image_compress_pvrtc4_func;
-
- Image::_image_compress_pvrtc2_func = _compress_pvrtc2;
- Image::_image_compress_pvrtc4_func = _compress_pvrtc4;
-}
diff --git a/editor/quick_open.cpp b/editor/quick_open.cpp
index e1308b4895..7ffe5bc9a7 100644
--- a/editor/quick_open.cpp
+++ b/editor/quick_open.cpp
@@ -107,11 +107,11 @@ void EditorQuickOpen::_update_search() {
to_select->set_as_cursor(0);
search_options->scroll_to_item(to_select);
- get_ok()->set_disabled(false);
+ get_ok_button()->set_disabled(false);
} else {
search_options->deselect_all();
- get_ok()->set_disabled(true);
+ get_ok_button()->set_disabled(true);
}
}
@@ -256,6 +256,6 @@ EditorQuickOpen::EditorQuickOpen() {
search_options->add_theme_constant_override("draw_guides", 1);
vbc->add_margin_child(TTR("Matches:"), search_options, true);
- get_ok()->set_text(TTR("Open"));
+ get_ok_button()->set_text(TTR("Open"));
set_hide_on_ok(false);
}
diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp
index 318324e56d..a60937a86b 100644
--- a/editor/rename_dialog.cpp
+++ b/editor/rename_dialog.cpp
@@ -286,7 +286,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
// ---- Dialog related
set_min_size(Size2(383, 0));
- get_ok()->set_text(TTR("Rename"));
+ get_ok_button()->set_text(TTR("Rename"));
Button *but_reset = add_button(TTR("Reset"));
eh.errfunc = _error_handler;
diff --git a/editor/reparent_dialog.cpp b/editor/reparent_dialog.cpp
index 0ff27af7c1..c7f1a1b45d 100644
--- a/editor/reparent_dialog.cpp
+++ b/editor/reparent_dialog.cpp
@@ -87,7 +87,7 @@ ReparentDialog::ReparentDialog() {
//cancel->connect("pressed", this,"_cancel");
- get_ok()->set_text(TTR("Reparent"));
+ get_ok_button()->set_text(TTR("Reparent"));
}
ReparentDialog::~ReparentDialog() {
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 91dffb504f..72703623ab 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -2982,7 +2982,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
clear_inherit_confirm = memnew(ConfirmationDialog);
clear_inherit_confirm->set_text(TTR("Clear Inheritance? (No Undo!)"));
- clear_inherit_confirm->get_ok()->set_text(TTR("Clear"));
+ clear_inherit_confirm->get_ok_button()->set_text(TTR("Clear"));
add_child(clear_inherit_confirm);
set_process_input(true);
diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp
index b5f11fc6f9..9c3e381dc8 100644
--- a/editor/script_create_dialog.cpp
+++ b/editor/script_create_dialog.cpp
@@ -522,7 +522,7 @@ void ScriptCreateDialog::_browse_path(bool browse_parent, bool p_save) {
if (p_save) {
file_browse->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
file_browse->set_title(TTR("Open Script / Choose Location"));
- file_browse->get_ok()->set_text(TTR("Open"));
+ file_browse->get_ok_button()->set_text(TTR("Open"));
} else {
file_browse->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
file_browse->set_title(TTR("Open Script"));
@@ -686,7 +686,7 @@ void ScriptCreateDialog::_update_dialog() {
builtin_warning_label->set_visible(is_built_in);
if (is_built_in) {
- get_ok()->set_text(TTR("Create"));
+ get_ok_button()->set_text(TTR("Create"));
parent_name->set_editable(true);
parent_search_button->set_disabled(false);
parent_browse_button->set_disabled(!can_inherit_from_file);
@@ -694,7 +694,7 @@ void ScriptCreateDialog::_update_dialog() {
} else if (is_new_script_created) {
// New script created.
- get_ok()->set_text(TTR("Create"));
+ get_ok_button()->set_text(TTR("Create"));
parent_name->set_editable(true);
parent_search_button->set_disabled(false);
parent_browse_button->set_disabled(!can_inherit_from_file);
@@ -704,7 +704,7 @@ void ScriptCreateDialog::_update_dialog() {
} else if (load_enabled) {
// Script loaded.
- get_ok()->set_text(TTR("Load"));
+ get_ok_button()->set_text(TTR("Load"));
parent_name->set_editable(false);
parent_search_button->set_disabled(true);
parent_browse_button->set_disabled(true);
@@ -712,7 +712,7 @@ void ScriptCreateDialog::_update_dialog() {
_msg_path_valid(true, TTR("Will load an existing script file."));
}
} else {
- get_ok()->set_text(TTR("Create"));
+ get_ok_button()->set_text(TTR("Create"));
parent_name->set_editable(true);
parent_search_button->set_disabled(false);
parent_browse_button->set_disabled(!can_inherit_from_file);
@@ -721,7 +721,7 @@ void ScriptCreateDialog::_update_dialog() {
script_ok = false;
}
- get_ok()->set_disabled(!script_ok);
+ get_ok_button()->set_disabled(!script_ok);
Callable entered_call = callable_mp(this, &ScriptCreateDialog::_path_entered);
if (script_ok) {
@@ -878,7 +878,7 @@ ScriptCreateDialog::ScriptCreateDialog() {
file_browse->connect("file_selected", callable_mp(this, &ScriptCreateDialog::_file_selected));
file_browse->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
add_child(file_browse);
- get_ok()->set_text(TTR("Create"));
+ get_ok_button()->set_text(TTR("Create"));
alert = memnew(AcceptDialog);
alert->get_label()->set_autowrap(true);
alert->get_label()->set_align(Label::ALIGN_CENTER);
diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp
index 864e5976b2..a29b6aded7 100644
--- a/editor/settings_config_dialog.cpp
+++ b/editor/settings_config_dialog.cpp
@@ -275,8 +275,8 @@ void EditorSettingsDialog::_shortcut_button_pressed(Object *p_item, int p_column
last_wait_for_key = Ref<InputEventKey>();
press_a_key->popup_centered(Size2(250, 80) * EDSCALE);
//press_a_key->grab_focus();
- press_a_key->get_ok()->set_focus_mode(Control::FOCUS_NONE);
- press_a_key->get_cancel()->set_focus_mode(Control::FOCUS_NONE);
+ press_a_key->get_ok_button()->set_focus_mode(Control::FOCUS_NONE);
+ press_a_key->get_cancel_button()->set_focus_mode(Control::FOCUS_NONE);
shortcut_configured = item;
} else if (p_idx == 1) { //erase
@@ -488,7 +488,7 @@ EditorSettingsDialog::EditorSettingsDialog() {
timer->set_one_shot(true);
add_child(timer);
EditorSettings::get_singleton()->connect("settings_changed", callable_mp(this, &EditorSettingsDialog::_settings_changed));
- get_ok()->set_text(TTR("Close"));
+ get_ok_button()->set_text(TTR("Close"));
updating = false;
}
diff --git a/editor/translations/af.po b/editor/translations/af.po
index 3a699cee71..a42302460b 100644
--- a/editor/translations/af.po
+++ b/editor/translations/af.po
@@ -5,12 +5,13 @@
# Ray West <the.raxar@gmail.com>, 2017.
# Julius Stopforth <jjstopforth@gmail.com>, 2018.
# Isa Tippens <isatippens2@gmail.com>, 2019.
+# Henry Geyser <thegoat187@gmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2019-03-28 09:36+0000\n"
-"Last-Translator: Isa Tippens <isatippens2@gmail.com>\n"
+"PO-Revision-Date: 2020-12-01 20:29+0000\n"
+"Last-Translator: Henry Geyser <thegoat187@gmail.com>\n"
"Language-Team: Afrikaans <https://hosted.weblate.org/projects/godot-engine/"
"godot/af/>\n"
"Language: af\n"
@@ -18,7 +19,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 3.6-dev\n"
+"X-Generator: Weblate 4.4-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -27,7 +28,7 @@ msgstr "Ongeldige tiepe argument om te omskep(), gebruik TYPE_* konstante"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
-msgstr ""
+msgstr "Verwag 'n string van lengte 1 ('n karakter)."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/mono/glue/gd_glue.cpp
@@ -50,72 +51,71 @@ msgstr "Ongeldige operande vir operateur %s, %s en %s."
#: core/math/expression.cpp
msgid "Invalid index of type %s for base type %s"
-msgstr ""
+msgstr "Ongeldige indeks van tipe %s vir basiese tipe %s"
#: core/math/expression.cpp
msgid "Invalid named index '%s' for base type %s"
-msgstr ""
+msgstr "Ongeldige benaming van indeks '%s' vir basiese tipe %s"
#: core/math/expression.cpp
msgid "Invalid arguments to construct '%s'"
-msgstr ""
+msgstr "Ongeldige argument om '%s' te genereer"
#: core/math/expression.cpp
msgid "On call to '%s':"
-msgstr ""
+msgstr "Aan roep tot '%s':"
#: core/ustring.cpp
msgid "B"
-msgstr ""
+msgstr "B"
#: core/ustring.cpp
msgid "KiB"
-msgstr ""
+msgstr "KiB"
#: core/ustring.cpp
msgid "MiB"
-msgstr ""
+msgstr "MiB"
#: core/ustring.cpp
msgid "GiB"
-msgstr ""
+msgstr "GiB"
#: core/ustring.cpp
msgid "TiB"
-msgstr ""
+msgstr "TiB"
#: core/ustring.cpp
msgid "PiB"
-msgstr ""
+msgstr "PiB"
#: core/ustring.cpp
msgid "EiB"
-msgstr ""
+msgstr "EiB"
#: editor/animation_bezier_editor.cpp
msgid "Free"
-msgstr "Bevry"
+msgstr "Bevry / Verniet"
#: editor/animation_bezier_editor.cpp
msgid "Balanced"
-msgstr ""
+msgstr "Gebalanseer"
#: editor/animation_bezier_editor.cpp
msgid "Mirror"
-msgstr ""
+msgstr "Spieel"
#: editor/animation_bezier_editor.cpp editor/editor_profiler.cpp
msgid "Time:"
-msgstr ""
+msgstr "Tyd:"
#: editor/animation_bezier_editor.cpp
msgid "Value:"
-msgstr ""
+msgstr "Waarde:"
#: editor/animation_bezier_editor.cpp
-#, fuzzy
msgid "Insert Key Here"
-msgstr "Anim Voeg Sleutel by"
+msgstr "Voeg Sleutel Hier"
#: editor/animation_bezier_editor.cpp
#, fuzzy
@@ -123,18 +123,16 @@ msgid "Duplicate Selected Key(s)"
msgstr "Dupliseer Seleksie"
#: editor/animation_bezier_editor.cpp
-#, fuzzy
msgid "Delete Selected Key(s)"
-msgstr "Skrap gekose lêers?"
+msgstr "Skrap gekose sleutels"
#: editor/animation_bezier_editor.cpp
msgid "Add Bezier Point"
-msgstr ""
+msgstr "Voeg Bezier Punt By"
#: editor/animation_bezier_editor.cpp
-#, fuzzy
msgid "Move Bezier Points"
-msgstr "Skuif Gunsteling Op"
+msgstr "Verskuif Bezier Punte"
#: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp
msgid "Anim Duplicate Keys"
@@ -145,9 +143,8 @@ msgid "Anim Delete Keys"
msgstr "Anim Skrap Sleutels"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Change Keyframe Time"
-msgstr "Anim Verander Waarde"
+msgstr "Anim Verander Sleutelraam Tyd"
#: editor/animation_track_editor.cpp
msgid "Anim Change Transition"
@@ -155,51 +152,44 @@ msgstr "Anim Verander Oorgang"
#: editor/animation_track_editor.cpp
msgid "Anim Change Transform"
-msgstr "Anim Verander Transform"
+msgstr "Anim Verander Transformasie"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Change Keyframe Value"
-msgstr "Anim Verander Waarde"
+msgstr "Anim Verander Sleutelraam Waarde"
#: editor/animation_track_editor.cpp
msgid "Anim Change Call"
msgstr "Anim Verander Roep"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Multi Change Keyframe Time"
-msgstr "Anim Verander Waarde"
+msgstr "Anim Herhaalde Verandering Van Sleutelraam Tye"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Multi Change Transition"
-msgstr "Anim Verander Oorgang"
+msgstr "Anim Herhaalde Veranderinde Transisie"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Multi Change Transform"
-msgstr "Anim Verander Transform"
+msgstr "Anim Herhaalde Verandering van Transformasie"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Multi Change Keyframe Value"
-msgstr "Anim Verander Waarde"
+msgstr "Anim Herhaalde Verandering Van Sleutelraam Waarde"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Multi Change Call"
-msgstr "Anim Verander Roep"
+msgstr "Anim Herhaalde Verandering van Roep"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Change Animation Length"
-msgstr "Verander Anim Lente"
+msgstr "Verander Animasie Lente"
#: editor/animation_track_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Change Animation Loop"
-msgstr ""
+msgstr "Verander Animasie Omloop"
#: editor/animation_track_editor.cpp
msgid "Property Track"
@@ -1136,7 +1126,7 @@ msgstr "Verweerde Hulpbron Verkenner"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3716,6 +3706,16 @@ 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 ""
@@ -3770,26 +3770,12 @@ msgstr ""
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr ""
-
-#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Duplicate..."
-msgstr "Dupliseer"
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
#, fuzzy
-msgid "Move to Trash"
-msgstr "Skuif AutoLaai"
-
-#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "New Scene..."
msgstr "Stoor Hulpbron As..."
@@ -3814,10 +3800,17 @@ msgid "Collapse All"
msgstr "Vervang Alles"
#: 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"
+#, fuzzy
+msgid "Duplicate..."
+msgstr "Dupliseer"
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "Skuif AutoLaai"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
msgstr ""
#: editor/filesystem_dock.cpp
@@ -3855,7 +3848,10 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
+#: 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
@@ -9870,6 +9866,10 @@ 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"
@@ -12366,6 +12366,26 @@ msgid ""
"\"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\" "
@@ -12626,6 +12646,26 @@ msgid ""
"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-"
diff --git a/editor/translations/ar.po b/editor/translations/ar.po
index ff705883d5..2bd95e230b 100644
--- a/editor/translations/ar.po
+++ b/editor/translations/ar.po
@@ -50,8 +50,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-11-25 14:09+0000\n"
-"Last-Translator: Omar Aglan <omar.aglan91@yahoo.com>\n"
+"PO-Revision-Date: 2020-12-07 08:11+0000\n"
+"Last-Translator: Musab Alasaifer <mousablasefer@gmail.com>\n"
"Language-Team: Arabic <https://hosted.weblate.org/projects/godot-engine/"
"godot/ar/>\n"
"Language: ar\n"
@@ -1071,15 +1071,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:"
@@ -1123,7 +1123,7 @@ msgstr "متصÙØ­ الموارد أورÙان"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -1632,22 +1632,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. قم بتمكين 'Import 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. قم بتمكين "
+"'Import Etc 2' او 'Import Pvrtc' ÙÙŠ إعدادات المشروع."
#: editor/editor_export.cpp
#, fuzzy
@@ -3721,6 +3719,16 @@ 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 "إعادة تسمية ملÙ:"
@@ -3768,24 +3776,11 @@ msgstr "تعديل التبعيات..."
msgid "View Owners..."
msgstr "أظهر المÙلاك..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "إعادة تسمية..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "تكرير..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "تحريك إلي..."
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Move to Trash"
-msgstr "نقل التحميل التلقائي"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "مشهد جديد..."
@@ -3808,11 +3803,17 @@ msgid "Collapse All"
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 "إعادة التسمية"
+msgid "Duplicate..."
+msgstr "تكرير..."
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+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"
@@ -3847,8 +3848,11 @@ msgid "Move"
msgstr "تحريك"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "يوجد بالÙعل مل٠أو مجلد بنÙس الاسم ÙÙŠ هذا المكان."
+#: 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"
@@ -9827,6 +9831,10 @@ msgid "OpenGL ES 3.0"
msgstr "OpenGL ES 3.0"
#: 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"
@@ -12393,6 +12401,26 @@ msgstr ""
"(CPUParticles2D) استخدام لوحة-مادة-العنصر (CanvasItemMaterial) مع تÙعيل"
"\"الرسوم المتحركة للجزيئات\"."
+#: 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\" "
@@ -12730,6 +12758,26 @@ msgstr ""
"بواسطة محرك الÙيزياء عند التشغيل.\n"
"قم بتغيير الحجم ÙÙŠ أشكال تصادم الأتباع (Children) بدلاً من ذلك."
+#: 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-"
@@ -12970,6 +13018,9 @@ msgstr "يمكن تعيين المتغيرات Ùقط ÙÙŠ الذروة ."
msgid "Constants cannot be modified."
msgstr "لا يمكن تعديل الثوابت."
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "يوجد بالÙعل مل٠أو مجلد بنÙس الاسم ÙÙŠ هذا المكان."
+
#~ msgid "Error trying to save layout!"
#~ msgstr "خطآ ÙÙŠ محاولة Ø­Ùظ النسق!"
diff --git a/editor/translations/bg.po b/editor/translations/bg.po
index bbf679961c..2f1a9145e4 100644
--- a/editor/translations/bg.po
+++ b/editor/translations/bg.po
@@ -12,11 +12,12 @@
# Stoyan <stoyan.stoyanov99@protonmail.com>, 2020.
# zooid <the.zooid@gmail.com>, 2020.
# Любомир ВаÑилев <lyubomirv@gmx.com>, 2020.
+# Ziv D <wizdavid@gmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-11-08 10:26+0000\n"
+"PO-Revision-Date: 2020-12-07 08:11+0000\n"
"Last-Translator: Любомир ВаÑилев <lyubomirv@gmx.com>\n"
"Language-Team: Bulgarian <https://hosted.weblate.org/projects/godot-engine/"
"godot/bg/>\n"
@@ -25,7 +26,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.3.2\n"
+"X-Generator: Weblate 4.4-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -889,9 +890,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?"
@@ -1015,12 +1015,12 @@ 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 ""
-"Да Ñе премахнат ли избраните файлове от проекта? (ДейÑтвието е необратимо)"
+"Да Ñе премахнат ли избраните файлове от проекта? (ДейÑтвието е необратимо)\n"
+"Ще можете да ги откриете в кошчето, ако иÑкате да ги възÑтановите."
#: editor/dependency_editor.cpp
msgid ""
@@ -1072,7 +1072,7 @@ msgstr ""
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -1629,9 +1629,8 @@ msgid "Node Dock"
msgstr "Панел за възлите"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "FileSystem Dock"
-msgstr "Показване във файловата ÑиÑтема"
+msgstr "Панел за файловата ÑиÑтема"
#: editor/editor_feature_profile.cpp
msgid "Import Dock"
@@ -1938,7 +1937,7 @@ msgstr "ÐаÑледÑва:"
#: editor/editor_help.cpp
msgid "Inherited by:"
-msgstr ""
+msgstr "ÐаÑледÑва Ñе от:"
#: editor/editor_help.cpp
msgid "Description"
@@ -2396,9 +2395,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 ""
@@ -2864,9 +2862,8 @@ msgid "Q&A"
msgstr ""
#: editor/editor_node.cpp
-#, fuzzy
msgid "Report a Bug"
-msgstr "Повторно внаÑÑне"
+msgstr "Докладване на проблем"
#: editor/editor_node.cpp
msgid "Send Docs Feedback"
@@ -3552,6 +3549,16 @@ 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 "Преименуване на файла:"
@@ -3568,9 +3575,8 @@ msgid "Duplicating folder:"
msgstr ""
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "New Inherited Scene"
-msgstr "Ðов Ñкрипт"
+msgstr "Ðова Ñцена – наÑледник"
#: editor/filesystem_dock.cpp
msgid "Set As Main Scene"
@@ -3600,24 +3606,11 @@ msgstr ""
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr ""
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr ""
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Move to Trash"
-msgstr "ПремеÑтване на кадъра"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "Ðова Ñцена..."
@@ -3640,10 +3633,15 @@ msgid "Collapse All"
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"
+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
@@ -3677,7 +3675,10 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
+#: 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
@@ -4460,7 +4461,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Directions"
-msgstr "УказаниÑ"
+msgstr "ÐаправлениÑ"
#: editor/plugins/animation_player_editor_plugin.cpp
#, fuzzy
@@ -5259,9 +5260,8 @@ msgid "Create Custom Bone(s) from Node(s)"
msgstr "Възпроизвеждане на Ñцена по избор"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Clear Bones"
-msgstr "Възпроизвеждане на Ñцена по избор"
+msgstr "ИзчиÑтване на коÑтите"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Make IK Chain"
@@ -5280,9 +5280,8 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/texture_region_editor_plugin.cpp
#: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp
-#, fuzzy
msgid "Zoom Reset"
-msgstr "Оригинално увеличение"
+msgstr "Връщане на Ð¾Ñ€Ð¸Ð³Ð¸Ð½Ð°Ð»Ð½Ð¸Ñ Ð¼Ð°Ñ‰Ð°Ð±"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5317,9 +5316,8 @@ msgstr "Режим на завъртане"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Scale Mode"
-msgstr "Режим на Селектиране"
+msgstr "Режим на Ñкалиране"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -6330,9 +6328,8 @@ msgid "Transform UV Map"
msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Transform Polygon"
-msgstr "Създаване на папка"
+msgstr "Преобразуване на полигона"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Paint Bone Weights"
@@ -6367,22 +6364,20 @@ msgid "Move Points"
msgstr "ПремеÑтване на точките"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Command: Rotate"
-msgstr "Влачене: завъртане"
+msgstr "Command: завъртане"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Shift: Move All"
msgstr "Shift: премеÑтване на вÑичко"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Shift+Command: Scale"
-msgstr "Shift+Ctrl: мащабиране"
+msgstr "Shift+Command: мащабиране"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Ctrl: Rotate"
-msgstr "Ctrl: Завъртане"
+msgstr "Ctrl: завъртане"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Shift+Ctrl: Scale"
@@ -6423,14 +6418,12 @@ msgid "Radius:"
msgstr "РадиуÑ:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Copy Polygon to UV"
-msgstr "Полигон -> UV"
+msgstr "Копиране на полигона в UV"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Copy UV to Polygon"
-msgstr "Превръщане в Polygon2D"
+msgstr "Копиране на UV в полигона"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Clear UV"
@@ -6694,9 +6687,8 @@ msgid "Copy Script Path"
msgstr ""
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "History Previous"
-msgstr "ИÑÑ‚Ð¾Ñ€Ð¸Ñ Ðазад"
+msgstr "Ðазад в иÑториÑта"
#: editor/plugins/script_editor_plugin.cpp
msgid "History Next"
@@ -7018,9 +7010,8 @@ msgid "This skeleton has no bones, create some children Bone2D nodes."
msgstr ""
#: editor/plugins/skeleton_2d_editor_plugin.cpp
-#, fuzzy
msgid "Create Rest Pose from Bones"
-msgstr "Възпроизвеждане на Ñцена по избор"
+msgstr "Създаване на поза на Ð¿Ð¾ÐºÐ¾Ñ Ð¾Ñ‚ коÑтите"
#: editor/plugins/skeleton_2d_editor_plugin.cpp
msgid "Set Rest Pose to Bones"
@@ -7231,9 +7222,8 @@ msgid "View Information"
msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "View FPS"
-msgstr "Преглед на файловете"
+msgstr "Показване на кадри/Ñек"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Half Resolution"
@@ -7244,9 +7234,8 @@ msgid "Audio Listener"
msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Enable Doppler"
-msgstr "Позволи филтриране"
+msgstr "Включване на Ð´Ð¾Ð¿Ð»ÐµÑ€Ð¾Ð²Ð¸Ñ ÐµÑ„ÐµÐºÑ‚"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Cinematic Preview"
@@ -7502,14 +7491,12 @@ msgid "Create Mesh2D"
msgstr "Създаване на Mesh2D"
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "Mesh2D Preview"
-msgstr "Преглед"
+msgstr "Преглед на Mesh2D"
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "Create Polygon2D"
-msgstr "Създаване на папка"
+msgstr "Създаване на Polygon2D"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Polygon2D Preview"
@@ -7560,9 +7547,8 @@ msgid "Invalid geometry, can't create collision polygon."
msgstr ""
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "Create CollisionPolygon2D Sibling"
-msgstr "Създаване на папка"
+msgstr "Създаване на ÑÑŠÑеден CollisionPolygon2D"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Invalid geometry, can't create light occluder."
@@ -7649,9 +7635,8 @@ msgid "New Animation"
msgstr "Ðова анимациÑ"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Speed:"
-msgstr "СкороÑÑ‚ (кадри в Ñекунда):"
+msgstr "СкороÑÑ‚:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Loop"
@@ -7789,20 +7774,19 @@ msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
msgid "Create Empty Template"
-msgstr ""
+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"
-msgstr ""
+msgstr "Създаване от текущата тема на редактора"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Toggle Button"
-msgstr "Средно копче"
+msgstr "Бутон-превключвател"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Disabled Button"
@@ -7906,9 +7890,8 @@ msgid "Color"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Theme File"
-msgstr "Тема"
+msgstr "Файл Ñ Ñ‚ÐµÐ¼Ð°"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Erase Selection"
@@ -7920,18 +7903,16 @@ msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "Cut Selection"
-msgstr "Центрирай върху СелекциÑта"
+msgstr "ИзрÑзване на избраното"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Paint TileMap"
msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Line Draw"
-msgstr "Линейно"
+msgstr "Изчертаване на линиÑ"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Rectangle Paint"
@@ -7958,14 +7939,12 @@ msgid "Disable Autotile"
msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Enable Priority"
-msgstr "Промени Филтрите"
+msgstr "Включване на приоритета"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Filter tiles"
-msgstr "ПоÑтавÑне на възелите"
+msgstr "Филтриране на плочките"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Give a TileSet resource to this TileMap to use its tiles."
@@ -7992,14 +7971,12 @@ msgid "Pick Tile"
msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Rotate Left"
-msgstr "Режим на Завъртане"
+msgstr "Завъртане налÑво"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Rotate Right"
-msgstr "Завъртане на Полигон"
+msgstr "Завъртане надÑÑно"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Flip Horizontally"
@@ -8010,9 +7987,8 @@ msgid "Flip Vertically"
msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Clear Transform"
-msgstr "ИзнаÑÑне към платформа"
+msgstr "ИзчиÑтване на транÑформациÑта"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Add Texture(s) to TileSet."
@@ -8045,27 +8021,24 @@ msgid "New Atlas"
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Next Coordinate"
-msgstr "Следващ Ñкрипт"
+msgstr "Следваща координата"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Select the next shape, subtile, or Tile."
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Previous Coordinate"
-msgstr "Предишен подпрозорец"
+msgstr "Предходна координата"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Select the previous shape, subtile, or Tile."
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Region"
-msgstr "Режим на Завъртане"
+msgstr "Регион"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Collision"
@@ -8077,28 +8050,24 @@ msgid "Occlusion"
msgstr "ПриÑтавки"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Navigation"
-msgstr "Ðнимационен Възел"
+msgstr "ÐавигациÑ"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Bitmask"
-msgstr "Режим на Завъртане"
+msgstr "Побитова маÑка"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Priority"
msgstr "Приоритет"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Z Index"
-msgstr "Панорамен режим на ОтмеÑтване (на Ñ€Ð°Ð±Ð¾Ñ‚Ð½Ð¸Ñ Ð¿Ñ€Ð¾Ð·Ð¾Ñ€ÐµÑ†)"
+msgstr "Ð˜Ð½Ð´ÐµÐºÑ Ð¿Ð¾ Z"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Region Mode"
-msgstr "Режим на Завъртане"
+msgstr "Режим на регион"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Collision Mode"
@@ -8110,28 +8079,24 @@ msgid "Occlusion Mode"
msgstr "ПриÑтавки"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Navigation Mode"
-msgstr "Ðнимационен Възел"
+msgstr "Режим на навигациÑ"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Bitmask Mode"
-msgstr "Режим на Завъртане"
+msgstr "Режим на побитова маÑка"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Priority Mode"
msgstr "Режим на приоритет"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Icon Mode"
-msgstr "Панорамен режим на ОтмеÑтване (на Ñ€Ð°Ð±Ð¾Ñ‚Ð½Ð¸Ñ Ð¿Ñ€Ð¾Ð·Ð¾Ñ€ÐµÑ†)"
+msgstr "Режим на иконки"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Z Index Mode"
-msgstr "Панорамен режим на ОтмеÑтване (на Ñ€Ð°Ð±Ð¾Ñ‚Ð½Ð¸Ñ Ð¿Ñ€Ð¾Ð·Ð¾Ñ€ÐµÑ†)"
+msgstr "Режим на Ð¸Ð½Ð´ÐµÐºÑ Ð¿Ð¾ Z"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Copy bitmask."
@@ -8142,34 +8107,28 @@ msgid "Paste bitmask."
msgstr "ПоÑтавÑне на битова маÑка."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Erase bitmask."
-msgstr "Изтрий точки."
+msgstr "Изтриване на побитовата маÑка."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Create a new rectangle."
-msgstr "Създай нови възли."
+msgstr "Създаване на нов правоъгълник."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Rectangle"
-msgstr "Ðова Ñцена"
+msgstr "Ðов правоъгълник"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Create a new polygon."
-msgstr "Създай нов полигон от нулата."
+msgstr "Създаване на нов полигон."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Polygon"
-msgstr "ПремеÑтване на полигона"
+msgstr "Ðов полигон"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete Selected Shape"
-msgstr "Изтриване на избран(и) ключ(ове)"
+msgstr "Изтриване на избраната форма"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Keep polygon inside region Rect."
@@ -8189,9 +8148,10 @@ msgid ""
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Remove selected texture? This will remove all tiles which use it."
-msgstr "ПремеÑтване на пътечката нагоре."
+msgstr ""
+"ПремеÑтване на избраната текÑтура? Това ще премахне вÑички плочки, които Ñ "
+"ползват."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "You haven't selected a texture to remove."
@@ -8206,9 +8166,8 @@ msgid "Merge from scene?"
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Remove Texture"
-msgstr "ВнаÑÑне на текÑтури"
+msgstr "Премахване на текÑтурата"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "%s file(s) were not added because was already on the list."
@@ -8270,23 +8229,20 @@ msgstr ""
"Щракнете на друга плочка, за да Ñ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð°Ñ‚Ðµ."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Set Tile Region"
-msgstr "Двуизмерна текÑтура"
+msgstr "Задаване на регион от плочки"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Create Tile"
-msgstr "Създаване на папка"
+msgstr "Създаване на плочка"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Set Tile Icon"
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Edit Tile Bitmask"
-msgstr "Промени Филтрите"
+msgstr "Редактиране на побитовата маÑка на плочката"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Edit Collision Polygon"
@@ -8302,33 +8258,28 @@ msgid "Edit Navigation Polygon"
msgstr "Редактиране на полигона за навигациÑ"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Paste Tile Bitmask"
-msgstr "ПоÑтавÑне на възелите"
+msgstr "ПоÑтавÑне на побитовата маÑка на плочката"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Clear Tile Bitmask"
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Make Polygon Concave"
-msgstr "ПремеÑтване на Полигон"
+msgstr "Преобразуване на полигона във вдлъбнат"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Make Polygon Convex"
-msgstr "ПремеÑтване на Полигон"
+msgstr "Преобразуване на полигона в изпъкнал"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Remove Tile"
-msgstr "ЗатварÑне на вÑичко"
+msgstr "Премахване на плочката"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Remove Collision Polygon"
-msgstr "ПремеÑтване на Полигон"
+msgstr "Премахване на полигона за колизии"
#: editor/plugins/tile_set_editor_plugin.cpp
#, fuzzy
@@ -8336,28 +8287,24 @@ msgid "Remove Occlusion Polygon"
msgstr "ПремеÑтване на Полигон"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Remove Navigation Polygon"
-msgstr "Завъртане на Полигон"
+msgstr "Премахване на полигона за навигациÑ"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Edit Tile Priority"
-msgstr "Промени Филтрите"
+msgstr "Редактиране на приоритета на плочката"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Edit Tile Z Index"
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Make Convex"
-msgstr "ПремеÑтване на Полигон"
+msgstr "Преобразуване в изпъкнал"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Make Concave"
-msgstr "ПремеÑтване на Полигон"
+msgstr "Преобразуване във вдлъбнат"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create Collision Polygon"
@@ -8404,9 +8351,8 @@ msgid "Version Control System"
msgstr ""
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Initialize"
-msgstr "Ð’ÑÑка дума Ñ Ð“Ð»Ð°Ð²Ð½Ð° буква"
+msgstr "Инициализиране"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Staging area"
@@ -8425,14 +8371,12 @@ msgid "Modified"
msgstr ""
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Renamed"
-msgstr "Възел"
+msgstr "Преименуван"
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Deleted"
-msgstr "Изтрий"
+msgstr "Изтрит"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Typechange"
@@ -8486,9 +8430,8 @@ msgid "Scalar"
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Vector"
-msgstr "ИнÑпектор"
+msgstr "Вектор"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Boolean"
@@ -8551,9 +8494,8 @@ msgid "Add Node to Visual Shader"
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Node(s) Moved"
-msgstr "Възелът е премеÑтен"
+msgstr "Възлите Ñа премеÑтени"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Duplicate Nodes"
@@ -9573,6 +9515,10 @@ 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"
@@ -10307,9 +10253,8 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Detach Script"
-msgstr "Закачане на Ñкрипт"
+msgstr "Разкачане на Ñкрипта"
#: editor/scene_tree_dock.cpp
msgid "This operation can't be done on the tree root."
@@ -10344,9 +10289,8 @@ msgid "Make node as Root"
msgstr "Превръщане на възела в корен"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Delete %d nodes and any children?"
-msgstr "Изтриване на %d възела?"
+msgstr "Изтриване на %d възела и дъщерните им елементи?"
#: editor/scene_tree_dock.cpp
msgid "Delete %d nodes?"
@@ -12059,6 +12003,26 @@ msgid ""
"\"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
#, fuzzy
msgid ""
@@ -12338,6 +12302,26 @@ msgid ""
"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
#, fuzzy
msgid ""
diff --git a/editor/translations/bn.po b/editor/translations/bn.po
index 0ff139a1f1..4526860a7a 100644
--- a/editor/translations/bn.po
+++ b/editor/translations/bn.po
@@ -1123,7 +1123,7 @@ msgstr "মালিকবিহীন রিসোরà§à¦¸à§‡à¦° অনà§à¦¸à
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3916,6 +3916,16 @@ 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
#, fuzzy
msgid "Renaming file:"
msgstr "চলক/ভেরিয়েবল-à¦à¦° নামানà§à¦¤à¦° করà§à¦¨"
@@ -3972,27 +3982,12 @@ msgstr "নিরà§à¦­à¦°à¦¤à¦¾à¦¸à¦®à§‚হ সমà§à¦ªà¦¾à¦¦à¦¨ করà§à¦¨.
msgid "View Owners..."
msgstr "সà§à¦¬à¦¤à§à¦¬à¦¾à¦§à¦¿à¦•à¦¾à¦°à§€à¦¦à§‡à¦° দেখà§à¦¨..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
-msgid "Rename..."
-msgstr "পà§à¦¨à¦ƒà¦¨à¦¾à¦®à¦•à¦°à¦£ করà§à¦¨"
-
-#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Duplicate..."
-msgstr "ডà§à¦ªà§à¦²à¦¿à¦•à§‡à¦Ÿ"
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "à¦à¦–ানে সরান..."
#: editor/filesystem_dock.cpp
#, fuzzy
-msgid "Move to Trash"
-msgstr "Autoload সà§à¦¥à¦¾à¦¨à¦¾à¦¨à§à¦¤à¦° করà§à¦¨"
-
-#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "New Scene..."
msgstr "নতà§à¦¨ দৃশà§à¦¯"
@@ -4019,10 +4014,18 @@ msgid "Collapse All"
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"
+#, fuzzy
+msgid "Duplicate..."
+msgstr "ডà§à¦ªà§à¦²à¦¿à¦•à§‡à¦Ÿ"
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "Autoload সà§à¦¥à¦¾à¦¨à¦¾à¦¨à§à¦¤à¦° করà§à¦¨"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+#, fuzzy
+msgid "Rename..."
msgstr "পà§à¦¨à¦ƒà¦¨à¦¾à¦®à¦•à¦°à¦£ করà§à¦¨"
#: editor/filesystem_dock.cpp
@@ -4062,9 +4065,11 @@ msgid "Move"
msgstr "সরান"
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "There is already file or folder with the same name in this location."
-msgstr "গà§à¦°à§à¦ªà§‡à¦° নাম ইতিমধà§à¦¯à§‡à¦‡ আছে!"
+#: 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"
@@ -10437,6 +10442,10 @@ 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"
@@ -13134,6 +13143,26 @@ msgid ""
"\"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
#, fuzzy
msgid ""
@@ -13428,6 +13457,26 @@ msgid ""
"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
#, fuzzy
msgid ""
@@ -13653,6 +13702,10 @@ msgstr ""
msgid "Constants cannot be modified."
msgstr ""
+#, fuzzy
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "গà§à¦°à§à¦ªà§‡à¦° নাম ইতিমধà§à¦¯à§‡à¦‡ আছে!"
+
#~ msgid "Error trying to save layout!"
#~ msgstr "লেআউট/নকশা সংরকà§à¦·à¦£à§‡à¦° চেষà§à¦Ÿà¦¾à§Ÿ সমসà§à¦¯à¦¾ হয়েছে!"
diff --git a/editor/translations/ca.po b/editor/translations/ca.po
index 36f6096591..d0921e2a61 100644
--- a/editor/translations/ca.po
+++ b/editor/translations/ca.po
@@ -1100,7 +1100,7 @@ msgstr "Navegador de Recursos Orfes"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3747,6 +3747,16 @@ msgid "Name contains invalid characters."
msgstr "El Nom conté caràcters que no són vàlids."
#: 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 "Reanomenant fitxer:"
@@ -3795,24 +3805,11 @@ msgstr "Edita Dependències..."
msgid "View Owners..."
msgstr "Mostra Propietaris..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Reanomena..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "Duplica..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "Mou cap a..."
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Move to Trash"
-msgstr "Mou l'AutoCàrrega"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "Nova Escena..."
@@ -3835,11 +3832,17 @@ msgid "Collapse All"
msgstr "Col·lapsar tot"
#: 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 "Reanomena"
+msgid "Duplicate..."
+msgstr "Duplica..."
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "Mou l'AutoCàrrega"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "Reanomena..."
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -3874,8 +3877,11 @@ msgid "Move"
msgstr "Mou"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "Ja hi existex un fitxer o directori amb aquest nom."
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr "Reanomena"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
@@ -10086,6 +10092,10 @@ msgid "OpenGL ES 3.0"
msgstr "OpenGL ES 3.0"
#: 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"
@@ -12752,6 +12762,26 @@ msgid ""
"\"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
#, fuzzy
msgid ""
@@ -13080,6 +13110,26 @@ msgstr ""
"RigidBody(Caràcter o Rígid). \n"
"Modifica la mida de les Formes de Col. lisió Filles."
+#: 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
#, fuzzy
msgid ""
@@ -13327,6 +13377,9 @@ msgstr ""
msgid "Constants cannot be modified."
msgstr "Les constants no es poden modificar."
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "Ja hi existex un fitxer o directori amb aquest nom."
+
#~ msgid "Error trying to save layout!"
#~ msgstr "Error en desar els canvis!"
diff --git a/editor/translations/cs.po b/editor/translations/cs.po
index fc0a47e554..4dd0050197 100644
--- a/editor/translations/cs.po
+++ b/editor/translations/cs.po
@@ -28,7 +28,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-11-20 23:08+0000\n"
+"PO-Revision-Date: 2020-11-29 08:28+0000\n"
"Last-Translator: Václav Blažej <vaclavblazej@seznam.cz>\n"
"Language-Team: Czech <https://hosted.weblate.org/projects/godot-engine/godot/"
"cs/>\n"
@@ -1107,7 +1107,7 @@ msgstr "Průzkumník osiřelých zdrojů"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3709,6 +3709,16 @@ msgid "Name contains invalid characters."
msgstr "Jméno obsahuje neplatné znaky."
#: 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 "Přejmenovávání souboru:"
@@ -3756,23 +3766,11 @@ msgstr "Upravit závislosti..."
msgid "View Owners..."
msgstr "Zobrazit vlastníky..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Přejmenovat..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "Duplikovat..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "Přesunout do..."
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr "Přesunout do koše"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "Nová scéna..."
@@ -3795,11 +3793,16 @@ msgid "Collapse All"
msgstr "Sbalit vše"
#: 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 "Přejmenovat"
+msgid "Duplicate..."
+msgstr "Duplikovat..."
+
+#: editor/filesystem_dock.cpp
+msgid "Move to Trash"
+msgstr "Přesunout do koše"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "Přejmenovat..."
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -3834,8 +3837,11 @@ msgid "Move"
msgstr "Přesunout"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "Soubor nebo složka se stejným názvem již na tomto místě existuje."
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr "Přejmenovat"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
@@ -8305,23 +8311,20 @@ msgid "Create a new rectangle."
msgstr "Vytvořit nový obdélník."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Rectangle"
-msgstr "Nakreslit obdélník"
+msgstr "Nový obdélník"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new polygon."
msgstr "Vytvořit nový polygon."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Polygon"
-msgstr "Přesunout polygon"
+msgstr "Nový polygon"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete Selected Shape"
-msgstr "Smazat vybraný"
+msgstr "Smazat vybraný tvar"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Keep polygon inside region Rect."
@@ -9790,6 +9793,10 @@ msgid "OpenGL ES 3.0"
msgstr "OpenGL ES 3.0"
#: 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"
@@ -12344,6 +12351,26 @@ msgstr ""
"Animace CPUParticles2D vyžaduje použití CanvasItemMaterial se zapnutým "
"\"Particles Animation\"."
+#: 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\" "
@@ -12664,6 +12691,26 @@ msgstr ""
"přepsány fyzikálním enginem.\n"
"Změňte velikost kolizních tvarů v uzlech potomků."
+#: 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-"
@@ -12903,6 +12950,9 @@ msgstr "Odlišnosti mohou být přiřazeny pouze ve vertex funkci."
msgid "Constants cannot be modified."
msgstr "Konstanty není možné upravovat."
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "Soubor nebo složka se stejným názvem již na tomto místě existuje."
+
#~ msgid "Missing 'build-tools' directory!"
#~ msgstr "Chybí složka \"build-tools\"!"
diff --git a/editor/translations/da.po b/editor/translations/da.po
index d9f131db67..b8dfa199e8 100644
--- a/editor/translations/da.po
+++ b/editor/translations/da.po
@@ -1140,7 +1140,7 @@ msgstr "Forældreløs ressource udforsker"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3809,6 +3809,16 @@ msgid "Name contains invalid characters."
msgstr "Navnet indeholder ugyldige karakterer."
#: 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 "Omdøb fil:"
@@ -3863,26 +3873,12 @@ msgstr "Rediger Afhængigheder..."
msgid "View Owners..."
msgstr "Vis Ejere..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Omdøb..."
-
-#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Duplicate..."
-msgstr "Duplikere"
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "Flyt Til..."
#: editor/filesystem_dock.cpp
#, fuzzy
-msgid "Move to Trash"
-msgstr "Flyt Autoload"
-
-#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "New Scene..."
msgstr "Ny Scene"
@@ -3909,11 +3905,18 @@ msgid "Collapse All"
msgstr "Klap alle sammen"
#: 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 "Omdøb"
+#, fuzzy
+msgid "Duplicate..."
+msgstr "Duplikere"
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "Flyt Autoload"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "Omdøb..."
#: editor/filesystem_dock.cpp
#, fuzzy
@@ -3952,9 +3955,11 @@ msgid "Move"
msgstr "Flyt"
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "There is already file or folder with the same name in this location."
-msgstr "En fil eller mappe med dette navn findes allerede."
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr "Omdøb"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
@@ -10080,6 +10085,10 @@ 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"
@@ -12655,6 +12664,26 @@ msgid ""
"\"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
#, fuzzy
msgid ""
@@ -12948,6 +12977,26 @@ msgid ""
"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
#, fuzzy
msgid ""
@@ -13172,6 +13221,10 @@ msgstr ""
msgid "Constants cannot be modified."
msgstr "Konstanter kan ikke ændres."
+#, fuzzy
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "En fil eller mappe med dette navn findes allerede."
+
#~ msgid "Error trying to save layout!"
#~ msgstr "Fejl, under forsøg på at gemme layout!"
diff --git a/editor/translations/de.po b/editor/translations/de.po
index 2e7b01f9bb..a7c6f3dddc 100644
--- a/editor/translations/de.po
+++ b/editor/translations/de.po
@@ -66,8 +66,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-11-20 23:08+0000\n"
-"Last-Translator: Günther Bohn <ciscouser@gmx.de>\n"
+"PO-Revision-Date: 2020-12-01 20:29+0000\n"
+"Last-Translator: So Wieso <sowieso@dukun.de>\n"
"Language-Team: German <https://hosted.weblate.org/projects/godot-engine/"
"godot/de/>\n"
"Language: de\n"
@@ -1154,7 +1154,7 @@ msgstr "Unbenutzte Dateien ansehen"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3787,6 +3787,16 @@ msgid "Name contains invalid characters."
msgstr "Name enthält ungültige Zeichen."
#: 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 "Benenne Datei um:"
@@ -3834,23 +3844,11 @@ msgstr "Abhängigkeiten bearbeiten..."
msgid "View Owners..."
msgstr "Zeige Besitzer..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Umbenennen..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "Duplizieren..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "Verschiebe zu..."
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr "In Papierkorb werfen"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "Neue Szene…"
@@ -3873,11 +3871,16 @@ msgid "Collapse All"
msgstr "Alle einklappen"
#: 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 "Umbenennen"
+msgid "Duplicate..."
+msgstr "Duplizieren..."
+
+#: editor/filesystem_dock.cpp
+msgid "Move to Trash"
+msgstr "In Papierkorb werfen"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "Umbenennen..."
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -3912,10 +3915,11 @@ msgid "Move"
msgstr "Verschieben"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr ""
-"Es existiert bereits eine Datei oder ein Ordner an diesem Pfad mit dem "
-"angegebenen Namen."
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr "Umbenennen"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
@@ -8421,23 +8425,20 @@ msgid "Create a new rectangle."
msgstr "Neues Rechteck erstellen."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Rectangle"
-msgstr "Rechteck zeichnen"
+msgstr "Neues Rechteck"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new polygon."
msgstr "Neues Polygon erstellen."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Polygon"
-msgstr "Polygon verschieben"
+msgstr "Neues Polygon"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete Selected Shape"
-msgstr "Auswahl löschen"
+msgstr "Ausgewählte Form löschen"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Keep polygon inside region Rect."
@@ -9919,6 +9920,10 @@ msgid "OpenGL ES 3.0"
msgstr "OpenGL ES 3.0"
#: 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"
@@ -12509,6 +12514,26 @@ msgstr ""
"CPUParticles2D-Animationen benötigen ein CanvasItemMaterial mit der "
"Eigenschaft „Particles Animation“ aktiviert."
+#: 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\" "
@@ -12852,6 +12877,26 @@ msgstr ""
"Die Größe der entsprechenden Collisionshape-Unterobjekte sollte stattdessen "
"geändert werden."
+#: 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-"
@@ -13105,6 +13150,11 @@ msgstr "Varyings können nur in Vertex-Funktion zugewiesen werden."
msgid "Constants cannot be modified."
msgstr "Konstanten können nicht verändert werden."
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr ""
+#~ "Es existiert bereits eine Datei oder ein Ordner an diesem Pfad mit dem "
+#~ "angegebenen Namen."
+
#~ msgid "Missing 'build-tools' directory!"
#~ msgstr "‚build-tools‘-Verzeichnis fehlt!"
diff --git a/editor/translations/editor.pot b/editor/translations/editor.pot
index bb04c064f0..23a0ea8480 100644
--- a/editor/translations/editor.pot
+++ b/editor/translations/editor.pot
@@ -1050,7 +1050,7 @@ msgstr ""
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3526,6 +3526,16 @@ 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 ""
@@ -3573,23 +3583,11 @@ msgstr ""
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr ""
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr ""
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr ""
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr ""
@@ -3612,10 +3610,15 @@ msgid "Collapse All"
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"
+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
@@ -3649,7 +3652,10 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
+#: 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
@@ -9421,6 +9427,10 @@ 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"
@@ -11834,6 +11844,26 @@ msgid ""
"\"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\" "
@@ -12094,6 +12124,26 @@ msgid ""
"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-"
diff --git a/editor/translations/el.po b/editor/translations/el.po
index 0b2c2fa7b4..fde979b618 100644
--- a/editor/translations/el.po
+++ b/editor/translations/el.po
@@ -1099,7 +1099,7 @@ msgstr "ΕξεÏευνητής αχÏησιμοποίητων πόÏων"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3731,6 +3731,16 @@ 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 "Μετονομασία αÏχείου:"
@@ -3778,24 +3788,11 @@ msgstr "ΕπεξεÏγασία εξαÏτήσεων..."
msgid "View Owners..."
msgstr "ΠÏοβολή ιδιοκτητών..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Μετονομασία..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "ΑναπαÏαγωγή..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "Μετακίνηση σε..."
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Move to Trash"
-msgstr "Μετακίνηση AutoLoad"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "Îέα Σκηνή..."
@@ -3818,11 +3815,17 @@ msgid "Collapse All"
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 "Μετονομασία"
+msgid "Duplicate..."
+msgstr "ΑναπαÏαγωγή..."
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "Μετακίνηση AutoLoad"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "Μετονομασία..."
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -3857,8 +3860,11 @@ msgid "Move"
msgstr "Μετακίνηση"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "ΥπάÏχει ήδη αÏχείο ή φάκελος με το ίδιο όνομα στη διαδÏομή."
+#: 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"
@@ -9879,6 +9885,10 @@ msgid "OpenGL ES 3.0"
msgstr "OpenGL ES 3.0"
#: 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"
@@ -12470,6 +12480,26 @@ msgstr ""
"Η κίνηση CPUParticles2D απαιτεί την χÏήση CanvasItemMaterial με το "
"«Particles Animation» ενεÏγό."
+#: 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\" "
@@ -12805,6 +12835,26 @@ msgstr ""
"αντικατασταθοÏνε από την μηχανή φυσικής κατά την εκτέλεση.\n"
"Αλλάξτε μέγεθος στα σχήματα σÏγκÏουσης των παιδιών."
+#: 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-"
@@ -13051,6 +13101,9 @@ msgstr "Τα «varying» μποÏοÏν να ανατεθοÏν μόνο στηÎ
msgid "Constants cannot be modified."
msgstr "Οι σταθεÏές δεν μποÏοÏν να Ï„ÏοποποιηθοÏν."
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "ΥπάÏχει ήδη αÏχείο ή φάκελος με το ίδιο όνομα στη διαδÏομή."
+
#~ msgid "Error trying to save layout!"
#~ msgstr "Σφάλμα κατά την αποθήκευση διάταξης!"
diff --git a/editor/translations/eo.po b/editor/translations/eo.po
index 671c2e1c6d..c4b2e447f1 100644
--- a/editor/translations/eo.po
+++ b/editor/translations/eo.po
@@ -1086,7 +1086,7 @@ msgstr ""
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3630,6 +3630,16 @@ 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 ""
@@ -3678,23 +3688,11 @@ msgstr ""
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr ""
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr ""
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr ""
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "Nova sceno..."
@@ -3717,11 +3715,16 @@ msgid "Collapse All"
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 "Renomi"
+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"
@@ -3754,8 +3757,11 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr ""
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr "Renomi"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
@@ -9561,6 +9567,10 @@ msgid "OpenGL ES 3.0"
msgstr ""
#: editor/project_manager.cpp
+msgid "Not supported by your GPU drivers."
+msgstr ""
+
+#: editor/project_manager.cpp
#, fuzzy
msgid ""
"Higher visual quality\n"
@@ -12012,6 +12022,26 @@ msgid ""
"\"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\" "
@@ -12272,6 +12302,26 @@ msgid ""
"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-"
diff --git a/editor/translations/es.po b/editor/translations/es.po
index aea60effae..6920aa1bf7 100644
--- a/editor/translations/es.po
+++ b/editor/translations/es.po
@@ -54,12 +54,13 @@
# José Manuel Jurado Bujalance <darkbird@vivaldi.net>, 2020.
# Skarline <lihue-molina@hotmail.com>, 2020.
# Oxixes <oxixes@protonmail.com>, 2020.
+# David Aroca Rojas <arocarojasdavid@gmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-11-24 16:44+0000\n"
-"Last-Translator: Skarline <lihue-molina@hotmail.com>\n"
+"PO-Revision-Date: 2020-12-07 08:11+0000\n"
+"Last-Translator: Lisandro Lorea <lisandrolorea@gmail.com>\n"
"Language-Team: Spanish <https://hosted.weblate.org/projects/godot-engine/"
"godot/es/>\n"
"Language: es\n"
@@ -1150,7 +1151,7 @@ msgstr "Explorador de Recursos Huérfanos"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -2384,6 +2385,9 @@ msgid ""
"To restore the Default layout to its base settings, use the Delete Layout "
"option and delete the Default layout."
msgstr ""
+"Layout por defecto del editor sobreescrita.\n"
+"Para recuperar el layout por defecto, utiliza la opción Eliminar Layout y "
+"borra el Layout por defecto."
#: editor/editor_node.cpp
msgid "Layout name not found!"
@@ -3784,6 +3788,16 @@ msgid "Name contains invalid characters."
msgstr "El nombre contiene caracteres inválidos."
#: 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 "Renombrar archivo:"
@@ -3831,23 +3845,11 @@ msgstr "Editar Dependencias..."
msgid "View Owners..."
msgstr "Ver Propietarios..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Renombrar..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "Duplicar..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "Mover a..."
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr "Mover a la papelera"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "Nueva Escena..."
@@ -3870,11 +3872,16 @@ msgid "Collapse All"
msgstr "Colapsar Todo"
#: 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 "Renombrar"
+msgid "Duplicate..."
+msgstr "Duplicar..."
+
+#: editor/filesystem_dock.cpp
+msgid "Move to Trash"
+msgstr "Mover a la papelera"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "Renombrar..."
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -3909,8 +3916,11 @@ msgid "Move"
msgstr "Mover"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "Ya hay un archivo o carpeta con el mismo nombre en esta ubicación."
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr "Renombrar"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
@@ -6641,7 +6651,7 @@ msgstr "Mover Puntos"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Command: Rotate"
-msgstr "Comando: Rotar"
+msgstr "Command: Rotar"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Shift: Move All"
@@ -8410,23 +8420,20 @@ msgid "Create a new rectangle."
msgstr "Cree un nuevo rectángulo."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Rectangle"
-msgstr "Dibujar Rectángulo"
+msgstr "Nuevo Rectángulo"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new polygon."
msgstr "Crear un nuevo polígono."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Polygon"
-msgstr "Mover Polígono"
+msgstr "Nuevo Polígono"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete Selected Shape"
-msgstr "Eliminar Seleccionados"
+msgstr "Eliminar Formas Seleccionadas"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Keep polygon inside region Rect."
@@ -9909,6 +9916,10 @@ msgid "OpenGL ES 3.0"
msgstr "OpenGL ES 3.0"
#: 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"
@@ -12308,7 +12319,7 @@ msgid ""
"outputs."
msgstr ""
"No se puede copiar y renombrar el archivo de exportación, comprueba el "
-"directorio del proyecto de graduación para ver los resultados."
+"directorio del proyecto de gradle para ver los resultados."
#: platform/iphone/export/export.cpp
msgid "Identifier is missing."
@@ -12510,6 +12521,26 @@ msgstr ""
"La animación CPUParticles2D requiere el uso de un CanvasItemMaterial con "
"\"Particles Animation\" activado."
+#: 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\" "
@@ -12844,6 +12875,26 @@ msgstr ""
"anulado por el motor de la física cuando esté ejecutándose.\n"
"En su lugar, cambia el tamaño en las formas de colisión de los hijos."
+#: 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-"
@@ -13089,6 +13140,9 @@ msgstr "Solo se pueden asignar variaciones en funciones de vértice."
msgid "Constants cannot be modified."
msgstr "Las constantes no pueden modificarse."
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "Ya hay un archivo o carpeta con el mismo nombre en esta ubicación."
+
#~ msgid "Missing 'build-tools' directory!"
#~ msgstr "¡No se encontró el directorio 'build-tools'!"
diff --git a/editor/translations/es_AR.po b/editor/translations/es_AR.po
index 83a1334dd6..49b2358aed 100644
--- a/editor/translations/es_AR.po
+++ b/editor/translations/es_AR.po
@@ -20,8 +20,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-11-20 23:08+0000\n"
-"Last-Translator: Skarline <lihue-molina@hotmail.com>\n"
+"PO-Revision-Date: 2020-12-07 08:11+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"
"Language: es_AR\n"
@@ -34,7 +34,8 @@ msgstr ""
#: 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 "Argumento de tipo incorrecto en convert(), utilizá constantes TYPE_*."
+msgstr ""
+"Tipo de argumento inválido para 'convert()', utiliza constantes TYPE_*."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
@@ -1045,15 +1046,15 @@ msgid "Owners Of:"
msgstr "Dueños De:"
#: 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 ""
-"¿Eliminar los archivos seleccionados del proyecto? (No puede ser restaurado)"
+"¿Eliminar los archivos seleccionados del proyecto? (irreversible)\n"
+"Podés encontrar los archivos eliminados en la papelera de reciclaje del "
+"sistema para restaurarlos."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1062,7 +1063,9 @@ msgid ""
msgstr ""
"Los archivos que se están removiendo son requeridos por otros recursos para "
"funcionar.\n"
-"Quitarlos de todos modos? (imposible deshacer)"
+"¿Eliminarlos de todos modos? (irreversible)\n"
+"Podés encontrar los archivos eliminados en la papelera de reciclaje del "
+"sistema para restaurarlos."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1106,7 +1109,7 @@ msgstr "Explorador de Recursos Huérfanos"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -1168,14 +1171,12 @@ msgid "Gold Sponsors"
msgstr "Sponsor Oro"
#: editor/editor_about.cpp
-#, fuzzy
msgid "Silver Sponsors"
-msgstr "Donantes Plata"
+msgstr "Sponsors Plata"
#: editor/editor_about.cpp
-#, fuzzy
msgid "Bronze Sponsors"
-msgstr "Donantes Bronce"
+msgstr "Sponsors Bronce"
#: editor/editor_about.cpp
msgid "Mini Sponsors"
@@ -1617,35 +1618,32 @@ msgstr ""
"Respaldo Activado\"."
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'PVRTC' texture compression for GLES2. Enable "
"'Import Pvrtc' in Project Settings."
msgstr ""
-"La plataforma de destino requiere compresión de texturas 'ETC' para GLES2. "
-"Activá 'Import Etc' en Ajustes del Proyecto."
+"La plataforma de destino requiere compresión de texturas 'PVRTC' para GLES2. "
+"Activá 'Import Pvrtc' en Ajustes del Proyecto."
#: 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 ""
-"La plataforma de destino requiere compresión de texturas 'ETC2' para GLES3. "
-"Activá 'Importar Etc 2' en Ajustes del Proyecto."
+"La plataforma de destino requiere compresión de texturas 'ETC2' o 'PVRTC' "
+"para GLES3. Activá 'Import Etc 2' o 'Import Pvrtc' en Ajustes del Proyecto."
#: 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 ""
-"La plataforma de destino requiere compresión de texturas 'ETC' para usar "
-"GLES2 como controlador de respaldo.\n"
-"Activá 'Importar Etc' en Ajustes del Proyecto, o desactivá \"Controlador de "
-"Respaldo Activado\"."
+"La plataforma del objetivo requiere compresión de texturas 'PVRTC' para el "
+"driver fallback de GLES2.\n"
+"Activá Import Pvrtc' en la Ajustes del Proyecto, o desactiva 'Driver "
+"Fallback Enabled'."
#: editor/editor_export.cpp platform/android/export/export.cpp
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
@@ -1689,9 +1687,8 @@ msgid "Node Dock"
msgstr "Dock de Nodos"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "FileSystem Dock"
-msgstr "Sistema de Archivos"
+msgstr "Panel de Sistema de Archivos"
#: editor/editor_feature_profile.cpp
msgid "Import Dock"
@@ -2335,6 +2332,9 @@ msgid ""
"An error occurred while trying to save the editor layout.\n"
"Make sure the editor's user data path is writable."
msgstr ""
+"Ocurrió un error mientras se intentaba guardar el layout del editor.\n"
+"Chequeá que la ruta de datos de usuario del editor tenga permisos de "
+"escritura."
#: editor/editor_node.cpp
msgid ""
@@ -2342,15 +2342,17 @@ msgid ""
"To restore the Default layout to its base settings, use the Delete Layout "
"option and delete the Default layout."
msgstr ""
+"Se sobreescribió el layout de editor Por Defecto.\n"
+"Para restaurar el layout Por Defecto a su configuración de base, usá la "
+"opcion Eliminar Layout y eliminá el layout Por Defecto."
#: editor/editor_node.cpp
msgid "Layout name not found!"
msgstr "Nombre de layout no encontrado!"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Restored the Default layout to its base settings."
-msgstr "Se restauró el layout por defecto a su configuración básica."
+msgstr "Se restauró el layout Por Defecto a su configuración básica."
#: editor/editor_node.cpp
msgid ""
@@ -2862,14 +2864,18 @@ msgid ""
"mobile device).\n"
"You don't need to enable it to use the GDScript debugger locally."
msgstr ""
+"Cuando esta opción está activada, al utilizar el deploy en un click, el "
+"ejecutable intentará conectarse a la IP de este equipo para que el proyecto "
+"en ejecución pueda ser depurado.\n"
+"Esta opción está pensada para ser usada en la depuración remota "
+"( normalmente con un dispositivo móvil).\n"
+"No es necesario habilitarla para usar el depurador GDScript localmente."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Small Deploy with Network Filesystem"
-msgstr "Deploy Pequeño con recursos en red"
+msgstr "Deploy Reducido con el Sistema de Archivos en Red"
#: 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"
@@ -2878,74 +2884,68 @@ msgid ""
"On Android, deploying will use the USB cable for faster performance. This "
"option speeds up testing for projects with large assets."
msgstr ""
-"Cuando esta opción está activa, exportar o hacer deploy producirá un "
-"ejecutable mínimo.\n"
-"El sistema de archivos sera proveído desde el proyecto por el editor sobre "
-"la red.\n"
-"En Android, deploy usará el cable USB para mejor performance. Esta opción "
-"acelera el testeo para juegos con footprint grande."
+"Cuando esta opción está activada, al usar deploy en un click para Android "
+"sólo se exportará un ejecutable sin los datos del proyecto.\n"
+"El sistema de archivos será proporcionado desde el proyecto por el editor a "
+"través de la red.\n"
+"En Android, el deploy usará el cable USB para un rendimiento más rápido. "
+"Esta opción acelera las pruebas de los proyectos con recursos grandes."
#: editor/editor_node.cpp
msgid "Visible Collision Shapes"
msgstr "Collision Shapes Visibles"
#: 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 ""
-"Los Collision shapes y nodos raycast (para 2D y 3D) serán visibles durante "
-"la ejecución del juego cuando esta opción queda activada."
+"Cuando esta opción está activada, las formas de colisión y los nodos de "
+"raycast (para 2D y 3D) serán visibles en el proyecto en ejecución."
#: editor/editor_node.cpp
msgid "Visible Navigation"
msgstr "Navegación Visible"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, navigation meshes and polygons will be visible "
"in the running project."
msgstr ""
-"Los meshes de navegación y los polígonos serán visibles durante la ejecución "
-"del juego si esta opción queda activada."
+"Cuando esta opción está activada, las mallas de navegación y los polígonos "
+"serán visibles en el proyecto en ejecución."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Synchronize Scene Changes"
msgstr "Sincronizar Cambios de Escena"
#: 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 ""
-"Cuando esta opción esté encendida, cualquier cambio hecho a la escena en el "
-"editor será replicado en el juego en ejecución.\n"
-"Cuando se usa remotamente en un dispositivo, esto es más eficiente con un "
-"sistema de archivos remoto."
+"Cuando esta opción esté activada, cualquier cambio hecho a la escena en el "
+"editor será replicado en el proyecto en ejecución.\n"
+"Cuando se usa remotamente en un dispositivo, esto es más eficiente cuando el "
+"sistema la opción de sistema de archivos de redes esta activada."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Synchronize Script Changes"
msgstr "Sincronizar Cambios en Scripts"
#: 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 ""
-"Cuando esta opción está activa, cualquier script que se guarde sera vuelto a "
-"cargar en el juego en ejecución.\n"
-"Cuando se use remotamente en un dispositivo, esto es más eficiente con un "
-"sistema de archivos de red."
+"Cuando esta opción está activada, cualquier script que se guarde se "
+"recargará en el proyecto en ejecución.\n"
+"Cuando se utiliza de forma remota en un dispositivo, esto es más eficiente "
+"cuando la opción de sistema de archivos en red está activada."
#: editor/editor_node.cpp editor/script_create_dialog.cpp
msgid "Editor"
@@ -3423,7 +3423,6 @@ msgid "Add Key/Value Pair"
msgstr "Agregar Par Clave/Valor"
#: 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 "
@@ -3431,7 +3430,8 @@ msgid ""
msgstr ""
"No se encontró ningún preset de exportación ejecutable para esta "
"plataforma.\n"
-"Por favor agregue un preset ejecutable en el menú de exportación."
+"Por favor agregá un preset ejecutable en el menú Exportar o definí un preset "
+"como ejecutable."
#: editor/editor_run_script.cpp
msgid "Write your logic in the _run() method."
@@ -3742,6 +3742,16 @@ msgid "Name contains invalid characters."
msgstr "El nombre indicado contiene caracteres inválidos."
#: 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 "Renombrando archivo:"
@@ -3789,24 +3799,11 @@ msgstr "Editar Dependencias..."
msgid "View Owners..."
msgstr "Ver Dueños..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Renombrar..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "Duplicar..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "Mover A..."
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Move to Trash"
-msgstr "Mover Autoload"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "Nueva Escena..."
@@ -3829,11 +3826,16 @@ msgid "Collapse All"
msgstr "Colapsar Todos"
#: 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 "Renombrar"
+msgid "Duplicate..."
+msgstr "Duplicar..."
+
+#: editor/filesystem_dock.cpp
+msgid "Move to Trash"
+msgstr "Mover a La Papelera"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "Renombrar..."
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -3868,8 +3870,11 @@ msgid "Move"
msgstr "Mover"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "Ya hay un archivo o carpeta con el mismo nombre en esta ubicación."
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr "Renombrar"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
@@ -5274,50 +5279,43 @@ msgstr "Crear Guías Horizontales y Verticales"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Set CanvasItem \"%s\" Pivot Offset to (%d, %d)"
-msgstr ""
+msgstr "Ajustar el Offfset del Pivote del CanvasItem \"%s\" a (%d, %d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Rotate %d CanvasItems"
-msgstr "Rotar CanvasItem"
+msgstr "Rotar %d CanvasItems"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Rotate CanvasItem \"%s\" to %d degrees"
-msgstr "Rotar CanvasItem"
+msgstr "Rotar CanvasItem \"%s\" a %d grados"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move CanvasItem \"%s\" Anchor"
-msgstr "Mover CanvasItem"
+msgstr "Mover Ancla del CanvasItem \"%s\""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Scale Node2D \"%s\" to (%s, %s)"
-msgstr ""
+msgstr "Escalar Node2D \"%s\" a (%s, %s)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Resize Control \"%s\" to (%d, %d)"
-msgstr ""
+msgstr "Redimensionar Control \"%s\" a (%d, %d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Scale %d CanvasItems"
-msgstr "Escalar CanvasItem"
+msgstr "Escalar %d CanvasItems"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Scale CanvasItem \"%s\" to (%s, %s)"
-msgstr "Escalar CanvasItem"
+msgstr "Escalar CanvasItem \"%s\" a (%s, %s)"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move %d CanvasItems"
-msgstr "Mover CanvasItem"
+msgstr "Mover %d CanvasItems"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move CanvasItem \"%s\" to (%d, %d)"
-msgstr "Mover CanvasItem"
+msgstr "Mover CanvasItem \"%s\" a (%d, %d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid ""
@@ -6600,18 +6598,16 @@ msgid "Move Points"
msgstr "Mover Puntos"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Command: Rotate"
-msgstr "Arrastrar: Rotar"
+msgstr "Command: Rotar"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Shift: Move All"
msgstr "Shift: Mover Todos"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Shift+Command: Scale"
-msgstr "Shift+Ctrl: Escalar"
+msgstr "Shift+Command: Escalar"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Ctrl: Rotate"
@@ -6660,14 +6656,12 @@ msgid "Radius:"
msgstr "Radio:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Copy Polygon to UV"
-msgstr "Crear Polígono y UV"
+msgstr "Copiar Polígono a UV"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Copy UV to Polygon"
-msgstr "Convertir a Polygon2D"
+msgstr "Copiar UV al Polígono"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Clear UV"
@@ -7894,9 +7888,8 @@ msgid "New Animation"
msgstr "Nueva Animación"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Speed:"
-msgstr "Velocidad (FPS):"
+msgstr "Velocidad:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Loop"
@@ -8214,13 +8207,12 @@ msgid "Paint Tile"
msgstr "Pintar Tile"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid ""
"Shift+LMB: Line Draw\n"
"Shift+Command+LMB: Rectangle Paint"
msgstr ""
-"Shift + Clic izq: Dibujar línea\n"
-"Shift + Ctrl + Clic izq: Pintar Rectángulo"
+"Shift+Click izq: Dibujar línea\n"
+"Shift+Command+Click der: Pintar Rectángulo"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid ""
@@ -8375,23 +8367,20 @@ msgid "Create a new rectangle."
msgstr "Crear un rectángulo nuevo."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Rectangle"
-msgstr "Pintar Rectángulo"
+msgstr "Nuevo Rectángulo"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new polygon."
msgstr "Crear un nuevo polígono."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Polygon"
-msgstr "Mover Polígono"
+msgstr "Nuevo Polígono"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete Selected Shape"
-msgstr "Eliminar Seleccionados"
+msgstr "Eliminar Formas Seleccionadas"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Keep polygon inside region Rect."
@@ -8761,9 +8750,8 @@ msgid "Add Node to Visual Shader"
msgstr "Agregar Nodo al Visual Shader"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Node(s) Moved"
-msgstr "Nodo Movido"
+msgstr "Nodo(s) Movido(s)"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Duplicate Nodes"
@@ -8783,9 +8771,8 @@ msgid "Visual Shader Input Type Changed"
msgstr "Se cambió el Tipo de Entrada de Visual Shader"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "UniformRef Name Changed"
-msgstr "Asignar Nombre a Uniform"
+msgstr "Nombre de UniformRef Cambiado"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vertex"
@@ -9505,7 +9492,7 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "A reference to an existing uniform."
-msgstr ""
+msgstr "Una referencia a un uniform existente."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "(Fragment/Light mode only) Scalar derivative function."
@@ -9875,6 +9862,10 @@ msgid "OpenGL ES 3.0"
msgstr "OpenGL ES 3.0"
#: 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"
@@ -10484,19 +10475,16 @@ msgid "Batch Rename"
msgstr "Renombrar en Masa"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Replace:"
-msgstr "Reemplazar: "
+msgstr "Reemplazar:"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Prefix:"
-msgstr "Prefijo"
+msgstr "Prefijo:"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Suffix:"
-msgstr "Sufijo"
+msgstr "Sufijo:"
#: editor/rename_dialog.cpp
msgid "Use Regular Expressions"
@@ -10543,9 +10531,9 @@ msgid "Per-level Counter"
msgstr "Contador Por Nivel"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "If set, the counter restarts for each group of child nodes."
-msgstr "Si esta activo el contador reinicia por cada grupo de nodos hijos"
+msgstr ""
+"Si está activado, el contador se reinicia por cada grupo de nodos hijos."
#: editor/rename_dialog.cpp
msgid "Initial value for the counter"
@@ -10604,9 +10592,8 @@ msgid "Reset"
msgstr "Resetear"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Regular Expression Error:"
-msgstr "Error de Expresión Regular"
+msgstr "Error de Expresión Regular:"
#: editor/rename_dialog.cpp
msgid "At character %s"
@@ -12163,7 +12150,7 @@ msgstr ""
#: platform/android/export/export.cpp
msgid "Missing 'platform-tools' directory!"
-msgstr ""
+msgstr "¡No se encontró el directorio 'platform-tools'!"
#: platform/android/export/export.cpp
msgid ""
@@ -12217,18 +12204,20 @@ msgstr ""
#: platform/android/export/export.cpp
msgid "\"Export AAB\" is only valid when \"Use Custom Build\" is enabled."
msgstr ""
+"\"Export AAB\" sólo es válido cuando \"Use Custom Build\" está activado."
#: platform/android/export/export.cpp
msgid "Invalid filename! Android App Bundle requires the *.aab extension."
msgstr ""
+"¡Nombre de archivo inválido! Android App Bundle requiere la extensión *.aab."
#: platform/android/export/export.cpp
msgid "APK Expansion not compatible with Android App Bundle."
-msgstr ""
+msgstr "La Expansión APK no es compatible con Android App Bundle."
#: platform/android/export/export.cpp
msgid "Invalid filename! Android APK requires the *.apk extension."
-msgstr ""
+msgstr "¡Nombre de archivo inválido! Android APK requiere la extensión *.apk."
#: platform/android/export/export.cpp
msgid ""
@@ -12267,13 +12256,15 @@ msgstr ""
#: platform/android/export/export.cpp
msgid "Moving output"
-msgstr ""
+msgstr "Moviendo salida"
#: platform/android/export/export.cpp
msgid ""
"Unable to copy and rename export file, check gradle project directory for "
"outputs."
msgstr ""
+"No se puede copiar y renombrar el archivo de exportación, comprobá el "
+"directorio del proyecto de gradle para ver los resultados."
#: platform/iphone/export/export.cpp
msgid "Identifier is missing."
@@ -12472,6 +12463,26 @@ msgstr ""
"Animar CPUParticles2D requiere el uso de un CanvasItemMaterial con "
"\"Particles Animation\" activado."
+#: 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\" "
@@ -12736,7 +12747,7 @@ msgstr ""
#: scene/3d/interpolated_camera.cpp
msgid ""
"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
+msgstr "InterpolatedCamera ha sido deprecado y será eliminado en Godot 4.0."
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
@@ -12804,6 +12815,26 @@ msgstr ""
"sobreescritos por el motor de física al ejecutar.\n"
"Cambiá el tamaño de los collision shapes hijos."
+#: 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-"
@@ -13046,6 +13077,9 @@ msgstr "Solo se pueden asignar variaciones en funciones de vértice."
msgid "Constants cannot be modified."
msgstr "Las constantes no pueden modificarse."
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "Ya hay un archivo o carpeta con el mismo nombre en esta ubicación."
+
#~ msgid "Error trying to save layout!"
#~ msgstr "Error al tratar de guardar el layout!"
diff --git a/editor/translations/et.po b/editor/translations/et.po
index 9c886f42d4..9ede0a7465 100644
--- a/editor/translations/et.po
+++ b/editor/translations/et.po
@@ -9,7 +9,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
-"PO-Revision-Date: 2020-09-01 10:38+0000\n"
+"PO-Revision-Date: 2020-12-02 09:52+0000\n"
"Last-Translator: StReef <streef.gtx@gmail.com>\n"
"Language-Team: Estonian <https://hosted.weblate.org/projects/godot-engine/"
"godot/et/>\n"
@@ -17,7 +17,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.2.1-dev\n"
+"X-Generator: Weblate 4.4-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1064,7 +1064,7 @@ msgstr ""
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -2566,7 +2566,7 @@ msgstr "Vaikimisi"
#: editor/editor_node.cpp editor/editor_properties.cpp
#: editor/plugins/script_editor_plugin.cpp editor/property_editor.cpp
msgid "Show in FileSystem"
-msgstr ""
+msgstr "Kuva failikuvajas"
#: editor/editor_node.cpp
msgid "Play This Scene"
@@ -3582,6 +3582,16 @@ 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 ""
@@ -3629,23 +3639,11 @@ msgstr "Redigeeri sõltuvusi..."
msgid "View Owners..."
msgstr "Kuva omanikud..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Muuda nime..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "Duplikeeri..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "Teisalda..."
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr ""
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "Uus stseen..."
@@ -3668,11 +3666,16 @@ msgid "Collapse All"
msgstr "Ahenda kõik"
#: 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 "Nimeta ümber"
+msgid "Duplicate..."
+msgstr "Duplikeeri..."
+
+#: editor/filesystem_dock.cpp
+msgid "Move to Trash"
+msgstr ""
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "Muuda nime..."
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -3705,8 +3708,11 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr ""
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr "Nimeta ümber"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
@@ -3961,7 +3967,7 @@ msgstr ""
#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp
msgid "Save As..."
-msgstr ""
+msgstr "Salvest kui..."
#: editor/inspector_dock.cpp
msgid "Copy Params"
@@ -5283,7 +5289,7 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Select Mode"
-msgstr ""
+msgstr "Valimisrežiim"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Drag: Rotate"
@@ -5304,17 +5310,17 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Move Mode"
-msgstr ""
+msgstr "Liigutamisrežiim"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rotate Mode"
-msgstr ""
+msgstr "Pööramisrežiim"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Scale Mode"
-msgstr ""
+msgstr "Skaleerimisrežiim"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5349,7 +5355,7 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Grid Snap"
-msgstr ""
+msgstr "Kasuta ruudustiku naksamist"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snapping Options"
@@ -5407,7 +5413,7 @@ 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 ""
+msgstr "Lukusta valitud objekt praegusele kohale (seda ei saa liigutada)."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -6555,7 +6561,7 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
msgid "New Text File..."
-msgstr ""
+msgstr "Uus tekstifail..."
#: editor/plugins/script_editor_plugin.cpp
msgid "Open File"
@@ -6563,7 +6569,7 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
msgid "Save File As..."
-msgstr ""
+msgstr "Salvesta fail kui..."
#: editor/plugins/script_editor_plugin.cpp
msgid "Can't obtain the script for running."
@@ -6596,7 +6602,7 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
msgid "Save Theme As..."
-msgstr ""
+msgstr "Salvesta teema kui..."
#: editor/plugins/script_editor_plugin.cpp
msgid "%s Class Reference"
@@ -6650,19 +6656,19 @@ msgstr "Eelmine skript"
#: editor/plugins/script_editor_plugin.cpp
msgid "File"
-msgstr ""
+msgstr "Fail"
#: editor/plugins/script_editor_plugin.cpp
msgid "Open..."
-msgstr ""
+msgstr "Ava..."
#: editor/plugins/script_editor_plugin.cpp
msgid "Reopen Closed Script"
-msgstr ""
+msgstr "Taasava suletud skript"
#: editor/plugins/script_editor_plugin.cpp
msgid "Save All"
-msgstr ""
+msgstr "Salvesta kõik"
#: editor/plugins/script_editor_plugin.cpp
msgid "Soft Reload Script"
@@ -7177,11 +7183,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Display Normal"
-msgstr ""
+msgstr "Kuva tavaliselt"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Display Wireframe"
-msgstr ""
+msgstr "Kuva traadiraamina"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Display Overdraw"
@@ -7189,7 +7195,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Display Unshaded"
-msgstr ""
+msgstr "Kuva varjutamata"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Environment"
@@ -7205,7 +7211,7 @@ msgstr "Kuva informatsioon"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View FPS"
-msgstr ""
+msgstr "Kuva kaardisagedus"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Half Resolution"
@@ -7213,7 +7219,7 @@ msgstr "Poolresolutioon"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Audio Listener"
-msgstr ""
+msgstr "Heli kuulaja"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Enable Doppler"
@@ -7299,11 +7305,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Use Local Space"
-msgstr ""
+msgstr "Kasuta kohalikku ruumi"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Use Snap"
-msgstr ""
+msgstr "Kasuta naksamist"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Bottom View"
@@ -9481,6 +9487,10 @@ 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"
@@ -9990,7 +10000,7 @@ msgstr ""
#: editor/property_editor.cpp
msgid "File..."
-msgstr ""
+msgstr "Fail..."
#: editor/property_editor.cpp
msgid "Dir..."
@@ -10281,7 +10291,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Save New Scene As..."
-msgstr ""
+msgstr "Salvesta uus stseen kui..."
#: editor/scene_tree_dock.cpp
msgid ""
@@ -10490,7 +10500,7 @@ msgstr ""
#: editor/scene_tree_editor.cpp
msgid "Open Script:"
-msgstr ""
+msgstr "Ava skript:"
#: editor/scene_tree_editor.cpp
msgid ""
@@ -10506,7 +10516,7 @@ msgstr ""
#: editor/scene_tree_editor.cpp
msgid "Toggle Visibility"
-msgstr ""
+msgstr "Sea nähtavus sisse/välja"
#: editor/scene_tree_editor.cpp
msgid ""
@@ -11896,6 +11906,26 @@ msgid ""
"\"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\" "
@@ -12156,6 +12186,26 @@ msgid ""
"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-"
diff --git a/editor/translations/eu.po b/editor/translations/eu.po
index 8a0aab6f15..e27515849d 100644
--- a/editor/translations/eu.po
+++ b/editor/translations/eu.po
@@ -1061,7 +1061,7 @@ msgstr "Baliabide umezurtzen arakatzailea"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3543,6 +3543,16 @@ 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 ""
@@ -3590,23 +3600,11 @@ msgstr ""
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr ""
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr ""
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr ""
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr ""
@@ -3629,10 +3627,15 @@ msgid "Collapse All"
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"
+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
@@ -3668,7 +3671,10 @@ msgid "Move"
msgstr "Mugitu"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
+#: 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
@@ -9444,6 +9450,10 @@ 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"
@@ -11865,6 +11875,26 @@ msgid ""
"\"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\" "
@@ -12125,6 +12155,26 @@ msgid ""
"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-"
diff --git a/editor/translations/fa.po b/editor/translations/fa.po
index bdbb10725c..f7bef53811 100644
--- a/editor/translations/fa.po
+++ b/editor/translations/fa.po
@@ -1100,7 +1100,7 @@ msgstr "پوینده‌ی منبع جدا اÙتاده"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3624,6 +3624,16 @@ 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
#, fuzzy
msgid "Renaming file:"
msgstr "تغییر متغیر"
@@ -3678,26 +3688,12 @@ msgstr ""
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "تغییر نام..."
-
-#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Duplicate..."
-msgstr "انتخاب شده را به دو تا تکثیر کن"
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
#, fuzzy
-msgid "Move to Trash"
-msgstr "بارگیری خودکار را انجام دهید"
-
-#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "New Scene..."
msgstr "صحنه جدید"
@@ -3723,11 +3719,18 @@ msgid "Collapse All"
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 "تغییر نام"
+#, fuzzy
+msgid "Duplicate..."
+msgstr "انتخاب شده را به دو تا تکثیر کن"
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "بارگیری خودکار را انجام دهید"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "تغییر نام..."
#: editor/filesystem_dock.cpp
#, fuzzy
@@ -3764,8 +3767,11 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr ""
+#: 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"
@@ -9899,6 +9905,10 @@ 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"
@@ -12503,6 +12513,26 @@ msgid ""
"\"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
#, fuzzy
msgid ""
@@ -12797,6 +12827,26 @@ msgid ""
"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
#, fuzzy
msgid ""
diff --git a/editor/translations/fi.po b/editor/translations/fi.po
index 2c5d6290f7..7a47df373d 100644
--- a/editor/translations/fi.po
+++ b/editor/translations/fi.po
@@ -15,7 +15,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-11-20 23:08+0000\n"
+"PO-Revision-Date: 2020-11-29 08:29+0000\n"
"Last-Translator: Tapani Niemi <tapani.niemi@kapsi.fi>\n"
"Language-Team: Finnish <https://hosted.weblate.org/projects/godot-engine/"
"godot/fi/>\n"
@@ -1091,7 +1091,7 @@ msgstr "Irrallisten resurssien hallinta"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3700,6 +3700,16 @@ msgid "Name contains invalid characters."
msgstr "Nimi sisältää virheellisiä kirjainmerkkejä."
#: 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 "Nimetään tiedosto uudelleen:"
@@ -3747,23 +3757,11 @@ msgstr "Muokkaa riippuvuuksia..."
msgid "View Owners..."
msgstr "Tarkastele omistajia..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Nimeä uudelleen..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "Kahdenna..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "Siirrä..."
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr "Siirrä roskakoriin"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "Uusi skene..."
@@ -3786,11 +3784,16 @@ msgid "Collapse All"
msgstr "Tiivistä kaikki"
#: 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 "Nimeä uudelleen"
+msgid "Duplicate..."
+msgstr "Kahdenna..."
+
+#: editor/filesystem_dock.cpp
+msgid "Move to Trash"
+msgstr "Siirrä roskakoriin"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "Nimeä uudelleen..."
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -3825,8 +3828,11 @@ msgid "Move"
msgstr "Siirrä"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "Tästä sijainnista löytyy jo samanniminen tiedosto tai kansio."
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr "Nimeä uudelleen"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
@@ -8316,23 +8322,20 @@ msgid "Create a new rectangle."
msgstr "Luo uusi suorakulmio."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Rectangle"
-msgstr "Suorakaidetäyttö"
+msgstr "Uusi suorakaide"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new polygon."
msgstr "Luo uusi polygoni."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Polygon"
-msgstr "Siirrä polygonia"
+msgstr "Uusi polygoni"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete Selected Shape"
-msgstr "Poista valitut"
+msgstr "Poista valittu muoto"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Keep polygon inside region Rect."
@@ -9808,6 +9811,10 @@ msgid "OpenGL ES 3.0"
msgstr "OpenGL ES 3.0"
#: 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"
@@ -12386,6 +12393,26 @@ msgstr ""
"CPUParticles2D animaatio edellyttää CanvasItemMaterial käyttöä niin että "
"\"Particles Animation\" on kytketty päälle."
+#: 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\" "
@@ -12716,6 +12743,26 @@ msgstr ""
"jäykkätilassa) ajon aikana.\n"
"Muuta sen sijaan solmun alla olevia törmäysmuotoja."
+#: 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-"
@@ -12957,6 +13004,9 @@ msgstr "Varying tyypin voi sijoittaa vain vertex-funktiossa."
msgid "Constants cannot be modified."
msgstr "Vakioita ei voi muokata."
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "Tästä sijainnista löytyy jo samanniminen tiedosto tai kansio."
+
#~ msgid "Missing 'build-tools' directory!"
#~ msgstr "'build-tools' hakemisto puuttuu!"
diff --git a/editor/translations/fil.po b/editor/translations/fil.po
index 542596ed45..c430475062 100644
--- a/editor/translations/fil.po
+++ b/editor/translations/fil.po
@@ -1064,7 +1064,7 @@ msgstr ""
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3543,6 +3543,16 @@ 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 ""
@@ -3590,23 +3600,11 @@ msgstr ""
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr ""
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr ""
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr ""
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr ""
@@ -3629,10 +3627,15 @@ msgid "Collapse All"
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"
+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
@@ -3666,7 +3669,10 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
+#: 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
@@ -9447,6 +9453,10 @@ 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"
@@ -11866,6 +11876,26 @@ msgid ""
"\"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\" "
@@ -12126,6 +12156,26 @@ msgid ""
"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-"
diff --git a/editor/translations/fr.po b/editor/translations/fr.po
index b5bb7cbdcd..3085e78d7b 100644
--- a/editor/translations/fr.po
+++ b/editor/translations/fr.po
@@ -81,7 +81,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-11-26 08:43+0000\n"
+"PO-Revision-Date: 2020-12-10 14:11+0100\n"
"Last-Translator: Rémi Verschelde <akien@godotengine.org>\n"
"Language-Team: French <https://hosted.weblate.org/projects/godot-engine/"
"godot/fr/>\n"
@@ -90,7 +90,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
-"X-Generator: Weblate 4.4-dev\n"
+"X-Generator: Poedit 2.4.2\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1172,7 +1172,7 @@ msgstr "Explorateur de ressources orphelines"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3815,6 +3815,22 @@ msgid "Name contains invalid characters."
msgstr "Le nom contient des caractères invalides."
#: 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 ""
+"Les fichiers ou dossiers suivants entrent en conflit avec des éléments de la "
+"destination '%s' :\n"
+"\n"
+"%s\n"
+"\n"
+"Souhaitez-vous les écraser ?"
+
+#: editor/filesystem_dock.cpp
msgid "Renaming file:"
msgstr "Renommer le fichier :"
@@ -3862,23 +3878,11 @@ msgstr "Modifier les dépendances…"
msgid "View Owners..."
msgstr "Voir les propriétaires…"
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Renommer..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "Dupliquer…"
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "Déplacer vers…"
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr "Déplacer vers la corbeille"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "Nouvelle scène..."
@@ -3901,11 +3905,16 @@ msgid "Collapse All"
msgstr "Réduire tout"
#: 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 "Renommer"
+msgid "Duplicate..."
+msgstr "Dupliquer…"
+
+#: editor/filesystem_dock.cpp
+msgid "Move to Trash"
+msgstr "Déplacer vers la corbeille"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "Renommer..."
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -3940,9 +3949,11 @@ msgid "Move"
msgstr "Déplacer"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr ""
-"Il existe déjà un fichier ou un dossier ayant le même nom à cet emplacement."
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr "Renommer"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
@@ -9959,6 +9970,10 @@ msgid "OpenGL ES 3.0"
msgstr "OpenGL ES 3.0"
#: editor/project_manager.cpp
+msgid "Not supported by your GPU drivers."
+msgstr "Non supporté par les drivers de votre carte graphique."
+
+#: editor/project_manager.cpp
msgid ""
"Higher visual quality\n"
"All features available\n"
@@ -12569,6 +12584,26 @@ msgstr ""
"L'animation de CPUParticles2D a besoin d'un CanvasItemMaterial avec "
"« Particles Animation » activé."
+#: scene/2d/joints_2d.cpp
+msgid "Node A and Node B must be PhysicsBody2Ds"
+msgstr "Node A et Node B doivent être des PhysicsBody2D"
+
+#: scene/2d/joints_2d.cpp
+msgid "Node A must be a PhysicsBody2D"
+msgstr "Node A doit être un PhysicsBody2D"
+
+#: scene/2d/joints_2d.cpp
+msgid "Node B must be a PhysicsBody2D"
+msgstr "Node B doit être un PhysicsBody2D"
+
+#: 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\" "
@@ -12909,6 +12944,26 @@ msgstr ""
"rigide) seront remplacées par le moteur physique lors de l'exécution.\n"
"Modifiez la taille dans les formes de collision enfant à la place."
+#: scene/3d/physics_joint.cpp
+msgid "Node A and Node B must be PhysicsBodies"
+msgstr "Node A et Node B doivent être des PhysicsBody"
+
+#: scene/3d/physics_joint.cpp
+msgid "Node A must be a PhysicsBody"
+msgstr "Node A doit être un PhysicsBody"
+
+#: scene/3d/physics_joint.cpp
+msgid "Node B must be a PhysicsBody"
+msgstr "Node B doit être un PhysicsBody"
+
+#: scene/3d/physics_joint.cpp
+msgid "Joint is not connected to any PhysicsBodies"
+msgstr "Le joint n'est connecté à aucun PhysicsBody"
+
+#: scene/3d/physics_joint.cpp
+msgid "Node A and Node B must be different PhysicsBodies"
+msgstr "Node A et Node B doivent être des PhysicsBody différents"
+
#: scene/3d/remote_transform.cpp
msgid ""
"The \"Remote Path\" property must point to a valid Spatial or Spatial-"
@@ -13156,6 +13211,11 @@ msgstr "Les variations ne peuvent être affectées que dans la fonction vertex."
msgid "Constants cannot be modified."
msgstr "Les constantes ne peuvent être modifiées."
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr ""
+#~ "Il existe déjà un fichier ou un dossier ayant le même nom à cet "
+#~ "emplacement."
+
#~ msgid "Missing 'build-tools' directory!"
#~ msgstr "Dossier « build-tools » manquant !"
diff --git a/editor/translations/ga.po b/editor/translations/ga.po
index 025d5778f8..971c0b0bec 100644
--- a/editor/translations/ga.po
+++ b/editor/translations/ga.po
@@ -1057,7 +1057,7 @@ msgstr ""
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3536,6 +3536,16 @@ 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 ""
@@ -3583,23 +3593,11 @@ msgstr ""
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr ""
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr ""
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr ""
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr ""
@@ -3622,10 +3620,15 @@ msgid "Collapse All"
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"
+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
@@ -3659,7 +3662,10 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
+#: 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
@@ -9442,6 +9448,10 @@ msgid "OpenGL ES 3.0"
msgstr "OpenGL ES 3.0"
#: 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"
@@ -11862,6 +11872,26 @@ msgid ""
"\"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\" "
@@ -12122,6 +12152,26 @@ msgid ""
"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-"
diff --git a/editor/translations/he.po b/editor/translations/he.po
index 5ac3e3f060..ebccec8d4b 100644
--- a/editor/translations/he.po
+++ b/editor/translations/he.po
@@ -22,7 +22,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-11-25 14:10+0000\n"
+"PO-Revision-Date: 2020-12-03 19:28+0000\n"
"Last-Translator: Ziv D <wizdavid@gmail.com>\n"
"Language-Team: Hebrew <https://hosted.weblate.org/projects/godot-engine/"
"godot/he/>\n"
@@ -1098,7 +1098,7 @@ msgstr "דפדפן מש××‘×™× ×™×ª×•×ž×™×"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3683,6 +3683,16 @@ 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 "שינוי ×©× ×”×§×•×‘×¥:"
@@ -3734,25 +3744,12 @@ msgstr "עריכת תלויות…"
msgid "View Owners..."
msgstr "צפייה בבעלי×…"
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "שינוי ש×…"
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "שכפול…"
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "העברה ×ל…"
#: editor/filesystem_dock.cpp
#, fuzzy
-msgid "Move to Trash"
-msgstr "הזזת טעינה ×וטומטית"
-
-#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "New Scene..."
msgstr "סצנה חדשה"
@@ -3779,11 +3776,17 @@ msgid "Collapse All"
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 "שינוי ש×"
+msgid "Duplicate..."
+msgstr "שכפול…"
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "הזזת טעינה ×וטומטית"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "שינוי ש×…"
#: editor/filesystem_dock.cpp
#, fuzzy
@@ -3822,9 +3825,11 @@ msgid "Move"
msgstr "העברה"
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "There is already file or folder with the same name in this location."
-msgstr "כבר ×§×™×™×ž×™× ×§×•×‘×¥ ×ו תיקייה ×‘×©× ×”×–×”."
+#: 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"
@@ -5133,29 +5138,27 @@ msgstr "קטגוריה:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Site:"
-msgstr ""
+msgstr "×תר:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Support"
-msgstr "ייבו×"
+msgstr "תמיכה"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Official"
-msgstr ""
+msgstr "רשמי"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Testing"
-msgstr ""
+msgstr "בבדיקה"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Loading..."
-msgstr "טעינה"
+msgstr "בטעינה…"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Assets ZIP File"
-msgstr ""
+msgstr "קובץ ZIP של נכסי×"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
@@ -5163,58 +5166,60 @@ msgid ""
"Save your scene (for images to be saved in the same dir), or pick a save "
"path from the BakedLightmap properties."
msgstr ""
+"×ין ×פשרות לקבוע נתיב שמירה עבור תמונות lightmap.\n"
+"שמור/×™ ×ת הסצינה שלך (כדי שתמונות יישמרו ב×ותה תיקייה), ×ו בחר/×™ נתיב שמירה "
+"ממ×פייני BakedLightmap."
#: 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 ""
+msgstr "×ין רשתות ל×פייה. וד×/×™ ×©×”× ×ž×›×™×œ×™× ×¢×¨×•×¥ UV2 והדגל 'Bake Light' מ×ופשר."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Failed creating lightmap images, make sure path is writable."
-msgstr ""
+msgstr "יצירת תמונות lightmap נכשלה, וד×/×™ שהנתיב ניתן לכתיבה."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Bake Lightmaps"
-msgstr ""
+msgstr "×פיית Lightmaps"
#: editor/plugins/camera_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Preview"
-msgstr ""
+msgstr "תצוגה מקדימה"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Configure Snap"
-msgstr ""
+msgstr "הגדרת הצמדה"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Grid Offset:"
-msgstr ""
+msgstr "היסט רשת:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Grid Step:"
-msgstr ""
+msgstr "שלב רשת:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Primary Line Every:"
-msgstr ""
+msgstr "קו ר×שי כל:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "steps"
-msgstr ""
+msgstr "צעדי×"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotation Offset:"
-msgstr ""
+msgstr "היסט סיבוב:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotation Step:"
-msgstr ""
+msgstr "צעד סיבוב:"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Scale Step:"
-msgstr "יחס מתיחה:"
+msgstr "צעד קנה מידה:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Move Vertical Guide"
@@ -9893,6 +9898,10 @@ 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"
@@ -12400,6 +12409,26 @@ msgstr ""
"הנפשת CPUParticles2D מחייבת שימוש ב-CanvasItemMaterial ×¢× \"הנפשת חלקיקי×\" "
"מ×ופשרת."
+#: 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\" "
@@ -12703,6 +12732,26 @@ msgstr ""
"הפיזיקה בזמן ריצה.\n"
"×‘×ž×§×•× ×–×ת יש לשנות ×ת גודל צורות ההתנגשות של הצ×צ××™×."
+#: 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-"
@@ -12934,6 +12983,10 @@ msgstr "ניתן להקצות ×©×™× ×•×™×™× ×¨×§ בפונקצית vertex."
msgid "Constants cannot be modified."
msgstr "××™ ×פשר לשנות קבועי×."
+#, fuzzy
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "כבר ×§×™×™×ž×™× ×§×•×‘×¥ ×ו תיקייה ×‘×©× ×”×–×”."
+
#~ msgid "Error trying to save layout!"
#~ msgstr "שמירת הפריסה נכשלה!"
diff --git a/editor/translations/hi.po b/editor/translations/hi.po
index de3b8630ab..03fbdc1971 100644
--- a/editor/translations/hi.po
+++ b/editor/translations/hi.po
@@ -1089,7 +1089,7 @@ msgstr "अनाथ संसाधन à¤à¤•à¥à¤¸à¤ªà¥à¤²à¥‹à¤°à¤°"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3670,6 +3670,16 @@ 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 "फ़ाइल का नाम बदल रहे है:"
@@ -3717,24 +3727,11 @@ msgstr "निरà¥à¤­à¤°à¤¿à¤¤ फ़ाइलें संपादित क
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr ""
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "डà¥à¤ªà¥à¤²à¤¿à¤•à¥‡à¤Ÿ..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Move to Trash"
-msgstr "औटोलोड हिलाइये"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "नया दृशà¥à¤¯..."
@@ -3757,10 +3754,16 @@ msgid "Collapse All"
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"
+msgid "Duplicate..."
+msgstr "डà¥à¤ªà¥à¤²à¤¿à¤•à¥‡à¤Ÿ..."
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "औटोलोड हिलाइये"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
msgstr ""
#: editor/filesystem_dock.cpp
@@ -3794,7 +3797,10 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
+#: 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
@@ -9659,6 +9665,10 @@ 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"
@@ -12125,6 +12135,26 @@ msgid ""
"\"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\" "
@@ -12385,6 +12415,26 @@ msgid ""
"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-"
diff --git a/editor/translations/hr.po b/editor/translations/hr.po
index 3b79d58af0..c762ff0562 100644
--- a/editor/translations/hr.po
+++ b/editor/translations/hr.po
@@ -1071,7 +1071,7 @@ msgstr "IstraživaÄ napuÅ¡tenih resursa"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3548,6 +3548,16 @@ 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 ""
@@ -3595,24 +3605,11 @@ msgstr ""
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr ""
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr ""
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Move to Trash"
-msgstr "Premjesti Autoload"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr ""
@@ -3635,10 +3632,16 @@ msgid "Collapse All"
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"
+msgid "Duplicate..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "Premjesti Autoload"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
msgstr ""
#: editor/filesystem_dock.cpp
@@ -3672,7 +3675,10 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
+#: 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
@@ -9457,6 +9463,10 @@ 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"
@@ -11878,6 +11888,26 @@ msgid ""
"\"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\" "
@@ -12138,6 +12168,26 @@ msgid ""
"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-"
diff --git a/editor/translations/hu.po b/editor/translations/hu.po
index dfa4c1255c..bd67e49dfd 100644
--- a/editor/translations/hu.po
+++ b/editor/translations/hu.po
@@ -12,12 +12,14 @@
# sztrovacsek <magadeve@gmail.com>, 2019.
# Ãcs Zoltán <acszoltan111@gmail.com>, 2020.
# cefrebevalo <szmarci711@gmail.com>, 2020.
+# thekeymethod <csokan.andras87@protonmail.ch>, 2020.
+# Czmorek Dávid <czmdav.soft@gmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-09-22 03:23+0000\n"
-"Last-Translator: Ãcs Zoltán <acszoltan111@gmail.com>\n"
+"PO-Revision-Date: 2020-12-07 08:11+0000\n"
+"Last-Translator: Czmorek Dávid <czmdav.soft@gmail.com>\n"
"Language-Team: Hungarian <https://hosted.weblate.org/projects/godot-engine/"
"godot/hu/>\n"
"Language: hu\n"
@@ -25,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.3-dev\n"
+"X-Generator: Weblate 4.4-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -34,9 +36,8 @@ msgstr ""
"Érvénytelen típusargumentum a convert()-hez használjon TYPE_* konstansokat."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
-#, fuzzy
msgid "Expected a string of length 1 (a character)."
-msgstr "Egy hosszúságú karaktersorozat szükséges."
+msgstr "Szöveg elvárt hossza 1 ( egy karakter)."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/mono/glue/gd_glue.cpp
@@ -58,7 +59,7 @@ msgstr "Érvénytelen operandusok az %s, %s és %s operátorhoz."
#: core/math/expression.cpp
msgid "Invalid index of type %s for base type %s"
-msgstr ""
+msgstr "Érvénytelen %s típusú index %s típusú alaphoz"
#: core/math/expression.cpp
msgid "Invalid named index '%s' for base type %s"
@@ -66,7 +67,7 @@ msgstr "Érvénytelen nevezett index '%s' %s alaptípushoz"
#: core/math/expression.cpp
msgid "Invalid arguments to construct '%s'"
-msgstr ""
+msgstr "Érvénytelen argumentumok a(z) '%s' építőben"
#: core/math/expression.cpp
msgid "On call to '%s':"
@@ -122,127 +123,120 @@ msgstr "Érték:"
#: editor/animation_bezier_editor.cpp
msgid "Insert Key Here"
-msgstr "Kulcs beszúrása"
+msgstr "Kulcs Beszúrása Ide"
#: editor/animation_bezier_editor.cpp
msgid "Duplicate Selected Key(s)"
-msgstr "Kiválasztott kulcs(ok) megkettőzése"
+msgstr "Kiválasztott Kulcs(ok) Megkettőzése"
#: editor/animation_bezier_editor.cpp
msgid "Delete Selected Key(s)"
-msgstr "Kiválasztott kulcs(ok) törlése"
+msgstr "Kiválasztott Kulcs(ok) Törlése"
#: editor/animation_bezier_editor.cpp
msgid "Add Bezier Point"
-msgstr "Bézier pont hozzáadása"
+msgstr "Bézier Pont Hozzáadása"
#: editor/animation_bezier_editor.cpp
msgid "Move Bezier Points"
-msgstr "Bézier pontok áthelyezése"
+msgstr "Bézier Pontok Mozgatása"
#: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp
msgid "Anim Duplicate Keys"
-msgstr "Animáció kulcsok megkettőzése"
+msgstr "Animáció - Kulcsok Megkettőzése"
#: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp
msgid "Anim Delete Keys"
-msgstr "Animáció kulcsok törlése"
+msgstr "Animáció - Kulcsok Törlése"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Change Keyframe Time"
-msgstr "Animáció kulcsképkocka idő változtatás"
+msgstr "Animáció - Kulcskép Idő Változtatása"
#: editor/animation_track_editor.cpp
msgid "Anim Change Transition"
-msgstr "Animáció átmenet változtatása"
+msgstr "Animáció - Ãtmenet Változtatása"
#: editor/animation_track_editor.cpp
msgid "Anim Change Transform"
-msgstr "Animáció transzformáció változtatás"
+msgstr "Animáció - Transzformáció Változtatása"
#: editor/animation_track_editor.cpp
msgid "Anim Change Keyframe Value"
-msgstr "Animáció kulcsképkocka érték változtatás"
+msgstr "Animáció - Kulcskép Érték Változtatása"
#: editor/animation_track_editor.cpp
msgid "Anim Change Call"
-msgstr "Animáció hívás változtatás"
+msgstr "Animáció - Hívás Változtatása"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Multi Change Keyframe Time"
-msgstr "Animáció kulcsképkocka idő változtatás"
+msgstr "Animáció - Több Kulcskép Idő Változtatása"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Multi Change Transition"
-msgstr "Animáció átmenet változtatása"
+msgstr "Animáció - Több Ãtmenet Változtatása"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Multi Change Transform"
-msgstr "Animáció transzformáció változtatás"
+msgstr "Animáció - Több Transzformáció Változtatása"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Multi Change Keyframe Value"
-msgstr "Animáció kulcsképkocka érték változtatás"
+msgstr "Animáció - Több Kulcskép Érték Változtatása"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Multi Change Call"
-msgstr "Animáció hívás változtatás"
+msgstr "Animáció - Több Hívás Változtatása"
#: editor/animation_track_editor.cpp
msgid "Change Animation Length"
-msgstr "Animáció hosszának változtatása"
+msgstr "Animáció Hosszának Változtatása"
#: editor/animation_track_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Change Animation Loop"
-msgstr "Animációs ciklus változtatása"
+msgstr "Animáció Ismétlésének Változtatása"
#: editor/animation_track_editor.cpp
msgid "Property Track"
-msgstr "Tulajdonságkövetés"
+msgstr "Tulajdonság Sáv"
#: editor/animation_track_editor.cpp
msgid "3D Transform Track"
-msgstr ""
+msgstr "3D Transzform Sáv"
#: editor/animation_track_editor.cpp
msgid "Call Method Track"
-msgstr "Hívás módszer követése"
+msgstr "Metódus Hívás Sáv"
#: editor/animation_track_editor.cpp
msgid "Bezier Curve Track"
-msgstr "Bézier görbe nyomvonal"
+msgstr "Bézier Görbe Sáv"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Audio Playback Track"
-msgstr "Hang lejátszás követése"
+msgstr "Hang Lejátszás Sáv"
#: editor/animation_track_editor.cpp
msgid "Animation Playback Track"
-msgstr ""
+msgstr "Animáció Lejátszás Sáv"
#: editor/animation_track_editor.cpp
msgid "Animation length (frames)"
-msgstr "Animáció hossza (képkockákban)"
+msgstr "Animáció hossza (képkockák)"
#: editor/animation_track_editor.cpp
msgid "Animation length (seconds)"
-msgstr "Animáció hossza (másodpercben)"
+msgstr "Animáció hossza (másodpercek)"
#: editor/animation_track_editor.cpp
msgid "Add Track"
-msgstr "Nyomvonal hozzáadása"
+msgstr "Sáv Hozzáadása"
#: editor/animation_track_editor.cpp
msgid "Animation Looping"
-msgstr "Animáció ismétlése"
+msgstr "Animáció Ismétlése"
#: editor/animation_track_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
@@ -250,39 +244,36 @@ msgid "Functions:"
msgstr "Függvények:"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Audio Clips:"
-msgstr "Audió klipek:"
+msgstr "Hang Klipek:"
#: editor/animation_track_editor.cpp
msgid "Anim Clips:"
-msgstr "Animáció klipek:"
+msgstr "Animáció Klipek:"
#: editor/animation_track_editor.cpp
msgid "Change Track Path"
-msgstr ""
+msgstr "Sáv Útvonal Változtatás"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Toggle this track on/off."
-msgstr "A sáv ki/be kapcsolása."
+msgstr "Jelen sáv ki/be kapcsolása."
#: editor/animation_track_editor.cpp
msgid "Update Mode (How this property is set)"
-msgstr ""
+msgstr "Frissítés Módja (Hogyan van ez a tulajdonság beállítva)"
#: editor/animation_track_editor.cpp
msgid "Interpolation Mode"
-msgstr "Interpolációs mód"
+msgstr "Interpolálás Módja"
#: editor/animation_track_editor.cpp
msgid "Loop Wrap Mode (Interpolate end with beginning on loop)"
-msgstr ""
+msgstr "Összefűzés Módja (Vége és kezdete interpolálása ismétlés esetén)"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Remove this track."
-msgstr "Kiválasztott nyomvonal eltávolítása."
+msgstr "Jelen sáv eltávolítása."
#: editor/animation_track_editor.cpp
msgid "Time (s): "
@@ -290,7 +281,7 @@ msgstr "Idő (mp): "
#: editor/animation_track_editor.cpp
msgid "Toggle Track Enabled"
-msgstr ""
+msgstr "Sáv Engedélyezés Kapcsolása"
#: editor/animation_track_editor.cpp
msgid "Continuous"
@@ -298,7 +289,7 @@ msgstr "Folyamatos"
#: editor/animation_track_editor.cpp
msgid "Discrete"
-msgstr "Diszkrét"
+msgstr "Pontozott"
#: editor/animation_track_editor.cpp
msgid "Trigger"
@@ -323,48 +314,48 @@ msgstr "Köbös"
#: editor/animation_track_editor.cpp
msgid "Clamp Loop Interp"
-msgstr ""
+msgstr "Ãtmenet Nélküli Interpoláció"
#: editor/animation_track_editor.cpp
msgid "Wrap Loop Interp"
-msgstr ""
+msgstr "Folytatólagos Interpoláció"
#: editor/animation_track_editor.cpp
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Insert Key"
-msgstr "Kulcs beszúrása"
+msgstr "Kulcs Beszúrása"
#: editor/animation_track_editor.cpp
msgid "Duplicate Key(s)"
-msgstr "Kulcs(ok) megkettőzése"
+msgstr "Kulcs(ok) Megkettőzése"
#: editor/animation_track_editor.cpp
msgid "Delete Key(s)"
-msgstr "Kulcs(ok) törlése"
+msgstr "Kulcs(ok) Törlése"
#: editor/animation_track_editor.cpp
msgid "Change Animation Update Mode"
-msgstr "Animáció frissítés módjának megváltoztatása"
+msgstr "Animáció Frissítés Módjának Változtatása"
#: editor/animation_track_editor.cpp
msgid "Change Animation Interpolation Mode"
-msgstr ""
+msgstr "Animáció Interpolálás Módjának Változtatása"
#: editor/animation_track_editor.cpp
msgid "Change Animation Loop Mode"
-msgstr "Animáció hurok mód változtatása"
+msgstr "Animáció Összefűzés Módjának Változtatása"
#: editor/animation_track_editor.cpp
msgid "Remove Anim Track"
-msgstr "Animáció nyomvonal eltávolítás"
+msgstr "Animáció Sáv Eltávolítása"
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
-msgstr "ÚJ nyomvonalat hoz létre a következőhöz: %s, és beszúrja a kulcsot?"
+msgstr "Létrehoz ÚJ sávot a következőhöz: %s, és beszúrja a kulcsot?"
#: editor/animation_track_editor.cpp
msgid "Create %d NEW tracks and insert keys?"
-msgstr "Létrehoz %d ÚJ nyomvonalat és beszúrja a kulcsokat?"
+msgstr "Létrehoz %d ÚJ sávot és beszúrja a kulcsokat?"
#: editor/animation_track_editor.cpp editor/create_dialog.cpp
#: editor/editor_audio_buses.cpp editor/editor_feature_profile.cpp
@@ -380,36 +371,39 @@ msgstr "Létrehozás"
#: editor/animation_track_editor.cpp
msgid "Anim Insert"
-msgstr "Animáció beszúrása"
+msgstr "Animáció - Beszúrás"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "AnimationPlayer can't animate itself, only other players."
-msgstr "Az AnimationPlayer nem tudja animálni önmagát, csak más játékosokat."
+msgstr ""
+"AnimationPlayer nem tudja önmagát animálni, csak más AnimationPlayer "
+"elemeket."
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
-msgstr "Animáció létrehozása és beillesztése"
+msgstr "Animáció - Létrehozás és Beillesztés"
#: editor/animation_track_editor.cpp
msgid "Anim Insert Track & Key"
-msgstr "Animáció nyomvonal és kulcs beszúrása"
+msgstr "Animáció - Sáv és Kulcs Beszúrása"
#: editor/animation_track_editor.cpp
msgid "Anim Insert Key"
-msgstr "Animáció kulcs beillesztés"
+msgstr "Animáció - Kulcs Beszúrása"
#: editor/animation_track_editor.cpp
msgid "Change Animation Step"
-msgstr "Animáció léptékének megváltoztatása"
+msgstr "Animáció Léptékének Változtatása"
#: editor/animation_track_editor.cpp
msgid "Rearrange Tracks"
-msgstr ""
+msgstr "Sávok Újrarendezése"
#: editor/animation_track_editor.cpp
msgid "Transform tracks only apply to Spatial-based nodes."
msgstr ""
+"A transzform sávok csak a Spatial típusú vagy azt bővítő elemekre "
+"vonatkoznak."
#: editor/animation_track_editor.cpp
msgid ""
@@ -418,59 +412,64 @@ msgid ""
"-AudioStreamPlayer2D\n"
"-AudioStreamPlayer3D"
msgstr ""
+"Hang sávok csak a következő típusú node-ra mutathatnak:\n"
+"-AudioStreamPlayer\n"
+"-AudioStreamPlayer2D\n"
+"-AudioStreamPlayer3D"
#: editor/animation_track_editor.cpp
msgid "Animation tracks can only point to AnimationPlayer nodes."
-msgstr ""
+msgstr "Animáció sávok csak AnimationPlayer node-ra mutathatnak."
#: editor/animation_track_editor.cpp
msgid "An animation player can't animate itself, only other players."
msgstr ""
+"Egy AnimationPlayer nem tudja önmagát animálni, csak más AnimationPlayer "
+"node-okat."
#: editor/animation_track_editor.cpp
msgid "Not possible to add a new track without a root"
-msgstr ""
+msgstr "Új sáv hozzáadása nem lehetséges gyökér nélkül"
#: editor/animation_track_editor.cpp
msgid "Invalid track for Bezier (no suitable sub-properties)"
-msgstr ""
+msgstr "Érvénytelen sáv Bezier számára (nincs megfelelő al-tulajdonság)"
#: editor/animation_track_editor.cpp
msgid "Add Bezier Track"
-msgstr ""
+msgstr "Beizer Sáv Hozzáadása"
#: editor/animation_track_editor.cpp
msgid "Track path is invalid, so can't add a key."
-msgstr ""
+msgstr "Sáv elérési útja helytelen, kulcs hozzáadása nem lehetséges."
#: editor/animation_track_editor.cpp
msgid "Track is not of type Spatial, can't insert key"
-msgstr ""
+msgstr "Sáv típusa nem Spatial, kulcs hozzáadása nem lehetséges"
#: editor/animation_track_editor.cpp
msgid "Add Transform Track Key"
-msgstr ""
+msgstr "Transzform Sáv Kulcs hozzáadása"
#: editor/animation_track_editor.cpp
msgid "Add Track Key"
-msgstr "Nyomvonal kulcs hozzáadása"
+msgstr "Sáv Kulcs Hozzáadása"
#: editor/animation_track_editor.cpp
msgid "Track path is invalid, so can't add a method key."
-msgstr ""
+msgstr "Sáv elérési útja helytelen, kulcs hozzáadása nem lehetséges."
#: editor/animation_track_editor.cpp
msgid "Add Method Track Key"
-msgstr "Metódus nyomvonal kulcs beillesztése"
+msgstr "Metódus Sáv Kulcs Hozzáadása"
#: editor/animation_track_editor.cpp
msgid "Method not found in object: "
msgstr "A metódus nem található az objektumban: "
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Move Keys"
-msgstr "Animáció kulcsok mozgatása"
+msgstr "Animáció - Kulcsok Mozgatása"
#: editor/animation_track_editor.cpp
msgid "Clipboard is empty"
@@ -478,17 +477,17 @@ msgstr "A vágólap üres"
#: editor/animation_track_editor.cpp
msgid "Paste Tracks"
-msgstr "Nyomvonalak beillesztése"
+msgstr "Sávok beillesztése"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Scale Keys"
-msgstr "Animáció kulcsok nyújtás"
+msgstr "Animáció - Kulcsok Nyújtása"
#: editor/animation_track_editor.cpp
msgid ""
"This option does not work for Bezier editing, as it's only a single track."
msgstr ""
+"Ez az opció nem működik Bezier szerkesztésre, mert ez csak egyetlen sáv."
#: editor/animation_track_editor.cpp
msgid ""
@@ -502,6 +501,15 @@ msgid ""
"Alternatively, use an import preset that imports animations to separate "
"files."
msgstr ""
+"Ez az animáció egy importált jelenethez tartozik, ezért az importált sávok "
+"módosításai nem lesznek mentve.\n"
+"\n"
+"Egyedi sávok hozzáadásának engedélyezéséhez navigáljon a jelenet importálás "
+"beállításaihoz, állítsa be\n"
+"\"Animation > Storage\" értékét \"Files\"-ra, engedélyezze a(z) \"Animation "
+"> Keep Custom Tracks\" opciót, majd importálja újra.\n"
+"Egy másik megoldás, ha olyan import előbeállítást használ, ami az "
+"animációkat külön fájlba importálja."
#: editor/animation_track_editor.cpp
msgid "Warning: Editing imported animation"
@@ -515,11 +523,12 @@ msgstr ""
#: editor/animation_track_editor.cpp
msgid "Only show tracks from nodes selected in tree."
-msgstr ""
+msgstr "Csak a fában kiválosztott node-ok sávjainak megjelenítése."
#: editor/animation_track_editor.cpp
msgid "Group tracks by node or display them as plain list."
msgstr ""
+"Sávok csoportosítása node-ok szerint, vagy megjelenítés egyszerű listaként."
#: editor/animation_track_editor.cpp
msgid "Snap:"
@@ -554,44 +563,43 @@ msgstr "Animáció tulajdonságok."
#: editor/animation_track_editor.cpp
msgid "Copy Tracks"
-msgstr "Nyomvonalak másolása"
+msgstr "Sávok Másolása"
#: editor/animation_track_editor.cpp
msgid "Scale Selection"
-msgstr "Kijelölés átméretezése"
+msgstr "Kijelölés Nyújtása"
#: editor/animation_track_editor.cpp
msgid "Scale From Cursor"
-msgstr "Ãtméretezés a kurzortól"
+msgstr "Nyújtás a Kurzortól"
#: editor/animation_track_editor.cpp modules/gridmap/grid_map_editor_plugin.cpp
msgid "Duplicate Selection"
-msgstr "Kijelölés megkettőzése"
+msgstr "Kijelölés Megkettőzése"
#: editor/animation_track_editor.cpp
msgid "Duplicate Transposed"
-msgstr "Ãthelyezettek megkettÅ‘zése"
+msgstr "Ãthelyezettek MegkettÅ‘zése"
#: editor/animation_track_editor.cpp
msgid "Delete Selection"
-msgstr "Kijelölés törlése"
+msgstr "Kijelölés Törlése"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Go to Next Step"
-msgstr "Ugrás a következő lépésre"
+msgstr "Ugrás a Következő Lépésre"
#: editor/animation_track_editor.cpp
msgid "Go to Previous Step"
-msgstr "Ugrás az előző lépésre"
+msgstr "Ugrás az Előző Lépésre"
#: editor/animation_track_editor.cpp
msgid "Optimize Animation"
-msgstr "Animáció optimalizálása"
+msgstr "Animáció Optimalizálása"
#: editor/animation_track_editor.cpp
msgid "Clean-Up Animation"
-msgstr "Animáció tisztítása"
+msgstr "Animáció Tisztítása"
#: editor/animation_track_editor.cpp
msgid "Pick the node that will be animated:"
@@ -1096,7 +1104,7 @@ msgstr "Ãrva Forrás KezelÅ‘"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3404,7 +3412,7 @@ msgstr "Nem sikerült a szkript futtatása:"
#: editor/editor_run_script.cpp
msgid "Did you forget the '_run' method?"
-msgstr "Nem felejtette el a '_run' metódust?"
+msgstr "Elfelejtette a '_run' metódust?"
#: editor/editor_spin_slider.cpp
msgid "Hold Ctrl to round to integers. Hold Shift for more precise changes."
@@ -3525,7 +3533,7 @@ msgstr "A kérés sikertelen."
#: editor/export_template_manager.cpp
msgid "Redirect Loop."
-msgstr "Ãtirányítási Hurok."
+msgstr "Ciklus átiránítása."
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -3687,6 +3695,16 @@ msgid "Name contains invalid characters."
msgstr "A név érvénytelen karaktereket tartalmaz."
#: 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 "Fájl átnevezése:"
@@ -3734,24 +3752,11 @@ msgstr "Függőségek Szerkesztése..."
msgid "View Owners..."
msgstr "Tulajdonosok Megtekintése..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Ãtnevezés..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "Megkettőzés..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "Ãthelyezés..."
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Move to Trash"
-msgstr "AutoLoad Ãthelyezése"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "Új jelenet..."
@@ -3774,11 +3779,17 @@ msgid "Collapse All"
msgstr "Összes becsukása"
#: 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 "Ãtnevezés"
+msgid "Duplicate..."
+msgstr "Megkettőzés..."
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "AutoLoad Ãthelyezése"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "Ãtnevezés..."
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -3813,8 +3824,11 @@ msgid "Move"
msgstr "Ãthelyezés"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "Ezen a helyen már van azonos nevű fájl vagy mappa."
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr "Ãtnevezés"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
@@ -3950,15 +3964,15 @@ msgstr "Importálás Külön Anyagokkal"
#: editor/import/resource_importer_scene.cpp
msgid "Import with Separate Objects"
-msgstr "Importálás Külön Objektumokkal"
+msgstr "Importálás külön objektumokkal"
#: editor/import/resource_importer_scene.cpp
msgid "Import with Separate Objects+Materials"
-msgstr "Importálás Külön Objektumokkal És Anyagokkal"
+msgstr "Importálás külön objektumokkal és anyagokkal"
#: editor/import/resource_importer_scene.cpp
msgid "Import with Separate Objects+Animations"
-msgstr "Importálás Külön Objektumokkal És Animációkkal"
+msgstr "Importálás külön objektumokkal és animációkkal"
#: editor/import/resource_importer_scene.cpp
msgid "Import with Separate Materials+Animations"
@@ -3966,7 +3980,7 @@ msgstr "Importálás Külön Anyagokkal És Animációkkal"
#: editor/import/resource_importer_scene.cpp
msgid "Import with Separate Objects+Materials+Animations"
-msgstr "Importálás Külön Objektumokkal, Anyagokkal És Animációkkal"
+msgstr "Importálás külön objektumokkal, anyagokkal és animációkkal"
#: editor/import/resource_importer_scene.cpp
msgid "Import as Multiple Scenes"
@@ -4114,15 +4128,15 @@ msgstr "A jelenleg szerkesztett erőforrás elmentése."
#: editor/inspector_dock.cpp
msgid "Go to the previous edited object in history."
-msgstr "Ugrás az előzőleg módosított objektumra a történelemben."
+msgstr "Ugrás az előzőleg módosított objektumra az előzményekben."
#: editor/inspector_dock.cpp
msgid "Go to the next edited object in history."
-msgstr "Ugrás a következő módosított objektumra a történelemben."
+msgstr "Ugrás a következő módosított objektumra az előzményekben."
#: editor/inspector_dock.cpp
msgid "History of recently edited objects."
-msgstr "A nemrég módosított objektumok történelme."
+msgstr "A nemrég módosított objektumok előzményei."
#: editor/inspector_dock.cpp
msgid "Object properties."
@@ -4951,7 +4965,7 @@ msgstr "Kérés sikertelen, túl sok átirányítás"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Redirect loop."
-msgstr "Hurok átirányítása."
+msgstr "Ciklus átirányítása."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Request failed, timeout"
@@ -5461,8 +5475,8 @@ msgid ""
"Show a list of all objects at the position clicked\n"
"(same as Alt+RMB in select mode)."
msgstr ""
-"Lista mutatási minden objektumról a kattintás helye alatt\n"
-"(ugyanaz, mint Alt + Jobb Egérgomb Kiválasztó Módban)."
+"Lista megjelenítése minden objektumról a kattintás helyénél\n"
+"(ugyanaz, mint Alt + jobb egérgomb kiválasztó módban)."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Click to change object's rotation pivot."
@@ -5548,12 +5562,12 @@ msgstr "Illesztés segédvonalakhoz"
#: 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 "A kiválasztott objektum zárolása (mozgathatatlanná tétele)."
+msgstr "A kiválasztott objektum zárolása (nem lesz mozgatható)."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Unlock the selected object (can be moved)."
-msgstr "A kiválasztott objektum feloldása (mozgathatóvá tétele)."
+msgstr "A kiválasztott objektum feloldása (mozgatható lesz)."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -6773,12 +6787,13 @@ msgid "Filter scripts"
msgstr "Szkriptek szűrése"
#: editor/plugins/script_editor_plugin.cpp
+#, fuzzy
msgid "Toggle alphabetical sorting of the method list."
-msgstr ""
+msgstr "Ãbécészerinti rendezés változtatása a metóduslistában."
#: editor/plugins/script_editor_plugin.cpp
msgid "Filter methods"
-msgstr ""
+msgstr "Metódusok szűrése"
#: editor/plugins/script_editor_plugin.cpp
msgid "Sort"
@@ -6942,7 +6957,7 @@ msgstr "Legutóbbi szkriptek törlése"
#: editor/plugins/script_text_editor.cpp
msgid "Connections to method:"
-msgstr ""
+msgstr "Kapcsolatok a metódushoz:"
#: editor/plugins/script_text_editor.cpp editor/script_editor_debugger.cpp
msgid "Source"
@@ -7244,7 +7259,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
-msgstr ""
+msgstr "Rajzolt objektumok"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Material Changes"
@@ -7780,7 +7795,7 @@ msgstr ""
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Loop"
-msgstr ""
+msgstr "Ciklus"
#: editor/plugins/sprite_frames_editor_plugin.cpp
#, fuzzy
@@ -8485,7 +8500,6 @@ msgid "Version Control System"
msgstr ""
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Initialize"
msgstr "Inicializálás"
@@ -8503,7 +8517,7 @@ msgstr "Változások"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Modified"
-msgstr ""
+msgstr "Módosított"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Renamed"
@@ -9664,6 +9678,10 @@ 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"
@@ -9805,9 +9823,8 @@ msgid "Scan"
msgstr "Keresés"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Select a Folder to Scan"
-msgstr "Válasszon egy beolvasandó mappát"
+msgstr "Válassza ki a mappát a kereséshez"
#: editor/project_manager.cpp
msgid "New Project"
@@ -9827,7 +9844,7 @@ msgstr "Újraindítás most"
#: editor/project_manager.cpp
msgid "Can't run project"
-msgstr "Nem lehet futtatni a projektet"
+msgstr "A projekt futtatása nem sikerült"
#: editor/project_manager.cpp
msgid ""
@@ -9848,11 +9865,11 @@ msgstr "Kulcs "
#: editor/project_settings_editor.cpp
msgid "Joy Button"
-msgstr ""
+msgstr "Joy gomb"
#: editor/project_settings_editor.cpp
msgid "Joy Axis"
-msgstr ""
+msgstr "Joy tengely"
#: editor/project_settings_editor.cpp
msgid "Mouse Button"
@@ -9890,7 +9907,7 @@ msgstr "Eszköz"
#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
msgid "Press a Key..."
-msgstr "Nyomj meg egy gombot..."
+msgstr "Nyomjon le egy billentyűt"
#: editor/project_settings_editor.cpp
#, fuzzy
@@ -10000,7 +10017,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Delete Item"
-msgstr ""
+msgstr "Elem törlése"
#: editor/project_settings_editor.cpp
msgid ""
@@ -10211,20 +10228,19 @@ msgstr ""
#: editor/property_selector.cpp
msgid "Select Virtual Method"
-msgstr ""
+msgstr "Virtuális metódus kiválasztása"
#: editor/property_selector.cpp
msgid "Select Method"
-msgstr ""
+msgstr "Metódus kiválasztása"
#: editor/rename_dialog.cpp editor/scene_tree_dock.cpp
msgid "Batch Rename"
msgstr "Csoportos átnevezés"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Replace:"
-msgstr "Csere: "
+msgstr "Csere:"
#: editor/rename_dialog.cpp
msgid "Prefix:"
@@ -10335,9 +10351,8 @@ msgid "Reset"
msgstr "Visszaállítás"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Regular Expression Error:"
-msgstr "Reguláris kifejezés használata"
+msgstr "Reguláris Kifejezési Hiba:"
#: editor/rename_dialog.cpp
#, fuzzy
@@ -11160,7 +11175,7 @@ msgstr ""
#: modules/gdscript/gdscript_functions.cpp
msgid "Not based on a script"
-msgstr ""
+msgstr "Nem alapul szkripten"
#: modules/gdscript/gdscript_functions.cpp
msgid "Not based on a resource file"
@@ -11168,19 +11183,21 @@ msgstr ""
#: modules/gdscript/gdscript_functions.cpp
msgid "Invalid instance dictionary format (missing @path)"
-msgstr ""
+msgstr "Érvénytelen példány szótár formátum (hiányzó @path)"
#: modules/gdscript/gdscript_functions.cpp
msgid "Invalid instance dictionary format (can't load script at @path)"
msgstr ""
+"Érvénytelen példány szótár formátum (nem lehet kódot betölteni a @path "
+"helyén)"
#: modules/gdscript/gdscript_functions.cpp
msgid "Invalid instance dictionary format (invalid script at @path)"
-msgstr ""
+msgstr "Érvénytelen példány szótár formátum (hibás kód a @path helyén)"
#: modules/gdscript/gdscript_functions.cpp
msgid "Invalid instance dictionary (invalid subclasses)"
-msgstr ""
+msgstr "Érvénytelen példány szótár (érvénytelen alosztályok)"
#: modules/gdscript/gdscript_functions.cpp
msgid "Object can't provide a length."
@@ -11476,7 +11493,7 @@ msgstr "A név nem érvényes azonosító:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Name already in use by another func/var/signal:"
-msgstr ""
+msgstr "A nevet már használja egy függvény/változó/jelzés:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Rename Function"
@@ -11516,7 +11533,7 @@ msgstr "Kimeneti port eltávolítása"
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Expression"
-msgstr "Kifejezés módosítása"
+msgstr "Kifejezés változtatása"
#: modules/visual_script/visual_script_editor.cpp
msgid "Remove VisualScript Nodes"
@@ -11552,11 +11569,11 @@ msgstr ""
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Preload Node"
-msgstr ""
+msgstr "Előre betöltött node hozzáadása"
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Node(s) From Tree"
-msgstr ""
+msgstr "Node(ok) hozzáadása a fáról"
#: modules/visual_script/visual_script_editor.cpp
msgid ""
@@ -11694,11 +11711,11 @@ msgstr ""
#: modules/visual_script/visual_script_editor.cpp
msgid "Delete Selected"
-msgstr "Kijelöltek törlése"
+msgstr "Kiválasztottak törlése"
#: modules/visual_script/visual_script_editor.cpp
msgid "Find Node Type"
-msgstr ""
+msgstr "Node típus keresése"
#: modules/visual_script/visual_script_editor.cpp
msgid "Copy Nodes"
@@ -12099,6 +12116,26 @@ msgid ""
"\"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\" "
@@ -12359,6 +12396,26 @@ msgid ""
"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-"
@@ -12566,6 +12623,9 @@ msgstr ""
msgid "Constants cannot be modified."
msgstr ""
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "Ezen a helyen már van azonos nevű fájl vagy mappa."
+
#~ msgid "Error trying to save layout!"
#~ msgstr "Hiba történt az elrendezés mentésekor!"
diff --git a/editor/translations/id.po b/editor/translations/id.po
index 153df872de..1e88404be4 100644
--- a/editor/translations/id.po
+++ b/editor/translations/id.po
@@ -1112,7 +1112,7 @@ msgstr "Penjelajah Resource Orphan"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3732,6 +3732,16 @@ msgid "Name contains invalid characters."
msgstr "Nama mengandung karakter tidak valid."
#: 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 "Mengubah nama berkas dengan:"
@@ -3779,24 +3789,11 @@ msgstr "Sunting Dependensi..."
msgid "View Owners..."
msgstr "Tampilkan Pemilik Berkas..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Ubah Nama..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "Gandakan..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "Pindahkan ke..."
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Move to Trash"
-msgstr "Pindahkan Autoload"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "Skena Baru…"
@@ -3819,11 +3816,17 @@ msgid "Collapse All"
msgstr "Lipat Semua"
#: 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 "Ubah Nama"
+msgid "Duplicate..."
+msgstr "Gandakan..."
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "Pindahkan Autoload"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "Ubah Nama..."
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -3858,8 +3861,11 @@ msgid "Move"
msgstr "Pindahkan"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "Sudah ada nama berkas atau folder seperti itu di lokasi ini."
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr "Ubah Nama"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
@@ -9853,6 +9859,10 @@ msgid "OpenGL ES 3.0"
msgstr "OpenGL ES 3.0"
#: 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"
@@ -12429,6 +12439,26 @@ msgstr ""
"Animasi CPUParticles2D membutuhkan penggunaan CanvasItemMaterial dengan "
"\"Animasi Partikel\" diaktifkan."
+#: 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\" "
@@ -12746,6 +12776,26 @@ msgid ""
"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
#, fuzzy
msgid ""
@@ -12988,6 +13038,9 @@ msgstr "Variasi hanya bisa ditetapkan dalam fungsi vertex."
msgid "Constants cannot be modified."
msgstr "Konstanta tidak dapat dimodifikasi."
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "Sudah ada nama berkas atau folder seperti itu di lokasi ini."
+
#~ msgid "Error trying to save layout!"
#~ msgstr "Error mencoba untuk menyimpan layout!"
diff --git a/editor/translations/is.po b/editor/translations/is.po
index c478090e4d..e6f66312bc 100644
--- a/editor/translations/is.po
+++ b/editor/translations/is.po
@@ -1092,7 +1092,7 @@ msgstr ""
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3578,6 +3578,16 @@ 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 ""
@@ -3625,25 +3635,11 @@ msgstr "Breyta"
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr ""
-
-#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Duplicate..."
-msgstr "Hreyfimynd Tvöfalda Lykla"
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Move to Trash"
-msgstr "Hreyfa Viðbótar Lykil"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr ""
@@ -3666,10 +3662,17 @@ msgid "Collapse All"
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"
+#, fuzzy
+msgid "Duplicate..."
+msgstr "Hreyfimynd Tvöfalda Lykla"
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "Hreyfa Viðbótar Lykil"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
msgstr ""
#: editor/filesystem_dock.cpp
@@ -3703,7 +3706,10 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
+#: 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
@@ -9548,6 +9554,10 @@ 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"
@@ -11987,6 +11997,26 @@ msgid ""
"\"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\" "
@@ -12247,6 +12277,26 @@ msgid ""
"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-"
diff --git a/editor/translations/it.po b/editor/translations/it.po
index 03396bfa1f..8eefe1b29d 100644
--- a/editor/translations/it.po
+++ b/editor/translations/it.po
@@ -59,8 +59,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-11-23 21:42+0000\n"
-"Last-Translator: Lorenzo Cerqua <lorenzocerqua@tutanota.com>\n"
+"PO-Revision-Date: 2020-12-07 08:11+0000\n"
+"Last-Translator: Mirko <miknsop@gmail.com>\n"
"Language-Team: Italian <https://hosted.weblate.org/projects/godot-engine/"
"godot/it/>\n"
"Language: it\n"
@@ -72,9 +72,8 @@ msgstr ""
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
-#, fuzzy
msgid "Invalid type argument to convert(), use TYPE_* constants."
-msgstr "Argomento tipo non valido per convert(), usare le costanti TYPE_*."
+msgstr "Tipo argomento non valido per convert(), usa le costanti TYPE_*."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
@@ -83,11 +82,10 @@ msgstr "Prevista una stringa di lunghezza 1 (un singolo carattere)."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/mono/glue/gd_glue.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
-#, fuzzy
msgid "Not enough bytes for decoding bytes, or invalid format."
msgstr ""
-"Non ci sono abbastanza byte per riuscire a decodificarli, oppure il formato "
-"non è valido."
+"Non ci sono abbastanza byte per decodificarli, oppure il formato non è "
+"valido."
#: core/math/expression.cpp
msgid "Invalid input %i (not passed) in expression"
@@ -178,14 +176,12 @@ msgid "Delete Selected Key(s)"
msgstr "Elimina le chiavi selezionate"
#: editor/animation_bezier_editor.cpp
-#, fuzzy
msgid "Add Bezier Point"
-msgstr "Aggiungi punto Bézier"
+msgstr "Aggiungi Punto Bezier"
#: editor/animation_bezier_editor.cpp
-#, fuzzy
msgid "Move Bezier Points"
-msgstr "Sposta punto Bézier"
+msgstr "Sposta Punti Bezier"
#: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp
msgid "Anim Duplicate Keys"
@@ -1092,16 +1088,16 @@ msgstr ""
"Puoi trovare i file rimossi nel cestino di sistema per ripristinarli."
#: 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 ""
-"I file che stanno per essere rimossi sono richiesti da altre risorse perché "
-"esse funzionino.\n"
-"Rimuoverli comunque? (non annullabile)"
+"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."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1145,7 +1141,7 @@ msgstr "Esplora risorse orfane"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -2178,6 +2174,7 @@ msgid "Property:"
msgstr "Proprietà:"
#: editor/editor_inspector.cpp
+#, fuzzy
msgid "Set"
msgstr "Imposta"
@@ -2370,6 +2367,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."
#: editor/editor_node.cpp
msgid ""
@@ -2386,9 +2386,8 @@ msgid "Layout name not found!"
msgstr "Nome della disposizione non trovato!"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Restored the Default layout to its base settings."
-msgstr "Ripristinata la disposizione predefinita alle impostazioni originali."
+msgstr "Ripristinato il layout default alle impostazioni base."
#: editor/editor_node.cpp
msgid ""
@@ -3777,6 +3776,16 @@ msgid "Name contains invalid characters."
msgstr "Il nome contiene caratteri non validi."
#: 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 "Rinomina file:"
@@ -3824,23 +3833,11 @@ msgstr "Modifica Dipendenze..."
msgid "View Owners..."
msgstr "Vedi Proprietari..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Rinomina..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "Duplica..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "Sposta in..."
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr "Sposta nel cestino"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "Nuova scena…"
@@ -3863,11 +3860,16 @@ msgid "Collapse All"
msgstr "Comprimi Tutto"
#: 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 "Rinomina"
+msgid "Duplicate..."
+msgstr "Duplica..."
+
+#: editor/filesystem_dock.cpp
+msgid "Move to Trash"
+msgstr "Sposta nel cestino"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "Rinomina..."
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -3902,8 +3904,11 @@ msgid "Move"
msgstr "Sposta"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "C'è già un file o una cartella con lo stesso nome in questo percorso."
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr "Rinomina"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
@@ -6608,14 +6613,12 @@ msgid "Paint Bone Weights"
msgstr "Dipingi peso delle ossa"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Open Polygon 2D UV editor."
-msgstr "Apri editor Poligono 2D UV."
+msgstr "Apri l'editor UV di Polygon2D."
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Polygon 2D UV Editor"
-msgstr "Polygon 2D UV Editor"
+msgstr "Editor UV Polygon 2D"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "UV"
@@ -6712,14 +6715,12 @@ msgid "Grid Settings"
msgstr "Impostazioni griglia"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Snap"
msgstr "Snap"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Enable Snap"
-msgstr "Abilita snap"
+msgstr "Abilita Snap"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid"
@@ -6771,9 +6772,8 @@ msgid "Delete Resource"
msgstr "Elimina risorsa"
#: editor/plugins/resource_preloader_editor_plugin.cpp
-#, fuzzy
msgid "Resource clipboard is empty!"
-msgstr "Gli appunti risorse sono vuoti!"
+msgstr "La clipboard delle risorse è vuota!"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "Paste Resource"
@@ -6915,9 +6915,8 @@ msgid "Filter scripts"
msgstr "Filtra gli script"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Toggle alphabetical sorting of the method list."
-msgstr "Attiva/Disattiva l'ordinazione alfabetica della lista dei metodi."
+msgstr "Abilita/Disabilita l'ordinamento alfabetico della lista dei metodi."
#: editor/plugins/script_editor_plugin.cpp
msgid "Filter methods"
@@ -7084,7 +7083,6 @@ msgid "Clear Recent Scripts"
msgstr "Rimuovi Script Recenti"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Connections to method:"
msgstr "Connessioni al metodo:"
@@ -7097,7 +7095,6 @@ msgid "Target"
msgstr "Target"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid ""
"Missing connected method '%s' for signal '%s' from node '%s' to node '%s'."
msgstr ""
@@ -7135,9 +7132,8 @@ msgid "Pick Color"
msgstr "Scegli un colore"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
-#, fuzzy
msgid "Convert Case"
-msgstr "Converti capitalizzazione"
+msgstr "Converti Maiuscole/Minuscole"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Uppercase"
@@ -7192,9 +7188,8 @@ msgid "Indent Right"
msgstr "Indenta a destra"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Toggle Comment"
-msgstr "Attiva/Disattiva commento"
+msgstr "Attiva/Disattiva Commento"
#: editor/plugins/script_text_editor.cpp
msgid "Fold/Unfold Line"
@@ -7270,9 +7265,8 @@ msgstr "Vai alla linea..."
#: editor/plugins/script_text_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Toggle Breakpoint"
-msgstr "Attiva/Disattiva punti di interruzione"
+msgstr "Attiva/Disattiva Punto D'Interruzione"
#: editor/plugins/script_text_editor.cpp
msgid "Remove All Breakpoints"
@@ -7303,12 +7297,10 @@ msgid "This skeleton has no bones, create some children Bone2D nodes."
msgstr "Questo scheletro non ha ossa, crea dei nodi figlio Bone2D."
#: editor/plugins/skeleton_2d_editor_plugin.cpp
-#, fuzzy
msgid "Create Rest Pose from Bones"
msgstr "Crea Posizione di Riposo dalle Ossa"
#: editor/plugins/skeleton_2d_editor_plugin.cpp
-#, fuzzy
msgid "Set Rest Pose to Bones"
msgstr "Imposta Ossa in Posizione di Riposo"
@@ -7317,12 +7309,10 @@ msgid "Skeleton2D"
msgstr "Skeleton2D"
#: editor/plugins/skeleton_2d_editor_plugin.cpp
-#, fuzzy
msgid "Make Rest Pose (From Bones)"
msgstr "Crea Posizione di Riposo (Dalle Ossa)"
#: editor/plugins/skeleton_2d_editor_plugin.cpp
-#, fuzzy
msgid "Set Bones to Rest Pose"
msgstr "Imposta Ossa in Posizione di Riposo"
@@ -7331,6 +7321,7 @@ msgid "Create physical bones"
msgstr "Crea ossa fisiche"
#: editor/plugins/skeleton_editor_plugin.cpp
+#, fuzzy
msgid "Skeleton"
msgstr "Scheletro"
@@ -7678,6 +7669,7 @@ msgstr "Abilita/Disabilita Vista libera"
#: editor/plugins/spatial_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
+#, fuzzy
msgid "Transform"
msgstr "Trasforma"
@@ -8425,23 +8417,20 @@ msgid "Create a new rectangle."
msgstr "Crea un nuovo rettangolo."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Rectangle"
-msgstr "Riempi Rettangolo"
+msgstr "Nuovo Rettangolo"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new polygon."
msgstr "Crea un nuovo poligono."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Polygon"
-msgstr "Sposta poligono"
+msgstr "Nuovo Poligono"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete Selected Shape"
-msgstr "Elimina selezionati"
+msgstr "Elimina Forma Selezionata"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Keep polygon inside region Rect."
@@ -8752,8 +8741,9 @@ msgid "Scalar"
msgstr "Scalare"
#: editor/plugins/visual_shader_editor_plugin.cpp
+#, fuzzy
msgid "Vector"
-msgstr "Vettore"
+msgstr "Vector"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Boolean"
@@ -9929,6 +9919,10 @@ msgid "OpenGL ES 3.0"
msgstr "OpenGL ES 3.0"
#: 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"
@@ -11282,6 +11276,7 @@ msgid "Value"
msgstr "Valore"
#: editor/script_editor_debugger.cpp
+#, fuzzy
msgid "Monitors"
msgstr "Monitor"
@@ -12206,7 +12201,7 @@ msgstr ""
#: platform/android/export/export.cpp
msgid "Missing 'platform-tools' directory!"
-msgstr ""
+msgstr "Cartella 'platform-tools' inesistente!"
#: platform/android/export/export.cpp
msgid ""
@@ -12523,6 +12518,26 @@ msgstr ""
"L'animazione CPUParticles2D richiede l'utilizzo di un CanvasItemMaterial con "
"\"Animazione Particelle\" abilitata."
+#: 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\" "
@@ -12856,6 +12871,26 @@ msgstr ""
"rigide) saranno sovrascritti dal motore fisico quando in esecuzione.\n"
"Modifica invece la dimensione in sagome di collisione figlie."
+#: 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-"
@@ -13091,14 +13126,18 @@ msgid "Assignment to uniform."
msgstr "Assegnazione all'uniforme."
#: servers/visual/shader_language.cpp
-#, fuzzy
msgid "Varyings can only be assigned in vertex function."
-msgstr "Varyings può essere assegnato soltanto nella funzione del vertice."
+msgstr ""
+"Le variabili possono essere assegnate soltanto in funzione del vertice."
#: servers/visual/shader_language.cpp
msgid "Constants cannot be modified."
msgstr "Le constanti non possono essere modificate."
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr ""
+#~ "C'è già un file o una cartella con lo stesso nome in questo percorso."
+
#~ msgid "Error trying to save layout!"
#~ msgstr "Errore nel salvataggio della disposizione!"
diff --git a/editor/translations/ja.po b/editor/translations/ja.po
index 4b107d82e1..0ec6a58ed9 100644
--- a/editor/translations/ja.po
+++ b/editor/translations/ja.po
@@ -36,7 +36,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-11-24 16:44+0000\n"
+"PO-Revision-Date: 2020-12-01 20:29+0000\n"
"Last-Translator: Wataru Onuki <bettawat@yahoo.co.jp>\n"
"Language-Team: Japanese <https://hosted.weblate.org/projects/godot-engine/"
"godot/ja/>\n"
@@ -1116,7 +1116,7 @@ msgstr "孤立リソース エクスプローラー"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3728,6 +3728,16 @@ 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 "ファイルåを変更:"
@@ -3775,23 +3785,11 @@ msgstr "ä¾å­˜é–¢ä¿‚ã®ç·¨é›†..."
msgid "View Owners..."
msgstr "オーナーを見る..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "åå‰ã‚’変更..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "複製..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "移動..."
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr "ã”ã¿ç®±ã¸ç§»å‹•"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "æ–°è¦ã‚·ãƒ¼ãƒ³..."
@@ -3814,11 +3812,16 @@ msgid "Collapse All"
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 "åå‰ã®å¤‰æ›´"
+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"
@@ -3853,8 +3856,11 @@ msgid "Move"
msgstr "移動"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "ã“ã®ãƒ‘スã«ã¯ã€æ—¢ã«åŒåã®ãƒ•ã‚¡ã‚¤ãƒ«ã‹ãƒ•ã‚©ãƒ«ãƒ€ãŒã‚ã‚Šã¾ã™ã€‚"
+#: 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"
@@ -8333,27 +8339,24 @@ msgid "Create a new rectangle."
msgstr "æ–°ã—ã長方形を作æˆã€‚"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Rectangle"
-msgstr "長方形ペイント"
+msgstr "æ–°è¦é•·æ–¹å½¢"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new polygon."
msgstr "æ–°è¦ãƒãƒªã‚´ãƒ³ã‚’生æˆã€‚"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Polygon"
-msgstr "ãƒãƒªã‚´ãƒ³ã‚’移動"
+msgstr "æ–°è¦ãƒãƒªã‚´ãƒ³"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete Selected Shape"
-msgstr "é¸æŠžå¯¾è±¡ã‚’削除"
+msgstr "é¸æŠžã—ãŸã‚·ã‚§ã‚¤ãƒ—を削除"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Keep polygon inside region Rect."
-msgstr "領域Rect内ã®ãƒãƒªã‚´ãƒ³ã‚’ä¿æŒã—ã¾ã™ã€‚"
+msgstr "領域 Rect 内ã®ãƒãƒªã‚´ãƒ³ã‚’ä¿æŒã—ã¾ã™ã€‚"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Enable snap and show grid (configurable via the Inspector)."
@@ -9821,6 +9824,10 @@ msgid "OpenGL ES 3.0"
msgstr "OpenGL ES 3.0"
#: 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"
@@ -12370,8 +12377,8 @@ msgid ""
"A shape must be provided for CollisionShape2D to function. Please create a "
"shape resource for it!"
msgstr ""
-"関数ã«å¯¾ã—㦠CollisionShape2D ã®å½¢çŠ¶(シェイプ)を指定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚ãã®"
-"ãŸã‚ã®ã‚·ã‚§ã‚¤ãƒ—リソースを作æˆã—ã¦ãã ã•ã„!"
+"関数ã«å¯¾ã—㦠CollisionShape2D ã®å½¢çŠ¶ (シェイプ) を指定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚ã"
+"ã®ãŸã‚ã®ã‚·ã‚§ã‚¤ãƒ—リソースを作æˆã—ã¦ãã ã•ã„ï¼"
#: scene/2d/collision_shape_2d.cpp
msgid ""
@@ -12389,6 +12396,26 @@ msgstr ""
"CPUParticles2Dアニメーションã§ã¯ã€ \"Particles Animation\" を有効ã«ã—ãŸ"
"CanvasItemMaterialを使用ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
+#: 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\" "
@@ -12412,8 +12439,8 @@ msgid ""
"A NavigationPolygon resource must be set or created for this node to work. "
"Please set a property or draw a polygon."
msgstr ""
-"NavigationPolygon リソースを設定ã¾ãŸã¯å‹•ä½œã™ã‚‹ã‚ˆã†ã«ã“ã®ãƒŽãƒ¼ãƒ‰ç”¨ã«ä½œæˆã™ã‚‹å¿…"
-"è¦ãŒã‚ã‚Šã¾ã™ã€‚プロパティを設定ã™ã‚‹ã‹ã€ãƒãƒªã‚´ãƒ³ã‚’æç”»ã—ã¦ãã ã•ã„。"
+"ã“ã®ãƒŽãƒ¼ãƒ‰ç”¨ã« NavigationPolygon リソースを設定ã¾ãŸã¯ä½œæˆã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
+"プロパティを設定ã™ã‚‹ã‹ã€ãƒãƒªã‚´ãƒ³ã‚’æç”»ã—ã¦ãã ã•ã„。"
#: scene/2d/navigation_polygon.cpp
msgid ""
@@ -12717,6 +12744,26 @@ msgstr ""
"物ç†ã‚¨ãƒ³ã‚¸ãƒ³ã«ã‚ˆã£ã¦ã‚ªãƒ¼ãƒãƒ¼ãƒ©ã‚¤ãƒ‰ã•ã‚Œã¾ã™ã€‚\n"
"代ã‚ã‚Šã«ã€å­ã®è¡çªã‚·ã‚§ã‚¤ãƒ—ã®ã‚µã‚¤ã‚ºã‚’変更ã—ã¦ãã ã•ã„。"
+#: 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-"
@@ -12958,6 +13005,9 @@ msgstr "Varying変数ã¯é ‚点関数ã«ã®ã¿å‰²ã‚Šå½“ã¦ã‚‹ã“ã¨ãŒã§ãã¾ã
msgid "Constants cannot be modified."
msgstr "定数ã¯å¤‰æ›´ã§ãã¾ã›ã‚“。"
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "ã“ã®ãƒ‘スã«ã¯ã€æ—¢ã«åŒåã®ãƒ•ã‚¡ã‚¤ãƒ«ã‹ãƒ•ã‚©ãƒ«ãƒ€ãŒã‚ã‚Šã¾ã™ã€‚"
+
#~ msgid "Missing 'build-tools' directory!"
#~ msgstr "'build-tools' ディレクトリãŒã‚ã‚Šã¾ã›ã‚“ï¼"
diff --git a/editor/translations/ka.po b/editor/translations/ka.po
index 55895c0e5e..ae770dc05a 100644
--- a/editor/translations/ka.po
+++ b/editor/translations/ka.po
@@ -1136,7 +1136,7 @@ msgstr "áƒáƒ‘áƒáƒšáƒ˜ რესურსების მáƒáƒ«áƒ˜áƒ”ბელá
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3669,6 +3669,16 @@ 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 ""
@@ -3719,23 +3729,11 @@ msgstr ""
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr ""
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr ""
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr ""
-
-#: editor/filesystem_dock.cpp
#, fuzzy
msgid "New Scene..."
msgstr "რესურსი"
@@ -3761,10 +3759,15 @@ msgid "Collapse All"
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"
+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
@@ -3799,7 +3802,10 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
+#: 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
@@ -9751,6 +9757,10 @@ 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"
@@ -12226,6 +12236,26 @@ msgid ""
"\"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\" "
@@ -12486,6 +12516,26 @@ msgid ""
"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-"
diff --git a/editor/translations/ko.po b/editor/translations/ko.po
index 9d1ccc2440..14f197d86e 100644
--- a/editor/translations/ko.po
+++ b/editor/translations/ko.po
@@ -1103,7 +1103,7 @@ msgstr "미사용 리소스 íƒìƒ‰ê¸°"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3693,6 +3693,16 @@ 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 "íŒŒì¼ ì´ë¦„ 바꾸기:"
@@ -3740,24 +3750,11 @@ msgstr "ì¢…ì† ê´€ê³„ 편집..."
msgid "View Owners..."
msgstr "ì†Œìœ ìž ë³´ê¸°..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "ì´ë¦„ 바꾸기..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "복제..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "여기로 ì´ë™..."
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Move to Trash"
-msgstr "오토로드 ì´ë™"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "새 씬..."
@@ -3780,11 +3777,17 @@ msgid "Collapse All"
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 "ì´ë¦„ 바꾸기"
+msgid "Duplicate..."
+msgstr "복제..."
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+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"
@@ -3819,8 +3822,11 @@ msgid "Move"
msgstr "ì´ë™"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "ì´ ìœ„ì¹˜ì—는 ê°™ì€ ì´ë¦„ì˜ íŒŒì¼ì´ë‚˜ í´ë”ê°€ 있습니다."
+#: 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"
@@ -9763,6 +9769,10 @@ msgid "OpenGL ES 3.0"
msgstr "OpenGL ES 3.0"
#: 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"
@@ -12302,6 +12312,26 @@ msgstr ""
"CPUParticles2D 애니메ì´ì…˜ì—는 \"Particles Animation\"ì´ ì¼œì§„ "
"CanvasItemMaterialì„ ì‚¬ìš©í•´ì•¼ 합니다."
+#: 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\" "
@@ -12619,6 +12649,26 @@ msgstr ""
"í° ë¶€ë‹´ì´ ë©ë‹ˆë‹¤.\n"
"대신 ìžì‹ ì¶©ëŒ ëª¨ì–‘ì˜ í¬ê¸°ë¥¼ 변경하세요."
+#: 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-"
@@ -12856,6 +12906,9 @@ msgstr "Varyingì€ ê¼­ì§“ì  í•¨ìˆ˜ì—만 지정할 수 있습니다."
msgid "Constants cannot be modified."
msgstr "ìƒìˆ˜ëŠ” 수정할 수 없습니다."
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "ì´ ìœ„ì¹˜ì—는 ê°™ì€ ì´ë¦„ì˜ íŒŒì¼ì´ë‚˜ í´ë”ê°€ 있습니다."
+
#~ msgid "Error trying to save layout!"
#~ msgstr "ë ˆì´ì•„웃 저장 중 오류!"
diff --git a/editor/translations/lt.po b/editor/translations/lt.po
index 28cb35e017..6dafdd84e0 100644
--- a/editor/translations/lt.po
+++ b/editor/translations/lt.po
@@ -1097,7 +1097,7 @@ msgstr ""
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3629,6 +3629,16 @@ 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 ""
@@ -3681,26 +3691,12 @@ msgstr ""
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr ""
-
-#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Duplicate..."
-msgstr "Duplikuoti"
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
#, fuzzy
-msgid "Move to Trash"
-msgstr "Mix Nodas"
-
-#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "New Scene..."
msgstr "Atidaryti Skriptų Editorių"
@@ -3723,10 +3719,17 @@ msgid "Collapse All"
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"
+#, fuzzy
+msgid "Duplicate..."
+msgstr "Duplikuoti"
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "Mix Nodas"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
msgstr ""
#: editor/filesystem_dock.cpp
@@ -3762,7 +3765,10 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
+#: 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
@@ -9728,6 +9734,10 @@ 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"
@@ -12197,6 +12207,26 @@ msgid ""
"\"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\" "
@@ -12459,6 +12489,26 @@ msgid ""
"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-"
diff --git a/editor/translations/lv.po b/editor/translations/lv.po
index 2284a0fe02..64a29939e9 100644
--- a/editor/translations/lv.po
+++ b/editor/translations/lv.po
@@ -1093,7 +1093,7 @@ msgstr "BÄreņu Resursu PÄrlÅ«ks"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3578,6 +3578,16 @@ 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 ""
@@ -3625,23 +3635,11 @@ msgstr ""
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr ""
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr ""
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr ""
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "Jauna Aina..."
@@ -3664,10 +3662,15 @@ msgid "Collapse All"
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"
+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
@@ -3701,7 +3704,10 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
+#: 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
@@ -9547,6 +9553,10 @@ 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"
@@ -11995,6 +12005,26 @@ msgid ""
"\"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\" "
@@ -12255,6 +12285,26 @@ msgid ""
"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-"
diff --git a/editor/translations/mi.po b/editor/translations/mi.po
index adae136a19..df5a0dcf55 100644
--- a/editor/translations/mi.po
+++ b/editor/translations/mi.po
@@ -1048,7 +1048,7 @@ msgstr ""
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3524,6 +3524,16 @@ 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 ""
@@ -3571,23 +3581,11 @@ msgstr ""
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr ""
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr ""
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr ""
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr ""
@@ -3610,10 +3608,15 @@ msgid "Collapse All"
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"
+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
@@ -3647,7 +3650,10 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
+#: 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
@@ -9419,6 +9425,10 @@ 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"
@@ -11832,6 +11842,26 @@ msgid ""
"\"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\" "
@@ -12092,6 +12122,26 @@ msgid ""
"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-"
diff --git a/editor/translations/ml.po b/editor/translations/ml.po
index f09e381719..346d52b331 100644
--- a/editor/translations/ml.po
+++ b/editor/translations/ml.po
@@ -1058,7 +1058,7 @@ msgstr ""
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3536,6 +3536,16 @@ 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 ""
@@ -3583,23 +3593,11 @@ msgstr ""
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr ""
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr ""
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr ""
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr ""
@@ -3622,10 +3620,15 @@ msgid "Collapse All"
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"
+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
@@ -3659,7 +3662,10 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
+#: 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
@@ -9436,6 +9442,10 @@ 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"
@@ -11850,6 +11860,26 @@ msgid ""
"\"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\" "
@@ -12110,6 +12140,26 @@ msgid ""
"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-"
diff --git a/editor/translations/mr.po b/editor/translations/mr.po
index 8ea8dc7027..8f588050ab 100644
--- a/editor/translations/mr.po
+++ b/editor/translations/mr.po
@@ -1055,7 +1055,7 @@ msgstr ""
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3531,6 +3531,16 @@ 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 ""
@@ -3578,23 +3588,11 @@ msgstr ""
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr ""
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr ""
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr ""
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr ""
@@ -3617,10 +3615,15 @@ msgid "Collapse All"
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"
+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
@@ -3654,7 +3657,10 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
+#: 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
@@ -9427,6 +9433,10 @@ 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"
@@ -11840,6 +11850,26 @@ msgid ""
"\"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\" "
@@ -12100,6 +12130,26 @@ msgid ""
"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-"
diff --git a/editor/translations/ms.po b/editor/translations/ms.po
index 01affc2669..d00dfd659f 100644
--- a/editor/translations/ms.po
+++ b/editor/translations/ms.po
@@ -13,7 +13,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-09-15 07:17+0000\n"
+"PO-Revision-Date: 2020-12-02 09:52+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 +22,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.3-dev\n"
+"X-Generator: Weblate 4.4-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -904,9 +904,8 @@ msgid "Signals"
msgstr "Isyarat"
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Filter signals"
-msgstr "Dari Isyarat:"
+msgstr "Tapis isyarat"
#: editor/connections_dialog.cpp
msgid "Are you sure you want to remove all connections from this signal?"
@@ -1035,14 +1034,15 @@ msgid "Owners Of:"
msgstr "Pemilik:"
#: 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 "Alih keluar fail terpilih dari projek? (Tidak dapat dipulihkan)"
+msgstr ""
+"Alih keluar fail terpilih dari projek? (Tidak boleh buat asal)\n"
+"Anda boleh mencari fail yang dikeluarkan dalam tong sampah untuk "
+"memulihkannya."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1051,7 +1051,9 @@ msgid ""
msgstr ""
"Fail yang akan dikeluarkan diperlukan oleh sumber lain agar dapat "
"berfungsi.\n"
-"Masih mahu keluarkan fail tersebut? (tidak boleh buat asal)"
+"Masih mahu keluarkan fail tersebut? (tidak boleh buat asal)\n"
+"Anda boleh mencari fail yang dikeluarkan dalam tong sampah untuk "
+"memulihkannya."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1095,7 +1097,7 @@ msgstr "Penjelajah Sumber Yatim"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -1157,12 +1159,10 @@ msgid "Gold Sponsors"
msgstr "Penaja Emas"
#: editor/editor_about.cpp
-#, fuzzy
msgid "Silver Sponsors"
msgstr "Penderma Perak"
#: editor/editor_about.cpp
-#, fuzzy
msgid "Bronze Sponsors"
msgstr "Penderma Gangsa"
@@ -3637,6 +3637,16 @@ 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 ""
@@ -3684,24 +3694,11 @@ msgstr ""
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr ""
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr ""
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Move to Trash"
-msgstr "Pindah Autoload"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr ""
@@ -3724,10 +3721,16 @@ msgid "Collapse All"
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"
+msgid "Duplicate..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "Pindah Autoload"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
msgstr ""
#: editor/filesystem_dock.cpp
@@ -3761,7 +3764,10 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
+#: 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
@@ -9562,6 +9568,10 @@ 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"
@@ -11986,6 +11996,26 @@ msgid ""
"\"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\" "
@@ -12246,6 +12276,26 @@ msgid ""
"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-"
diff --git a/editor/translations/nb.po b/editor/translations/nb.po
index 4028e7b357..b1bb5ead4b 100644
--- a/editor/translations/nb.po
+++ b/editor/translations/nb.po
@@ -1148,7 +1148,7 @@ msgstr "Foreldreløs ressursutforsker"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3889,6 +3889,16 @@ msgid "Name contains invalid characters."
msgstr "Navn inneholder ugyldige tegn."
#: 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 "Endrer filnavn:"
@@ -3943,26 +3953,12 @@ msgstr "Endre Avhengigheter..."
msgid "View Owners..."
msgstr "Vis Eiere..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Endre Navn..."
-
-#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Duplicate..."
-msgstr "Duplisér"
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "Flytt Til..."
#: editor/filesystem_dock.cpp
#, fuzzy
-msgid "Move to Trash"
-msgstr "Flytt Autoload"
-
-#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "New Scene..."
msgstr "Ny Scene"
@@ -3989,11 +3985,18 @@ msgid "Collapse All"
msgstr "Kollaps alle"
#: 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 "Endre navn"
+#, fuzzy
+msgid "Duplicate..."
+msgstr "Duplisér"
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "Flytt Autoload"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "Endre Navn..."
#: editor/filesystem_dock.cpp
#, fuzzy
@@ -4032,9 +4035,11 @@ msgid "Move"
msgstr "Flytt"
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "There is already file or folder with the same name in this location."
-msgstr "En fil eller mappe med dette navnet eksisterer allerede."
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr "Endre navn"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
@@ -10271,6 +10276,10 @@ 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"
@@ -12860,6 +12869,26 @@ msgid ""
"\"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\" "
@@ -13120,6 +13149,26 @@ msgid ""
"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-"
@@ -13329,6 +13378,10 @@ msgstr ""
msgid "Constants cannot be modified."
msgstr "Konstanter kan ikke endres."
+#, fuzzy
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "En fil eller mappe med dette navnet eksisterer allerede."
+
#~ msgid "Error trying to save layout!"
#~ msgstr "Error ved lagring av layout!"
diff --git a/editor/translations/nl.po b/editor/translations/nl.po
index 9311078bae..2b0d754edd 100644
--- a/editor/translations/nl.po
+++ b/editor/translations/nl.po
@@ -47,7 +47,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-10-30 10:21+0000\n"
+"PO-Revision-Date: 2020-11-29 08:28+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 +56,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.3.2-dev\n"
+"X-Generator: Weblate 4.4-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -940,9 +940,8 @@ msgid "Signals"
msgstr "Signalen"
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Filter signals"
-msgstr "Filter tegels"
+msgstr "Signalen filteren"
#: editor/connections_dialog.cpp
msgid "Are you sure you want to remove all connections from this signal?"
@@ -1071,16 +1070,16 @@ msgid "Owners Of:"
msgstr "Eigenaren van:"
#: 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 ""
"Geselecteerde bestanden uit het project verwijderen? (Kan niet ongedaan "
-"gemaakt worden)"
+"gemaakt worden)\n"
+"De bestanden kunnen mogelijk vanuit de prullenbak van het systeem hersteld "
+"worden."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1089,7 +1088,9 @@ msgid ""
msgstr ""
"De bestanden die verwijderd worden zijn nodig om andere bronnen te laten "
"werken.\n"
-"Toch verwijderen? (Onomkeerbaar)"
+"Toch verwijderen? (Onomkeerbaar)\n"
+"De bestanden kunnen mogelijk vanuit de prullenbak van het systeem hersteld "
+"worden."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1133,7 +1134,7 @@ msgstr "Weesbronnen bekijken"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -1195,14 +1196,12 @@ msgid "Gold Sponsors"
msgstr "Gouden Sponsors"
#: editor/editor_about.cpp
-#, fuzzy
msgid "Silver Sponsors"
-msgstr "Zilveren Donors"
+msgstr "Zilveren Sponsoren"
#: editor/editor_about.cpp
-#, fuzzy
msgid "Bronze Sponsors"
-msgstr "Bronzen Donors"
+msgstr "Bronzen Sponsoren"
#: editor/editor_about.cpp
msgid "Mini Sponsors"
@@ -1715,9 +1714,8 @@ msgid "Node Dock"
msgstr "Knooptabblad"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "FileSystem Dock"
-msgstr "Bestandssysteem"
+msgstr "Bestandssysteempaneel"
#: editor/editor_feature_profile.cpp
msgid "Import Dock"
@@ -2359,6 +2357,8 @@ msgid ""
"An error occurred while trying to save the editor layout.\n"
"Make sure the editor's user data path is writable."
msgstr ""
+"Fout tijdens het opslaan van de editorindeling.\n"
+"Zorg dat er naar het pad voor editorgebruikgegevens beschrijfbaar is."
#: editor/editor_node.cpp
msgid ""
@@ -2366,15 +2366,17 @@ msgid ""
"To restore the Default layout to its base settings, use the Delete Layout "
"option and delete the Default layout."
msgstr ""
+"Standaardindeling overschreven.\n"
+"Om de oorspronkelijke instellingen van de standaardindeling te herstellen, "
+"moet je de standaardindeling verwijderen met de optie 'Indeling verwijderen'."
#: editor/editor_node.cpp
msgid "Layout name not found!"
msgstr "Indelingsnaam niet gevonden!"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Restored the Default layout to its base settings."
-msgstr "Standaardindeling teruggezet naar basisinstellingen."
+msgstr "Standaardindeling teruggezet naar oorspronkelijke instellingen."
#: editor/editor_node.cpp
msgid ""
@@ -2867,7 +2869,7 @@ msgstr "Debuggen"
#: editor/editor_node.cpp
msgid "Deploy with Remote Debug"
-msgstr "Opstarten met debugging op afstand"
+msgstr "Uitrollen met debugging op afstand"
#: editor/editor_node.cpp
msgid ""
@@ -2878,11 +2880,15 @@ msgid ""
"mobile device).\n"
"You don't need to enable it to use the GDScript debugger locally."
msgstr ""
+"Als deze optie geactiveerd is, zal één-klik uitrol het programma proberen "
+"een verbinding te sarten met het IP-adres van deze computer.\n"
+"Deze optie is bedoeld om op afstand fouten op te sporen (gewoonlijk met een "
+"mobiel toestel).\n"
+"Je hebt dit niet nodig om het draaiende programma lokaal te inspecteren."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Small Deploy with Network Filesystem"
-msgstr "Klein uitvoerbaar bestand opstarten met netwerk bestandsserver"
+msgstr "Kleine uitrol met netwerkbestandssysteem"
#: editor/editor_node.cpp
#, fuzzy
@@ -2928,12 +2934,10 @@ msgstr ""
"deze optie aanstaat."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Synchronize Scene Changes"
-msgstr "Scèneveranderingen synchroniseren"
+msgstr "Veranderingen in de scène synchroniseren"
#: 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"
@@ -2941,14 +2945,13 @@ msgid ""
"filesystem option is enabled."
msgstr ""
"Wanneer deze optie aanstaat, wordt elke verandering gemaakt in de editor "
-"toegepast op het draaiend spel.\n"
+"toegepast op het lopende spel.\n"
"Wanneer dit op afstand wordt gebruikt op een andere machine, is dit "
"efficiënter met het netwerk bestandssysteem."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Synchronize Script Changes"
-msgstr "Scriptveranderingen synchroniseren"
+msgstr "Veranderingen in scripts synchroniseren"
#: editor/editor_node.cpp
#, fuzzy
@@ -3755,6 +3758,16 @@ msgid "Name contains invalid characters."
msgstr "Naam bevat ongeldige tekens."
#: 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 "Bestand hernoemen:"
@@ -3802,24 +3815,11 @@ msgstr "Afhankelijkheden aanpassen..."
msgid "View Owners..."
msgstr "Bekijk eigenaren..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Hernoemen..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "Dupliceren..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "Verplaats Naar..."
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Move to Trash"
-msgstr "Autoload verplaatsen"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "Nieuwe scène..."
@@ -3842,11 +3842,16 @@ msgid "Collapse All"
msgstr "Alles inklappen"
#: 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 "Naam wijzigen"
+msgid "Duplicate..."
+msgstr "Dupliceren..."
+
+#: editor/filesystem_dock.cpp
+msgid "Move to Trash"
+msgstr "Naar prullenbak verplaatsen"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "Hernoemen..."
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -3881,8 +3886,11 @@ msgid "Move"
msgstr "Verplaatsen"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "Er is al een bestand of map met dezelfde naam op dit pad."
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr "Naam wijzigen"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
@@ -5285,27 +5293,24 @@ msgid "Set CanvasItem \"%s\" Pivot Offset to (%d, %d)"
msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Rotate %d CanvasItems"
-msgstr "CanvasItem roteren"
+msgstr "%d CanvasItems roteren"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Rotate CanvasItem \"%s\" to %d degrees"
-msgstr "CanvasItem roteren"
+msgstr "CanvasItem \"%s\" roteren tot %d graden"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move CanvasItem \"%s\" Anchor"
-msgstr "Verplaats CanvasItem"
+msgstr "Verplaats Anker van CanvasItem \"%s\""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Scale Node2D \"%s\" to (%s, %s)"
-msgstr ""
+msgstr "Node2D \"%s\" verschalen naar (%s, %s)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Resize Control \"%s\" to (%d, %d)"
-msgstr ""
+msgstr "Control \"%s\" vergrootten tot (%d, %d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
#, fuzzy
@@ -9892,6 +9897,10 @@ msgid "OpenGL ES 3.0"
msgstr "OpenGL ES 3.0"
#: 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"
@@ -12468,6 +12477,26 @@ msgstr ""
"CPUParticles2D vereist een CanvasItemMaterial met \"Particles Animation\" "
"ingeschakeld."
+#: 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\" "
@@ -12798,6 +12827,26 @@ msgstr ""
"overschreven worden door de physics engine als het spel start.\n"
"Verander in plaats daarvan de grootte van CollisionShapes in de kinderen."
+#: 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-"
@@ -13039,6 +13088,9 @@ msgstr "Varyings kunnen alleen worden toegewezenin vertex functies."
msgid "Constants cannot be modified."
msgstr "Constanten kunnen niet worden aangepast."
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "Er is al een bestand of map met dezelfde naam op dit pad."
+
#~ msgid "Error trying to save layout!"
#~ msgstr "Fout bij het opslaan van indeling!"
diff --git a/editor/translations/or.po b/editor/translations/or.po
index e5c61be021..ba12c5c7eb 100644
--- a/editor/translations/or.po
+++ b/editor/translations/or.po
@@ -1054,7 +1054,7 @@ msgstr ""
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3530,6 +3530,16 @@ 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 ""
@@ -3577,23 +3587,11 @@ msgstr ""
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr ""
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr ""
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr ""
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr ""
@@ -3616,10 +3614,15 @@ msgid "Collapse All"
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"
+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
@@ -3653,7 +3656,10 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
+#: 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
@@ -9425,6 +9431,10 @@ 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"
@@ -11838,6 +11848,26 @@ msgid ""
"\"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\" "
@@ -12098,6 +12128,26 @@ msgid ""
"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-"
diff --git a/editor/translations/pl.po b/editor/translations/pl.po
index 580715c76d..3e67b723b5 100644
--- a/editor/translations/pl.po
+++ b/editor/translations/pl.po
@@ -44,12 +44,13 @@
# Roman Skiba <romanskiba0@gmail.com>, 2020.
# Piotr Grodzki <ziemniakglados@gmail.com>, 2020.
# Dzejkop <jakubtrad@gmail.com>, 2020.
+# Mateusz Grzonka <alpinus4@gmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-11-20 23:08+0000\n"
-"Last-Translator: Tomek <kobewi4e@gmail.com>\n"
+"PO-Revision-Date: 2020-12-01 20:29+0000\n"
+"Last-Translator: Mateusz Grzonka <alpinus4@gmail.com>\n"
"Language-Team: Polish <https://hosted.weblate.org/projects/godot-engine/"
"godot/pl/>\n"
"Language: pl\n"
@@ -1127,7 +1128,7 @@ msgstr "Eksplorator osieroconych zasobów"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3733,6 +3734,16 @@ msgid "Name contains invalid characters."
msgstr "Nazwa zawiera niedozwolone znaki."
#: 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 "Zmiana nazwy pliku:"
@@ -3780,23 +3791,11 @@ msgstr "Edytuj zależności..."
msgid "View Owners..."
msgstr "Pokaż właścicieli..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Zmień nazwę..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "Duplikuj..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "PrzenieÅ› do..."
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr "PrzenieÅ› do kosza"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "Nowa scena..."
@@ -3819,11 +3818,16 @@ msgid "Collapse All"
msgstr "Zwiń wszystko"
#: 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 "Zmień nazwę"
+msgid "Duplicate..."
+msgstr "Duplikuj..."
+
+#: editor/filesystem_dock.cpp
+msgid "Move to Trash"
+msgstr "PrzenieÅ› do kosza"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "Zmień nazwę..."
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -3858,8 +3862,11 @@ msgid "Move"
msgstr "PrzenieÅ›"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "W tej lokalizacji istnieje już plik lub folder o podanej nazwie."
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr "Zmień nazwę"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
@@ -8348,23 +8355,20 @@ msgid "Create a new rectangle."
msgstr "Utwórz nowy prostokąt."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Rectangle"
-msgstr "Malowanie prostokÄ…tne"
+msgstr "Nowy prostokÄ…t"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new polygon."
msgstr "Utwórz nowy wielokąt."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Polygon"
-msgstr "Przesuń Wielokąt"
+msgstr "Nowy WielokÄ…t"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete Selected Shape"
-msgstr "Usuń zaznaczone"
+msgstr "Usuń Zaznaczony Kształt"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Keep polygon inside region Rect."
@@ -9840,6 +9844,10 @@ msgid "OpenGL ES 3.0"
msgstr "OpenGL ES 3.0"
#: 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"
@@ -12420,6 +12428,26 @@ msgstr ""
"Animacja CPUParticles2D wymaga użycia CanvasItemMaterial z włączonym "
"\"Particles Animation\"."
+#: 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\" "
@@ -12751,6 +12779,26 @@ msgstr ""
"nadpisane przez silnik fizyki podczas działania.\n"
"Zamiast tego, zmień rozmiary kształtów kolizji w węzłach podrzędnych."
+#: 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-"
@@ -12990,6 +13038,9 @@ msgstr "Varying może być przypisane tylko w funkcji wierzchołków."
msgid "Constants cannot be modified."
msgstr "Stałe nie mogą być modyfikowane."
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "W tej lokalizacji istnieje już plik lub folder o podanej nazwie."
+
#~ msgid "Missing 'build-tools' directory!"
#~ msgstr "Brakuje folderu \"build-tools\"!"
diff --git a/editor/translations/pr.po b/editor/translations/pr.po
index 740aaabb1e..ca0f2d5f7e 100644
--- a/editor/translations/pr.po
+++ b/editor/translations/pr.po
@@ -1098,7 +1098,7 @@ msgstr ""
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3647,6 +3647,16 @@ 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
#, fuzzy
msgid "Renaming file:"
msgstr "Rename Variable"
@@ -3698,24 +3708,11 @@ msgstr ""
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr ""
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr ""
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Move to Trash"
-msgstr "Forge yer Node!"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr ""
@@ -3738,10 +3735,16 @@ msgid "Collapse All"
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"
+msgid "Duplicate..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "Forge yer Node!"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
msgstr ""
#: editor/filesystem_dock.cpp
@@ -3778,7 +3781,10 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
+#: 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
@@ -9756,6 +9762,10 @@ 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"
@@ -12279,6 +12289,26 @@ msgid ""
"\"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\" "
@@ -12539,6 +12569,26 @@ msgid ""
"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-"
diff --git a/editor/translations/pt.po b/editor/translations/pt.po
index c114c09299..b675b90e75 100644
--- a/editor/translations/pt.po
+++ b/editor/translations/pt.po
@@ -22,7 +22,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-11-24 16:44+0000\n"
+"PO-Revision-Date: 2020-12-01 20:29+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"
@@ -1104,7 +1104,7 @@ msgstr "Explorador de Recursos Órfãos"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3721,6 +3721,16 @@ msgid "Name contains invalid characters."
msgstr "O nome contém caracteres inválidos."
#: 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 "Mudar nome do Ficheiro:"
@@ -3768,23 +3778,11 @@ msgstr "Editar Dependências..."
msgid "View Owners..."
msgstr "Ver proprietários..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Renomear..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "Duplicar..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "Mover para..."
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr "Mover para Reciclagem"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "Nova Cena..."
@@ -3807,11 +3805,16 @@ msgid "Collapse All"
msgstr "Colapsar Tudo"
#: 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 "Renomear"
+msgid "Duplicate..."
+msgstr "Duplicar..."
+
+#: editor/filesystem_dock.cpp
+msgid "Move to Trash"
+msgstr "Mover para Reciclagem"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "Renomear..."
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -3846,8 +3849,11 @@ msgid "Move"
msgstr "Mover"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "Já existe um ficheiro ou pasta com o mesmo nome nesta localização."
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr "Renomear"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
@@ -8321,23 +8327,20 @@ msgid "Create a new rectangle."
msgstr "Criar novo retângulo."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Rectangle"
-msgstr "Pintar retângulo"
+msgstr "Novo Retângulo"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new polygon."
msgstr "Criar um novo polígono."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Polygon"
-msgstr "Mover Polígono"
+msgstr "Novo Polígono"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete Selected Shape"
-msgstr "Apagar Selecionado"
+msgstr "Apagar Forma Selecionada"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Keep polygon inside region Rect."
@@ -9809,6 +9812,10 @@ msgid "OpenGL ES 3.0"
msgstr "OpenGL ES 3.0"
#: 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"
@@ -12390,6 +12397,26 @@ msgstr ""
"Animação CPUParticles2D requer o uso de um CanvasItemMaterial com "
"\"Particles Animation\" ativada."
+#: 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\" "
@@ -12714,6 +12741,26 @@ msgstr ""
"reescritas pelo motor de física na execução.\n"
"Mude antes o tamanho das formas de colisão filhas."
+#: 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-"
@@ -12954,6 +13001,9 @@ msgstr "Variações só podem ser atribuídas na função vértice."
msgid "Constants cannot be modified."
msgstr "Constantes não podem ser modificadas."
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "Já existe um ficheiro ou pasta com o mesmo nome nesta localização."
+
#~ msgid "Missing 'build-tools' directory!"
#~ msgstr "Diretoria 'build-tools' em falta!"
diff --git a/editor/translations/pt_BR.po b/editor/translations/pt_BR.po
index 8e2b759cec..90d332c743 100644
--- a/editor/translations/pt_BR.po
+++ b/editor/translations/pt_BR.po
@@ -101,12 +101,15 @@
# 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.
+# Elton <eltondeoliveira@outlook.com>, 2020.
+# ThiagoCTN <thiagocampostn@gmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: 2016-05-30\n"
-"PO-Revision-Date: 2020-10-05 01:02+0000\n"
-"Last-Translator: Rafael Henrique Capati <rhcapati@gmail.com>\n"
+"PO-Revision-Date: 2020-12-07 08:11+0000\n"
+"Last-Translator: ThiagoCTN <thiagocampostn@gmail.com>\n"
"Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/"
"godot-engine/godot/pt_BR/>\n"
"Language: pt_BR\n"
@@ -114,7 +117,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
-"X-Generator: Weblate 4.3-dev\n"
+"X-Generator: Weblate 4.4-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1123,14 +1126,15 @@ msgid "Owners Of:"
msgstr "Donos De:"
#: 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 "Remover arquivos selecionados do projeto? (irreversível)"
+msgstr ""
+"Remover arquivos selecionados do projeto? (irreversível)\n"
+"Você pode encontrar os arquivos removidos na lixeira e restaurá-los caso "
+"seja necessário."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1139,7 +1143,9 @@ msgid ""
msgstr ""
"Os arquivos sendo removidos são requeridos por outros recursos para que "
"funcionem.\n"
-"Removê-los mesmo assim? (irreversível)"
+"Removê-los mesmo assim? (irreversível)\n"
+"Você pode encontrar os arquivos removidos na lixeira e restaurá-los caso "
+"necessário."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1167,7 +1173,7 @@ msgstr "Consertar Dependências"
#: editor/dependency_editor.cpp
msgid "Errors loading!"
-msgstr "Erros ao carregar!"
+msgstr "Erro ao carregar!"
#: editor/dependency_editor.cpp
msgid "Permanently delete %d item(s)? (No undo!)"
@@ -1183,7 +1189,7 @@ msgstr "Explorador de Recursos Órfãos"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -1692,35 +1698,33 @@ msgstr ""
"Fallback Enabled' (Recuperação de driver ativada)."
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'PVRTC' texture compression for GLES2. Enable "
"'Import Pvrtc' in Project Settings."
msgstr ""
-"A plataforma alvo requer compressão de texturas 'ETC' para GLES2. Habilite "
-"'Import Etc' nas Configurações de Projeto."
+"A plataforma alvo requer compressão de texturas 'PVRTC' para GLES2. Habilite "
+"'Importar Pvrtc' nas Configurações de Projeto."
#: 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 ""
-"A plataforma de destino requer compactação de textura 'ETC2' para GLES3. "
-"Ativar 'Importar Etc 2' nas Configurações do Projeto."
+"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 "
+"Projeto."
#: 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 ""
-"A plataforma de destino requer compactação de textura 'ETC' para o driver "
+"A plataforma de destino requer compressão de textura 'PVRTC' para o driver "
"retornar ao GLES2.\n"
-"Ativar 'Importar Etc' em Configurações do Projeto ou desabilitar 'Driver "
-"Fallback Enabled' (Recuperação de driver ativada)."
+"Habilite 'Importar Pvrtc' em Configurações do Projeto ou desabilite 'Driver "
+"Reserva Ativado'."
#: editor/editor_export.cpp platform/android/export/export.cpp
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
@@ -2405,6 +2409,8 @@ msgid ""
"An error occurred while trying to save the editor layout.\n"
"Make sure the editor's user data path is writable."
msgstr ""
+"Ocorreu um erro ao tentar salvar o layout do editor.\n"
+"Certifique-se de que o caminho de dados do usuário do editor seja gravável."
#: editor/editor_node.cpp
msgid ""
@@ -2412,15 +2418,17 @@ msgid ""
"To restore the Default layout to its base settings, use the Delete Layout "
"option and delete the Default layout."
msgstr ""
+"Layout do editor padrão substituído.\n"
+"Para restaurar o layout padrão para suas configurações básicas, use a opção "
+"Excluir layout e exclua o layout padrão."
#: editor/editor_node.cpp
msgid "Layout name not found!"
msgstr "Nome do layout não encontrado!"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Restored the Default layout to its base settings."
-msgstr "Layout padrão restaurado às configurações base."
+msgstr "Layout padrão restaurado às configurações básicas."
#: editor/editor_node.cpp
msgid ""
@@ -3802,6 +3810,16 @@ msgid "Name contains invalid characters."
msgstr "Nome contém caracteres inválidos."
#: 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 "Renomear arquivo:"
@@ -3849,24 +3867,11 @@ msgstr "Editar Dependências..."
msgid "View Owners..."
msgstr "Visualizar Proprietários..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Renomear..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "Duplicar..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "Mover Para..."
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Move to Trash"
-msgstr "Mover Autoload"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "Nova Cena..."
@@ -3889,11 +3894,16 @@ msgid "Collapse All"
msgstr "Recolher Tudo"
#: 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 "Renomear"
+msgid "Duplicate..."
+msgstr "Duplicar..."
+
+#: editor/filesystem_dock.cpp
+msgid "Move to Trash"
+msgstr "Mover para o Lixo"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "Renomear..."
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -3928,8 +3938,11 @@ msgid "Move"
msgstr "Mover"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "Já há uma pasta ou arquivo neste caminho com o nome especificado."
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr "Renomear"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
@@ -5333,50 +5346,43 @@ msgstr "Criar Guias Horizontais e Verticais"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Set CanvasItem \"%s\" Pivot Offset to (%d, %d)"
-msgstr ""
+msgstr "Definir Deslocamento do Pivô do CanvasItem \"%s\" para (%d, %d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Rotate %d CanvasItems"
-msgstr "Rotacionar CanvasItem"
+msgstr "Rotacionar %d CanvasItem"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Rotate CanvasItem \"%s\" to %d degrees"
-msgstr "Rotacionar CanvasItem"
+msgstr "Rotacionar CanvasItem \"%s\" para %d graus"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move CanvasItem \"%s\" Anchor"
-msgstr "Mover CanvaItem"
+msgstr "Mover Âncora do CanvaItem \"%s\""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Scale Node2D \"%s\" to (%s, %s)"
-msgstr ""
+msgstr "Dimensionar Node2D \"%s\" para (%s, %s)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Resize Control \"%s\" to (%d, %d)"
-msgstr ""
+msgstr "Redimensinar Controle \"%s\" para (%d, %d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Scale %d CanvasItems"
-msgstr "Tamanho CanvasItem"
+msgstr "Dimensionar %d CanvasItem"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Scale CanvasItem \"%s\" to (%s, %s)"
-msgstr "Tamanho CanvasItem"
+msgstr "Redimensionar CanvasItem \"%s\" para (%s, %s)"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move %d CanvasItems"
-msgstr "Mover CanvaItem"
+msgstr "Mover %d CanvaItem"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move CanvasItem \"%s\" to (%d, %d)"
-msgstr "Mover CanvaItem"
+msgstr "Mover CanvaItem \"%s\" para (%d, %d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid ""
@@ -6657,18 +6663,16 @@ msgid "Move Points"
msgstr "Mover pontos"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Command: Rotate"
-msgstr "Arrastar: Rotacionar"
+msgstr "Command: Rotacionar"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Shift: Move All"
msgstr "Shift: Mover Todos"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Shift+Command: Scale"
-msgstr "Shift+Ctrl: Escala"
+msgstr "Shift+Command: Redimensionar"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Ctrl: Rotate"
@@ -6717,14 +6721,12 @@ msgid "Radius:"
msgstr "Raio:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Copy Polygon to UV"
-msgstr "Criar Polígono & UV"
+msgstr "Copiar Polígono para UV"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Copy UV to Polygon"
-msgstr "Converter para Polígono2D"
+msgstr "Copiar UV para Polígono"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Clear UV"
@@ -8269,13 +8271,12 @@ msgid "Paint Tile"
msgstr "Pintar Tile"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid ""
"Shift+LMB: Line Draw\n"
"Shift+Command+LMB: Rectangle Paint"
msgstr ""
"Shift+LMB: Desenhar Linha\n"
-"Shift+Ctrl+LMB: Pintar Retângulo"
+"Shift+Command+LMB: Pintar Retângulo"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid ""
@@ -8287,7 +8288,7 @@ msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Pick Tile"
-msgstr "Pegar Tile"
+msgstr "Escolher Tile"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Rotate Left"
@@ -8430,23 +8431,20 @@ msgid "Create a new rectangle."
msgstr "Criar um novo retângulo."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Rectangle"
-msgstr "Pintura Retângular"
+msgstr "Novo Retângulo"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new polygon."
msgstr "Criar um novo polígono."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Polygon"
-msgstr "Mover Polígono"
+msgstr "Novo Polígono"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete Selected Shape"
-msgstr "Excluir Selecionados"
+msgstr "Excluir Formas Selecionados"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Keep polygon inside region Rect."
@@ -8815,9 +8813,8 @@ msgid "Add Node to Visual Shader"
msgstr "Adicionar Nó ao Visual Shader"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Node(s) Moved"
-msgstr "Nó Movido"
+msgstr "Node(s) Movidos"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Duplicate Nodes"
@@ -9554,8 +9551,9 @@ msgstr ""
"uniformes e constantes."
#: editor/plugins/visual_shader_editor_plugin.cpp
+#, fuzzy
msgid "A reference to an existing uniform."
-msgstr ""
+msgstr "Uma referência a um uniforme existente."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "(Fragment/Light mode only) Scalar derivative function."
@@ -9922,6 +9920,10 @@ msgid "OpenGL ES 3.0"
msgstr "OpenGL ES 3.0"
#: 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"
@@ -12497,6 +12499,26 @@ msgstr ""
"A animação CPUParticles2D requer o uso de um CanvasItemMaterial com "
"\"Animação de partículas\" ativada."
+#: 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\" "
@@ -12825,6 +12847,26 @@ msgstr ""
"sobrescritas pelo motor de física ao executar.\n"
"Ao invés disso, altere o tamanho nas formas de colisão filhas."
+#: 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-"
@@ -13068,6 +13110,9 @@ msgstr "Variáveis só podem ser atribuídas na função de vértice."
msgid "Constants cannot be modified."
msgstr "Constantes não podem serem modificadas."
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "Já há uma pasta ou arquivo neste caminho com o nome especificado."
+
#~ msgid "Error trying to save layout!"
#~ msgstr "Erro ao salvar o layout!"
diff --git a/editor/translations/ro.po b/editor/translations/ro.po
index a36099f15d..95bca8b085 100644
--- a/editor/translations/ro.po
+++ b/editor/translations/ro.po
@@ -1102,7 +1102,7 @@ msgstr "Explorator de Resurse Orfane"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3707,6 +3707,16 @@ msgid "Name contains invalid characters."
msgstr "Numele furnizat conține caractere nevalide."
#: 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 "Redenumind fișierul:"
@@ -3754,24 +3764,11 @@ msgstr "Editează Dependințele..."
msgid "View Owners..."
msgstr "Vizualizează Proprietarii..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Redenumește..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "Duplicați..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "Mută În..."
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Move to Trash"
-msgstr "Mutați Autoload"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "Scenă nouă..."
@@ -3794,11 +3791,17 @@ msgid "Collapse All"
msgstr "Reduceți Toate"
#: 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 "Redenumește"
+msgid "Duplicate..."
+msgstr "Duplicați..."
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "Mutați Autoload"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "Redenumește..."
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -3833,8 +3836,11 @@ msgid "Move"
msgstr "Mută"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "Există deja un fișier sau un dosar cu același nume în această locație."
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr "Redenumește"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
@@ -9899,6 +9905,10 @@ 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"
@@ -12401,6 +12411,26 @@ msgid ""
"\"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\" "
@@ -12661,6 +12691,26 @@ msgid ""
"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-"
@@ -12866,6 +12916,10 @@ msgstr ""
msgid "Constants cannot be modified."
msgstr ""
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr ""
+#~ "Există deja un fișier sau un dosar cu același nume în această locație."
+
#~ msgid "Error trying to save layout!"
#~ msgstr "Eroare la încercarea de a salva schema!"
diff --git a/editor/translations/ru.po b/editor/translations/ru.po
index 1ed11041e2..7a6d423212 100644
--- a/editor/translations/ru.po
+++ b/editor/translations/ru.po
@@ -88,11 +88,12 @@
# NeoLan Qu <it.bulla@mail.ru>, 2020.
# Nikita Epifanov <nikgreens@protonmail.com>, 2020.
# Cube Show <griiv.06@gmail.com>, 2020.
+# Roman Tolkachyov <roman@tolkachyov.name>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-11-20 23:08+0000\n"
+"PO-Revision-Date: 2020-12-01 20:29+0000\n"
"Last-Translator: Danil Alexeev <danil@alexeev.xyz>\n"
"Language-Team: Russian <https://hosted.weblate.org/projects/godot-engine/"
"godot/ru/>\n"
@@ -1172,7 +1173,7 @@ msgstr "Обзор подключённых реÑурÑов"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3786,6 +3787,16 @@ 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 "Переименование файла:"
@@ -3833,23 +3844,11 @@ msgstr "Редактировать завиÑимоÑти..."
msgid "View Owners..."
msgstr "ПроÑмотреть владельцев..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Переименовать..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "Дублировать..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "ПеремеÑтить в..."
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr "Удалить в Корзину"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "ÐÐ¾Ð²Ð°Ñ Ñцена..."
@@ -3872,11 +3871,16 @@ msgid "Collapse All"
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 "Переименовать"
+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"
@@ -3911,8 +3915,11 @@ msgid "Move"
msgstr "ПеремеÑтить"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "По Ñтому пути уже ÑущеÑтвует файл или папка Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ñ‹Ð¼ именем."
+#: 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"
@@ -8395,23 +8402,20 @@ msgid "Create a new rectangle."
msgstr "Создать новый прÑмоугольник."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Rectangle"
-msgstr "ПрÑÐ¼Ð¾ÑƒÐ³Ð¾Ð»ÑŒÐ½Ð°Ñ Ð¿Ð¾ÐºÑ€Ð°Ñка"
+msgstr "Ðовый прÑмоугольник"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new polygon."
msgstr "Создать новый полигон."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Polygon"
-msgstr "Передвинуть полигон"
+msgstr "Ðовый полигон"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete Selected Shape"
-msgstr "Удалить выделенное"
+msgstr "Удалить выбранную форму"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Keep polygon inside region Rect."
@@ -9886,6 +9890,10 @@ msgid "OpenGL ES 3.0"
msgstr "OpenGL ES 3.0"
#: 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"
@@ -12459,6 +12467,26 @@ msgstr ""
"ÐÐ½Ð¸Ð¼Ð°Ñ†Ð¸Ñ CPUParticles2D требует иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ CanvasItemMaterial Ñ "
"включённой опцией «Particles Animation»."
+#: 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\" "
@@ -12785,6 +12813,26 @@ msgstr ""
"переопределены движком при запуÑке.\n"
"Измените размер дочерней формы коллизии."
+#: 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-"
@@ -13027,6 +13075,9 @@ msgstr "Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ быть назначены только Ð
msgid "Constants cannot be modified."
msgstr "КонÑтанты не могут быть изменены."
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "По Ñтому пути уже ÑущеÑтвует файл или папка Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ñ‹Ð¼ именем."
+
#~ msgid "Missing 'build-tools' directory!"
#~ msgstr "Ð”Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ Â«build-tools» отÑутÑтвует!"
diff --git a/editor/translations/si.po b/editor/translations/si.po
index 5afc820f33..e1675c412f 100644
--- a/editor/translations/si.po
+++ b/editor/translations/si.po
@@ -1077,7 +1077,7 @@ msgstr ""
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3556,6 +3556,16 @@ 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 ""
@@ -3603,23 +3613,11 @@ msgstr ""
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr ""
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr ""
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr ""
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr ""
@@ -3642,10 +3640,15 @@ msgid "Collapse All"
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"
+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
@@ -3679,7 +3682,10 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
+#: 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
@@ -9503,6 +9509,10 @@ 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"
@@ -11933,6 +11943,26 @@ msgid ""
"\"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\" "
@@ -12193,6 +12223,26 @@ msgid ""
"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-"
diff --git a/editor/translations/sk.po b/editor/translations/sk.po
index bfffcb5afc..db612cbd65 100644
--- a/editor/translations/sk.po
+++ b/editor/translations/sk.po
@@ -1086,7 +1086,7 @@ msgstr "Orphan Resource Explorer"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3691,6 +3691,16 @@ msgid "Name contains invalid characters."
msgstr "Meno obsahuje neplatné písmená."
#: 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 "Zostávajúce súbory:"
@@ -3738,24 +3748,11 @@ msgstr "Editovať Závislosti..."
msgid "View Owners..."
msgstr "Zobraziť Majiteľov..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Premenovať..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "Duplikovať..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "Presunúť Do..."
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Move to Trash"
-msgstr "Presunúť AutoLoad-y"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "Nová Scéna..."
@@ -3778,11 +3775,17 @@ msgid "Collapse All"
msgstr "Collapse All"
#: 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 "Premenovať"
+msgid "Duplicate..."
+msgstr "Duplikovať..."
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "Presunúť AutoLoad-y"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "Premenovať..."
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -3817,8 +3820,11 @@ msgid "Move"
msgstr "Presunúť"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "Už tu je súbor alebo prieÄinok pomenovaný rovnako."
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr "Premenovať"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
@@ -9801,6 +9807,10 @@ 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"
@@ -12302,6 +12312,26 @@ msgid ""
"\"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
#, fuzzy
msgid ""
@@ -12571,6 +12601,26 @@ msgid ""
"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-"
@@ -12776,6 +12826,9 @@ msgstr ""
msgid "Constants cannot be modified."
msgstr ""
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "Už tu je súbor alebo prieÄinok pomenovaný rovnako."
+
#~ msgid "Error trying to save layout!"
#~ msgstr "Error pri ukladaní layout-i!"
diff --git a/editor/translations/sl.po b/editor/translations/sl.po
index 8e123095e3..0326de6a9f 100644
--- a/editor/translations/sl.po
+++ b/editor/translations/sl.po
@@ -1144,7 +1144,7 @@ msgstr "Raziskovalec Osamljenih Virov"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3829,6 +3829,16 @@ msgid "Name contains invalid characters."
msgstr "Ime vsebuje neveljavne znake."
#: 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 "Preimenovanje Datoteke:"
@@ -3881,25 +3891,12 @@ msgstr "Uredi Odvisnosti..."
msgid "View Owners..."
msgstr "Poglej Lastnike..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Preimenuj..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "Podvoji..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "Premakni V..."
#: editor/filesystem_dock.cpp
#, fuzzy
-msgid "Move to Trash"
-msgstr "Premakni SamodejnoNalaganje"
-
-#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "New Scene..."
msgstr "Nov Prizor"
@@ -3926,11 +3923,17 @@ msgid "Collapse All"
msgstr "SkrÄi vse"
#: 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 "Preimenuj"
+msgid "Duplicate..."
+msgstr "Podvoji..."
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "Premakni SamodejnoNalaganje"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "Preimenuj..."
#: editor/filesystem_dock.cpp
#, fuzzy
@@ -3969,9 +3972,11 @@ msgid "Move"
msgstr "Premakni"
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "There is already file or folder with the same name in this location."
-msgstr "Datoteka ali mapa s tem imenom že obstaja."
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr "Preimenuj"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
@@ -10140,6 +10145,10 @@ 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"
@@ -12698,6 +12707,26 @@ msgid ""
"\"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\" "
@@ -12963,6 +12992,26 @@ msgid ""
"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-"
@@ -13181,6 +13230,10 @@ msgstr ""
msgid "Constants cannot be modified."
msgstr "Konstante ni možno spreminjati."
+#, fuzzy
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "Datoteka ali mapa s tem imenom že obstaja."
+
#~ msgid "Error trying to save layout!"
#~ msgstr "Napaka pri shranjevanju postavitev!"
diff --git a/editor/translations/sq.po b/editor/translations/sq.po
index 4cd813a759..434fd72854 100644
--- a/editor/translations/sq.po
+++ b/editor/translations/sq.po
@@ -1086,7 +1086,7 @@ msgstr "Eksploruesi I Resurseve Pa Zotërues"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3769,6 +3769,16 @@ msgid "Name contains invalid characters."
msgstr "Emri permban karaktere të pasakta."
#: 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 "Duke riemërtuar skedarin:"
@@ -3821,25 +3831,12 @@ msgstr "Modifiko Varësitë..."
msgid "View Owners..."
msgstr "Shiko Pronarët..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Riemërto..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "Dyfisho..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "Lëviz në..."
#: editor/filesystem_dock.cpp
#, fuzzy
-msgid "Move to Trash"
-msgstr "Lëviz Autoload-in"
-
-#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "New Scene..."
msgstr "Skenë e Re"
@@ -3862,11 +3859,17 @@ msgid "Collapse All"
msgstr "Mbyll të Gjitha"
#: 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 "Riemërto"
+msgid "Duplicate..."
+msgstr "Dyfisho..."
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "Lëviz Autoload-in"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "Riemërto..."
#: editor/filesystem_dock.cpp
#, fuzzy
@@ -3904,10 +3907,11 @@ msgid "Move"
msgstr "Lëviz"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr ""
-"Ekziston që më parë një skedar ose folder me të njëjtin emër në këtë "
-"vendndodhje."
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr "Riemërto"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
@@ -9798,6 +9802,10 @@ 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"
@@ -12279,6 +12287,26 @@ msgid ""
"\"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\" "
@@ -12539,6 +12567,26 @@ msgid ""
"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-"
@@ -12741,6 +12789,11 @@ msgstr ""
msgid "Constants cannot be modified."
msgstr ""
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr ""
+#~ "Ekziston që më parë një skedar ose folder me të njëjtin emër në këtë "
+#~ "vendndodhje."
+
#~ msgid "Error trying to save layout!"
#~ msgstr "Gabim duke provuar të ruaj faqosjen!"
diff --git a/editor/translations/sr_Cyrl.po b/editor/translations/sr_Cyrl.po
index b941a7097c..d5b4d28f95 100644
--- a/editor/translations/sr_Cyrl.po
+++ b/editor/translations/sr_Cyrl.po
@@ -1200,7 +1200,7 @@ msgstr "Преглед повезаних реÑурÑа"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -4021,6 +4021,16 @@ 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 "Преименовање датотеке:"
@@ -4075,26 +4085,12 @@ msgstr "Измени завиÑноÑти..."
msgid "View Owners..."
msgstr "Погледај влаÑнике..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Преименуј..."
-
-#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Duplicate..."
-msgstr "Дуплирај"
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "Помери у..."
#: editor/filesystem_dock.cpp
#, fuzzy
-msgid "Move to Trash"
-msgstr "Помери аутоматÑко учитавање"
-
-#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "New Scene..."
msgstr "Ðова Ñцена"
@@ -4121,11 +4117,18 @@ msgid "Collapse All"
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 "Преименуј"
+#, fuzzy
+msgid "Duplicate..."
+msgstr "Дуплирај"
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "Помери аутоматÑко учитавање"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "Преименуј..."
#: editor/filesystem_dock.cpp
#, fuzzy
@@ -4164,9 +4167,11 @@ msgid "Move"
msgstr "Помери"
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "There is already file or folder with the same name in this location."
-msgstr "Датотека или директоријум Ñа овим именом већ поÑтоји."
+#: 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
#, fuzzy
@@ -10925,6 +10930,10 @@ msgid "OpenGL ES 3.0"
msgstr "OpenGL ES 3.0"
#: editor/project_manager.cpp
+msgid "Not supported by your GPU drivers."
+msgstr ""
+
+#: editor/project_manager.cpp
#, fuzzy
msgid ""
"Higher visual quality\n"
@@ -13947,6 +13956,26 @@ msgstr ""
"ПроцеÑорЧеÑтице2Д анимација захтева коришћење ПлатноПредметМатеријала Ñа "
"омогућеном \"Ðнимациом ЧеÑтица\"."
+#: 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
#, fuzzy
msgid ""
@@ -14315,6 +14344,26 @@ 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
#, fuzzy
msgid ""
@@ -14593,6 +14642,10 @@ msgstr "Варијације могу Ñамо бити одређене у фу
msgid "Constants cannot be modified."
msgstr "КонÑтанте није могуће мењати."
+#, fuzzy
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "Датотека или директоријум Ñа овим именом већ поÑтоји."
+
#~ msgid "Error trying to save layout!"
#~ msgstr "Грешка при чувању раÑпореда!"
diff --git a/editor/translations/sr_Latn.po b/editor/translations/sr_Latn.po
index db169729e3..3343da96fc 100644
--- a/editor/translations/sr_Latn.po
+++ b/editor/translations/sr_Latn.po
@@ -1086,7 +1086,7 @@ msgstr ""
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3573,6 +3573,16 @@ 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 ""
@@ -3620,23 +3630,11 @@ msgstr ""
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr ""
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr ""
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr ""
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr ""
@@ -3659,10 +3657,15 @@ msgid "Collapse All"
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"
+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
@@ -3696,7 +3699,10 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
+#: 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
@@ -9581,6 +9587,10 @@ 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"
@@ -12024,6 +12034,26 @@ msgid ""
"\"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\" "
@@ -12284,6 +12314,26 @@ msgid ""
"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-"
diff --git a/editor/translations/sv.po b/editor/translations/sv.po
index 3d2eea1ceb..faab1ec8ed 100644
--- a/editor/translations/sv.po
+++ b/editor/translations/sv.po
@@ -1104,7 +1104,7 @@ msgstr "Föräldralös Resursutforskare"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3768,6 +3768,16 @@ 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 "Byter namn på filen:"
@@ -3823,16 +3833,6 @@ msgstr ""
msgid "View Owners..."
msgstr "Visa Ägare..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
-msgid "Rename..."
-msgstr "Byt namn..."
-
-#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Duplicate..."
-msgstr "Duplicera"
-
#: editor/filesystem_dock.cpp
#, fuzzy
msgid "Move To..."
@@ -3840,11 +3840,6 @@ msgstr "Flytta Till..."
#: editor/filesystem_dock.cpp
#, fuzzy
-msgid "Move to Trash"
-msgstr "Flytta Autoload"
-
-#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "New Scene..."
msgstr "Ny Scen"
@@ -3871,11 +3866,19 @@ msgid "Collapse All"
msgstr "Stäng Alla"
#: 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 "Byt namn"
+#, fuzzy
+msgid "Duplicate..."
+msgstr "Duplicera"
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "Flytta Autoload"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+#, fuzzy
+msgid "Rename..."
+msgstr "Byt namn..."
#: editor/filesystem_dock.cpp
#, fuzzy
@@ -3912,9 +3915,11 @@ msgid "Move"
msgstr "Flytta"
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "There is already file or folder with the same name in this location."
-msgstr "En fil eller mapp med detta namn finns redan."
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr "Byt namn"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
@@ -10021,6 +10026,10 @@ 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"
@@ -12577,6 +12586,26 @@ msgid ""
"\"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\" "
@@ -12856,6 +12885,26 @@ msgid ""
"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
#, fuzzy
msgid ""
@@ -13067,6 +13116,10 @@ msgstr ""
msgid "Constants cannot be modified."
msgstr ""
+#, fuzzy
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "En fil eller mapp med detta namn finns redan."
+
#~ msgid "Error trying to save layout!"
#~ msgstr "Fel vid försök att spara layout!"
diff --git a/editor/translations/ta.po b/editor/translations/ta.po
index 4a056fc781..c89be893b8 100644
--- a/editor/translations/ta.po
+++ b/editor/translations/ta.po
@@ -1082,7 +1082,7 @@ msgstr ""
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3563,6 +3563,16 @@ 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 ""
@@ -3610,25 +3620,11 @@ msgstr ""
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr ""
-
-#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Duplicate..."
-msgstr "அசைவூடà¯à®Ÿà¯ போலிபசà¯à®šà®¾à®µà®¿à®•à®³à¯"
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Move to Trash"
-msgstr "சேர௠மà¯à®•à¯à®•à®¿à®¯à®ªà¯à®ªà¯à®³à¯à®³à®¿à®¯à¯ˆ நகரà¯à®¤à¯à®¤à¯"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr ""
@@ -3651,10 +3647,17 @@ msgid "Collapse All"
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"
+#, fuzzy
+msgid "Duplicate..."
+msgstr "அசைவூடà¯à®Ÿà¯ போலிபசà¯à®šà®¾à®µà®¿à®•à®³à¯"
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "சேர௠மà¯à®•à¯à®•à®¿à®¯à®ªà¯à®ªà¯à®³à¯à®³à®¿à®¯à¯ˆ நகரà¯à®¤à¯à®¤à¯"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
msgstr ""
#: editor/filesystem_dock.cpp
@@ -3688,7 +3691,10 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
+#: 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
@@ -9503,6 +9509,10 @@ 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"
@@ -11933,6 +11943,26 @@ msgid ""
"\"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\" "
@@ -12193,6 +12223,26 @@ msgid ""
"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-"
diff --git a/editor/translations/te.po b/editor/translations/te.po
index 8d186752d1..806a6bb133 100644
--- a/editor/translations/te.po
+++ b/editor/translations/te.po
@@ -1057,7 +1057,7 @@ msgstr ""
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3533,6 +3533,16 @@ 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 ""
@@ -3580,23 +3590,11 @@ msgstr ""
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr ""
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr ""
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr ""
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr ""
@@ -3619,10 +3617,15 @@ msgid "Collapse All"
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"
+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
@@ -3656,7 +3659,10 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
+#: 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
@@ -9429,6 +9435,10 @@ 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"
@@ -11842,6 +11852,26 @@ msgid ""
"\"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\" "
@@ -12102,6 +12132,26 @@ msgid ""
"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-"
diff --git a/editor/translations/th.po b/editor/translations/th.po
index 60db227d35..1a36ecf42b 100644
--- a/editor/translations/th.po
+++ b/editor/translations/th.po
@@ -7,12 +7,13 @@
# Thanachart Monpassorn <nunf_2539@hotmail.com>, 2020.
# Anonymous <noreply@weblate.org>, 2020.
# Lon3r <mptube.p@gmail.com>, 2020.
+# Kongfa Warorot <gongpha@hotmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-11-20 23:08+0000\n"
-"Last-Translator: Thanachart Monpassorn <nunf_2539@hotmail.com>\n"
+"PO-Revision-Date: 2020-12-01 20:29+0000\n"
+"Last-Translator: Kongfa Warorot <gongpha@hotmail.com>\n"
"Language-Team: Thai <https://hosted.weblate.org/projects/godot-engine/godot/"
"th/>\n"
"Language: th\n"
@@ -1080,7 +1081,7 @@ msgstr "ทรัพยาà¸à¸£à¸—ี่ไม่ได้ใช้"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -1171,7 +1172,7 @@ msgstr "ผู้บริจาค"
#: editor/editor_about.cpp
msgid "License"
-msgstr "สัà¸à¸à¸²à¸­à¸™à¸¸à¸à¸²à¸•"
+msgstr "ลิขสิทธิ์"
#: editor/editor_about.cpp
msgid "Third-party Licenses"
@@ -3634,6 +3635,16 @@ 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 "เปลี่ยนชื่อไฟล์:"
@@ -3681,23 +3692,11 @@ msgstr "à¹à¸à¹‰à¹„ขà¸à¸²à¸£à¸­à¹‰à¸²à¸‡à¸­à¸´à¸‡..."
msgid "View Owners..."
msgstr "ดูเจ้าของ..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "เปลี่ยนชื่อ..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "ทำซ้ำ..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "ย้ายไป..."
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr "ย้ายไปถังขยะ"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "ฉาà¸à¹ƒà¸«à¸¡à¹ˆ..."
@@ -3720,11 +3719,16 @@ msgid "Collapse All"
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 "เปลี่ยนชื่อ"
+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"
@@ -3759,8 +3763,11 @@ msgid "Move"
msgstr "ย้าย"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "มีไฟล์หรือโฟลเดอร์ชื่อเดียวà¸à¸±à¸™à¸­à¸¢à¸¹à¹ˆà¹à¸¥à¹‰à¸§"
+#: 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"
@@ -7173,7 +7180,7 @@ msgstr "à¹à¸—รà¸à¸„ีย์à¹à¸­à¸™à¸´à¹€à¸¡à¸Šà¸±à¸™"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Pitch"
-msgstr "เสียงสูงต่ำ"
+msgstr "Pitch"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Yaw"
@@ -8201,23 +8208,20 @@ msgid "Create a new rectangle."
msgstr "สร้างสี่เหลี่ยมใหม่"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Rectangle"
-msgstr "วาดสี่เหลี่ยม"
+msgstr "สี่เหลี่ยมใหม่"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new polygon."
msgstr "สร้างรูปหลายเหลี่ยมใหม่"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Polygon"
-msgstr "ย้ายรูปหลายเหลี่ยม"
+msgstr "รูปหลายเหลี่ยมใหม่"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete Selected Shape"
-msgstr "ลบสิ่งที่เลือà¸"
+msgstr "ลบรูปร่างที่เลือà¸"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Keep polygon inside region Rect."
@@ -9654,6 +9658,10 @@ msgid "OpenGL ES 3.0"
msgstr "OpenGL ES 3.0"
#: 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"
@@ -12161,6 +12169,26 @@ msgstr ""
"à¹à¸­à¸™à¸´à¹€à¸¡à¸Šà¸±à¸™ CPUParticles2D จำเป็นต้องใช้ CanvasItemMaterial โดยเปิดà¸à¸²à¸£à¸—ำงาน "
"\"Particles Animation\""
+#: 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\" "
@@ -12455,6 +12483,26 @@ msgstr ""
"จะถูà¸à¹à¸—นที่โดยเอ็นจิ้นฟิสิà¸à¸ªà¹Œà¹€à¸¡à¸·à¹ˆà¸­à¸—ำงาน\n"
"เปลี่ยนขนาดในขอบเขตà¸à¸²à¸£à¸Šà¸™à¸¥à¸¹à¸à¹à¸—น"
+#: 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-"
@@ -12681,6 +12729,9 @@ msgstr "Varyings สามารถà¸à¸³à¸«à¸™à¸”ในังà¸à¹Œà¸Šà¸±à¸™à¹€
msgid "Constants cannot be modified."
msgstr "ค่าคงที่ไม่สามารถà¹à¸à¹‰à¹„ขได้"
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "มีไฟล์หรือโฟลเดอร์ชื่อเดียวà¸à¸±à¸™à¸­à¸¢à¸¹à¹ˆà¹à¸¥à¹‰à¸§"
+
#~ msgid "Missing 'build-tools' directory!"
#~ msgstr "ไดเร็à¸à¸—อรี 'build-tools' หายไป!"
diff --git a/editor/translations/tr.po b/editor/translations/tr.po
index 61eb8819f9..0d0c2ff2ee 100644
--- a/editor/translations/tr.po
+++ b/editor/translations/tr.po
@@ -59,7 +59,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-11-25 14:10+0000\n"
+"PO-Revision-Date: 2020-11-29 08:29+0000\n"
"Last-Translator: Zsosu Ktosu <zktosu@gmail.com>\n"
"Language-Team: Turkish <https://hosted.weblate.org/projects/godot-engine/"
"godot/tr/>\n"
@@ -1140,7 +1140,7 @@ msgstr "Orphan Kaynak Araştırıcı"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -2150,7 +2150,7 @@ msgstr "Metot"
#: editor/editor_help_search.cpp editor/plugins/script_text_editor.cpp
msgid "Signal"
-msgstr "Sinyaller"
+msgstr "Sinyal"
#: editor/editor_help_search.cpp editor/plugins/theme_editor_plugin.cpp
msgid "Constant"
@@ -3753,6 +3753,16 @@ msgid "Name contains invalid characters."
msgstr "İsim geçersiz karkterler içeriyor."
#: 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 "Dosya yeniden-adlandırma:"
@@ -3800,23 +3810,11 @@ msgstr "Bağımlılıkları Düzenle..."
msgid "View Owners..."
msgstr "Sahipleri Görüntüle..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Yeniden Adlandır..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "Çoğalt..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "Şuraya Taşı..."
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr "Çöpe At"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "Yeni Sahne..."
@@ -3839,11 +3837,16 @@ msgid "Collapse All"
msgstr "Hepsini Daralt"
#: 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 "Yeniden Adlandır"
+msgid "Duplicate..."
+msgstr "Çoğalt..."
+
+#: editor/filesystem_dock.cpp
+msgid "Move to Trash"
+msgstr "Çöpe At"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "Yeniden Adlandır..."
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -3878,8 +3881,11 @@ msgid "Move"
msgstr "Taşı"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "Bu konumda zaten aynı ada sahip bir dosya veya klasör var."
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr "Yeniden Adlandır"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
@@ -8361,23 +8367,20 @@ msgid "Create a new rectangle."
msgstr "Yeni dikdörtgen oluştur."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Rectangle"
-msgstr "Dikdörtgen Boya"
+msgstr "Dolu Dikdörtgen"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new polygon."
msgstr "Yeni bir çokgen oluşturun."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Polygon"
-msgstr "Çokgeni Taşı"
+msgstr "Yeni Çokgen"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete Selected Shape"
-msgstr "Seçilenleri Sil"
+msgstr "Seçilen Şekli Sil"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Keep polygon inside region Rect."
@@ -9849,6 +9852,10 @@ msgid "OpenGL ES 3.0"
msgstr "OpenGL ES 3"
#: 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"
@@ -12415,6 +12422,26 @@ msgstr ""
"CPUParçacık2B animasyonu \"Parçacık Animasyonu\" seçimi etkin olarak "
"CanvasÖgesiMalzemesi kullanımı gerektirir."
+#: 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\" "
@@ -12746,6 +12773,26 @@ msgstr ""
"çalıştığında geçersiz kılınacak.\n"
"Boyu değişikliğini bunun yerine çocuk çarpışma şekilleri içinden yapın."
+#: 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-"
@@ -12988,6 +13035,9 @@ msgstr "varyings yalnızca vertex işlevinde atanabilir."
msgid "Constants cannot be modified."
msgstr "Sabit deÄŸerler deÄŸiÅŸtirilemez."
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "Bu konumda zaten aynı ada sahip bir dosya veya klasör var."
+
#~ msgid "Missing 'build-tools' directory!"
#~ msgstr "Eksik 'inşa-araçları' dizini!"
diff --git a/editor/translations/tzm.po b/editor/translations/tzm.po
index 6d0b1ff421..b9c48c5b34 100644
--- a/editor/translations/tzm.po
+++ b/editor/translations/tzm.po
@@ -1055,7 +1055,7 @@ msgstr ""
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3531,6 +3531,16 @@ 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 ""
@@ -3578,23 +3588,11 @@ msgstr ""
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr ""
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr ""
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr ""
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr ""
@@ -3617,10 +3615,15 @@ msgid "Collapse All"
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"
+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
@@ -3654,7 +3657,10 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
+#: 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
@@ -9426,6 +9432,10 @@ 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"
@@ -11839,6 +11849,26 @@ msgid ""
"\"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\" "
@@ -12099,6 +12129,26 @@ msgid ""
"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-"
diff --git a/editor/translations/uk.po b/editor/translations/uk.po
index 19d0cee9a7..dd03dac3cf 100644
--- a/editor/translations/uk.po
+++ b/editor/translations/uk.po
@@ -20,8 +20,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Ukrainian (Godot Engine)\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-11-23 21:42+0000\n"
-"Last-Translator: Miroslav <zinmirx@gmail.com>\n"
+"PO-Revision-Date: 2020-11-29 08:29+0000\n"
+"Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
"Language-Team: Ukrainian <https://hosted.weblate.org/projects/godot-engine/"
"godot/uk/>\n"
"Language: uk\n"
@@ -1109,7 +1109,7 @@ msgstr "ОглÑд підключених реÑурÑів"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3730,6 +3730,16 @@ 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 "ÐŸÐµÑ€ÐµÐ¹Ð¼ÐµÐ½ÑƒÐ²Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ:"
@@ -3777,23 +3787,11 @@ msgstr "Редагувати залежноÑÑ‚Ñ–..."
msgid "View Owners..."
msgstr "ПереглÑнути влаÑників..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Перейменувати..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "Дублювати..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "ПереміÑтити до..."
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr "ПереÑунути до Ñмітника"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "Створити Ñцену…"
@@ -3816,11 +3814,16 @@ msgid "Collapse All"
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 "Перейменувати"
+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"
@@ -3855,8 +3858,11 @@ msgid "Move"
msgstr "ПереміÑтити"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "У вказаному каталозі вже міÑтитьÑÑ Ñ‚ÐµÐºÐ° або файл із вказано назвою."
+#: 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"
@@ -8349,23 +8355,20 @@ msgid "Create a new rectangle."
msgstr "Створити прÑмокутник."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Rectangle"
-msgstr "Ðамалювати прÑмокутник"
+msgstr "Ðовий прÑмокутник"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new polygon."
msgstr "Створити новий полігон."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Polygon"
-msgstr "ПереміÑтити полігон"
+msgstr "Ðовий полігон"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete Selected Shape"
-msgstr "Вилучити вибране"
+msgstr "Вилучити позначену форму"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Keep polygon inside region Rect."
@@ -9846,6 +9849,10 @@ msgid "OpenGL ES 3.0"
msgstr "OpenGL ES 3.0"
#: 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"
@@ -12441,6 +12448,26 @@ msgstr ""
"ÐÐ½Ñ–Ð¼Ð°Ñ†Ñ–Ñ CPUParticles2D потребує викориÑÑ‚Ð°Ð½Ð½Ñ CanvasItemMaterial із "
"увімкненим параметром «ÐÐ½Ñ–Ð¼Ð°Ñ†Ñ–Ñ Ñ‡Ð°Ñток»."
+#: 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\" "
@@ -12774,6 +12801,26 @@ msgstr ""
"фізичним рушієм під Ñ‡Ð°Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸.\n"
"ЗаміÑÑ‚ÑŒ цієї зміни, вам варто змінити розміри дочірніх форм зіткненнÑ."
+#: 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-"
@@ -13018,6 +13065,9 @@ msgstr "Змінні величини можна пов'Ñзувати лише
msgid "Constants cannot be modified."
msgstr "Сталі не можна змінювати."
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "У вказаному каталозі вже міÑтитьÑÑ Ñ‚ÐµÐºÐ° або файл із вказано назвою."
+
#~ msgid "Missing 'build-tools' directory!"
#~ msgstr "Ðе знайдено каталогу «build-tools»!"
diff --git a/editor/translations/ur_PK.po b/editor/translations/ur_PK.po
index 33902a4398..a87c4865c2 100644
--- a/editor/translations/ur_PK.po
+++ b/editor/translations/ur_PK.po
@@ -1075,7 +1075,7 @@ msgstr ""
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3597,6 +3597,16 @@ 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 ""
@@ -3649,25 +3659,12 @@ msgstr ""
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr ""
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr ""
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr ""
#: editor/filesystem_dock.cpp
#, fuzzy
-msgid "Move to Trash"
-msgstr "ایکشن منتقل کریں"
-
-#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "New Scene..."
msgstr "سب سکریپشن بنائیں"
@@ -3691,10 +3688,16 @@ msgid "Collapse All"
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"
+msgid "Duplicate..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "ایکشن منتقل کریں"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
msgstr ""
#: editor/filesystem_dock.cpp
@@ -3728,7 +3731,10 @@ msgid "Move"
msgstr ""
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
+#: 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
@@ -9667,6 +9673,10 @@ 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"
@@ -12141,6 +12151,26 @@ msgid ""
"\"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\" "
@@ -12401,6 +12431,26 @@ msgid ""
"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-"
diff --git a/editor/translations/vi.po b/editor/translations/vi.po
index 500ad127b4..f08207bd30 100644
--- a/editor/translations/vi.po
+++ b/editor/translations/vi.po
@@ -1100,7 +1100,7 @@ msgstr ""
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3702,6 +3702,16 @@ msgid "Name contains invalid characters."
msgstr "Tên có chứa kí tự không hợp lệ."
#: 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 "Äổi tên tệp tin:"
@@ -3750,25 +3760,12 @@ msgstr "Chỉnh sửa các phần phụ thuộc..."
msgid "View Owners..."
msgstr "Xem các scene sở hữu..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "Äổi tên..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "Nhân đôi..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "Di chuyển đến..."
#: editor/filesystem_dock.cpp
#, fuzzy
-msgid "Move to Trash"
-msgstr "Di chuyển Nút"
-
-#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "New Scene..."
msgstr "Tạo Cảnh Mới"
@@ -3791,11 +3788,17 @@ msgid "Collapse All"
msgstr "Thu gá»n Tất cả"
#: 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 "Äổi tên"
+msgid "Duplicate..."
+msgstr "Nhân đôi..."
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "Di chuyển Nút"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr "Äổi tên..."
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -3830,8 +3833,11 @@ msgid "Move"
msgstr "Di chuyển"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "Äã có tệp tin hoặc thÆ° mục cùng tên tại vị trí này."
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr "Äổi tên"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
@@ -9839,6 +9845,10 @@ 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"
@@ -12390,6 +12400,26 @@ msgid ""
"\"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\" "
@@ -12650,6 +12680,26 @@ msgid ""
"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-"
@@ -12861,6 +12911,9 @@ msgstr ""
msgid "Constants cannot be modified."
msgstr "Không thể chỉnh sửa hằng số."
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "Äã có tệp tin hoặc thÆ° mục cùng tên tại vị trí này."
+
#~ msgid "Error trying to save layout!"
#~ msgstr "Lỗi khi cố gắng lưu bố cục!"
diff --git a/editor/translations/zh_CN.po b/editor/translations/zh_CN.po
index 3bf38ece6c..bd6c730382 100644
--- a/editor/translations/zh_CN.po
+++ b/editor/translations/zh_CN.po
@@ -72,11 +72,12 @@
# Gardner Belgrade <hapenia@sina.com>, 2020.
# godhidden <z2zz2zz@yahoo.com>, 2020.
# BinotaLIU <me@binota.org>, 2020.
+# TakWolf <takwolf@foxmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Chinese (Simplified) (Godot Engine)\n"
"POT-Creation-Date: 2018-01-20 12:15+0200\n"
-"PO-Revision-Date: 2020-11-20 23:08+0000\n"
+"PO-Revision-Date: 2020-11-29 08:29+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"
@@ -1144,7 +1145,7 @@ msgstr "孤立资æºæµè§ˆå™¨"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3689,6 +3690,16 @@ 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 "é‡å‘½å文件:"
@@ -3736,23 +3747,11 @@ msgstr "编辑ä¾èµ–..."
msgid "View Owners..."
msgstr "查看所有者..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "é‡å‘½å为..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "é‡å¤..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "移动..."
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr "移动至回收站"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "新建场景..."
@@ -3775,11 +3774,16 @@ msgid "Collapse All"
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 "é‡å‘½å"
+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"
@@ -3814,8 +3818,11 @@ msgid "Move"
msgstr "移动"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "当å‰ä½ç½®å·²å­˜åœ¨åŒå文件或文件夹。"
+#: 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"
@@ -7326,7 +7333,7 @@ msgstr "é”定视角旋转"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Display Normal"
-msgstr "显示法线"
+msgstr "显示标准"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Display Wireframe"
@@ -8254,23 +8261,20 @@ msgid "Create a new rectangle."
msgstr "创建新矩形。"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Rectangle"
-msgstr "绘制矩形"
+msgstr "新建矩形"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new polygon."
msgstr "创建新多边形。"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Polygon"
-msgstr "移动多边形"
+msgstr "新建多边形"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete Selected Shape"
-msgstr "删除选中项"
+msgstr "删除所选形状"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Keep polygon inside region Rect."
@@ -9700,6 +9704,10 @@ msgid "OpenGL ES 3.0"
msgstr "OpenGL ES 3.0"
#: 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"
@@ -12201,6 +12209,26 @@ msgstr ""
"CPUParticles2D 动画需è¦ä½¿ç”¨å¯ç”¨äº† “Particles Animation†的 "
"CanvasItemMaterial。"
+#: 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\" "
@@ -12497,6 +12525,26 @@ msgstr ""
"的覆盖。\n"
"建议您修改å­èŠ‚点的碰撞形状。"
+#: 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-"
@@ -12727,6 +12775,9 @@ msgstr "å˜é‡åªèƒ½åœ¨é¡¶ç‚¹å‡½æ•°ä¸­æŒ‡å®šã€‚"
msgid "Constants cannot be modified."
msgstr "ä¸å…许修改常é‡ã€‚"
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "当å‰ä½ç½®å·²å­˜åœ¨åŒå文件或文件夹。"
+
#~ msgid "Missing 'build-tools' directory!"
#~ msgstr "缺失“build-toolsâ€ç›®å½•ï¼"
diff --git a/editor/translations/zh_HK.po b/editor/translations/zh_HK.po
index 5ed91fb436..b3faa76c3c 100644
--- a/editor/translations/zh_HK.po
+++ b/editor/translations/zh_HK.po
@@ -1128,7 +1128,7 @@ msgstr ""
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3801,6 +3801,16 @@ 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 "é‡æ–°å‘½å檔案:"
@@ -3853,26 +3863,12 @@ msgstr "編輯Dependencies..."
msgid "View Owners..."
msgstr ""
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
-msgid "Rename..."
-msgstr "é‡æ–°å‘½å..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "å†è£½..."
-
#: editor/filesystem_dock.cpp
#, fuzzy
msgid "Move To..."
msgstr "æ¬åˆ°..."
#: editor/filesystem_dock.cpp
-#, fuzzy
-msgid "Move to Trash"
-msgstr "移動Autoload"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "新增場景..."
@@ -3895,11 +3891,18 @@ msgid "Collapse All"
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 "é‡æ–°å‘½å"
+msgid "Duplicate..."
+msgstr "å†è£½..."
+
+#: editor/filesystem_dock.cpp
+#, fuzzy
+msgid "Move to Trash"
+msgstr "移動Autoload"
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+#, fuzzy
+msgid "Rename..."
+msgstr "é‡æ–°å‘½å..."
#: editor/filesystem_dock.cpp
#, fuzzy
@@ -3937,8 +3940,11 @@ msgid "Move"
msgstr "移動"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "æ­¤ä½ç½®å·²å­˜åœ¨åŒå的檔案或資料夾。"
+#: 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
#, fuzzy
@@ -10089,6 +10095,10 @@ 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"
@@ -12663,6 +12673,26 @@ msgid ""
"\"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\" "
@@ -12923,6 +12953,26 @@ msgid ""
"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-"
@@ -13131,6 +13181,9 @@ msgstr ""
msgid "Constants cannot be modified."
msgstr ""
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "æ­¤ä½ç½®å·²å­˜åœ¨åŒå的檔案或資料夾。"
+
#, fuzzy
#~ msgid "Error trying to save layout!"
#~ msgstr "儲存佈局時出ç¾éŒ¯èª¤ï¼"
diff --git a/editor/translations/zh_TW.po b/editor/translations/zh_TW.po
index 1c9d2b77c1..dc3c1f49f7 100644
--- a/editor/translations/zh_TW.po
+++ b/editor/translations/zh_TW.po
@@ -29,7 +29,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-11-20 23:08+0000\n"
+"PO-Revision-Date: 2020-12-07 08:11+0000\n"
"Last-Translator: BinotaLIU <me@binota.org>\n"
"Language-Team: Chinese (Traditional) <https://hosted.weblate.org/projects/"
"godot-engine/godot/zh_Hant/>\n"
@@ -1097,7 +1097,7 @@ msgstr "孤立資æºç€è¦½å™¨"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.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"
@@ -3644,6 +3644,16 @@ 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 "é‡æ–°å‘½å檔案:"
@@ -3691,23 +3701,11 @@ msgstr "編輯相ä¾æ€§..."
msgid "View Owners..."
msgstr "檢視æ“有者..."
-#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
-msgid "Rename..."
-msgstr "é‡æ–°å‘½å..."
-
-#: editor/filesystem_dock.cpp
-msgid "Duplicate..."
-msgstr "é‡è¤‡..."
-
#: editor/filesystem_dock.cpp
msgid "Move To..."
msgstr "移動至..."
#: editor/filesystem_dock.cpp
-msgid "Move to Trash"
-msgstr "移動至資æºå›žæ”¶æ¡¶"
-
-#: editor/filesystem_dock.cpp
msgid "New Scene..."
msgstr "新增場景..."
@@ -3730,11 +3728,16 @@ msgid "Collapse All"
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 "é‡æ–°å‘½å"
+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"
@@ -3769,8 +3772,11 @@ msgid "Move"
msgstr "移動"
#: editor/filesystem_dock.cpp
-msgid "There is already file or folder with the same name in this location."
-msgstr "該ä½ç½®å·²æœ‰ç›¸åŒå稱的檔案或資料夾。"
+#: 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"
@@ -8210,23 +8216,20 @@ msgid "Create a new rectangle."
msgstr "建立新矩形。"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Rectangle"
-msgstr "矩形繪製"
+msgstr "新增矩形"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new polygon."
msgstr "建立新多邊形。"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Polygon"
-msgstr "移動多邊形"
+msgstr "新增多邊形"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete Selected Shape"
-msgstr "刪除所é¸"
+msgstr "刪除所é¸å½¢ç‹€"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Keep polygon inside region Rect."
@@ -9656,6 +9659,10 @@ msgid "OpenGL ES 3.0"
msgstr "OpenGL ES 3.0"
#: 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"
@@ -12162,6 +12169,26 @@ msgstr ""
"CPUParticles2D 動畫需è¦ä½¿ç”¨æœ‰å•Ÿç”¨ã€ŒParticles Animation(粒å­å‹•ç•«ï¼‰ã€çš„ "
"CanvasItemMaterial。"
+#: 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\" "
@@ -12456,6 +12483,26 @@ msgstr ""
"複寫。\n"
"請改為修改其å­ç¯€é»žçš„碰撞形狀之大å°ã€‚"
+#: 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-"
@@ -12687,6 +12734,9 @@ msgstr "Varying 變數åªå¯åœ¨é ‚點函å¼ä¸­æŒ‡æ´¾ã€‚"
msgid "Constants cannot be modified."
msgstr "ä¸å¯ä¿®æ”¹å¸¸æ•¸ã€‚"
+#~ msgid "There is already file or folder with the same name in this location."
+#~ msgstr "該ä½ç½®å·²æœ‰ç›¸åŒå稱的檔案或資料夾。"
+
#~ msgid "Missing 'build-tools' directory!"
#~ msgstr "缺少「build-toolsã€è³‡æ–™å¤¾ï¼"
diff --git a/icon.png b/icon.png
index 6ad9b43117..aaa3782008 100644
--- a/icon.png
+++ b/icon.png
Binary files differ
diff --git a/icon.svg b/icon.svg
index 5d075125e3..1add292da2 100644
--- a/icon.svg
+++ b/icon.svg
@@ -1,6 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
@@ -13,7 +11,7 @@
height="1024"
id="svg3030"
version="1.1"
- inkscape:version="0.92.1 r15371"
+ inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
sodipodi:docname="icon.svg"
inkscape:export-filename="/home/akien/Projects/godot/godot.git/icon.png"
inkscape:export-xdpi="24"
@@ -27,17 +25,18 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
- inkscape:zoom="0.35"
- inkscape:cx="707.24666"
- inkscape:cy="14.063809"
+ inkscape:zoom="0.8359375"
+ inkscape:cx="512"
+ inkscape:cy="512"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
- inkscape:window-width="1920"
- inkscape:window-height="1011"
- inkscape:window-x="0"
- inkscape:window-y="0"
- inkscape:window-maximized="1" />
+ inkscape:window-width="1916"
+ inkscape:window-height="1025"
+ inkscape:window-x="1360"
+ inkscape:window-y="53"
+ inkscape:window-maximized="1"
+ inkscape:document-rotation="0" />
<metadata
id="metadata3035">
<rdf:RDF>
@@ -46,7 +45,7 @@
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title />
+ <dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
@@ -70,10 +69,11 @@
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 h 0.134 c 4.795,6.12 9.232,12.569 13.487,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.368,12.569 -4.928,6.12 -0.134,0 Z"
- style="fill:#478cbf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.32031175"
+ 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" />
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccsssscccccccccccccccccccsccccccccccc" />
</g>
<g
id="g86-7"
diff --git a/logo.png b/logo.png
index 60e2ee9532..c55a2772a9 100644
--- a/logo.png
+++ b/logo.png
Binary files differ
diff --git a/logo.svg b/logo.svg
index d6f4235ac3..d771908952 100644
--- a/logo.svg
+++ b/logo.svg
@@ -1,6 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
@@ -11,7 +9,7 @@
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg2"
version="1.1"
- inkscape:version="0.92.1 r15371"
+ inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
xml:space="preserve"
width="1024"
height="414"
@@ -22,7 +20,7 @@
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
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs6"><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath16"><path
@@ -37,21 +35,22 @@
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
- inkscape:window-width="1920"
- inkscape:window-height="1011"
+ inkscape:window-width="1916"
+ inkscape:window-height="1025"
id="namedview4"
showgrid="false"
- inkscape:zoom="0.63432763"
- inkscape:cx="166.44059"
- inkscape:cy="101.14582"
- inkscape:window-x="0"
- inkscape:window-y="0"
+ 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" /><g
+ fit-margin-bottom="48"
+ inkscape:document-rotation="0" /><g
id="g10"
inkscape:groupmode="layer"
inkscape:label="godot_engine_logo_2017_curves-01"
@@ -171,10 +170,11 @@
id="g82"
transform="matrix(1.1310535,0,0,1.1310535,126.80608,346.04533)"
style="stroke-width:0.88413143"><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 h 0.134 c 4.795,6.12 9.232,12.569 13.487,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.368,12.569 -4.928,6.12 -0.134,0 Z"
- style="fill:#478cbf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.88413143"
+ 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" /></g><g
+ 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.88413143"><path
diff --git a/main/main.cpp b/main/main.cpp
index a824b53e5a..c492cfaad7 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -1121,6 +1121,11 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
}
#endif
+ // Only flush stdout in debug builds by default, as spamming `print()` will
+ // decrease performance if this is enabled.
+ GLOBAL_DEF("application/run/flush_stdout_on_print", false);
+ GLOBAL_DEF("application/run/flush_stdout_on_print.debug", true);
+
GLOBAL_DEF("logging/file_logging/enable_file_logging", false);
// Only file logging by default on desktop platforms as logs can't be
// accessed easily on mobile/Web platforms (if at all).
diff --git a/methods.py b/methods.py
index f7134b472b..15eb82ae74 100644
--- a/methods.py
+++ b/methods.py
@@ -843,7 +843,7 @@ def show_progress(env):
try:
with open(node_count_fname) as f:
node_count_max = int(f.readline())
- except:
+ except Exception:
pass
cache_directory = os.environ.get("SCONS_CACHE")
diff --git a/misc/dist/document_icons/project.svg b/misc/dist/document_icons/project.svg
index 3feed413dd..9b2644186a 100644
--- a/misc/dist/document_icons/project.svg
+++ b/misc/dist/document_icons/project.svg
@@ -1 +1 @@
-<svg height="1024" width="1024" xmlns="http://www.w3.org/2000/svg"><path d="m812.681 293.783c-23.575-32.542-141.93-39.864-197.505-34.983 2.17-68.048 31.457-117.655-37.966-177.025m-415.32-32.625h302.11c77.128-2.02 126.554 37.836 178.444 84.882l123.665 109.83c63.819 56.94 89.13 110.624 96 188.174v542.885h-700.219z" fill="#eff1f5" stroke="#9f9fa1" stroke-linecap="round" stroke-linejoin="round" stroke-width="19.603"/><g stroke-width=".32"><path d="m712.572 590.17s-.666-4.089-1.056-4.052l-74.179 7.157a12.056 12.056 0 0 0 -10.9 11.191l-2.038 29.21-57.387 4.094-3.905-26.472c-.868-5.888-6.01-10.327-11.961-10.327h-78.292c-5.95 0-11.09 4.439-11.96 10.327l-3.906 26.472-57.387-4.095-2.038-29.208a12.057 12.057 0 0 0 -10.901-11.194l-74.214-7.155c-.384-.037-.665 4.056-1.049 4.056l-.1 16.052 62.853 10.136 2.059 29.47c.416 5.965 5.23 10.788 11.2 11.217l79.035 5.638c.299.021.594.033.89.033 5.94 0 11.072-4.44 11.941-10.329l4.017-27.237h57.414l4.017 27.237c.867 5.886 6.006 10.326 11.953 10.326.292 0 .583-.009.868-.03l79.046-5.638c5.967-.428 10.783-5.252 11.2-11.218l2.056-29.469 62.826-10.18z" fill="#fff"/><path d="m311.398 469.127v121.042c.221.003.443.01.662.031l74.207 7.155a7.99 7.99 0 0 1 7.204 7.4l2.289 32.756 64.731 4.619 4.46-30.234a7.99 7.99 0 0 1 7.904-6.824h78.292a7.99 7.99 0 0 1 7.904 6.824l4.458 30.234 64.733-4.619 2.287-32.757a7.993 7.993 0 0 1 7.203-7.4l74.178-7.154c.22-.02.44-.028.66-.031v-9.658l.032-.01v-111.373h.275c9.83-12.547 18.926-25.768 27.65-39.874-11.586-19.722-25.78-37.347-40.954-53.677-14.073 7.083-27.74 15.108-40.65 23.647-6.46-6.421-13.736-11.674-20.883-17.164-7.022-5.64-14.936-9.775-22.44-14.593 2.234-16.641 3.339-33.024 3.783-50.122-19.366-9.747-40.017-16.209-60.905-20.85-8.34 14.017-15.967 29.196-22.61 44.035-7.876-1.316-15.79-1.804-23.713-1.898v-.013c-.055 0-.107.013-.154.013-.05 0-.1-.013-.15-.013v.013c-7.937.095-15.845.582-23.724 1.898-6.638-14.84-14.261-30.018-22.613-44.035-20.879 4.641-41.532 11.104-60.895 20.85.442 17.098 1.548 33.48 3.788 50.122-7.52 4.818-15.423 8.953-22.447 14.592-7.137 5.491-14.425 10.745-20.887 17.165-12.91-8.539-26.573-16.564-40.65-23.646-15.173 16.329-29.36 33.953-40.95 53.676 8.72 14.106 17.823 27.327 27.65 39.874z" fill="#478cbf"/><path d="m646 612.615-2.3 32.93a7.992 7.992 0 0 1 -7.402 7.413l-79.044 5.64a7.991 7.991 0 0 1 -8.474-6.806l-4.531-30.74h-64.496l-4.533 30.74c-.608 4.137-4.308 7.112-8.474 6.806l-79.043-5.64a7.992 7.992 0 0 1 -7.402-7.413l-2.3-32.931-66.726-6.434c.032 7.173.124 15.028.124 16.592 0 70.472 89.397 104.344 200.465 104.734h.273c111.07-.39 200.435-34.262 200.435-104.734 0-1.592.096-9.416.129-16.592z" fill="#478cbf"/><path d="m451.527 518.261c0 24.71-20.02 44.725-44.72 44.725-24.688 0-44.714-20.016-44.714-44.725 0-24.691 20.026-44.697 44.713-44.697 24.7 0 44.72 20.006 44.72 44.697" fill="#fff"/><path d="m440.766 520.915c0 16.388-13.283 29.671-29.684 29.671-16.393 0-29.684-13.283-29.684-29.671 0-16.39 13.29-29.685 29.684-29.685 16.401 0 29.684 13.295 29.684 29.685" fill="#414042"/><path d="m511.997 567.054c-7.951 0-14.394-5.86-14.394-13.081v-41.17c0-7.216 6.444-13.08 14.394-13.08s14.408 5.864 14.408 13.08v41.17c0 7.222-6.458 13.081-14.408 13.081m60.477-48.793c0 24.71 20.02 44.725 44.724 44.725 24.686 0 44.71-20.016 44.71-44.725 0-24.691-20.024-44.697-44.71-44.697-24.704 0-44.724 20.006-44.724 44.697" fill="#fff"/><path d="m583.238 520.915c0 16.388 13.279 29.671 29.668 29.671 16.405 0 29.683-13.283 29.683-29.671 0-16.39-13.278-29.685-29.684-29.685-16.388 0-29.668 13.295-29.668 29.685" fill="#414042"/></g><text style="font-weight:800;font-size:16;font-family:Montserrat;letter-spacing:0;word-spacing:0;fill:#333f67" x="234.416" y="878.644"><tspan font-size="112" x="234.416" y="878.644">PROJECT</tspan></text></svg>
+<svg height="1024" width="1024" xmlns="http://www.w3.org/2000/svg"><path d="m812.681 293.783c-23.575-32.542-141.93-39.864-197.505-34.983 2.17-68.048 31.457-117.655-37.966-177.025m-415.32-32.625h302.11c77.128-2.02 126.554 37.836 178.444 84.882l123.665 109.83c63.819 56.94 89.13 110.624 96 188.174v542.885h-700.219z" fill="#eff1f5" stroke="#9f9fa1" stroke-linecap="round" stroke-linejoin="round" stroke-width="19.603"/><g stroke-width=".32"><path d="m712.572 590.17s-.666-4.089-1.056-4.052l-74.179 7.157a12.056 12.056 0 0 0 -10.9 11.191l-2.038 29.21-57.387 4.094-3.905-26.472c-.868-5.888-6.01-10.327-11.961-10.327h-78.292c-5.95 0-11.09 4.439-11.96 10.327l-3.906 26.472-57.387-4.095-2.038-29.208a12.057 12.057 0 0 0 -10.901-11.194l-74.214-7.155c-.384-.037-.665 4.056-1.049 4.056l-.1 16.052 62.853 10.136 2.059 29.47c.416 5.965 5.23 10.788 11.2 11.217l79.035 5.638c.299.021.594.033.89.033 5.94 0 11.072-4.44 11.941-10.329l4.017-27.237h57.414l4.017 27.237c.867 5.886 6.006 10.326 11.953 10.326.292 0 .583-.009.868-.03l79.046-5.638c5.967-.428 10.783-5.252 11.2-11.218l2.056-29.469 62.826-10.18z" fill="#fff"/><path d="m311.398 469.127v121.042c.221.003.443.01.662.031l74.207 7.155c3.88703.37478 6.93367 3.50431 7.204 7.4l2.289 32.756 64.731 4.619 4.46-30.234c.57822-3.91981 3.94178-6.82377 7.904-6.824h78.292c3.96222.00023 7.32578 2.90419 7.904 6.824l4.458 30.234 64.733-4.619 2.287-32.757c.27147-3.89481 3.31693-7.02357 7.203-7.4l74.178-7.154c.22-.02.44-.028.66-.031v-9.658l.032-.01v-111.373c10.4496-13.15476 20.3441-27.66594 27.925-39.874-11.586-19.722-25.78-37.347-40.954-53.677-14.073 7.083-27.74 15.108-40.65 23.647-6.46-6.421-13.736-11.674-20.883-17.164-7.022-5.64-14.936-9.775-22.44-14.593 2.234-16.641 3.339-33.024 3.783-50.122-19.366-9.747-40.017-16.209-60.905-20.85-8.34 14.017-15.967 29.196-22.61 44.035-7.876-1.316-15.79-1.804-23.713-1.898v-.013c-.055 0-.107.013-.154.013-.05 0-.1-.013-.15-.013v.013c-7.937.095-15.845.582-23.724 1.898-6.638-14.84-14.261-30.018-22.613-44.035-20.879 4.641-41.532 11.104-60.895 20.85.442 17.098 1.548 33.48 3.788 50.122-7.52 4.818-15.423 8.953-22.447 14.592-7.137 5.491-14.425 10.745-20.887 17.165-12.91-8.539-26.573-16.564-40.65-23.646-15.173 16.329-29.36 33.953-40.95 53.676 9.10746 14.29708 18.8786 28.66782 27.925 39.873z" fill="#478cbf"/><path d="m646 612.615-2.3 32.93a7.992 7.992 0 0 1 -7.402 7.413l-79.044 5.64a7.991 7.991 0 0 1 -8.474-6.806l-4.531-30.74h-64.496l-4.533 30.74c-.608 4.137-4.308 7.112-8.474 6.806l-79.043-5.64a7.992 7.992 0 0 1 -7.402-7.413l-2.3-32.931-66.726-6.434c.032 7.173.124 15.028.124 16.592 0 70.472 89.397 104.344 200.465 104.734h.273c111.07-.39 200.435-34.262 200.435-104.734 0-1.592.096-9.416.129-16.592z" fill="#478cbf"/><path d="m451.527 518.261c0 24.71-20.02 44.725-44.72 44.725-24.688 0-44.714-20.016-44.714-44.725 0-24.691 20.026-44.697 44.713-44.697 24.7 0 44.72 20.006 44.72 44.697" fill="#fff"/><path d="m440.766 520.915c0 16.388-13.283 29.671-29.684 29.671-16.393 0-29.684-13.283-29.684-29.671 0-16.39 13.29-29.685 29.684-29.685 16.401 0 29.684 13.295 29.684 29.685" fill="#414042"/><path d="m511.997 567.054c-7.951 0-14.394-5.86-14.394-13.081v-41.17c0-7.216 6.444-13.08 14.394-13.08s14.408 5.864 14.408 13.08v41.17c0 7.222-6.458 13.081-14.408 13.081m60.477-48.793c0 24.71 20.02 44.725 44.724 44.725 24.686 0 44.71-20.016 44.71-44.725 0-24.691-20.024-44.697-44.71-44.697-24.704 0-44.724 20.006-44.724 44.697" fill="#fff"/><path d="m583.238 520.915c0 16.388 13.279 29.671 29.668 29.671 16.405 0 29.683-13.283 29.683-29.671 0-16.39-13.278-29.685-29.684-29.685-16.388 0-29.668 13.295-29.668 29.685" fill="#414042"/></g><text style="font-weight:800;font-size:16;font-family:Montserrat;letter-spacing:0;word-spacing:0;fill:#333f67" x="234.416" y="878.644"><tspan font-size="112" x="234.416" y="878.644">PROJECT</tspan></text></svg>
diff --git a/misc/dist/document_icons/project_extra_small.svg b/misc/dist/document_icons/project_extra_small.svg
index f17789b69a..1fa1e728e9 100644
--- a/misc/dist/document_icons/project_extra_small.svg
+++ b/misc/dist/document_icons/project_extra_small.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M12.698 4.59c-.368-.508-2.218-.623-3.086-.546.034-1.064.492-1.839-.593-2.766m-6.49-.51H7.25c1.205-.032 1.977.591 2.788 1.326L11.97 3.81c.998.89 1.393 1.729 1.5 2.94v8.483H2.53z" fill="#eff1f5" stroke="#9f9fa1" stroke-linecap="round" stroke-linejoin="round"/><g stroke-width=".32"><path d="M12.062 10.583s-.014-.083-.022-.082l-1.502.145a.244.244 0 0 0-.22.226l-.042.592-1.162.083-.079-.536a.246.246 0 0 0-.242-.21H7.208c-.12 0-.225.09-.243.21l-.079.536-1.162-.083-.041-.592a.244.244 0 0 0-.22-.226L3.958 10.5c-.007-.001-.013.082-.02.082l-.003.325 1.273.205.042.597c.008.12.105.218.226.227l1.6.114h.019c.12 0 .224-.089.242-.208l.081-.552h1.163l.08.552a.246.246 0 0 0 .26.208l1.601-.114a.246.246 0 0 0 .227-.227l.042-.597 1.272-.206z" fill="#fff"/><path d="M3.938 8.132v2.45l.013.001 1.503.145a.162.162 0 0 1 .146.15l.046.663 1.311.094.09-.612a.162.162 0 0 1 .16-.138h1.586a.162.162 0 0 1 .16.138l.09.612 1.311-.094.046-.663a.162.162 0 0 1 .146-.15l1.502-.145h.014V8.132h.006c.2-.254.383-.522.56-.808a6.285 6.285 0 0 0-.83-1.087 8.105 8.105 0 0 0-.823.48c-.13-.13-.278-.237-.422-.348-.143-.115-.303-.198-.455-.296a9.38 9.38 0 0 0 .077-1.015 5.275 5.275 0 0 0-1.234-.422 8.781 8.781 0 0 0-.457.892 3.13 3.13 0 0 0-.48-.039H8h-.003c-.16.002-.32.012-.48.039a8.71 8.71 0 0 0-.458-.892 5.276 5.276 0 0 0-1.233.422c.009.346.031.678.076 1.015-.152.098-.312.181-.454.296-.145.11-.292.217-.423.347a8.093 8.093 0 0 0-.823-.479c-.307.331-.595.688-.83 1.087.177.286.361.554.56.808z" fill="#478cbf"/><path d="M10.714 11.037l-.047.667a.162.162 0 0 1-.15.15l-1.6.114a.162.162 0 0 1-.172-.137l-.092-.623H7.347l-.092.623a.162.162 0 0 1-.171.137l-1.6-.114a.162.162 0 0 1-.15-.15l-.047-.667-1.351-.13.002.336c0 1.427 1.81 2.113 4.06 2.12h.005c2.25-.007 4.059-.693 4.059-2.12l.002-.336z" fill="#478cbf"/><path d="M6.776 9.127a.905.905 0 1 1-1.811 0 .905.905 0 0 1 1.81 0" fill="#fff"/><path d="M6.558 9.18a.6.6 0 1 1-1.202 0 .6.6 0 0 1 1.202 0" fill="#414042"/><path d="M8 10.115c-.16 0-.291-.119-.291-.265v-.834c0-.146.13-.265.291-.265.161 0 .292.119.292.265v.834c0 .146-.13.265-.292.265m1.225-.988a.906.906 0 1 0 1.81 0 .906.906 0 0 0-1.81 0" fill="#fff"/><path d="M9.443 9.18a.6.6 0 1 0 1.201 0 .6.6 0 0 0-1.201 0" fill="#414042"/></g></svg>
+<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12.698 4.59c-.368-.508-2.218-.623-3.086-.546.034-1.064.492-1.839-.593-2.766m-6.49-.51h4.721c1.205-.032 1.977.591 2.788 1.326l1.932 1.716c.998.89 1.393 1.729 1.5 2.94v8.483h-10.94z" fill="#eff1f5" stroke="#9f9fa1" stroke-linecap="round" stroke-linejoin="round"/><g stroke-width=".32"><path d="m12.062 10.583s-.014-.083-.022-.082l-1.502.145a.244.244 0 0 0 -.22.226l-.042.592-1.162.083-.079-.536a.246.246 0 0 0 -.242-.21h-1.585c-.12 0-.225.09-.243.21l-.079.536-1.162-.083-.041-.592a.244.244 0 0 0 -.22-.226l-1.505-.146c-.007-.001-.013.082-.02.082l-.003.325 1.273.205.042.597c.008.12.105.218.226.227l1.6.114h.019c.12 0 .224-.089.242-.208l.081-.552h1.163l.08.552a.246.246 0 0 0 .26.208l1.601-.114a.246.246 0 0 0 .227-.227l.042-.597 1.272-.206z" fill="#fff"/><path d="m3.938 8.132v2.45l.013.001 1.503.145c.078773.0076.1405059.07105.146.15l.046.663 1.311.094.09-.612c.01187-.07924.079879-.137895.16-.138h1.586c.080121.000105.1481303.05876.16.138l.09.612 1.311-.094.046-.663c.0055-.07895.06723-.142375.146-.15l1.502-.145h.014v-2.451c.22118-.2597567.402804-.5673567.566-.808-.236303-.3914463-.514617-.7559371-.83-1.087-.283508.1437236-.558316.3040004-.823.48-.13-.13-.278-.237-.422-.348-.143-.115-.303-.198-.455-.296.044019-.3366902.069724-.6755224.077-1.015-.392294-.1911688-.8067944-.3329185-1.234-.422-.1691916.2883902-.3217734.5862085-.457.892-.158761-.0253078-.3192359-.0383464-.48-.039h-.004-.003c-.16.002-.32.012-.48.039-.135411-.3058816-.288331-.6037083-.458-.892-.4268603.0891708-.841019.2309186-1.233.422.009.346.031.678.076 1.015-.152.098-.312.181-.454.296-.145.11-.292.217-.423.347-.264694-.1756817-.5395029-.3356251-.823-.479-.307.331-.595.688-.83 1.087.1718588.2982703.3967405.5717122.566.808z" fill="#478cbf"/><path d="m10.714 11.037-.047.667a.162.162 0 0 1 -.15.15l-1.6.114a.162.162 0 0 1 -.172-.137l-.092-.623h-1.306l-.092.623a.162.162 0 0 1 -.171.137l-1.6-.114a.162.162 0 0 1 -.15-.15l-.047-.667-1.351-.13.002.336c0 1.427 1.81 2.113 4.06 2.12h.005c2.25-.007 4.059-.693 4.059-2.12l.002-.336z" fill="#478cbf"/><path d="m6.776 9.127a.905.905 0 1 1 -1.811 0 .905.905 0 0 1 1.81 0" fill="#fff"/><path d="m6.558 9.18a.6.6 0 1 1 -1.202 0 .6.6 0 0 1 1.202 0" fill="#414042"/><path d="m8 10.115c-.16 0-.291-.119-.291-.265v-.834c0-.146.13-.265.291-.265s.292.119.292.265v.834c0 .146-.13.265-.292.265m1.225-.988a.906.906 0 1 0 1.81 0 .906.906 0 0 0 -1.81 0" fill="#fff"/><path d="m9.443 9.18a.6.6 0 1 0 1.201 0 .6.6 0 0 0 -1.201 0" fill="#414042"/></g></svg>
diff --git a/misc/dist/document_icons/project_small.svg b/misc/dist/document_icons/project_small.svg
index d9473b1da3..058eded3ee 100644
--- a/misc/dist/document_icons/project_small.svg
+++ b/misc/dist/document_icons/project_small.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32"><path d="M25.396 9.18c-.736-1.016-4.435-1.245-6.172-1.093.068-2.126.983-3.676-1.186-5.532M5.059 1.536H14.5c2.41-.063 3.955 1.182 5.576 2.652l3.865 3.433c1.994 1.779 2.785 3.457 3 5.88v16.965H5.059z" fill="#eff1f5" stroke="#9f9fa1" stroke-linecap="round" stroke-linejoin="round"/><g stroke-width=".32"><path d="M22.268 20.443s-.02-.128-.033-.127l-2.318.224a.377.377 0 0 0-.34.35l-.064.912-1.793.128-.122-.827a.38.38 0 0 0-.374-.323h-2.447a.38.38 0 0 0-.374.323l-.122.827-1.793-.128-.064-.913a.377.377 0 0 0-.34-.35l-2.32-.223c-.011-.001-.02.127-.032.127l-.003.501 1.964.317.064.921a.38.38 0 0 0 .35.35l2.47.177h.028a.38.38 0 0 0 .373-.322l.125-.851h1.795l.125.851a.38.38 0 0 0 .4.322l2.471-.176a.38.38 0 0 0 .35-.351l.064-.92 1.964-.32z" fill="#fff"/><path d="M9.732 16.66v3.783h.02l2.32.224a.25.25 0 0 1 .224.231l.072 1.024 2.023.144.14-.945a.25.25 0 0 1 .246-.213h2.447a.25.25 0 0 1 .247.213l.14.945 2.022-.144.072-1.024a.25.25 0 0 1 .225-.23l2.318-.225h.02v-.302h.001V16.66h.009c.307-.392.591-.805.864-1.246a9.7 9.7 0 0 0-1.28-1.677c-.44.22-.867.472-1.27.738-.202-.2-.43-.364-.653-.536-.22-.176-.466-.305-.701-.456.07-.52.104-1.032.118-1.566a8.14 8.14 0 0 0-1.903-.652c-.26.438-.499.913-.707 1.376a4.832 4.832 0 0 0-.74-.059h-.01a4.837 4.837 0 0 0-.742.06 13.44 13.44 0 0 0-.706-1.377 8.142 8.142 0 0 0-1.903.652c.014.534.048 1.046.118 1.566-.235.15-.482.28-.701.456-.223.172-.451.336-.653.536-.403-.266-.83-.517-1.27-.738a9.704 9.704 0 0 0-1.28 1.677c.273.44.557.854.864 1.246z" fill="#478cbf"/><path d="M20.188 21.144l-.072 1.029a.25.25 0 0 1-.231.232l-2.47.176a.25.25 0 0 1-.265-.213l-.142-.96h-2.015l-.142.96a.25.25 0 0 1-.265.213l-2.47-.176a.25.25 0 0 1-.231-.232l-.072-1.03-2.085-.2c0 .224.004.47.004.518 0 2.203 2.793 3.261 6.264 3.273h.009c3.47-.012 6.263-1.07 6.263-3.273l.004-.518z" fill="#478cbf"/><path d="M14.11 18.195a1.397 1.397 0 1 1-2.794.001 1.397 1.397 0 0 1 2.795 0" fill="#fff"/><path d="M13.774 18.278a.927.927 0 1 1-1.854 0 .927.927 0 0 1 1.854 0" fill="#414042"/><path d="M16 19.72c-.248 0-.45-.183-.45-.409v-1.286c0-.226.202-.409.45-.409.249 0 .45.183.45.409v1.286c0 .226-.201.41-.45.41m1.89-1.526a1.397 1.397 0 1 0 2.795 0 1.397 1.397 0 0 0-2.795 0" fill="#fff"/><path d="M18.227 18.278a.927.927 0 1 0 1.854 0 .927.927 0 0 0-1.854 0" fill="#414042"/></g></svg>
+<svg height="32" width="32" xmlns="http://www.w3.org/2000/svg"><path d="m25.396 9.18c-.736-1.016-4.435-1.245-6.172-1.093.068-2.126.983-3.676-1.186-5.532m-12.979-1.019h9.441c2.41-.063 3.955 1.182 5.576 2.652l3.865 3.433c1.994 1.779 2.785 3.457 3 5.88v16.965h-21.882z" fill="#eff1f5" stroke="#9f9fa1" stroke-linecap="round" stroke-linejoin="round"/><g stroke-width=".32"><path d="m22.268 20.443s-.02-.128-.033-.127l-2.318.224a.377.377 0 0 0 -.34.35l-.064.912-1.793.128-.122-.827a.38.38 0 0 0 -.374-.323h-2.447a.38.38 0 0 0 -.374.323l-.122.827-1.793-.128-.064-.913a.377.377 0 0 0 -.34-.35l-2.32-.223c-.011-.001-.02.127-.032.127l-.003.501 1.964.317.064.921a.38.38 0 0 0 .35.35l2.47.177h.028a.38.38 0 0 0 .373-.322l.125-.851h1.795l.125.851a.38.38 0 0 0 .4.322l2.471-.176a.38.38 0 0 0 .35-.351l.064-.92 1.964-.32z" fill="#fff"/><path d="m9.732 16.66v3.783h.02l2.32.224c.120882.01233.215393.109796.224.231l.072 1.024 2.023.144.14-.945c.01825-.121952.122691-.212385.246-.213h2.447c.123688.000122.228694.09067.247.213l.14.945 2.022-.144.072-1.024c.0091-.121156.104074-.218195.225-.23l2.318-.225h.02v-.302h.001v-3.481c.337369-.403598.623887-.872775.873-1.246-.364428-.603874-.793632-1.166199-1.28-1.677-.44.22-.867.472-1.27.738-.202-.2-.43-.364-.653-.536-.22-.176-.466-.305-.701-.456.07-.52.104-1.032.118-1.566-.604936-.295179-1.244149-.514184-1.903-.652-.26.438-.499.913-.707 1.376-.244789-.03861-.492185-.05834-.74-.059h-.01c-.248507.00091-.496575.02097-.742.06-.208692-.472178-.444416-.93194-.706-1.377-.658846.137836-1.298056.35684-1.903.652.014.534.048 1.046.118 1.566-.235.15-.482.28-.701.456-.223.172-.451.336-.653.536-.403-.266-.83-.517-1.27-.738-.4863434.510822-.9155458 1.073144-1.28 1.677.2695251.457258.6077461.88389.873 1.246z" fill="#478cbf"/><path d="m20.188 21.144-.072 1.029a.25.25 0 0 1 -.231.232l-2.47.176a.25.25 0 0 1 -.265-.213l-.142-.96h-2.015l-.142.96a.25.25 0 0 1 -.265.213l-2.47-.176a.25.25 0 0 1 -.231-.232l-.072-1.03-2.085-.2c0 .224.004.47.004.518 0 2.203 2.793 3.261 6.264 3.273h.009c3.47-.012 6.263-1.07 6.263-3.273l.004-.518z" fill="#478cbf"/><path d="m14.11 18.195a1.397 1.397 0 1 1 -2.794.001 1.397 1.397 0 0 1 2.795 0" fill="#fff"/><path d="m13.774 18.278a.927.927 0 1 1 -1.854 0 .927.927 0 0 1 1.854 0" fill="#414042"/><path d="m16 19.72c-.248 0-.45-.183-.45-.409v-1.286c0-.226.202-.409.45-.409.249 0 .45.183.45.409v1.286c0 .226-.201.41-.45.41m1.89-1.526a1.397 1.397 0 1 0 2.795 0 1.397 1.397 0 0 0 -2.795 0" fill="#fff"/><path d="m18.227 18.278a.927.927 0 1 0 1.854 0 .927.927 0 0 0 -1.854 0" fill="#414042"/></g></svg>
diff --git a/misc/dist/html/logo.svg b/misc/dist/html/logo.svg
index 94641b054b..afca8a36da 100644
--- a/misc/dist/html/logo.svg
+++ b/misc/dist/html/logo.svg
@@ -1,6 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
@@ -11,7 +9,7 @@
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg2"
version="1.1"
- inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
+ inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
xml:space="preserve"
width="1024"
height="414"
@@ -37,21 +35,22 @@
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
- inkscape:window-width="1920"
- inkscape:window-height="1016"
+ inkscape:window-width="1916"
+ inkscape:window-height="1025"
id="namedview4"
showgrid="false"
- inkscape:zoom="0.63432763"
- inkscape:cx="110.47582"
- inkscape:cy="101.14582"
- inkscape:window-x="0"
- inkscape:window-y="27"
+ 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" /><g
+ fit-margin-bottom="48"
+ inkscape:document-rotation="0" /><g
id="g10"
inkscape:groupmode="layer"
inkscape:label="godot_engine_logo_2017_curves-01"
@@ -171,10 +170,11 @@
id="g82"
transform="matrix(1.1310535,0,0,1.1310535,126.80608,346.04533)"
style="stroke-width:0.88413143"><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 h 0.134 c 4.795,6.12 9.232,12.569 13.487,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.368,12.569 -4.928,6.12 -0.134,0 Z"
- style="fill:#478cbf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.88413143"
+ 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" /></g><g
+ 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.88413143"><path
diff --git a/misc/dist/project_icon.svg b/misc/dist/project_icon.svg
index 1a355131ba..cece381340 100644
--- a/misc/dist/project_icon.svg
+++ b/misc/dist/project_icon.svg
@@ -1 +1 @@
-<svg height="1024" width="1024" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -98.519719)"><rect fill="#1e1a21" height="1008" rx="176.28572" stroke="#2e2832" stroke-width="16" width="1008" x="8" y="106.51972"/><path d="m0 0v-47.514-6.035-5.492c.108-.001.216-.005.323-.015l36.196-3.49c1.896-.183 3.382-1.709 3.514-3.609l1.116-15.978 31.574-2.253 2.175 14.747c.282 1.912 1.922 3.329 3.856 3.329h38.188c1.933 0 3.573-1.417 3.855-3.329l2.175-14.747 31.575 2.253 1.115 15.978c.133 1.9 1.618 3.425 3.514 3.609l36.182 3.49c.107.01.214.014.322.015v4.711l.015.005v54.325h.134c4.795 6.12 9.232 12.569 13.487 19.449-5.651 9.62-12.575 18.217-19.976 26.182-6.864-3.455-13.531-7.369-19.828-11.534-3.151 3.132-6.7 5.694-10.186 8.372-3.425 2.751-7.285 4.768-10.946 7.118 1.09 8.117 1.629 16.108 1.846 24.448-9.446 4.754-19.519 7.906-29.708 10.17-4.068-6.837-7.788-14.241-11.028-21.479-3.842.642-7.702.88-11.567.926v.006c-.027 0-.052-.006-.075-.006-.024 0-.049.006-.073.006v-.006c-3.872-.046-7.729-.284-11.572-.926-3.238 7.238-6.956 14.642-11.03 21.479-10.184-2.264-20.258-5.416-29.703-10.17.216-8.34.755-16.331 1.848-24.448-3.668-2.35-7.523-4.367-10.949-7.118-3.481-2.678-7.036-5.24-10.188-8.372-6.297 4.165-12.962 8.079-19.828 11.534-7.401-7.965-14.321-16.562-19.974-26.182 4.253-6.88 8.693-13.329 13.487-19.449z" fill="#478cbf" transform="matrix(4.2343801 0 0 -4.2343764 97.676491 522.86238)"/><path d="m0 0-1.121-16.063c-.135-1.936-1.675-3.477-3.611-3.616l-38.555-2.751c-.094-.007-.188-.01-.281-.01-1.916 0-3.569 1.406-3.852 3.33l-2.211 14.994h-31.459l-2.211-14.994c-.297-2.018-2.101-3.469-4.133-3.32l-38.555 2.751c-1.936.139-3.476 1.68-3.611 3.616l-1.121 16.063-32.547 3.138c.015-3.498.06-7.33.06-8.093 0-34.374 43.605-50.896 97.781-51.086h.066.067c54.176.19 97.766 16.712 97.766 51.086 0 .777.047 4.593.063 8.093z" fill="#478cbf" transform="matrix(4.2343801 0 0 -4.2343764 788.7623 819.22103)"/><path d="m0 0c0-12.052-9.765-21.815-21.813-21.815-12.042 0-21.81 9.763-21.81 21.815 0 12.044 9.768 21.802 21.81 21.802 12.048 0 21.813-9.758 21.813-21.802" fill="#fff" transform="matrix(4.2343801 0 0 -4.2343764 387.09785 624.34645)"/><path d="m0 0c0-7.994-6.479-14.473-14.479-14.473-7.996 0-14.479 6.479-14.479 14.473s6.483 14.479 14.479 14.479c8 0 14.479-6.485 14.479-14.479" fill="#414042" transform="matrix(4.2343801 0 0 -4.2343764 364.87318 629.82505)"/><path d="m0 0c-3.878 0-7.021 2.858-7.021 6.381v20.081c0 3.52 3.143 6.381 7.021 6.381s7.028-2.861 7.028-6.381v-20.081c0-3.523-3.15-6.381-7.028-6.381" fill="#fff" transform="matrix(4.2343801 0 0 -4.2343764 511.99324 725.12292)"/><path d="m0 0c0-12.052 9.765-21.815 21.815-21.815 12.041 0 21.808 9.763 21.808 21.815 0 12.044-9.767 21.802-21.808 21.802-12.05 0-21.815-9.758-21.815-21.802" fill="#fff" transform="matrix(4.2343801 0 0 -4.2343764 636.90407 624.34645)"/><path d="m0 0c0-7.994 6.477-14.473 14.471-14.473 8.002 0 14.479 6.479 14.479 14.473s-6.477 14.479-14.479 14.479c-7.994 0-14.471-6.485-14.471-14.479" fill="#414042" transform="matrix(4.2343801 0 0 -4.2343764 659.13434 629.82505)"/></g></svg>
+<svg height="1024" width="1024" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -98.519719)"><rect fill="#1e1a21" height="1008" rx="176.28572" stroke="#2e2832" stroke-width="16" width="1008" x="8" y="106.51972"/><path d="m0 0v-47.514-6.035-5.492c.108-.001.216-.005.323-.015l36.196-3.49c1.896-.183 3.382-1.709 3.514-3.609l1.116-15.978 31.574-2.253 2.175 14.747c.282 1.912 1.922 3.329 3.856 3.329h38.188c1.933 0 3.573-1.417 3.855-3.329l2.175-14.747 31.575 2.253 1.115 15.978c.133 1.9 1.618 3.425 3.514 3.609l36.182 3.49c.107.01.214.014.322.015v4.711l.015.005v54.325c5.09692 6.4164712 9.92323 13.494208 13.621 19.449-5.651 9.62-12.575 18.217-19.976 26.182-6.864-3.455-13.531-7.369-19.828-11.534-3.151 3.132-6.7 5.694-10.186 8.372-3.425 2.751-7.285 4.768-10.946 7.118 1.09 8.117 1.629 16.108 1.846 24.448-9.446 4.754-19.519 7.906-29.708 10.17-4.068-6.837-7.788-14.241-11.028-21.479-3.842.642-7.702.88-11.567.926v.006c-.027 0-.052-.006-.075-.006-.024 0-.049.006-.073.006v-.006c-3.872-.046-7.729-.284-11.572-.926-3.238 7.238-6.956 14.642-11.03 21.479-10.184-2.264-20.258-5.416-29.703-10.17.216-8.34.755-16.331 1.848-24.448-3.668-2.35-7.523-4.367-10.949-7.118-3.481-2.678-7.036-5.24-10.188-8.372-6.297 4.165-12.962 8.079-19.828 11.534-7.401-7.965-14.321-16.562-19.974-26.182 4.4426581-6.973693 9.2079704-13.9828879 13.621-19.449z" fill="#478cbf" transform="matrix(4.2343801 0 0 -4.2343764 97.676491 522.86238)"/><path d="m0 0-1.121-16.063c-.135-1.936-1.675-3.477-3.611-3.616l-38.555-2.751c-.094-.007-.188-.01-.281-.01-1.916 0-3.569 1.406-3.852 3.33l-2.211 14.994h-31.459l-2.211-14.994c-.297-2.018-2.101-3.469-4.133-3.32l-38.555 2.751c-1.936.139-3.476 1.68-3.611 3.616l-1.121 16.063-32.547 3.138c.015-3.498.06-7.33.06-8.093 0-34.374 43.605-50.896 97.781-51.086h.066.067c54.176.19 97.766 16.712 97.766 51.086 0 .777.047 4.593.063 8.093z" fill="#478cbf" transform="matrix(4.2343801 0 0 -4.2343764 788.7623 819.22103)"/><path d="m0 0c0-12.052-9.765-21.815-21.813-21.815-12.042 0-21.81 9.763-21.81 21.815 0 12.044 9.768 21.802 21.81 21.802 12.048 0 21.813-9.758 21.813-21.802" fill="#fff" transform="matrix(4.2343801 0 0 -4.2343764 387.09785 624.34645)"/><path d="m0 0c0-7.994-6.479-14.473-14.479-14.473-7.996 0-14.479 6.479-14.479 14.473s6.483 14.479 14.479 14.479c8 0 14.479-6.485 14.479-14.479" fill="#414042" transform="matrix(4.2343801 0 0 -4.2343764 364.87318 629.82505)"/><path d="m0 0c-3.878 0-7.021 2.858-7.021 6.381v20.081c0 3.52 3.143 6.381 7.021 6.381s7.028-2.861 7.028-6.381v-20.081c0-3.523-3.15-6.381-7.028-6.381" fill="#fff" transform="matrix(4.2343801 0 0 -4.2343764 511.99324 725.12292)"/><path d="m0 0c0-12.052 9.765-21.815 21.815-21.815 12.041 0 21.808 9.763 21.808 21.815 0 12.044-9.767 21.802-21.808 21.802-12.05 0-21.815-9.758-21.815-21.802" fill="#fff" transform="matrix(4.2343801 0 0 -4.2343764 636.90407 624.34645)"/><path d="m0 0c0-7.994 6.477-14.473 14.471-14.473 8.002 0 14.479 6.479 14.479 14.473s-6.477 14.479-14.479 14.479c-7.994 0-14.471-6.485-14.471-14.479" fill="#414042" transform="matrix(4.2343801 0 0 -4.2343764 659.13434 629.82505)"/></g></svg>
diff --git a/modules/assimp/SCsub b/modules/assimp/SCsub
index f1d0c742b4..7213efb74d 100644
--- a/modules/assimp/SCsub
+++ b/modules/assimp/SCsub
@@ -5,8 +5,13 @@ Import("env_modules")
env_assimp = env_modules.Clone()
+# Thirdparty source files
+
+thirdparty_obj = []
+
# Force bundled version for now, there's no released version of Assimp with
# support for ArmaturePopulate which we use from their master branch.
+
if True: # env['builtin_assimp']:
thirdparty_dir = "#thirdparty/assimp"
@@ -84,11 +89,20 @@ if True: # env['builtin_assimp']:
env_thirdparty = env_assimp.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/CApi/*.cpp"))
- env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/Common/*.cpp"))
- env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/PostProcessing/*.cpp"))
- env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/Material/*.cpp"))
- env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/FBX/*.cpp"))
-
-# Godot's own source files
-env_assimp.add_source_files(env.modules_sources, "*.cpp")
+ env_thirdparty.add_source_files(thirdparty_obj, Glob("#thirdparty/assimp/code/CApi/*.cpp"))
+ env_thirdparty.add_source_files(thirdparty_obj, Glob("#thirdparty/assimp/code/Common/*.cpp"))
+ env_thirdparty.add_source_files(thirdparty_obj, Glob("#thirdparty/assimp/code/PostProcessing/*.cpp"))
+ env_thirdparty.add_source_files(thirdparty_obj, Glob("#thirdparty/assimp/code/Material/*.cpp"))
+ env_thirdparty.add_source_files(thirdparty_obj, Glob("#thirdparty/assimp/code/FBX/*.cpp"))
+ env.modules_sources += thirdparty_obj
+
+
+# Godot source files
+
+module_obj = []
+
+env_assimp.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/basis_universal/SCsub b/modules/basis_universal/SCsub
index dc7b176d24..351628a0e3 100644
--- a/modules/basis_universal/SCsub
+++ b/modules/basis_universal/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_basisu = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
# Not unbundled so far since not widespread as shared library
thirdparty_dir = "#thirdparty/basis_universal/"
tool_sources = [
@@ -41,8 +44,16 @@ if env["target"] == "debug":
env_thirdparty = env_basisu.Clone()
env_thirdparty.disable_warnings()
if env["tools"]:
- env_thirdparty.add_source_files(env.modules_sources, tool_sources)
-env_thirdparty.add_source_files(env.modules_sources, transcoder_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, tool_sources)
+env_thirdparty.add_source_files(thirdparty_obj, transcoder_sources)
+env.modules_sources += thirdparty_obj
# Godot source files
-env_basisu.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_basisu.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/bullet/SCsub b/modules/bullet/SCsub
index 21bdcca18e..bfac0df5b0 100644
--- a/modules/bullet/SCsub
+++ b/modules/bullet/SCsub
@@ -7,6 +7,8 @@ env_bullet = env_modules.Clone()
# Thirdparty source files
+thirdparty_obj = []
+
if env["builtin_bullet"]:
# Build only version 2 for now (as of 2.89)
# Sync file list with relevant upstream CMakeLists.txt for each folder.
@@ -208,8 +210,16 @@ if env["builtin_bullet"]:
env_thirdparty = env_bullet.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
# Godot source files
-env_bullet.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_bullet.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/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp
index 663ad6e3e1..3b548b7faa 100644
--- a/modules/bullet/bullet_physics_server.cpp
+++ b/modules/bullet/bullet_physics_server.cpp
@@ -1463,22 +1463,6 @@ bool BulletPhysicsServer3D::generic_6dof_joint_get_flag(RID p_joint, Vector3::Ax
return generic_6dof_joint->get_flag(p_axis, p_flag);
}
-void BulletPhysicsServer3D::generic_6dof_joint_set_precision(RID p_joint, int p_precision) {
- JointBullet *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND(!joint);
- ERR_FAIL_COND(joint->get_type() != JOINT_6DOF);
- Generic6DOFJointBullet *generic_6dof_joint = static_cast<Generic6DOFJointBullet *>(joint);
- generic_6dof_joint->set_precision(p_precision);
-}
-
-int BulletPhysicsServer3D::generic_6dof_joint_get_precision(RID p_joint) {
- JointBullet *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND_V(!joint, 0);
- ERR_FAIL_COND_V(joint->get_type() != JOINT_6DOF, 0);
- Generic6DOFJointBullet *generic_6dof_joint = static_cast<Generic6DOFJointBullet *>(joint);
- return generic_6dof_joint->get_precision();
-}
-
void BulletPhysicsServer3D::free(RID p_rid) {
if (shape_owner.owns(p_rid)) {
ShapeBullet *shape = shape_owner.getornull(p_rid);
diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h
index dca9339c44..07a32e510c 100644
--- a/modules/bullet/bullet_physics_server.h
+++ b/modules/bullet/bullet_physics_server.h
@@ -376,9 +376,6 @@ public:
virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag, bool p_enable) override;
virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag) override;
- virtual void generic_6dof_joint_set_precision(RID p_joint, int precision) override;
- virtual int generic_6dof_joint_get_precision(RID p_joint) override;
-
/* MISC */
virtual void free(RID p_rid) override;
diff --git a/modules/bullet/generic_6dof_joint_bullet.cpp b/modules/bullet/generic_6dof_joint_bullet.cpp
index 56a66dba45..d75bf1fb98 100644
--- a/modules/bullet/generic_6dof_joint_bullet.cpp
+++ b/modules/bullet/generic_6dof_joint_bullet.cpp
@@ -273,11 +273,3 @@ bool Generic6DOFJointBullet::get_flag(Vector3::Axis p_axis, PhysicsServer3D::G6D
ERR_FAIL_INDEX_V(p_axis, 3, false);
return flags[p_axis][p_flag];
}
-
-void Generic6DOFJointBullet::set_precision(int p_precision) {
- sixDOFConstraint->setOverrideNumSolverIterations(MAX(1, p_precision));
-}
-
-int Generic6DOFJointBullet::get_precision() const {
- return sixDOFConstraint->getOverrideNumSolverIterations();
-}
diff --git a/modules/bullet/generic_6dof_joint_bullet.h b/modules/bullet/generic_6dof_joint_bullet.h
index 316708bb11..ed25337745 100644
--- a/modules/bullet/generic_6dof_joint_bullet.h
+++ b/modules/bullet/generic_6dof_joint_bullet.h
@@ -68,9 +68,6 @@ public:
void set_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag, bool p_value);
bool get_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag) const;
-
- void set_precision(int p_precision);
- int get_precision() const;
};
#endif
diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp
index 0c64c3640f..284a22717b 100644
--- a/modules/bullet/rigid_body_bullet.cpp
+++ b/modules/bullet/rigid_body_bullet.cpp
@@ -323,9 +323,6 @@ void RigidBodyBullet::set_space(SpaceBullet *p_space) {
can_integrate_forces = false;
isScratchedSpaceOverrideModificator = false;
- // Remove all eventual constraints
- assert_no_constraints();
-
// Remove this object form the physics world
space->remove_rigid_body(this);
}
@@ -443,12 +440,6 @@ bool RigidBodyBullet::was_colliding(RigidBodyBullet *p_other_object) {
return false;
}
-void RigidBodyBullet::assert_no_constraints() {
- if (btBody->getNumConstraintRefs()) {
- WARN_PRINT("A body with a joints is destroyed. Please check the implementation in order to destroy the joint before the body.");
- }
-}
-
void RigidBodyBullet::set_activation_state(bool p_active) {
if (p_active) {
btBody->activate();
diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h
index c643611397..8ff96577b6 100644
--- a/modules/bullet/rigid_body_bullet.h
+++ b/modules/bullet/rigid_body_bullet.h
@@ -267,8 +267,6 @@ public:
bool add_collision_object(RigidBodyBullet *p_otherObject, const Vector3 &p_hitWorldLocation, const Vector3 &p_hitLocalLocation, const Vector3 &p_hitNormal, const float &p_appliedImpulse, int p_other_shape_index, int p_local_shape_index);
bool was_colliding(RigidBodyBullet *p_other_object);
- void assert_no_constraints();
-
void set_activation_state(bool p_active);
bool is_active() const;
diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp
index abad1beacb..3bfcd83606 100644
--- a/modules/bullet/space_bullet.cpp
+++ b/modules/bullet/space_bullet.cpp
@@ -478,10 +478,20 @@ void SpaceBullet::add_rigid_body(RigidBodyBullet *p_body) {
}
void SpaceBullet::remove_rigid_body(RigidBodyBullet *p_body) {
+ btRigidBody *btBody = p_body->get_bt_rigid_body();
+
+ int constraints = btBody->getNumConstraintRefs();
+ if (constraints > 0) {
+ WARN_PRINT("A body connected to joints was removed. Ensure bodies are disconnected from joints before removing them.");
+ for (int i = 0; i < constraints; i++) {
+ dynamicsWorld->removeConstraint(btBody->getConstraintRef(i));
+ }
+ }
+
if (p_body->is_static()) {
- dynamicsWorld->removeCollisionObject(p_body->get_bt_rigid_body());
+ dynamicsWorld->removeCollisionObject(btBody);
} else {
- dynamicsWorld->removeRigidBody(p_body->get_bt_rigid_body());
+ dynamicsWorld->removeRigidBody(btBody);
}
}
diff --git a/modules/cvtt/SCsub b/modules/cvtt/SCsub
index 5438f7ebac..e56177d6e9 100644
--- a/modules/cvtt/SCsub
+++ b/modules/cvtt/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_cvtt = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
thirdparty_dir = "#thirdparty/cvtt/"
thirdparty_sources = [
"ConvectionKernels.cpp",
@@ -17,7 +20,15 @@ env_cvtt.Prepend(CPPPATH=[thirdparty_dir])
env_thirdparty = env_cvtt.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
# Godot source files
-env_cvtt.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_cvtt.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/denoise/SCsub b/modules/denoise/SCsub
index bf3bd7d073..97feea2b44 100644
--- a/modules/denoise/SCsub
+++ b/modules/denoise/SCsub
@@ -8,6 +8,9 @@ Import("env_modules")
env_oidn = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
thirdparty_dir = "#thirdparty/oidn/"
thirdparty_sources = [
"core/api.cpp",
@@ -106,7 +109,8 @@ env_oidn.Append(
env_thirdparty = env_oidn.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
weights_in_path = thirdparty_dir + "weights/rtlightmap_hdr.tza"
weights_out_path = thirdparty_dir + "weights/rtlightmap_hdr.gen.cpp"
@@ -114,5 +118,12 @@ weights_out_path = thirdparty_dir + "weights/rtlightmap_hdr.gen.cpp"
env_thirdparty.Depends(weights_out_path, weights_in_path)
env_thirdparty.CommandNoCache(weights_out_path, weights_in_path, resource_to_cpp.tza_to_cpp)
-env_oidn.add_source_files(env.modules_sources, "denoise_wrapper.cpp")
-env_modules.add_source_files(env.modules_sources, ["register_types.cpp", "lightmap_denoiser.cpp"])
+# Godot source files
+
+module_obj = []
+
+env_oidn.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/enet/SCsub b/modules/enet/SCsub
index c8f4b3885e..580e5a3eb0 100644
--- a/modules/enet/SCsub
+++ b/modules/enet/SCsub
@@ -7,6 +7,8 @@ env_enet = env_modules.Clone()
# Thirdparty source files
+thirdparty_obj = []
+
if env["builtin_enet"]:
thirdparty_dir = "#thirdparty/enet/"
thirdparty_sources = [
@@ -26,6 +28,16 @@ if env["builtin_enet"]:
env_thirdparty = env_enet.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
+
+# Godot source files
+
+module_obj = []
+
+env_enet.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-env_enet.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/etc/SCsub b/modules/etc/SCsub
index 383bbf83c3..9b46f17916 100644
--- a/modules/etc/SCsub
+++ b/modules/etc/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_etc = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
# Not unbundled so far since not widespread as shared library
thirdparty_dir = "#thirdparty/etc2comp/"
thirdparty_sources = [
@@ -31,7 +34,15 @@ env_etc.Prepend(CPPPATH=[thirdparty_dir])
env_thirdparty = env_etc.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
# Godot source files
-env_etc.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_etc.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/etc/image_etc.cpp b/modules/etc/image_compress_etc.cpp
index 4e9e64c6a7..bcdea41b43 100644
--- a/modules/etc/image_etc.cpp
+++ b/modules/etc/image_compress_etc.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* image_etc.cpp */
+/* image_compress_etc.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,14 +28,16 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "image_etc.h"
-#include "Etc.h"
-#include "EtcFilter.h"
+#include "image_compress_etc.h"
+
#include "core/io/image.h"
#include "core/os/copymem.h"
#include "core/os/os.h"
#include "core/string/print_string.h"
+#include <Etc.h>
+#include <EtcFilter.h>
+
static Image::Format _get_etc2_mode(Image::UsedChannels format) {
switch (format) {
case Image::USED_CHANNELS_R:
diff --git a/modules/etc/image_etc.h b/modules/etc/image_compress_etc.h
index 7b4f26e127..016e64e4fc 100644
--- a/modules/etc/image_etc.h
+++ b/modules/etc/image_compress_etc.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* image_etc.h */
+/* image_compress_etc.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,9 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef IMAGE_ETC1_H
-#define IMAGE_ETC1_H
+#ifndef IMAGE_COMPRESS_ETC_H
+#define IMAGE_COMPRESS_ETC_H
void _register_etc_compress_func();
-#endif // IMAGE_ETC_H
+#endif // IMAGE_COMPRESS_ETC_H
diff --git a/modules/etc/register_types.cpp b/modules/etc/register_types.cpp
index 0972857808..225ba6b954 100644
--- a/modules/etc/register_types.cpp
+++ b/modules/etc/register_types.cpp
@@ -30,7 +30,7 @@
#include "register_types.h"
-#include "image_etc.h"
+#include "image_compress_etc.h"
#include "texture_loader_pkm.h"
static Ref<ResourceFormatPKM> resource_loader_pkm;
diff --git a/modules/freetype/SCsub b/modules/freetype/SCsub
index bfc1658bb4..fc2535a6ca 100644
--- a/modules/freetype/SCsub
+++ b/modules/freetype/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_freetype = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_freetype"]:
thirdparty_dir = "#thirdparty/freetype/"
thirdparty_sources = [
@@ -84,6 +87,7 @@ if env["builtin_freetype"]:
env_thirdparty = env_freetype.Clone()
env_thirdparty.disable_warnings()
lib = env_thirdparty.add_library("freetype_builtin", thirdparty_sources)
+ thirdparty_obj += lib
# Needs to be appended to arrive after libscene in the linker call,
# but we don't want it to arrive *after* system libs, so manual hack
@@ -98,5 +102,13 @@ if env["builtin_freetype"]:
if not inserted:
env.Append(LIBS=[lib])
+
# Godot source files
-env_freetype.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_freetype.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/gdnative/gdnative/rect2.cpp b/modules/gdnative/gdnative/rect2.cpp
index bacefced5d..0576fb569f 100644
--- a/modules/gdnative/gdnative/rect2.cpp
+++ b/modules/gdnative/gdnative/rect2.cpp
@@ -90,11 +90,11 @@ godot_bool GDAPI godot_rect2_has_no_area(const godot_rect2 *p_self) {
return self->has_no_area();
}
-godot_rect2 GDAPI godot_rect2_clip(const godot_rect2 *p_self, const godot_rect2 *p_b) {
+godot_rect2 GDAPI godot_rect2_intersection(const godot_rect2 *p_self, const godot_rect2 *p_b) {
godot_rect2 dest;
const Rect2 *self = (const Rect2 *)p_self;
const Rect2 *b = (const Rect2 *)p_b;
- *((Rect2 *)&dest) = self->clip(*b);
+ *((Rect2 *)&dest) = self->intersection(*b);
return dest;
}
@@ -233,11 +233,11 @@ godot_bool GDAPI godot_rect2i_has_no_area(const godot_rect2i *p_self) {
return self->has_no_area();
}
-godot_rect2i GDAPI godot_rect2i_clip(const godot_rect2i *p_self, const godot_rect2i *p_b) {
+godot_rect2i GDAPI godot_rect2i_intersection(const godot_rect2i *p_self, const godot_rect2i *p_b) {
godot_rect2i dest;
const Rect2i *self = (const Rect2i *)p_self;
const Rect2i *b = (const Rect2i *)p_b;
- *((Rect2i *)&dest) = self->clip(*b);
+ *((Rect2i *)&dest) = self->intersection(*b);
return dest;
}
diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json
index 84b36b3745..b3fd033e6c 100644
--- a/modules/gdnative/gdnative_api.json
+++ b/modules/gdnative/gdnative_api.json
@@ -3573,7 +3573,7 @@
]
},
{
- "name": "godot_rect2_clip",
+ "name": "godot_rect2_intersection",
"return_type": "godot_rect2",
"arguments": [
["const godot_rect2 *", "p_self"],
@@ -3715,7 +3715,7 @@
]
},
{
- "name": "godot_rect2i_clip",
+ "name": "godot_rect2i_intersection",
"return_type": "godot_rect2i",
"arguments": [
["const godot_rect2i *", "p_self"],
diff --git a/modules/gdnative/gdnative_library_editor_plugin.cpp b/modules/gdnative/gdnative_library_editor_plugin.cpp
index 719fcbc927..52f8c837c4 100644
--- a/modules/gdnative/gdnative_library_editor_plugin.cpp
+++ b/modules/gdnative/gdnative_library_editor_plugin.cpp
@@ -382,7 +382,7 @@ GDNativeLibraryEditor::GDNativeLibraryEditor() {
new_architecture_dialog->add_child(new_architecture_input);
// new_architecture_dialog->set_custom_minimum_size(Vector2(300, 80) * EDSCALE);
new_architecture_input->set_anchors_and_margins_preset(PRESET_HCENTER_WIDE, PRESET_MODE_MINSIZE, 5 * EDSCALE);
- new_architecture_dialog->get_ok()->connect("pressed", callable_mp(this, &GDNativeLibraryEditor::_on_create_new_entry));
+ new_architecture_dialog->get_ok_button()->connect("pressed", callable_mp(this, &GDNativeLibraryEditor::_on_create_new_entry));
}
void GDNativeLibraryEditorPlugin::edit(Object *p_node) {
diff --git a/modules/gdnative/include/gdnative/rect2.h b/modules/gdnative/include/gdnative/rect2.h
index f317afc9da..2c8f836d16 100644
--- a/modules/gdnative/include/gdnative/rect2.h
+++ b/modules/gdnative/include/gdnative/rect2.h
@@ -80,7 +80,7 @@ godot_bool GDAPI godot_rect2_encloses(const godot_rect2 *p_self, const godot_rec
godot_bool GDAPI godot_rect2_has_no_area(const godot_rect2 *p_self);
-godot_rect2 GDAPI godot_rect2_clip(const godot_rect2 *p_self, const godot_rect2 *p_b);
+godot_rect2 GDAPI godot_rect2_intersection(const godot_rect2 *p_self, const godot_rect2 *p_b);
godot_rect2 GDAPI godot_rect2_merge(const godot_rect2 *p_self, const godot_rect2 *p_b);
@@ -123,7 +123,7 @@ godot_bool GDAPI godot_rect2i_encloses(const godot_rect2i *p_self, const godot_r
godot_bool GDAPI godot_rect2i_has_no_area(const godot_rect2i *p_self);
-godot_rect2i GDAPI godot_rect2i_clip(const godot_rect2i *p_self, const godot_rect2i *p_b);
+godot_rect2i GDAPI godot_rect2i_intersection(const godot_rect2i *p_self, const godot_rect2i *p_b);
godot_rect2i GDAPI godot_rect2i_merge(const godot_rect2i *p_self, const godot_rect2i *p_b);
diff --git a/modules/gdnative/include/text/godot_text.h b/modules/gdnative/include/text/godot_text.h
index 2eac6adfb5..6885f2463d 100644
--- a/modules/gdnative/include/text/godot_text.h
+++ b/modules/gdnative/include/text/godot_text.h
@@ -82,6 +82,9 @@ typedef struct {
void (*font_set_antialiased)(void *, godot_rid *, bool);
bool (*font_get_antialiased)(void *, godot_rid *);
godot_dictionary (*font_get_feature_list)(void *, godot_rid *);
+ godot_dictionary (*font_get_variation_list)(void *, godot_rid *);
+ void (*font_set_variation)(void *, godot_rid *, const godot_string *, double);
+ double (*font_get_variation)(void *, godot_rid *, const godot_string *);
void (*font_set_distance_field_hint)(void *, godot_rid *, bool);
bool (*font_get_distance_field_hint)(void *, godot_rid *);
void (*font_set_hinting)(void *, godot_rid *, godot_int);
diff --git a/modules/gdnative/text/text_server_gdnative.cpp b/modules/gdnative/text/text_server_gdnative.cpp
index 68624260a6..cb87adafe8 100644
--- a/modules/gdnative/text/text_server_gdnative.cpp
+++ b/modules/gdnative/text/text_server_gdnative.cpp
@@ -148,6 +148,24 @@ bool TextServerGDNative::font_get_antialiased(RID p_font) const {
return interface->font_get_antialiased(data, (godot_rid *)&p_font);
}
+Dictionary TextServerGDNative::font_get_variation_list(RID p_font) const {
+ ERR_FAIL_COND_V(interface == nullptr, Dictionary());
+ godot_dictionary result = interface->font_get_variation_list(data, (godot_rid *)&p_font);
+ Dictionary info = *(Dictionary *)&result;
+ godot_dictionary_destroy(&result);
+
+ return info;
+}
+
+void TextServerGDNative::font_set_variation(RID p_font, const String &p_name, double p_value) {
+ ERR_FAIL_COND(interface == nullptr);
+ interface->font_set_variation(data, (godot_rid *)&p_font, (godot_string *)&p_name, p_value);
+}
+
+double TextServerGDNative::font_get_variation(RID p_font, const String &p_name) const {
+ return interface->font_get_variation(data, (godot_rid *)&p_font, (godot_string *)&p_name);
+}
+
void TextServerGDNative::font_set_hinting(RID p_font, TextServer::Hinting p_hinting) {
ERR_FAIL_COND(interface == nullptr);
interface->font_set_hinting(data, (godot_rid *)&p_font, (godot_int)p_hinting);
diff --git a/modules/gdnative/text/text_server_gdnative.h b/modules/gdnative/text/text_server_gdnative.h
index 0196120c00..959302aaf4 100644
--- a/modules/gdnative/text/text_server_gdnative.h
+++ b/modules/gdnative/text/text_server_gdnative.h
@@ -76,6 +76,10 @@ public:
virtual bool font_get_antialiased(RID p_font) const override;
virtual Dictionary font_get_feature_list(RID p_font) const override;
+ virtual Dictionary font_get_variation_list(RID p_font) const override;
+
+ virtual void font_set_variation(RID p_font, const String &p_name, double p_value) override;
+ virtual double font_get_variation(RID p_font, const String &p_name) const override;
virtual void font_set_hinting(RID p_font, Hinting p_hinting) override;
virtual Hinting font_get_hinting(RID p_font) const override;
diff --git a/modules/gdnavigation/SCsub b/modules/gdnavigation/SCsub
index 877d601c6a..22b5509b32 100644
--- a/modules/gdnavigation/SCsub
+++ b/modules/gdnavigation/SCsub
@@ -5,6 +5,10 @@ Import("env_modules")
env_navigation = env_modules.Clone()
+# Thirdparty source files
+
+thirdparty_obj = []
+
# Recast Thirdparty source files
if env["builtin_recast"]:
thirdparty_dir = "#thirdparty/recastnavigation/Recast/"
@@ -23,28 +27,37 @@ if env["builtin_recast"]:
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
- env_navigation.Prepend(CPPPATH=[thirdparty_dir + "/Include"])
+ env_navigation.Prepend(CPPPATH=[thirdparty_dir + "Include"])
env_thirdparty = env_navigation.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
-
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
# RVO Thirdparty source files
if env["builtin_rvo2"]:
- thirdparty_dir = "#thirdparty/rvo2"
+ thirdparty_dir = "#thirdparty/rvo2/"
thirdparty_sources = [
- "/src/Agent.cpp",
- "/src/KdTree.cpp",
+ "Agent.cpp",
+ "KdTree.cpp",
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
- env_navigation.Prepend(CPPPATH=[thirdparty_dir + "/src"])
+ env_navigation.Prepend(CPPPATH=[thirdparty_dir])
env_thirdparty = env_navigation.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+
+
+env.modules_sources += thirdparty_obj
# Godot source files
-env_navigation.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_navigation.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/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index eeb66ebfc0..4ed129b3ff 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -763,7 +763,7 @@
<argument index="1" name="exp" type="float">
</argument>
<description>
- Returns the result of [code]x[/code] raised to the power of [code]y[/code].
+ Returns the result of [code]base[/code] raised to the power of [code]exp[/code].
[codeblock]
pow(2, 5) # Returns 32.0
[/codeblock]
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 4425b59d62..8fa2de7063 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -2122,8 +2122,11 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
w++;
}
- for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) {
- p_words->push_back(GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i)));
+ List<StringName> functions;
+ GDScriptUtilityFunctions::get_function_list(&functions);
+
+ for (const List<StringName>::Element *E = functions.front(); E; E = E->next()) {
+ p_words->push_back(String(E->get()));
}
}
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index f949d26664..11c449c5f2 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -72,8 +72,8 @@ class GDScript : public Script {
friend class GDScriptFunction;
friend class GDScriptAnalyzer;
friend class GDScriptCompiler;
- friend class GDScriptFunctions;
friend class GDScriptLanguage;
+ friend struct GDScriptUtilityFunctionsDefinitions;
Ref<GDScriptNativeClass> native;
Ref<GDScript> base;
@@ -270,8 +270,8 @@ public:
class GDScriptInstance : public ScriptInstance {
friend class GDScript;
friend class GDScriptFunction;
- friend class GDScriptFunctions;
friend class GDScriptCompiler;
+ friend struct GDScriptUtilityFunctionsDefinitions;
ObjectID owner_id;
Object *owner;
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 1b76c7f967..19951ff17d 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -37,6 +37,7 @@
#include "core/os/file_access.h"
#include "core/templates/hash_map.h"
#include "gdscript.h"
+#include "gdscript_utility_functions.h"
// TODO: Move this to a central location (maybe core?).
static HashMap<StringName, StringName> underscore_map;
@@ -72,6 +73,39 @@ static StringName get_real_class_name(const StringName &p_source) {
return p_source;
}
+static MethodInfo info_from_utility_func(const StringName &p_function) {
+ ERR_FAIL_COND_V(!Variant::has_utility_function(p_function), MethodInfo());
+
+ MethodInfo info(p_function);
+
+ if (Variant::has_utility_function_return_value(p_function)) {
+ info.return_val.type = Variant::get_utility_function_return_type(p_function);
+ if (info.return_val.type == Variant::NIL) {
+ info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+ }
+ }
+
+ if (Variant::is_utility_function_vararg(p_function)) {
+ info.flags |= METHOD_FLAG_VARARG;
+ } else {
+ for (int i = 0; i < Variant::get_utility_function_argument_count(p_function); i++) {
+ PropertyInfo pi;
+#ifdef DEBUG_METHODS_ENABLED
+ pi.name = Variant::get_utility_function_argument_name(p_function, i);
+#else
+ pi.name = "arg" + itos(i + 1);
+#endif
+ pi.type = Variant::get_utility_function_argument_type(p_function, i);
+ if (pi.type == Variant::NIL) {
+ pi.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+ }
+ info.arguments.push_back(pi);
+ }
+ }
+
+ return info;
+}
+
void GDScriptAnalyzer::cleanup() {
underscore_map.clear();
}
@@ -1701,7 +1735,6 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
// Call to name directly.
StringName function_name = p_call->function_name;
Variant::Type builtin_type = GDScriptParser::get_builtin_type(function_name);
- GDScriptFunctions::Function builtin_function = GDScriptParser::get_builtin_function(function_name);
if (builtin_type < Variant::VARIANT_MAX) {
// Is a builtin constructor.
@@ -1843,10 +1876,52 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
}
p_call->set_datatype(call_type);
return;
- } else if (builtin_function < GDScriptFunctions::FUNC_MAX) {
- MethodInfo function_info = GDScriptFunctions::get_info(builtin_function);
+ } else if (GDScriptUtilityFunctions::function_exists(function_name)) {
+ MethodInfo function_info = GDScriptUtilityFunctions::get_function_info(function_name);
+
+ if (all_is_constant && GDScriptUtilityFunctions::is_function_constant(function_name)) {
+ // Can call on compilation.
+ Vector<const Variant *> args;
+ for (int i = 0; i < p_call->arguments.size(); i++) {
+ args.push_back(&(p_call->arguments[i]->reduced_value));
+ }
+
+ Variant value;
+ Callable::CallError err;
+ GDScriptUtilityFunctions::get_function(function_name)(&value, (const Variant **)args.ptr(), args.size(), err);
+
+ switch (err.error) {
+ case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: {
+ PropertyInfo wrong_arg = function_info.arguments[err.argument];
+ push_error(vformat(R"*(Invalid argument for "%s()" function: argument %d should be %s but is %s.)*", function_name, err.argument + 1,
+ type_from_property(wrong_arg).to_string(), p_call->arguments[err.argument]->get_datatype().to_string()),
+ p_call->arguments[err.argument]);
+ } break;
+ case Callable::CallError::CALL_ERROR_INVALID_METHOD:
+ push_error(vformat(R"(Invalid call for function "%s".)", function_name), p_call);
+ break;
+ case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS:
+ push_error(vformat(R"*(Too many arguments for "%s()" call. Expected at most %d but received %d.)*", function_name, err.expected, p_call->arguments.size()), p_call);
+ break;
+ case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
+ push_error(vformat(R"*(Too few arguments for "%s()" call. Expected at least %d but received %d.)*", function_name, err.expected, p_call->arguments.size()), p_call);
+ break;
+ case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL:
+ break; // Can't happen in a builtin constructor.
+ case Callable::CallError::CALL_OK:
+ p_call->is_constant = true;
+ p_call->reduced_value = value;
+ break;
+ }
+ } else {
+ validate_call_arg(function_info, p_call);
+ }
+ p_call->set_datatype(type_from_property(function_info.return_val));
+ return;
+ } else if (Variant::has_utility_function(function_name)) {
+ MethodInfo function_info = info_from_utility_func(function_name);
- if (all_is_constant && GDScriptFunctions::is_deterministic(builtin_function)) {
+ if (all_is_constant && Variant::get_utility_function_type(function_name) == Variant::UTILITY_FUNC_TYPE_MATH) {
// Can call on compilation.
Vector<const Variant *> args;
for (int i = 0; i < p_call->arguments.size(); i++) {
@@ -1855,23 +1930,23 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
Variant value;
Callable::CallError err;
- GDScriptFunctions::call(builtin_function, (const Variant **)args.ptr(), args.size(), value, err);
+ Variant::call_utility_function(function_name, &value, (const Variant **)args.ptr(), args.size(), err);
switch (err.error) {
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: {
PropertyInfo wrong_arg = function_info.arguments[err.argument];
- push_error(vformat(R"*(Invalid argument for "%s()" function: argument %d should be %s but is %s.)*", GDScriptFunctions::get_func_name(builtin_function), err.argument + 1,
+ push_error(vformat(R"*(Invalid argument for "%s()" function: argument %d should be %s but is %s.)*", function_name, err.argument + 1,
type_from_property(wrong_arg).to_string(), p_call->arguments[err.argument]->get_datatype().to_string()),
p_call->arguments[err.argument]);
} break;
case Callable::CallError::CALL_ERROR_INVALID_METHOD:
- push_error(vformat(R"(Invalid call for function "%s".)", GDScriptFunctions::get_func_name(builtin_function)), p_call);
+ push_error(vformat(R"(Invalid call for function "%s".)", function_name), p_call);
break;
case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS:
- push_error(vformat(R"*(Too many arguments for "%s()" call. Expected at most %d but received %d.)*", GDScriptFunctions::get_func_name(builtin_function), err.expected, p_call->arguments.size()), p_call);
+ push_error(vformat(R"*(Too many arguments for "%s()" call. Expected at most %d but received %d.)*", function_name, err.expected, p_call->arguments.size()), p_call);
break;
case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
- push_error(vformat(R"*(Too few arguments for "%s()" call. Expected at least %d but received %d.)*", GDScriptFunctions::get_func_name(builtin_function), err.expected, p_call->arguments.size()), p_call);
+ push_error(vformat(R"*(Too few arguments for "%s()" call. Expected at least %d but received %d.)*", function_name, err.expected, p_call->arguments.size()), p_call);
break;
case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL:
break; // Can't happen in a builtin constructor.
@@ -2385,7 +2460,7 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
// Not found.
// Check if it's a builtin function.
- if (parser->get_builtin_function(name) < GDScriptFunctions::FUNC_MAX) {
+ if (GDScriptUtilityFunctions::function_exists(name)) {
push_error(vformat(R"(Built-in function "%s" cannot be used as an identifier.)", name), p_identifier);
} else {
push_error(vformat(R"(Identifier "%s" not declared in the current scope.)", name), p_identifier);
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index d89b89c8b9..a5d96077d9 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -283,6 +283,30 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
function->_constructors_count = 0;
}
+ if (utilities_map.size()) {
+ function->utilities.resize(utilities_map.size());
+ function->_utilities_ptr = function->utilities.ptr();
+ function->_utilities_count = utilities_map.size();
+ for (const Map<Variant::ValidatedUtilityFunction, int>::Element *E = utilities_map.front(); E; E = E->next()) {
+ function->utilities.write[E->get()] = E->key();
+ }
+ } else {
+ function->_utilities_ptr = nullptr;
+ function->_utilities_count = 0;
+ }
+
+ if (gds_utilities_map.size()) {
+ function->gds_utilities.resize(gds_utilities_map.size());
+ function->_gds_utilities_ptr = function->gds_utilities.ptr();
+ function->_gds_utilities_count = gds_utilities_map.size();
+ for (const Map<GDScriptUtilityFunctions::FunctionPtr, int>::Element *E = gds_utilities_map.front(); E; E = E->next()) {
+ function->gds_utilities.write[E->get()] = E->key();
+ }
+ } else {
+ function->_gds_utilities_ptr = nullptr;
+ function->_gds_utilities_count = 0;
+ }
+
if (method_bind_map.size()) {
function->methods.resize(method_bind_map.size());
function->_methods_ptr = function->methods.ptrw();
@@ -404,7 +428,7 @@ void GDScriptByteCodeGenerator::write_end_and(const Address &p_target) {
patch_jump(logic_op_jump_pos2.back()->get());
logic_op_jump_pos1.pop_back();
logic_op_jump_pos2.pop_back();
- append(GDScriptFunction::OPCODE_ASSIGN_FALSE, 0);
+ append(GDScriptFunction::OPCODE_ASSIGN_FALSE, 1);
append(p_target);
}
@@ -429,7 +453,7 @@ void GDScriptByteCodeGenerator::write_end_or(const Address &p_target) {
// Jump away from the success condition.
append(GDScriptFunction::OPCODE_JUMP, 0);
append(opcodes.size() + 3);
- // Here it means one of operands is false.
+ // Here it means one of operands is true.
patch_jump(logic_op_jump_pos1.back()->get());
patch_jump(logic_op_jump_pos2.back()->get());
logic_op_jump_pos1.pop_back();
@@ -704,8 +728,8 @@ void GDScriptByteCodeGenerator::write_call_async(const Address &p_target, const
append(p_function_name);
}
-void GDScriptByteCodeGenerator::write_call_builtin(const Address &p_target, GDScriptFunctions::Function p_function, const Vector<Address> &p_arguments) {
- append(GDScriptFunction::OPCODE_CALL_BUILT_IN, 1 + p_arguments.size());
+void GDScriptByteCodeGenerator::write_call_gdscript_utility(const Address &p_target, GDScriptUtilityFunctions::FunctionPtr p_function, const Vector<Address> &p_arguments) {
+ append(GDScriptFunction::OPCODE_CALL_GDSCRIPT_UTILITY, 1 + p_arguments.size());
for (int i = 0; i < p_arguments.size(); i++) {
append(p_arguments[i]);
}
@@ -714,6 +738,41 @@ void GDScriptByteCodeGenerator::write_call_builtin(const Address &p_target, GDSc
append(p_function);
}
+void GDScriptByteCodeGenerator::write_call_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) {
+ bool is_validated = true;
+ if (Variant::is_utility_function_vararg(p_function)) {
+ is_validated = true; // Vararg works fine with any argument, since they can be any type.
+ } else if (p_arguments.size() == Variant::get_utility_function_argument_count(p_function)) {
+ bool all_types_exact = true;
+ for (int i = 0; i < p_arguments.size(); i++) {
+ if (!IS_BUILTIN_TYPE(p_arguments[i], Variant::get_utility_function_argument_type(p_function, i))) {
+ all_types_exact = false;
+ break;
+ }
+ }
+
+ is_validated = all_types_exact;
+ }
+
+ if (is_validated) {
+ append(GDScriptFunction::OPCODE_CALL_UTILITY_VALIDATED, 1 + p_arguments.size());
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(p_target);
+ append(p_arguments.size());
+ append(Variant::get_validated_utility_function(p_function));
+ } else {
+ append(GDScriptFunction::OPCODE_CALL_UTILITY, 1 + p_arguments.size());
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(p_target);
+ append(p_arguments.size());
+ append(p_function);
+ }
+}
+
void GDScriptByteCodeGenerator::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) {
bool is_validated = false;
diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h
index 5cbd12a0ba..21576b08a4 100644
--- a/modules/gdscript/gdscript_byte_codegen.h
+++ b/modules/gdscript/gdscript_byte_codegen.h
@@ -34,6 +34,7 @@
#include "gdscript_codegen.h"
#include "gdscript_function.h"
+#include "gdscript_utility_functions.h"
class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
bool ended = false;
@@ -76,6 +77,8 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
Map<Variant::ValidatedIndexedGetter, int> indexed_getters_map;
Map<Variant::ValidatedBuiltInMethod, int> builtin_method_map;
Map<Variant::ValidatedConstructor, int> constructors_map;
+ Map<Variant::ValidatedUtilityFunction, int> utilities_map;
+ Map<GDScriptUtilityFunctions::FunctionPtr, int> gds_utilities_map;
Map<MethodBind *, int> method_bind_map;
// Lists since these can be nested.
@@ -241,6 +244,24 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
return pos;
}
+ int get_utility_pos(const Variant::ValidatedUtilityFunction p_utility) {
+ if (utilities_map.has(p_utility)) {
+ return utilities_map[p_utility];
+ }
+ int pos = utilities_map.size();
+ utilities_map[p_utility] = pos;
+ return pos;
+ }
+
+ int get_gds_utility_pos(const GDScriptUtilityFunctions::FunctionPtr p_gds_utility) {
+ if (gds_utilities_map.has(p_gds_utility)) {
+ return gds_utilities_map[p_gds_utility];
+ }
+ int pos = gds_utilities_map.size();
+ gds_utilities_map[p_gds_utility] = pos;
+ return pos;
+ }
+
int get_method_bind_pos(MethodBind *p_method) {
if (method_bind_map.has(p_method)) {
return method_bind_map[p_method];
@@ -346,6 +367,14 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
opcodes.push_back(get_constructor_pos(p_constructor));
}
+ void append(const Variant::ValidatedUtilityFunction p_utility) {
+ opcodes.push_back(get_utility_pos(p_utility));
+ }
+
+ void append(const GDScriptUtilityFunctions::FunctionPtr p_gds_utility) {
+ opcodes.push_back(get_gds_utility_pos(p_gds_utility));
+ }
+
void append(MethodBind *p_method) {
opcodes.push_back(get_method_bind_pos(p_method));
}
@@ -406,7 +435,8 @@ public:
virtual void write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_call_async(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
- virtual void write_call_builtin(const Address &p_target, GDScriptFunctions::Function p_function, const Vector<Address> &p_arguments) override;
+ 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_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;
diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h
index 559f9b8406..e776007bd7 100644
--- a/modules/gdscript/gdscript_codegen.h
+++ b/modules/gdscript/gdscript_codegen.h
@@ -35,7 +35,7 @@
#include "core/string/string_name.h"
#include "core/variant/variant.h"
#include "gdscript_function.h"
-#include "gdscript_functions.h"
+#include "gdscript_utility_functions.h"
class GDScriptCodeGenerator {
public:
@@ -127,7 +127,8 @@ public:
virtual void write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_call_async(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
- virtual void write_call_builtin(const Address &p_target, GDScriptFunctions::Function p_function, const Vector<Address> &p_arguments) = 0;
+ 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_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;
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index e3f058886f..af6991041e 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -33,6 +33,7 @@
#include "gdscript.h"
#include "gdscript_byte_codegen.h"
#include "gdscript_cache.h"
+#include "gdscript_utility_functions.h"
bool GDScriptCompiler::_is_class_member_property(CodeGen &codegen, const StringName &p_name) {
if (codegen.function_node && codegen.function_node->is_static) {
@@ -456,15 +457,17 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
arguments.push_back(arg);
}
- if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name) != Variant::VARIANT_MAX) {
+ if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(call->function_name) != Variant::VARIANT_MAX) {
// Construct a built-in type.
Variant::Type vtype = GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name);
gen->write_construct(result, vtype, arguments);
- } else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_function(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name) != GDScriptFunctions::FUNC_MAX) {
- // Built-in function.
- GDScriptFunctions::Function func = GDScriptParser::get_builtin_function(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name);
- gen->write_call_builtin(result, func, arguments);
+ } else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && Variant::has_utility_function(call->function_name)) {
+ // Variant utility function.
+ gen->write_call_utility(result, call->function_name, arguments);
+ } else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptUtilityFunctions::function_exists(call->function_name)) {
+ // GDScript utility function.
+ gen->write_call_gdscript_utility(result, GDScriptUtilityFunctions::get_function(call->function_name), arguments);
} else {
// Regular function.
const GDScriptParser::ExpressionNode *callee = call->callee;
@@ -1135,7 +1138,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
// Evaluate expression type.
Vector<GDScriptCodeGenerator::Address> typeof_args;
typeof_args.push_back(expr_addr);
- codegen.generator->write_call_builtin(result_addr, GDScriptFunctions::TYPE_OF, typeof_args);
+ codegen.generator->write_call_utility(result_addr, "typeof", typeof_args);
// Check type equality.
codegen.generator->write_binary_operator(result_addr, Variant::OP_EQUAL, p_type_addr, result_addr);
@@ -1199,7 +1202,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
GDScriptCodeGenerator::Address value_length_addr = codegen.add_temporary(temp_type);
Vector<GDScriptCodeGenerator::Address> len_args;
len_args.push_back(p_value_addr);
- codegen.generator->write_call_builtin(value_length_addr, GDScriptFunctions::LEN, len_args);
+ codegen.generator->write_call_gdscript_utility(value_length_addr, GDScriptUtilityFunctions::get_function("len"), len_args);
// Test length compatibility.
temp_type.builtin_type = Variant::BOOL;
@@ -1253,7 +1256,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
// Also get type of element.
Vector<GDScriptCodeGenerator::Address> typeof_args;
typeof_args.push_back(element_addr);
- codegen.generator->write_call_builtin(element_type_addr, GDScriptFunctions::TYPE_OF, typeof_args);
+ codegen.generator->write_call_utility(element_type_addr, "typeof", typeof_args);
// Try the pattern inside the element.
test_addr = _parse_match_pattern(codegen, r_error, p_pattern->array[i], element_addr, element_type_addr, p_previous_test, false, true);
@@ -1298,7 +1301,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
GDScriptCodeGenerator::Address value_length_addr = codegen.add_temporary(temp_type);
Vector<GDScriptCodeGenerator::Address> func_args;
func_args.push_back(p_value_addr);
- codegen.generator->write_call_builtin(value_length_addr, GDScriptFunctions::LEN, func_args);
+ codegen.generator->write_call_gdscript_utility(value_length_addr, GDScriptUtilityFunctions::get_function("len"), func_args);
// Test length compatibility.
temp_type.builtin_type = Variant::BOOL;
@@ -1367,7 +1370,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
// Also get type of value.
func_args.clear();
func_args.push_back(element_addr);
- codegen.generator->write_call_builtin(element_type_addr, GDScriptFunctions::TYPE_OF, func_args);
+ codegen.generator->write_call_utility(element_type_addr, "typeof", func_args);
// Try the pattern inside the value.
test_addr = _parse_match_pattern(codegen, r_error, element.value_pattern, element_addr, element_type_addr, test_addr, false, true);
@@ -1500,7 +1503,7 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
Vector<GDScriptCodeGenerator::Address> typeof_args;
typeof_args.push_back(value);
- gen->write_call_builtin(type, GDScriptFunctions::TYPE_OF, typeof_args);
+ gen->write_call_utility(type, "typeof", typeof_args);
// Now we can actually start testing.
// For each branch.
diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp
index 92a44c57f8..5938cfd7b2 100644
--- a/modules/gdscript/gdscript_disassembler.cpp
+++ b/modules/gdscript/gdscript_disassembler.cpp
@@ -34,7 +34,6 @@
#include "core/string/string_builder.h"
#include "gdscript.h"
-#include "gdscript_functions.h"
static String _get_variant_string(const Variant &p_variant) {
String txt;
@@ -324,11 +323,8 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr += 4;
} break;
case OPCODE_ASSIGN_TYPED_NATIVE: {
- Variant class_name = _constants_ptr[_code_ptr[ip + 3]];
- GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(class_name.operator Object *());
-
text += "assign typed native (";
- text += nc->get_name().operator String();
+ text += DADDR(3);
text += ") ";
text += DADDR(1);
text += " = ";
@@ -607,13 +603,49 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr = 5 + argc;
} break;
- case OPCODE_CALL_BUILT_IN: {
- text += "call-built-in ";
+ case OPCODE_CALL_UTILITY: {
+ text += "call-utility ";
+
+ int argc = _code_ptr[ip + 1 + instr_var_args];
+ text += DADDR(1 + argc) + " = ";
+
+ text += _global_names_ptr[_code_ptr[ip + 2 + instr_var_args]];
+ text += "(";
+
+ for (int i = 0; i < argc; i++) {
+ if (i > 0)
+ text += ", ";
+ text += DADDR(1 + i);
+ }
+ text += ")";
+
+ incr = 4 + argc;
+ } break;
+ case OPCODE_CALL_UTILITY_VALIDATED: {
+ text += "call-utility ";
+
+ int argc = _code_ptr[ip + 1 + instr_var_args];
+ text += DADDR(1 + argc) + " = ";
+
+ text += "<unkown function>";
+ text += "(";
+
+ for (int i = 0; i < argc; i++) {
+ if (i > 0)
+ text += ", ";
+ text += DADDR(1 + i);
+ }
+ text += ")";
+
+ incr = 4 + argc;
+ } break;
+ case OPCODE_CALL_GDSCRIPT_UTILITY: {
+ text += "call-gscript-utility ";
int argc = _code_ptr[ip + 1 + instr_var_args];
text += DADDR(1 + argc) + " = ";
- text += GDScriptFunctions::get_func_name(GDScriptFunctions::Function(_code_ptr[ip + 2 + instr_var_args]));
+ text += "<unknown function>";
text += "(";
for (int i = 0; i < argc; i++) {
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index af9673a9b8..2181d17cf0 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -37,6 +37,7 @@
#include "gdscript_compiler.h"
#include "gdscript_parser.h"
#include "gdscript_tokenizer.h"
+#include "gdscript_utility_functions.h"
#ifdef TOOLS_ENABLED
#include "core/config/project_settings.h"
@@ -411,11 +412,14 @@ void GDScriptLanguage::get_recognized_extensions(List<String> *p_extensions) con
}
void GDScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const {
- for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) {
- p_functions->push_back(GDScriptFunctions::get_info(GDScriptFunctions::Function(i)));
+ List<StringName> functions;
+ GDScriptUtilityFunctions::get_function_list(&functions);
+
+ for (const List<StringName>::Element *E = functions.front(); E; E = E->next()) {
+ p_functions->push_back(GDScriptUtilityFunctions::get_function_info(E->get()));
}
- //not really "functions", but..
+ // Not really "functions", but show in documentation.
{
MethodInfo mi;
mi.name = "preload";
@@ -1030,9 +1034,12 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
_find_identifiers_in_class(p_context.current_class, p_only_functions, (!p_context.current_function || p_context.current_function->is_static), false, r_result, p_recursion_depth + 1);
}
- for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) {
- MethodInfo function = GDScriptFunctions::get_info(GDScriptFunctions::Function(i));
- ScriptCodeCompletionOption option(String(GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i))), ScriptCodeCompletionOption::KIND_FUNCTION);
+ List<StringName> functions;
+ GDScriptUtilityFunctions::get_function_list(&functions);
+
+ for (const List<StringName>::Element *E = functions.front(); E; E = E->next()) {
+ MethodInfo function = GDScriptUtilityFunctions::get_function_info(E->get());
+ ScriptCodeCompletionOption option(String(E->get()), ScriptCodeCompletionOption::KIND_FUNCTION);
if (function.arguments.size() || (function.flags & METHOD_FLAG_VARARG)) {
option.insert_text += "(";
} else {
@@ -1288,8 +1295,8 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context,
r_type.type.builtin_type = GDScriptParser::get_builtin_type(call->function_name);
found = true;
break;
- } else if (GDScriptParser::get_builtin_function(call->function_name) < GDScriptFunctions::FUNC_MAX) {
- MethodInfo mi = GDScriptFunctions::get_info(GDScriptParser::get_builtin_function(call->function_name));
+ } else if (GDScriptUtilityFunctions::function_exists(call->function_name)) {
+ MethodInfo mi = GDScriptUtilityFunctions::get_function_info(call->function_name);
r_type = _type_from_property(mi.return_val);
found = true;
break;
@@ -2342,8 +2349,8 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
GDScriptCompletionIdentifier connect_base;
- if (GDScriptParser::get_builtin_function(call->function_name) < GDScriptFunctions::FUNC_MAX) {
- MethodInfo info = GDScriptFunctions::get_info(GDScriptParser::get_builtin_function(call->function_name));
+ if (GDScriptUtilityFunctions::function_exists(call->function_name)) {
+ MethodInfo info = GDScriptUtilityFunctions::get_function_info(call->function_name);
r_arghint = _make_arguments_hint(info, p_argidx);
return;
} else if (GDScriptParser::get_builtin_type(call->function_name) < Variant::VARIANT_MAX) {
@@ -2971,13 +2978,11 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol
}
}
- for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) {
- if (GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i)) == p_symbol) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD;
- r_result.class_name = "@GDScript";
- r_result.class_member = p_symbol;
- return OK;
- }
+ if (GDScriptUtilityFunctions::function_exists(p_symbol)) {
+ r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD;
+ r_result.class_name = "@GDScript";
+ r_result.class_member = p_symbol;
+ return OK;
}
if ("PI" == p_symbol || "TAU" == p_symbol || "INF" == p_symbol || "NAN" == p_symbol) {
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index 7bc20672d5..b669870b51 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -38,6 +38,7 @@
#include "core/templates/pair.h"
#include "core/templates/self_list.h"
#include "core/variant/variant.h"
+#include "gdscript_utility_functions.h"
class GDScriptInstance;
class GDScript;
@@ -190,7 +191,9 @@ public:
OPCODE_CALL,
OPCODE_CALL_RETURN,
OPCODE_CALL_ASYNC,
- OPCODE_CALL_BUILT_IN,
+ OPCODE_CALL_UTILITY,
+ OPCODE_CALL_UTILITY_VALIDATED,
+ OPCODE_CALL_GDSCRIPT_UTILITY,
OPCODE_CALL_BUILTIN_TYPE_VALIDATED,
OPCODE_CALL_SELF_BASE,
OPCODE_CALL_METHOD_BIND,
@@ -344,6 +347,10 @@ private:
const Variant::ValidatedBuiltInMethod *_builtin_methods_ptr = nullptr;
int _constructors_count = 0;
const Variant::ValidatedConstructor *_constructors_ptr = nullptr;
+ int _utilities_count = 0;
+ const Variant::ValidatedUtilityFunction *_utilities_ptr = nullptr;
+ int _gds_utilities_count = 0;
+ const GDScriptUtilityFunctions::FunctionPtr *_gds_utilities_ptr = nullptr;
int _methods_count = 0;
MethodBind **_methods_ptr = nullptr;
const int *_code_ptr = nullptr;
@@ -372,6 +379,8 @@ private:
Vector<Variant::ValidatedIndexedGetter> indexed_getters;
Vector<Variant::ValidatedBuiltInMethod> builtin_methods;
Vector<Variant::ValidatedConstructor> constructors;
+ Vector<Variant::ValidatedUtilityFunction> utilities;
+ Vector<GDScriptUtilityFunctions::FunctionPtr> gds_utilities;
Vector<MethodBind *> methods;
Vector<int> code;
Vector<GDScriptDataType> argument_types;
diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp
deleted file mode 100644
index 3a7c1a8676..0000000000
--- a/modules/gdscript/gdscript_functions.cpp
+++ /dev/null
@@ -1,1942 +0,0 @@
-/*************************************************************************/
-/* gdscript_functions.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "gdscript_functions.h"
-
-#include "core/io/json.h"
-#include "core/io/marshalls.h"
-#include "core/math/math_funcs.h"
-#include "core/object/class_db.h"
-#include "core/object/reference.h"
-#include "core/os/os.h"
-#include "core/variant/variant_parser.h"
-#include "gdscript.h"
-
-const char *GDScriptFunctions::get_func_name(Function p_func) {
- ERR_FAIL_INDEX_V(p_func, FUNC_MAX, "");
-
- static const char *_names[FUNC_MAX] = {
- "sin",
- "cos",
- "tan",
- "sinh",
- "cosh",
- "tanh",
- "asin",
- "acos",
- "atan",
- "atan2",
- "sqrt",
- "fmod",
- "fposmod",
- "posmod",
- "floor",
- "ceil",
- "round",
- "abs",
- "sign",
- "pow",
- "log",
- "exp",
- "is_nan",
- "is_inf",
- "is_equal_approx",
- "is_zero_approx",
- "ease",
- "step_decimals",
- "stepify",
- "lerp",
- "lerp_angle",
- "inverse_lerp",
- "range_lerp",
- "smoothstep",
- "move_toward",
- "dectime",
- "randomize",
- "randi",
- "randf",
- "randf_range",
- "randi_range",
- "seed",
- "rand_seed",
- "deg2rad",
- "rad2deg",
- "linear2db",
- "db2linear",
- "polar2cartesian",
- "cartesian2polar",
- "wrapi",
- "wrapf",
- "max",
- "min",
- "clamp",
- "nearest_po2",
- "weakref",
- "convert",
- "typeof",
- "type_exists",
- "char",
- "ord",
- "str",
- "print",
- "printt",
- "prints",
- "printerr",
- "printraw",
- "print_debug",
- "push_error",
- "push_warning",
- "var2str",
- "str2var",
- "var2bytes",
- "bytes2var",
- "range",
- "load",
- "inst2dict",
- "dict2inst",
- "validate_json",
- "parse_json",
- "to_json",
- "hash",
- "Color8",
- "ColorN",
- "print_stack",
- "get_stack",
- "instance_from_id",
- "len",
- "is_instance_valid",
- };
-
- return _names[p_func];
-}
-
-void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_count, Variant &r_ret, Callable::CallError &r_error) {
- r_error.error = Callable::CallError::CALL_OK;
-#ifdef DEBUG_ENABLED
-
-#define VALIDATE_ARG_COUNT(m_count) \
- if (p_arg_count < m_count) { \
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; \
- r_error.argument = m_count; \
- r_error.expected = m_count; \
- r_ret = Variant(); \
- return; \
- } \
- if (p_arg_count > m_count) { \
- r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; \
- r_error.argument = m_count; \
- r_error.expected = m_count; \
- r_ret = Variant(); \
- return; \
- }
-
-#define VALIDATE_ARG_NUM(m_arg) \
- if (!p_args[m_arg]->is_num()) { \
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; \
- r_error.argument = m_arg; \
- r_error.expected = Variant::FLOAT; \
- r_ret = Variant(); \
- return; \
- }
-
-#else
-
-#define VALIDATE_ARG_COUNT(m_count)
-#define VALIDATE_ARG_NUM(m_arg)
-#endif
-
- //using a switch, so the compiler generates a jumptable
-
- switch (p_func) {
- case MATH_SIN: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::sin((double)*p_args[0]);
- } break;
- case MATH_COS: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::cos((double)*p_args[0]);
- } break;
- case MATH_TAN: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::tan((double)*p_args[0]);
- } break;
- case MATH_SINH: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::sinh((double)*p_args[0]);
- } break;
- case MATH_COSH: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::cosh((double)*p_args[0]);
- } break;
- case MATH_TANH: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::tanh((double)*p_args[0]);
- } break;
- case MATH_ASIN: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::asin((double)*p_args[0]);
- } break;
- case MATH_ACOS: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::acos((double)*p_args[0]);
- } break;
- case MATH_ATAN: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::atan((double)*p_args[0]);
- } break;
- case MATH_ATAN2: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::atan2((double)*p_args[0], (double)*p_args[1]);
- } break;
- case MATH_SQRT: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::sqrt((double)*p_args[0]);
- } break;
- case MATH_FMOD: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::fmod((double)*p_args[0], (double)*p_args[1]);
- } break;
- case MATH_FPOSMOD: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::fposmod((double)*p_args[0], (double)*p_args[1]);
- } break;
- case MATH_POSMOD: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::posmod((int)*p_args[0], (int)*p_args[1]);
- } break;
- case MATH_FLOOR: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::floor((double)*p_args[0]);
- } break;
- case MATH_CEIL: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::ceil((double)*p_args[0]);
- } break;
- case MATH_ROUND: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::round((double)*p_args[0]);
- } break;
- case MATH_ABS: {
- VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type() == Variant::INT) {
- int64_t i = *p_args[0];
- r_ret = ABS(i);
- } else if (p_args[0]->get_type() == Variant::FLOAT) {
- double r = *p_args[0];
- r_ret = Math::abs(r);
- } else {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::FLOAT;
- r_ret = Variant();
- }
- } break;
- case MATH_SIGN: {
- VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type() == Variant::INT) {
- int64_t i = *p_args[0];
- r_ret = i < 0 ? -1 : (i > 0 ? +1 : 0);
- } else if (p_args[0]->get_type() == Variant::FLOAT) {
- double r = *p_args[0];
- r_ret = r < 0.0 ? -1.0 : (r > 0.0 ? +1.0 : 0.0);
- } else {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::FLOAT;
- r_ret = Variant();
- }
- } break;
- case MATH_POW: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::pow((double)*p_args[0], (double)*p_args[1]);
- } break;
- case MATH_LOG: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::log((double)*p_args[0]);
- } break;
- case MATH_EXP: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::exp((double)*p_args[0]);
- } break;
- case MATH_ISNAN: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::is_nan((double)*p_args[0]);
- } break;
- case MATH_ISINF: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::is_inf((double)*p_args[0]);
- } break;
- case MATH_ISEQUALAPPROX: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::is_equal_approx((real_t)*p_args[0], (real_t)*p_args[1]);
- } break;
- case MATH_ISZEROAPPROX: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::is_zero_approx((real_t)*p_args[0]);
- } break;
- case MATH_EASE: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::ease((double)*p_args[0], (double)*p_args[1]);
- } break;
- case MATH_STEP_DECIMALS: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::step_decimals((double)*p_args[0]);
- } break;
- case MATH_STEPIFY: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::stepify((double)*p_args[0], (double)*p_args[1]);
- } break;
- case MATH_LERP: {
- VALIDATE_ARG_COUNT(3);
- VALIDATE_ARG_NUM(2);
- const double t = (double)*p_args[2];
- switch (p_args[0]->get_type() == p_args[1]->get_type() ? p_args[0]->get_type() : Variant::FLOAT) {
- case Variant::VECTOR2: {
- r_ret = ((Vector2)*p_args[0]).lerp((Vector2)*p_args[1], t);
- } break;
- case Variant::VECTOR3: {
- r_ret = (p_args[0]->operator Vector3()).lerp(p_args[1]->operator Vector3(), t);
- } break;
- case Variant::COLOR: {
- r_ret = ((Color)*p_args[0]).lerp((Color)*p_args[1], t);
- } break;
- default: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::lerp((double)*p_args[0], (double)*p_args[1], t);
- } break;
- }
- } break;
- case MATH_LERP_ANGLE: {
- VALIDATE_ARG_COUNT(3);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- r_ret = Math::lerp_angle((double)*p_args[0], (double)*p_args[1], (double)*p_args[2]);
- } break;
- case MATH_INVERSE_LERP: {
- VALIDATE_ARG_COUNT(3);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- r_ret = Math::inverse_lerp((double)*p_args[0], (double)*p_args[1], (double)*p_args[2]);
- } break;
- case MATH_RANGE_LERP: {
- VALIDATE_ARG_COUNT(5);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- VALIDATE_ARG_NUM(3);
- VALIDATE_ARG_NUM(4);
- r_ret = Math::range_lerp((double)*p_args[0], (double)*p_args[1], (double)*p_args[2], (double)*p_args[3], (double)*p_args[4]);
- } break;
- case MATH_SMOOTHSTEP: {
- VALIDATE_ARG_COUNT(3);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- r_ret = Math::smoothstep((double)*p_args[0], (double)*p_args[1], (double)*p_args[2]);
- } break;
- case MATH_MOVE_TOWARD: {
- VALIDATE_ARG_COUNT(3);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- r_ret = Math::move_toward((double)*p_args[0], (double)*p_args[1], (double)*p_args[2]);
- } break;
- case MATH_DECTIME: {
- VALIDATE_ARG_COUNT(3);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- r_ret = Math::dectime((double)*p_args[0], (double)*p_args[1], (double)*p_args[2]);
- } break;
- case MATH_RANDOMIZE: {
- VALIDATE_ARG_COUNT(0);
- Math::randomize();
- r_ret = Variant();
- } break;
- case MATH_RANDI: {
- VALIDATE_ARG_COUNT(0);
- r_ret = Math::rand();
- } break;
- case MATH_RANDF: {
- VALIDATE_ARG_COUNT(0);
- r_ret = Math::randf();
- } break;
- case MATH_RANDF_RANGE: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::random((double)*p_args[0], (double)*p_args[1]);
- } break;
- case MATH_RANDI_RANGE: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::random((int)*p_args[0], (int)*p_args[1]);
- } break;
- case MATH_SEED: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- uint64_t seed = *p_args[0];
- Math::seed(seed);
- r_ret = Variant();
- } break;
- case MATH_RANDSEED: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- uint64_t seed = *p_args[0];
- int ret = Math::rand_from_seed(&seed);
- Array reta;
- reta.push_back(ret);
- reta.push_back(seed);
- r_ret = reta;
-
- } break;
- case MATH_DEG2RAD: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::deg2rad((double)*p_args[0]);
- } break;
- case MATH_RAD2DEG: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::rad2deg((double)*p_args[0]);
- } break;
- case MATH_LINEAR2DB: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::linear2db((double)*p_args[0]);
- } break;
- case MATH_DB2LINEAR: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::db2linear((double)*p_args[0]);
- } break;
- case MATH_POLAR2CARTESIAN: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- double r = *p_args[0];
- double th = *p_args[1];
- r_ret = Vector2(r * Math::cos(th), r * Math::sin(th));
- } break;
- case MATH_CARTESIAN2POLAR: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- double x = *p_args[0];
- double y = *p_args[1];
- r_ret = Vector2(Math::sqrt(x * x + y * y), Math::atan2(y, x));
- } break;
- case MATH_WRAP: {
- VALIDATE_ARG_COUNT(3);
- r_ret = Math::wrapi((int64_t)*p_args[0], (int64_t)*p_args[1], (int64_t)*p_args[2]);
- } break;
- case MATH_WRAPF: {
- VALIDATE_ARG_COUNT(3);
- r_ret = Math::wrapf((double)*p_args[0], (double)*p_args[1], (double)*p_args[2]);
- } break;
- case LOGIC_MAX: {
- VALIDATE_ARG_COUNT(2);
- if (p_args[0]->get_type() == Variant::INT && p_args[1]->get_type() == Variant::INT) {
- int64_t a = *p_args[0];
- int64_t b = *p_args[1];
- r_ret = MAX(a, b);
- } else {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
-
- double a = *p_args[0];
- double b = *p_args[1];
-
- r_ret = MAX(a, b);
- }
-
- } break;
- case LOGIC_MIN: {
- VALIDATE_ARG_COUNT(2);
- if (p_args[0]->get_type() == Variant::INT && p_args[1]->get_type() == Variant::INT) {
- int64_t a = *p_args[0];
- int64_t b = *p_args[1];
- r_ret = MIN(a, b);
- } else {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
-
- double a = *p_args[0];
- double b = *p_args[1];
-
- r_ret = MIN(a, b);
- }
- } break;
- case LOGIC_CLAMP: {
- VALIDATE_ARG_COUNT(3);
- if (p_args[0]->get_type() == Variant::INT && p_args[1]->get_type() == Variant::INT && p_args[2]->get_type() == Variant::INT) {
- int64_t a = *p_args[0];
- int64_t b = *p_args[1];
- int64_t c = *p_args[2];
- r_ret = CLAMP(a, b, c);
- } else {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
-
- double a = *p_args[0];
- double b = *p_args[1];
- double c = *p_args[2];
-
- r_ret = CLAMP(a, b, c);
- }
- } break;
- case LOGIC_NEAREST_PO2: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- int64_t num = *p_args[0];
- r_ret = next_power_of_2(num);
- } break;
- case OBJ_WEAKREF: {
- VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type() == Variant::OBJECT) {
- if (p_args[0]->is_ref()) {
- Ref<WeakRef> wref = memnew(WeakRef);
- REF r = *p_args[0];
- if (r.is_valid()) {
- wref->set_ref(r);
- }
- r_ret = wref;
- } else {
- Ref<WeakRef> wref = memnew(WeakRef);
- Object *obj = *p_args[0];
- if (obj) {
- wref->set_obj(obj);
- }
- r_ret = wref;
- }
- } else if (p_args[0]->get_type() == Variant::NIL) {
- Ref<WeakRef> wref = memnew(WeakRef);
- r_ret = wref;
- } else {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- r_ret = Variant();
- return;
- }
- } break;
- case TYPE_CONVERT: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(1);
- int type = *p_args[1];
- if (type < 0 || type >= Variant::VARIANT_MAX) {
- r_ret = RTR("Invalid type argument to convert(), use TYPE_* constants.");
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::INT;
- return;
-
- } else {
- Variant::construct(Variant::Type(type), r_ret, p_args, 1, r_error);
- }
- } break;
- case TYPE_OF: {
- VALIDATE_ARG_COUNT(1);
- r_ret = p_args[0]->get_type();
-
- } break;
- case TYPE_EXISTS: {
- VALIDATE_ARG_COUNT(1);
- r_ret = ClassDB::class_exists(*p_args[0]);
-
- } break;
- case TEXT_CHAR: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- char32_t result[2] = { *p_args[0], 0 };
- r_ret = String(result);
- } break;
- case TEXT_ORD: {
- VALIDATE_ARG_COUNT(1);
-
- 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;
- r_ret = Variant();
- return;
- }
-
- String str = p_args[0]->operator String();
-
- if (str.length() != 1) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
- r_ret = RTR("Expected a string of length 1 (a character).");
- return;
- }
-
- r_ret = str.get(0);
-
- } break;
- case TEXT_STR: {
- if (p_arg_count < 1) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 1;
- r_ret = Variant();
-
- return;
- }
- String str;
- for (int i = 0; i < p_arg_count; i++) {
- String os = p_args[i]->operator String();
-
- if (i == 0) {
- str = os;
- } else {
- str += os;
- }
- }
-
- r_ret = str;
-
- } break;
- case TEXT_PRINT: {
- String str;
- for (int i = 0; i < p_arg_count; i++) {
- str += p_args[i]->operator String();
- }
-
- print_line(str);
- r_ret = Variant();
-
- } break;
- case TEXT_PRINT_TABBED: {
- String str;
- for (int i = 0; i < p_arg_count; i++) {
- if (i) {
- str += "\t";
- }
- str += p_args[i]->operator String();
- }
-
- print_line(str);
- r_ret = Variant();
-
- } break;
- case TEXT_PRINT_SPACED: {
- String str;
- for (int i = 0; i < p_arg_count; i++) {
- if (i) {
- str += " ";
- }
- str += p_args[i]->operator String();
- }
-
- print_line(str);
- r_ret = Variant();
-
- } break;
-
- case TEXT_PRINTERR: {
- String str;
- for (int i = 0; i < p_arg_count; i++) {
- str += p_args[i]->operator String();
- }
-
- print_error(str);
- r_ret = Variant();
-
- } break;
- case TEXT_PRINTRAW: {
- String str;
- for (int i = 0; i < p_arg_count; i++) {
- str += p_args[i]->operator String();
- }
-
- OS::get_singleton()->print("%s", str.utf8().get_data());
- r_ret = Variant();
-
- } break;
- case TEXT_PRINT_DEBUG: {
- String str;
- for (int i = 0; i < p_arg_count; i++) {
- str += p_args[i]->operator String();
- }
-
- ScriptLanguage *script = GDScriptLanguage::get_singleton();
- if (script->debug_get_stack_level_count() > 0) {
- str += "\n At: " + script->debug_get_stack_level_source(0) + ":" + itos(script->debug_get_stack_level_line(0)) + ":" + script->debug_get_stack_level_function(0) + "()";
- }
-
- print_line(str);
- r_ret = Variant();
- } break;
- case PUSH_ERROR: {
- VALIDATE_ARG_COUNT(1);
- 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;
- r_ret = Variant();
- break;
- }
-
- String message = *p_args[0];
- ERR_PRINT(message);
- r_ret = Variant();
- } break;
- case PUSH_WARNING: {
- VALIDATE_ARG_COUNT(1);
- 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;
- r_ret = Variant();
- break;
- }
-
- String message = *p_args[0];
- WARN_PRINT(message);
- r_ret = Variant();
- } break;
- case VAR_TO_STR: {
- VALIDATE_ARG_COUNT(1);
- String vars;
- VariantWriter::write_to_string(*p_args[0], vars);
- r_ret = vars;
- } break;
- case STR_TO_VAR: {
- VALIDATE_ARG_COUNT(1);
- 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;
- r_ret = Variant();
- return;
- }
- r_ret = *p_args[0];
-
- VariantParser::StreamString ss;
- ss.s = *p_args[0];
-
- String errs;
- int line;
- (void)VariantParser::parse(&ss, r_ret, errs, line);
- } break;
- case VAR_TO_BYTES: {
- bool full_objects = false;
- if (p_arg_count < 1) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 1;
- r_ret = Variant();
- return;
- } else if (p_arg_count > 2) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = 2;
- r_ret = Variant();
- } else if (p_arg_count == 2) {
- if (p_args[1]->get_type() != Variant::BOOL) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 1;
- r_error.expected = Variant::BOOL;
- r_ret = Variant();
- return;
- }
- full_objects = *p_args[1];
- }
-
- PackedByteArray barr;
- int len;
- Error err = encode_variant(*p_args[0], nullptr, len, full_objects);
- if (err) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::NIL;
- r_ret = "Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID).";
- return;
- }
-
- barr.resize(len);
- {
- uint8_t *w = barr.ptrw();
- encode_variant(*p_args[0], w, len, full_objects);
- }
- r_ret = barr;
- } break;
- case BYTES_TO_VAR: {
- bool allow_objects = false;
- if (p_arg_count < 1) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 1;
- r_ret = Variant();
- return;
- } else if (p_arg_count > 2) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = 2;
- r_ret = Variant();
- } else if (p_arg_count == 2) {
- if (p_args[1]->get_type() != Variant::BOOL) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 1;
- r_error.expected = Variant::BOOL;
- r_ret = Variant();
- return;
- }
- allow_objects = *p_args[1];
- }
-
- if (p_args[0]->get_type() != Variant::PACKED_BYTE_ARRAY) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 1;
- r_error.expected = Variant::PACKED_BYTE_ARRAY;
- r_ret = Variant();
- return;
- }
-
- PackedByteArray varr = *p_args[0];
- Variant ret;
- {
- const uint8_t *r = varr.ptr();
- Error err = decode_variant(ret, r, varr.size(), nullptr, allow_objects);
- if (err != OK) {
- r_ret = RTR("Not enough bytes for decoding bytes, or invalid format.");
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::PACKED_BYTE_ARRAY;
- return;
- }
- }
-
- r_ret = ret;
-
- } break;
- case GEN_RANGE: {
- switch (p_arg_count) {
- case 0: {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 1;
- r_error.expected = 1;
- r_ret = Variant();
-
- } break;
- case 1: {
- VALIDATE_ARG_NUM(0);
- int count = *p_args[0];
- Array arr;
- if (count <= 0) {
- r_ret = arr;
- return;
- }
- Error err = arr.resize(count);
- if (err != OK) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_ret = Variant();
- return;
- }
-
- for (int i = 0; i < count; i++) {
- arr[i] = i;
- }
-
- r_ret = arr;
- } break;
- case 2: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
-
- int from = *p_args[0];
- int to = *p_args[1];
-
- Array arr;
- if (from >= to) {
- r_ret = arr;
- return;
- }
- Error err = arr.resize(to - from);
- if (err != OK) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_ret = Variant();
- return;
- }
- for (int i = from; i < to; i++) {
- arr[i - from] = i;
- }
- r_ret = arr;
- } break;
- case 3: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
-
- int from = *p_args[0];
- int to = *p_args[1];
- int incr = *p_args[2];
- if (incr == 0) {
- r_ret = RTR("Step argument is zero!");
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return;
- }
-
- Array arr;
- if (from >= to && incr > 0) {
- r_ret = arr;
- return;
- }
- if (from <= to && incr < 0) {
- r_ret = arr;
- return;
- }
-
- //calculate how many
- int count = 0;
- if (incr > 0) {
- count = ((to - from - 1) / incr) + 1;
- } else {
- count = ((from - to - 1) / -incr) + 1;
- }
-
- Error err = arr.resize(count);
-
- if (err != OK) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_ret = Variant();
- return;
- }
-
- if (incr > 0) {
- int idx = 0;
- for (int i = from; i < to; i += incr) {
- arr[idx++] = i;
- }
- } else {
- int idx = 0;
- for (int i = from; i > to; i += incr) {
- arr[idx++] = i;
- }
- }
-
- r_ret = arr;
- } break;
- default: {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = 3;
- r_error.expected = 3;
- r_ret = Variant();
-
- } break;
- }
-
- } break;
- case RESOURCE_LOAD: {
- VALIDATE_ARG_COUNT(1);
- 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;
- r_ret = Variant();
- } else {
- r_ret = ResourceLoader::load(*p_args[0]);
- }
-
- } break;
- case INST2DICT: {
- VALIDATE_ARG_COUNT(1);
-
- if (p_args[0]->get_type() == Variant::NIL) {
- r_ret = Variant();
- } else if (p_args[0]->get_type() != Variant::OBJECT) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_ret = Variant();
- } else {
- Object *obj = *p_args[0];
- if (!obj) {
- r_ret = Variant();
-
- } else if (!obj->get_script_instance() || obj->get_script_instance()->get_language() != GDScriptLanguage::get_singleton()) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::DICTIONARY;
- r_ret = RTR("Not a script with an instance");
- return;
- } else {
- GDScriptInstance *ins = static_cast<GDScriptInstance *>(obj->get_script_instance());
- Ref<GDScript> base = ins->get_script();
- if (base.is_null()) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::DICTIONARY;
- r_ret = RTR("Not based on a script");
- return;
- }
-
- GDScript *p = base.ptr();
- Vector<StringName> sname;
-
- while (p->_owner) {
- sname.push_back(p->name);
- p = p->_owner;
- }
- sname.invert();
-
- if (!p->path.is_resource_file()) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::DICTIONARY;
- r_ret = Variant();
-
- r_ret = RTR("Not based on a resource file");
-
- return;
- }
-
- NodePath cp(sname, Vector<StringName>(), false);
-
- Dictionary d;
- d["@subpath"] = cp;
- d["@path"] = p->get_path();
-
- for (Map<StringName, GDScript::MemberInfo>::Element *E = base->member_indices.front(); E; E = E->next()) {
- if (!d.has(E->key())) {
- d[E->key()] = ins->members[E->get().index];
- }
- }
- r_ret = d;
- }
- }
-
- } break;
- case DICT2INST: {
- VALIDATE_ARG_COUNT(1);
-
- if (p_args[0]->get_type() != Variant::DICTIONARY) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::DICTIONARY;
- r_ret = Variant();
-
- return;
- }
-
- Dictionary d = *p_args[0];
-
- if (!d.has("@path")) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- r_ret = RTR("Invalid instance dictionary format (missing @path)");
-
- return;
- }
-
- Ref<Script> scr = ResourceLoader::load(d["@path"]);
- if (!scr.is_valid()) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- r_ret = RTR("Invalid instance dictionary format (can't load script at @path)");
- return;
- }
-
- Ref<GDScript> gdscr = scr;
-
- if (!gdscr.is_valid()) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- r_ret = Variant();
- r_ret = RTR("Invalid instance dictionary format (invalid script at @path)");
- return;
- }
-
- NodePath sub;
- if (d.has("@subpath")) {
- sub = d["@subpath"];
- }
-
- for (int i = 0; i < sub.get_name_count(); i++) {
- gdscr = gdscr->subclasses[sub.get_name(i)];
- if (!gdscr.is_valid()) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- r_ret = Variant();
- r_ret = RTR("Invalid instance dictionary (invalid subclasses)");
- return;
- }
- }
- r_ret = gdscr->_new(nullptr, -1 /*skip initializer*/, r_error);
-
- if (r_error.error != Callable::CallError::CALL_OK) {
- r_ret = Variant();
- return;
- }
-
- GDScriptInstance *ins = static_cast<GDScriptInstance *>(static_cast<Object *>(r_ret)->get_script_instance());
- Ref<GDScript> gd_ref = ins->get_script();
-
- for (Map<StringName, GDScript::MemberInfo>::Element *E = gd_ref->member_indices.front(); E; E = E->next()) {
- if (d.has(E->key())) {
- ins->members.write[E->get().index] = d[E->key()];
- }
- }
-
- } break;
- case VALIDATE_JSON: {
- VALIDATE_ARG_COUNT(1);
-
- 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;
- r_ret = Variant();
- return;
- }
-
- String errs;
- int errl;
-
- Error err = JSON::parse(*p_args[0], r_ret, errs, errl);
-
- if (err != OK) {
- r_ret = itos(errl) + ":" + errs;
- } else {
- r_ret = "";
- }
-
- } break;
- case PARSE_JSON: {
- VALIDATE_ARG_COUNT(1);
-
- 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;
- r_ret = Variant();
- return;
- }
-
- String errs;
- int errl;
-
- Error err = JSON::parse(*p_args[0], r_ret, errs, errl);
-
- if (err != OK) {
- r_ret = Variant();
- ERR_PRINT(vformat("Error parsing JSON at line %s: %s", errl, errs));
- }
-
- } break;
- case TO_JSON: {
- VALIDATE_ARG_COUNT(1);
-
- r_ret = JSON::print(*p_args[0]);
- } break;
- case HASH: {
- VALIDATE_ARG_COUNT(1);
- r_ret = p_args[0]->hash();
-
- } break;
- case COLOR8: {
- if (p_arg_count < 3) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 3;
- r_ret = Variant();
-
- return;
- }
- if (p_arg_count > 4) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = 4;
- r_ret = Variant();
-
- return;
- }
-
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
-
- Color color((float)*p_args[0] / 255.0f, (float)*p_args[1] / 255.0f, (float)*p_args[2] / 255.0f);
-
- if (p_arg_count == 4) {
- VALIDATE_ARG_NUM(3);
- color.a = (float)*p_args[3] / 255.0f;
- }
-
- r_ret = color;
-
- } break;
- case COLORN: {
- if (p_arg_count < 1) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 1;
- r_ret = Variant();
- return;
- }
-
- if (p_arg_count > 2) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = 2;
- r_ret = Variant();
- return;
- }
-
- if (p_args[0]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_ret = Variant();
- } else {
- Color color = Color::named(*p_args[0]);
- if (p_arg_count == 2) {
- VALIDATE_ARG_NUM(1);
- color.a = *p_args[1];
- }
- r_ret = color;
- }
-
- } break;
-
- case PRINT_STACK: {
- VALIDATE_ARG_COUNT(0);
-
- ScriptLanguage *script = GDScriptLanguage::get_singleton();
- for (int i = 0; i < script->debug_get_stack_level_count(); i++) {
- print_line("Frame " + itos(i) + " - " + script->debug_get_stack_level_source(i) + ":" + itos(script->debug_get_stack_level_line(i)) + " in function '" + script->debug_get_stack_level_function(i) + "'");
- };
- } break;
-
- case GET_STACK: {
- VALIDATE_ARG_COUNT(0);
-
- ScriptLanguage *script = GDScriptLanguage::get_singleton();
- Array ret;
- for (int i = 0; i < script->debug_get_stack_level_count(); i++) {
- Dictionary frame;
- frame["source"] = script->debug_get_stack_level_source(i);
- frame["function"] = script->debug_get_stack_level_function(i);
- frame["line"] = script->debug_get_stack_level_line(i);
- ret.push_back(frame);
- };
- r_ret = ret;
- } break;
-
- case INSTANCE_FROM_ID: {
- VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type() != Variant::INT && p_args[0]->get_type() != Variant::FLOAT) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::INT;
- r_ret = Variant();
- break;
- }
-
- ObjectID id = *p_args[0];
- r_ret = ObjectDB::get_instance(id);
-
- } break;
- case LEN: {
- VALIDATE_ARG_COUNT(1);
- switch (p_args[0]->get_type()) {
- case Variant::STRING: {
- String d = *p_args[0];
- r_ret = d.length();
- } break;
- case Variant::DICTIONARY: {
- Dictionary d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::ARRAY: {
- Array d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_BYTE_ARRAY: {
- Vector<uint8_t> d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_INT32_ARRAY: {
- Vector<int32_t> d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_INT64_ARRAY: {
- Vector<int64_t> d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_FLOAT32_ARRAY: {
- Vector<float> d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_FLOAT64_ARRAY: {
- Vector<double> d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_STRING_ARRAY: {
- Vector<String> d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_VECTOR2_ARRAY: {
- Vector<Vector2> d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_VECTOR3_ARRAY: {
- Vector<Vector3> d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_COLOR_ARRAY: {
- Vector<Color> d = *p_args[0];
- r_ret = d.size();
- } break;
- default: {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- r_ret = Variant();
- r_ret = RTR("Object can't provide a length.");
- }
- }
-
- } break;
- case IS_INSTANCE_VALID: {
- VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type() != Variant::OBJECT) {
- r_ret = false;
- } else {
- Object *obj = p_args[0]->get_validated_object();
- r_ret = obj != nullptr;
- }
-
- } break;
- case FUNC_MAX: {
- ERR_FAIL();
- } break;
- }
-}
-
-bool GDScriptFunctions::is_deterministic(Function p_func) {
- //man i couldn't have chosen a worse function name,
- //way too controversial..
-
- switch (p_func) {
- case MATH_SIN:
- case MATH_COS:
- case MATH_TAN:
- case MATH_SINH:
- case MATH_COSH:
- case MATH_TANH:
- case MATH_ASIN:
- case MATH_ACOS:
- case MATH_ATAN:
- case MATH_ATAN2:
- case MATH_SQRT:
- case MATH_FMOD:
- case MATH_FPOSMOD:
- case MATH_POSMOD:
- case MATH_FLOOR:
- case MATH_CEIL:
- case MATH_ROUND:
- case MATH_ABS:
- case MATH_SIGN:
- case MATH_POW:
- case MATH_LOG:
- case MATH_EXP:
- case MATH_ISNAN:
- case MATH_ISINF:
- case MATH_EASE:
- case MATH_STEP_DECIMALS:
- case MATH_STEPIFY:
- case MATH_LERP:
- case MATH_INVERSE_LERP:
- case MATH_RANGE_LERP:
- case MATH_SMOOTHSTEP:
- case MATH_MOVE_TOWARD:
- case MATH_DECTIME:
- case MATH_DEG2RAD:
- case MATH_RAD2DEG:
- case MATH_LINEAR2DB:
- case MATH_DB2LINEAR:
- case MATH_POLAR2CARTESIAN:
- case MATH_CARTESIAN2POLAR:
- case MATH_WRAP:
- case MATH_WRAPF:
- case LOGIC_MAX:
- case LOGIC_MIN:
- case LOGIC_CLAMP:
- case LOGIC_NEAREST_PO2:
- case TYPE_CONVERT:
- case TYPE_OF:
- case TYPE_EXISTS:
- case TEXT_CHAR:
- case TEXT_ORD:
- case TEXT_STR:
- case COLOR8:
- case LEN:
- // enable for debug only, otherwise not desirable - case GEN_RANGE:
- return true;
- default:
- return false;
- }
-
- return false;
-}
-
-MethodInfo GDScriptFunctions::get_info(Function p_func) {
-#ifdef DEBUG_ENABLED
- //using a switch, so the compiler generates a jumptable
-
- switch (p_func) {
- case MATH_SIN: {
- MethodInfo mi("sin", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
-
- } break;
- case MATH_COS: {
- MethodInfo mi("cos", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_TAN: {
- MethodInfo mi("tan", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_SINH: {
- MethodInfo mi("sinh", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_COSH: {
- MethodInfo mi("cosh", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_TANH: {
- MethodInfo mi("tanh", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_ASIN: {
- MethodInfo mi("asin", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_ACOS: {
- MethodInfo mi("acos", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_ATAN: {
- MethodInfo mi("atan", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_ATAN2: {
- MethodInfo mi("atan2", PropertyInfo(Variant::FLOAT, "y"), PropertyInfo(Variant::FLOAT, "x"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_SQRT: {
- MethodInfo mi("sqrt", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_FMOD: {
- MethodInfo mi("fmod", PropertyInfo(Variant::FLOAT, "a"), PropertyInfo(Variant::FLOAT, "b"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_FPOSMOD: {
- MethodInfo mi("fposmod", PropertyInfo(Variant::FLOAT, "a"), PropertyInfo(Variant::FLOAT, "b"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_POSMOD: {
- MethodInfo mi("posmod", PropertyInfo(Variant::INT, "a"), PropertyInfo(Variant::INT, "b"));
- mi.return_val.type = Variant::INT;
- return mi;
- } break;
- case MATH_FLOOR: {
- MethodInfo mi("floor", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_CEIL: {
- MethodInfo mi("ceil", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_ROUND: {
- MethodInfo mi("round", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_ABS: {
- MethodInfo mi("abs", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_SIGN: {
- MethodInfo mi("sign", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_POW: {
- MethodInfo mi("pow", PropertyInfo(Variant::FLOAT, "base"), PropertyInfo(Variant::FLOAT, "exp"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_LOG: {
- MethodInfo mi("log", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_EXP: {
- MethodInfo mi("exp", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_ISNAN: {
- MethodInfo mi("is_nan", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::BOOL;
- return mi;
- } break;
- case MATH_ISINF: {
- MethodInfo mi("is_inf", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::BOOL;
- return mi;
- } break;
- case MATH_ISEQUALAPPROX: {
- MethodInfo mi("is_equal_approx", PropertyInfo(Variant::FLOAT, "a"), PropertyInfo(Variant::FLOAT, "b"));
- mi.return_val.type = Variant::BOOL;
- return mi;
- } break;
- case MATH_ISZEROAPPROX: {
- MethodInfo mi("is_zero_approx", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::BOOL;
- return mi;
- } break;
- case MATH_EASE: {
- MethodInfo mi("ease", PropertyInfo(Variant::FLOAT, "s"), PropertyInfo(Variant::FLOAT, "curve"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_STEP_DECIMALS: {
- MethodInfo mi("step_decimals", PropertyInfo(Variant::FLOAT, "step"));
- mi.return_val.type = Variant::INT;
- return mi;
- } break;
- case MATH_STEPIFY: {
- MethodInfo mi("stepify", PropertyInfo(Variant::FLOAT, "s"), PropertyInfo(Variant::FLOAT, "step"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_LERP: {
- MethodInfo mi("lerp", PropertyInfo(Variant::NIL, "from"), PropertyInfo(Variant::NIL, "to"), PropertyInfo(Variant::FLOAT, "weight"));
- mi.return_val.type = Variant::NIL;
- mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- return mi;
- } break;
- case MATH_LERP_ANGLE: {
- MethodInfo mi("lerp_angle", PropertyInfo(Variant::FLOAT, "from"), PropertyInfo(Variant::FLOAT, "to"), PropertyInfo(Variant::FLOAT, "weight"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_INVERSE_LERP: {
- MethodInfo mi("inverse_lerp", PropertyInfo(Variant::FLOAT, "from"), PropertyInfo(Variant::FLOAT, "to"), PropertyInfo(Variant::FLOAT, "weight"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_RANGE_LERP: {
- MethodInfo mi("range_lerp", PropertyInfo(Variant::FLOAT, "value"), PropertyInfo(Variant::FLOAT, "istart"), PropertyInfo(Variant::FLOAT, "istop"), PropertyInfo(Variant::FLOAT, "ostart"), PropertyInfo(Variant::FLOAT, "ostop"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_SMOOTHSTEP: {
- MethodInfo mi("smoothstep", PropertyInfo(Variant::FLOAT, "from"), PropertyInfo(Variant::FLOAT, "to"), PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_MOVE_TOWARD: {
- MethodInfo mi("move_toward", PropertyInfo(Variant::FLOAT, "from"), PropertyInfo(Variant::FLOAT, "to"), PropertyInfo(Variant::FLOAT, "delta"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_DECTIME: {
- MethodInfo mi("dectime", PropertyInfo(Variant::FLOAT, "value"), PropertyInfo(Variant::FLOAT, "amount"), PropertyInfo(Variant::FLOAT, "step"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_RANDOMIZE: {
- MethodInfo mi("randomize");
- mi.return_val.type = Variant::NIL;
- return mi;
- } break;
- case MATH_RANDI: {
- MethodInfo mi("randi");
- mi.return_val.type = Variant::INT;
- return mi;
- } break;
- case MATH_RANDF: {
- MethodInfo mi("randf");
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_RANDF_RANGE: {
- MethodInfo mi("randf_range", PropertyInfo(Variant::FLOAT, "from"), PropertyInfo(Variant::FLOAT, "to"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_RANDI_RANGE: {
- MethodInfo mi("randi_range", PropertyInfo(Variant::INT, "from"), PropertyInfo(Variant::INT, "to"));
- mi.return_val.type = Variant::INT;
- return mi;
- } break;
- case MATH_SEED: {
- MethodInfo mi("seed", PropertyInfo(Variant::INT, "seed"));
- mi.return_val.type = Variant::NIL;
- return mi;
- } break;
- case MATH_RANDSEED: {
- MethodInfo mi("rand_seed", PropertyInfo(Variant::INT, "seed"));
- mi.return_val.type = Variant::ARRAY;
- return mi;
- } break;
- case MATH_DEG2RAD: {
- MethodInfo mi("deg2rad", PropertyInfo(Variant::FLOAT, "deg"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_RAD2DEG: {
- MethodInfo mi("rad2deg", PropertyInfo(Variant::FLOAT, "rad"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_LINEAR2DB: {
- MethodInfo mi("linear2db", PropertyInfo(Variant::FLOAT, "nrg"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_DB2LINEAR: {
- MethodInfo mi("db2linear", PropertyInfo(Variant::FLOAT, "db"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_POLAR2CARTESIAN: {
- MethodInfo mi("polar2cartesian", PropertyInfo(Variant::FLOAT, "r"), PropertyInfo(Variant::FLOAT, "th"));
- mi.return_val.type = Variant::VECTOR2;
- return mi;
- } break;
- case MATH_CARTESIAN2POLAR: {
- MethodInfo mi("cartesian2polar", PropertyInfo(Variant::FLOAT, "x"), PropertyInfo(Variant::FLOAT, "y"));
- mi.return_val.type = Variant::VECTOR2;
- return mi;
- } break;
- case MATH_WRAP: {
- MethodInfo mi("wrapi", PropertyInfo(Variant::INT, "value"), PropertyInfo(Variant::INT, "min"), PropertyInfo(Variant::INT, "max"));
- mi.return_val.type = Variant::INT;
- return mi;
- } break;
- case MATH_WRAPF: {
- MethodInfo mi("wrapf", PropertyInfo(Variant::FLOAT, "value"), PropertyInfo(Variant::FLOAT, "min"), PropertyInfo(Variant::FLOAT, "max"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case LOGIC_MAX: {
- MethodInfo mi("max", PropertyInfo(Variant::FLOAT, "a"), PropertyInfo(Variant::FLOAT, "b"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
-
- } break;
- case LOGIC_MIN: {
- MethodInfo mi("min", PropertyInfo(Variant::FLOAT, "a"), PropertyInfo(Variant::FLOAT, "b"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case LOGIC_CLAMP: {
- MethodInfo mi("clamp", PropertyInfo(Variant::FLOAT, "value"), PropertyInfo(Variant::FLOAT, "min"), PropertyInfo(Variant::FLOAT, "max"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case LOGIC_NEAREST_PO2: {
- MethodInfo mi("nearest_po2", PropertyInfo(Variant::INT, "value"));
- mi.return_val.type = Variant::INT;
- return mi;
- } break;
- case OBJ_WEAKREF: {
- MethodInfo mi("weakref", PropertyInfo(Variant::OBJECT, "obj"));
- mi.return_val.type = Variant::OBJECT;
- mi.return_val.class_name = "WeakRef";
-
- return mi;
-
- } break;
- case TYPE_CONVERT: {
- MethodInfo mi("convert", PropertyInfo(Variant::NIL, "what", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT), PropertyInfo(Variant::INT, "type"));
- mi.return_val.type = Variant::NIL;
- mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- return mi;
- } break;
- case TYPE_OF: {
- MethodInfo mi("typeof", PropertyInfo(Variant::NIL, "what", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT));
- mi.return_val.type = Variant::INT;
- return mi;
-
- } break;
- case TYPE_EXISTS: {
- MethodInfo mi("type_exists", PropertyInfo(Variant::STRING, "type"));
- mi.return_val.type = Variant::BOOL;
- return mi;
-
- } break;
- case TEXT_CHAR: {
- MethodInfo mi("char", PropertyInfo(Variant::INT, "code"));
- mi.return_val.type = Variant::STRING;
- return mi;
-
- } break;
- case TEXT_ORD: {
- MethodInfo mi("ord", PropertyInfo(Variant::STRING, "char"));
- mi.return_val.type = Variant::INT;
- return mi;
-
- } break;
- case TEXT_STR: {
- MethodInfo mi("str");
- mi.return_val.type = Variant::STRING;
- mi.flags |= METHOD_FLAG_VARARG;
- return mi;
-
- } break;
- case TEXT_PRINT: {
- MethodInfo mi("print");
- mi.return_val.type = Variant::NIL;
- mi.flags |= METHOD_FLAG_VARARG;
- return mi;
-
- } break;
- case TEXT_PRINT_TABBED: {
- MethodInfo mi("printt");
- mi.return_val.type = Variant::NIL;
- mi.flags |= METHOD_FLAG_VARARG;
- return mi;
-
- } break;
- case TEXT_PRINT_SPACED: {
- MethodInfo mi("prints");
- mi.return_val.type = Variant::NIL;
- mi.flags |= METHOD_FLAG_VARARG;
- return mi;
-
- } break;
- case TEXT_PRINTERR: {
- MethodInfo mi("printerr");
- mi.return_val.type = Variant::NIL;
- mi.flags |= METHOD_FLAG_VARARG;
- return mi;
-
- } break;
- case TEXT_PRINTRAW: {
- MethodInfo mi("printraw");
- mi.return_val.type = Variant::NIL;
- mi.flags |= METHOD_FLAG_VARARG;
- return mi;
-
- } break;
- case TEXT_PRINT_DEBUG: {
- MethodInfo mi("print_debug");
- mi.return_val.type = Variant::NIL;
- mi.flags |= METHOD_FLAG_VARARG;
- return mi;
-
- } break;
- case PUSH_ERROR: {
- MethodInfo mi(Variant::NIL, "push_error", PropertyInfo(Variant::STRING, "message"));
- mi.return_val.type = Variant::NIL;
- return mi;
-
- } break;
- case PUSH_WARNING: {
- MethodInfo mi(Variant::NIL, "push_warning", PropertyInfo(Variant::STRING, "message"));
- mi.return_val.type = Variant::NIL;
- return mi;
-
- } break;
- case VAR_TO_STR: {
- MethodInfo mi("var2str", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT));
- mi.return_val.type = Variant::STRING;
- return mi;
- } break;
- case STR_TO_VAR: {
- MethodInfo mi(Variant::NIL, "str2var", PropertyInfo(Variant::STRING, "string"));
- mi.return_val.type = Variant::NIL;
- mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- return mi;
- } break;
- case VAR_TO_BYTES: {
- MethodInfo mi("var2bytes", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT), PropertyInfo(Variant::BOOL, "full_objects"));
- mi.default_arguments.push_back(false);
- mi.return_val.type = Variant::PACKED_BYTE_ARRAY;
- return mi;
- } break;
- case BYTES_TO_VAR: {
- MethodInfo mi(Variant::NIL, "bytes2var", PropertyInfo(Variant::PACKED_BYTE_ARRAY, "bytes"), PropertyInfo(Variant::BOOL, "allow_objects"));
- mi.default_arguments.push_back(false);
- mi.return_val.type = Variant::NIL;
- mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- return mi;
- } break;
- case GEN_RANGE: {
- MethodInfo mi("range");
- mi.return_val.type = Variant::ARRAY;
- mi.flags |= METHOD_FLAG_VARARG;
- return mi;
- } break;
- case RESOURCE_LOAD: {
- MethodInfo mi("load", PropertyInfo(Variant::STRING, "path"));
- mi.return_val.type = Variant::OBJECT;
- mi.return_val.class_name = "Resource";
- return mi;
- } break;
- case INST2DICT: {
- MethodInfo mi("inst2dict", PropertyInfo(Variant::OBJECT, "inst"));
- mi.return_val.type = Variant::DICTIONARY;
- return mi;
- } break;
- case DICT2INST: {
- MethodInfo mi("dict2inst", PropertyInfo(Variant::DICTIONARY, "dict"));
- mi.return_val.type = Variant::OBJECT;
- return mi;
- } break;
- case VALIDATE_JSON: {
- MethodInfo mi("validate_json", PropertyInfo(Variant::STRING, "json"));
- mi.return_val.type = Variant::STRING;
- return mi;
- } break;
- case PARSE_JSON: {
- MethodInfo mi(Variant::NIL, "parse_json", PropertyInfo(Variant::STRING, "json"));
- mi.return_val.type = Variant::NIL;
- mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- return mi;
- } break;
- case TO_JSON: {
- MethodInfo mi("to_json", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT));
- mi.return_val.type = Variant::STRING;
- return mi;
- } break;
- case HASH: {
- MethodInfo mi("hash", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT));
- mi.return_val.type = Variant::INT;
- return mi;
- } break;
- case COLOR8: {
- MethodInfo mi("Color8", PropertyInfo(Variant::INT, "r8"), PropertyInfo(Variant::INT, "g8"), PropertyInfo(Variant::INT, "b8"), PropertyInfo(Variant::INT, "a8"));
- mi.default_arguments.push_back(255);
- mi.return_val.type = Variant::COLOR;
- return mi;
- } break;
- case COLORN: {
- MethodInfo mi("ColorN", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::FLOAT, "alpha"));
- mi.default_arguments.push_back(1.0f);
- mi.return_val.type = Variant::COLOR;
- return mi;
- } break;
-
- case PRINT_STACK: {
- MethodInfo mi("print_stack");
- mi.return_val.type = Variant::NIL;
- return mi;
- } break;
- case GET_STACK: {
- MethodInfo mi("get_stack");
- mi.return_val.type = Variant::ARRAY;
- return mi;
- } break;
-
- case INSTANCE_FROM_ID: {
- MethodInfo mi("instance_from_id", PropertyInfo(Variant::INT, "instance_id"));
- mi.return_val.type = Variant::OBJECT;
- return mi;
- } break;
- case LEN: {
- MethodInfo mi("len", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT));
- mi.return_val.type = Variant::INT;
- return mi;
- } break;
- case IS_INSTANCE_VALID: {
- MethodInfo mi("is_instance_valid", PropertyInfo(Variant::OBJECT, "instance"));
- mi.return_val.type = Variant::BOOL;
- return mi;
- } break;
- default: {
- ERR_FAIL_V(MethodInfo());
- } break;
- }
-#endif
- MethodInfo mi;
- mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- return mi;
-}
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 48fca16ab1..2c735049b6 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -98,15 +98,6 @@ void GDScriptParser::cleanup() {
builtin_types.clear();
}
-GDScriptFunctions::Function GDScriptParser::get_builtin_function(const StringName &p_name) {
- for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) {
- if (p_name == GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i))) {
- return GDScriptFunctions::Function(i);
- }
- }
- return GDScriptFunctions::FUNC_MAX;
-}
-
void GDScriptParser::get_annotation_list(List<MethodInfo> *r_annotations) const {
List<StringName> keys;
valid_annotations.get_key_list(&keys);
@@ -2553,7 +2544,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_call(ExpressionNode *p_pre
// Arguments.
CompletionType ct = COMPLETION_CALL_ARGUMENTS;
- if (get_builtin_function(call->function_name) == GDScriptFunctions::RESOURCE_LOAD) {
+ if (call->function_name == "load") {
ct = COMPLETION_RESOURCE_PATH;
}
push_completion_call(call);
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 44605bc20f..4cecdc6970 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -43,7 +43,6 @@
#include "core/templates/vector.h"
#include "core/variant/variant.h"
#include "gdscript_cache.h"
-#include "gdscript_functions.h"
#include "gdscript_tokenizer.h"
#ifdef DEBUG_ENABLED
@@ -1314,7 +1313,6 @@ public:
ClassNode *get_tree() const { return head; }
bool is_tool() const { return _is_tool; }
static Variant::Type get_builtin_type(const StringName &p_type);
- static GDScriptFunctions::Function get_builtin_function(const StringName &p_name);
CompletionContext get_completion_context() const { return completion_context; }
CompletionCall get_completion_call() const { return completion_call; }
diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp
new file mode 100644
index 0000000000..b1780446d0
--- /dev/null
+++ b/modules/gdscript/gdscript_utility_functions.cpp
@@ -0,0 +1,718 @@
+/*************************************************************************/
+/* gdscript_utility_functions.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gdscript_utility_functions.h"
+
+#include "core/io/resource_loader.h"
+#include "core/object/class_db.h"
+#include "core/object/method_bind.h"
+#include "core/object/object.h"
+#include "core/templates/oa_hash_map.h"
+#include "core/templates/vector.h"
+#include "gdscript.h"
+
+#ifdef DEBUG_ENABLED
+
+#define VALIDATE_ARG_COUNT(m_count) \
+ if (p_arg_count < m_count) { \
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; \
+ r_error.argument = m_count; \
+ r_error.expected = m_count; \
+ *r_ret = Variant(); \
+ return; \
+ } \
+ if (p_arg_count > m_count) { \
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; \
+ r_error.argument = m_count; \
+ r_error.expected = m_count; \
+ *r_ret = Variant(); \
+ return; \
+ }
+
+#define VALIDATE_ARG_INT(m_arg) \
+ if (p_args[m_arg]->get_type() != Variant::INT) { \
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; \
+ r_error.argument = m_arg; \
+ r_error.expected = Variant::INT; \
+ *r_ret = Variant(); \
+ return; \
+ }
+
+#define VALIDATE_ARG_NUM(m_arg) \
+ if (!p_args[m_arg]->is_num()) { \
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; \
+ r_error.argument = m_arg; \
+ r_error.expected = Variant::FLOAT; \
+ *r_ret = Variant(); \
+ return; \
+ }
+
+#else
+
+#define VALIDATE_ARG_COUNT(m_count)
+#define VALIDATE_ARG_INT(m_arg)
+#define VALIDATE_ARG_NUM(m_arg)
+
+#endif
+
+struct GDScriptUtilityFunctionsDefinitions {
+ static inline void convert(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(2);
+ VALIDATE_ARG_INT(1);
+ int type = *p_args[1];
+ if (type < 0 || type >= Variant::VARIANT_MAX) {
+ *r_ret = RTR("Invalid type argument to convert(), use TYPE_* constants.");
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::INT;
+ return;
+
+ } else {
+ Variant::construct(Variant::Type(type), *r_ret, p_args, 1, r_error);
+ }
+ }
+
+ static inline void type_exists(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(1);
+ *r_ret = ClassDB::class_exists(*p_args[0]);
+ }
+
+ static inline void _char(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(1);
+ VALIDATE_ARG_INT(0);
+ char32_t result[2] = { *p_args[0], 0 };
+ *r_ret = String(result);
+ }
+
+ static inline void str(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ if (p_arg_count < 1) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 1;
+ *r_ret = Variant();
+ return;
+ }
+
+ String str;
+ for (int i = 0; i < p_arg_count; i++) {
+ String os = p_args[i]->operator String();
+
+ if (i == 0) {
+ str = os;
+ } else {
+ str += os;
+ }
+ }
+ *r_ret = str;
+ }
+
+ static inline void range(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ switch (p_arg_count) {
+ case 0: {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 1;
+ r_error.expected = 1;
+ *r_ret = Variant();
+ } break;
+ case 1: {
+ VALIDATE_ARG_NUM(0);
+ int count = *p_args[0];
+ Array arr;
+ if (count <= 0) {
+ *r_ret = arr;
+ return;
+ }
+ Error err = arr.resize(count);
+ if (err != OK) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ *r_ret = Variant();
+ return;
+ }
+
+ for (int i = 0; i < count; i++) {
+ arr[i] = i;
+ }
+
+ *r_ret = arr;
+ } break;
+ case 2: {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+
+ int from = *p_args[0];
+ int to = *p_args[1];
+
+ Array arr;
+ if (from >= to) {
+ *r_ret = arr;
+ return;
+ }
+ Error err = arr.resize(to - from);
+ if (err != OK) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ *r_ret = Variant();
+ return;
+ }
+ for (int i = from; i < to; i++) {
+ arr[i - from] = i;
+ }
+ *r_ret = arr;
+ } break;
+ case 3: {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+
+ int from = *p_args[0];
+ int to = *p_args[1];
+ int incr = *p_args[2];
+ if (incr == 0) {
+ *r_ret = RTR("Step argument is zero!");
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return;
+ }
+
+ Array arr;
+ if (from >= to && incr > 0) {
+ *r_ret = arr;
+ return;
+ }
+ if (from <= to && incr < 0) {
+ *r_ret = arr;
+ return;
+ }
+
+ // Calculate how many.
+ int count = 0;
+ if (incr > 0) {
+ count = ((to - from - 1) / incr) + 1;
+ } else {
+ count = ((from - to - 1) / -incr) + 1;
+ }
+
+ Error err = arr.resize(count);
+
+ if (err != OK) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ *r_ret = Variant();
+ return;
+ }
+
+ if (incr > 0) {
+ int idx = 0;
+ for (int i = from; i < to; i += incr) {
+ arr[idx++] = i;
+ }
+ } else {
+ int idx = 0;
+ for (int i = from; i > to; i += incr) {
+ arr[idx++] = i;
+ }
+ }
+
+ *r_ret = arr;
+ } break;
+ default: {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = 3;
+ r_error.expected = 3;
+ *r_ret = Variant();
+
+ } break;
+ }
+ }
+
+ static inline void load(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(1);
+ 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;
+ *r_ret = Variant();
+ } else {
+ *r_ret = ResourceLoader::load(*p_args[0]);
+ }
+ }
+
+ static inline void inst2dict(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(1);
+
+ if (p_args[0]->get_type() == Variant::NIL) {
+ *r_ret = Variant();
+ } else if (p_args[0]->get_type() != Variant::OBJECT) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ *r_ret = Variant();
+ } else {
+ Object *obj = *p_args[0];
+ if (!obj) {
+ *r_ret = Variant();
+
+ } else if (!obj->get_script_instance() || obj->get_script_instance()->get_language() != GDScriptLanguage::get_singleton()) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::DICTIONARY;
+ *r_ret = RTR("Not a script with an instance");
+ return;
+ } else {
+ GDScriptInstance *ins = static_cast<GDScriptInstance *>(obj->get_script_instance());
+ Ref<GDScript> base = ins->get_script();
+ if (base.is_null()) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::DICTIONARY;
+ *r_ret = RTR("Not based on a script");
+ return;
+ }
+
+ GDScript *p = base.ptr();
+ Vector<StringName> sname;
+
+ while (p->_owner) {
+ sname.push_back(p->name);
+ p = p->_owner;
+ }
+ sname.invert();
+
+ if (!p->path.is_resource_file()) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::DICTIONARY;
+ *r_ret = Variant();
+
+ *r_ret = RTR("Not based on a resource file");
+
+ return;
+ }
+
+ NodePath cp(sname, Vector<StringName>(), false);
+
+ Dictionary d;
+ d["@subpath"] = cp;
+ d["@path"] = p->get_path();
+
+ for (Map<StringName, GDScript::MemberInfo>::Element *E = base->member_indices.front(); E; E = E->next()) {
+ if (!d.has(E->key())) {
+ d[E->key()] = ins->members[E->get().index];
+ }
+ }
+ *r_ret = d;
+ }
+ }
+ }
+
+ static inline void dict2inst(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(1);
+
+ if (p_args[0]->get_type() != Variant::DICTIONARY) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::DICTIONARY;
+ *r_ret = Variant();
+
+ return;
+ }
+
+ Dictionary d = *p_args[0];
+
+ if (!d.has("@path")) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::OBJECT;
+ *r_ret = RTR("Invalid instance dictionary format (missing @path)");
+
+ return;
+ }
+
+ Ref<Script> scr = ResourceLoader::load(d["@path"]);
+ if (!scr.is_valid()) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::OBJECT;
+ *r_ret = RTR("Invalid instance dictionary format (can't load script at @path)");
+ return;
+ }
+
+ Ref<GDScript> gdscr = scr;
+
+ if (!gdscr.is_valid()) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::OBJECT;
+ *r_ret = Variant();
+ *r_ret = RTR("Invalid instance dictionary format (invalid script at @path)");
+ return;
+ }
+
+ NodePath sub;
+ if (d.has("@subpath")) {
+ sub = d["@subpath"];
+ }
+
+ for (int i = 0; i < sub.get_name_count(); i++) {
+ gdscr = gdscr->subclasses[sub.get_name(i)];
+ if (!gdscr.is_valid()) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::OBJECT;
+ *r_ret = Variant();
+ *r_ret = RTR("Invalid instance dictionary (invalid subclasses)");
+ return;
+ }
+ }
+ *r_ret = gdscr->_new(nullptr, -1 /*skip initializer*/, r_error);
+
+ if (r_error.error != Callable::CallError::CALL_OK) {
+ *r_ret = Variant();
+ return;
+ }
+
+ GDScriptInstance *ins = static_cast<GDScriptInstance *>(static_cast<Object *>(*r_ret)->get_script_instance());
+ Ref<GDScript> gd_ref = ins->get_script();
+
+ for (Map<StringName, GDScript::MemberInfo>::Element *E = gd_ref->member_indices.front(); E; E = E->next()) {
+ if (d.has(E->key())) {
+ ins->members.write[E->get().index] = d[E->key()];
+ }
+ }
+ }
+
+ static inline void Color8(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ if (p_arg_count < 3) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 3;
+ *r_ret = Variant();
+ return;
+ }
+ if (p_arg_count > 4) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = 4;
+ *r_ret = Variant();
+ return;
+ }
+
+ VALIDATE_ARG_INT(0);
+ VALIDATE_ARG_INT(1);
+ VALIDATE_ARG_INT(2);
+
+ Color color((int64_t)*p_args[0] / 255.0f, (int64_t)*p_args[1] / 255.0f, (int64_t)*p_args[2] / 255.0f);
+
+ if (p_arg_count == 4) {
+ VALIDATE_ARG_INT(3);
+ color.a = (int64_t)*p_args[3] / 255.0f;
+ }
+
+ *r_ret = color;
+ }
+
+ static inline void print_debug(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ String str;
+ for (int i = 0; i < p_arg_count; i++) {
+ str += p_args[i]->operator String();
+ }
+
+ ScriptLanguage *script = GDScriptLanguage::get_singleton();
+ if (script->debug_get_stack_level_count() > 0) {
+ str += "\n At: " + script->debug_get_stack_level_source(0) + ":" + itos(script->debug_get_stack_level_line(0)) + ":" + script->debug_get_stack_level_function(0) + "()";
+ }
+
+ print_line(str);
+ *r_ret = Variant();
+ }
+
+ static inline void print_stack(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(0);
+
+ ScriptLanguage *script = GDScriptLanguage::get_singleton();
+ for (int i = 0; i < script->debug_get_stack_level_count(); i++) {
+ print_line("Frame " + itos(i) + " - " + script->debug_get_stack_level_source(i) + ":" + itos(script->debug_get_stack_level_line(i)) + " in function '" + script->debug_get_stack_level_function(i) + "'");
+ };
+ }
+
+ static inline void get_stack(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(0);
+
+ ScriptLanguage *script = GDScriptLanguage::get_singleton();
+ Array ret;
+ for (int i = 0; i < script->debug_get_stack_level_count(); i++) {
+ Dictionary frame;
+ frame["source"] = script->debug_get_stack_level_source(i);
+ frame["function"] = script->debug_get_stack_level_function(i);
+ frame["line"] = script->debug_get_stack_level_line(i);
+ ret.push_back(frame);
+ };
+ *r_ret = ret;
+ }
+
+ static inline void len(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(1);
+ switch (p_args[0]->get_type()) {
+ case Variant::STRING: {
+ String d = *p_args[0];
+ *r_ret = d.length();
+ } break;
+ case Variant::DICTIONARY: {
+ Dictionary d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::ARRAY: {
+ Array d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_BYTE_ARRAY: {
+ Vector<uint8_t> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_INT32_ARRAY: {
+ Vector<int32_t> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_INT64_ARRAY: {
+ Vector<int64_t> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_FLOAT32_ARRAY: {
+ Vector<float> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_FLOAT64_ARRAY: {
+ Vector<double> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_STRING_ARRAY: {
+ Vector<String> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_VECTOR2_ARRAY: {
+ Vector<Vector2> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_VECTOR3_ARRAY: {
+ Vector<Vector3> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_COLOR_ARRAY: {
+ Vector<Color> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ default: {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::NIL;
+ *r_ret = vformat(RTR("Value of type '%s' can't provide a length."), Variant::get_type_name(p_args[0]->get_type()));
+ }
+ }
+ }
+};
+
+struct GDScriptUtilityFunctionInfo {
+ GDScriptUtilityFunctions::FunctionPtr function;
+ MethodInfo info;
+ bool is_constant = false;
+};
+
+static OAHashMap<StringName, GDScriptUtilityFunctionInfo> utility_function_table;
+static List<StringName> utility_function_name_table;
+
+static void _register_function(const String &p_name, const MethodInfo &p_method_info, GDScriptUtilityFunctions::FunctionPtr p_function, bool p_is_const) {
+ StringName sname(p_name);
+
+ ERR_FAIL_COND(utility_function_table.has(sname));
+
+ GDScriptUtilityFunctionInfo function;
+ function.function = p_function;
+ function.info = p_method_info;
+ function.is_constant = p_is_const;
+
+ utility_function_table.insert(sname, function);
+ utility_function_name_table.push_back(sname);
+}
+
+#define REGISTER_FUNC(m_func, m_is_const, m_return_type, ...) \
+ { \
+ String name(#m_func); \
+ if (name.begins_with("_")) { \
+ name = name.substr(1, name.length() - 1); \
+ } \
+ MethodInfo info = MethodInfo(name, __VA_ARGS__); \
+ info.return_val.type = m_return_type; \
+ _register_function(name, info, GDScriptUtilityFunctionsDefinitions::m_func, m_is_const); \
+ }
+
+#define REGISTER_FUNC_NO_ARGS(m_func, m_is_const, m_return_type) \
+ { \
+ String name(#m_func); \
+ if (name.begins_with("_")) { \
+ name = name.substr(1, name.length() - 1); \
+ } \
+ MethodInfo info = MethodInfo(name); \
+ info.return_val.type = m_return_type; \
+ _register_function(name, info, GDScriptUtilityFunctionsDefinitions::m_func, m_is_const); \
+ }
+
+#define REGISTER_VARARG_FUNC(m_func, m_is_const, m_return_type) \
+ { \
+ String name(#m_func); \
+ if (name.begins_with("_")) { \
+ name = name.substr(1, name.length() - 1); \
+ } \
+ MethodInfo info = MethodInfo(name); \
+ info.return_val.type = m_return_type; \
+ info.flags |= METHOD_FLAG_VARARG; \
+ _register_function(name, info, GDScriptUtilityFunctionsDefinitions::m_func, m_is_const); \
+ }
+
+#define REGISTER_VARIANT_FUNC(m_func, m_is_const, ...) \
+ { \
+ String name(#m_func); \
+ if (name.begins_with("_")) { \
+ name = name.substr(1, name.length() - 1); \
+ } \
+ MethodInfo info = MethodInfo(name, __VA_ARGS__); \
+ info.return_val.type = Variant::NIL; \
+ info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; \
+ _register_function(name, info, GDScriptUtilityFunctionsDefinitions::m_func, m_is_const); \
+ }
+
+#define REGISTER_CLASS_FUNC(m_func, m_is_const, m_return_type, ...) \
+ { \
+ String name(#m_func); \
+ if (name.begins_with("_")) { \
+ name = name.substr(1, name.length() - 1); \
+ } \
+ MethodInfo info = MethodInfo(name, __VA_ARGS__); \
+ info.return_val.type = Variant::OBJECT; \
+ info.return_val.hint = PROPERTY_HINT_RESOURCE_TYPE; \
+ info.return_val.class_name = m_return_type; \
+ _register_function(name, info, GDScriptUtilityFunctionsDefinitions::m_func, m_is_const); \
+ }
+
+#define REGISTER_FUNC_DEF(m_func, m_is_const, m_default, m_return_type, ...) \
+ { \
+ String name(#m_func); \
+ if (name.begins_with("_")) { \
+ name = name.substr(1, name.length() - 1); \
+ } \
+ MethodInfo info = MethodInfo(name, __VA_ARGS__); \
+ info.return_val.type = m_return_type; \
+ info.default_arguments.push_back(m_default); \
+ _register_function(name, info, GDScriptUtilityFunctionsDefinitions::m_func, m_is_const); \
+ }
+
+#define ARG(m_name, m_type) \
+ PropertyInfo(m_type, m_name)
+
+#define VARARG(m_name) \
+ PropertyInfo(Variant::NIL, m_name, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT)
+
+void GDScriptUtilityFunctions::register_functions() {
+ REGISTER_VARIANT_FUNC(convert, true, VARARG("what"), ARG("type", Variant::INT));
+ REGISTER_FUNC(type_exists, true, Variant::BOOL, ARG("type", Variant::STRING_NAME));
+ REGISTER_FUNC(_char, true, Variant::STRING, ARG("char", Variant::INT));
+ REGISTER_VARARG_FUNC(str, true, Variant::STRING);
+ REGISTER_VARARG_FUNC(range, false, Variant::ARRAY);
+ REGISTER_CLASS_FUNC(load, false, "Resource", ARG("path", Variant::STRING));
+ REGISTER_FUNC(inst2dict, false, Variant::DICTIONARY, ARG("instance", Variant::OBJECT));
+ REGISTER_FUNC(dict2inst, false, Variant::OBJECT, ARG("dictionary", Variant::DICTIONARY));
+ REGISTER_FUNC_DEF(Color8, true, 255, Variant::COLOR, ARG("r8", Variant::INT), ARG("g8", Variant::INT), ARG("b8", Variant::INT), ARG("a8", Variant::INT));
+ REGISTER_VARARG_FUNC(print_debug, false, Variant::NIL);
+ REGISTER_FUNC_NO_ARGS(print_stack, false, Variant::NIL);
+ REGISTER_FUNC_NO_ARGS(get_stack, false, Variant::ARRAY);
+ REGISTER_FUNC(len, true, Variant::INT, VARARG("var"));
+}
+
+void GDScriptUtilityFunctions::unregister_functions() {
+ utility_function_name_table.clear();
+ utility_function_table.clear();
+}
+
+GDScriptUtilityFunctions::FunctionPtr GDScriptUtilityFunctions::get_function(const StringName &p_function) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, nullptr);
+ return info->function;
+}
+
+bool GDScriptUtilityFunctions::has_function_return_value(const StringName &p_function) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, false);
+ return info->info.return_val.type != Variant::NIL || bool(info->info.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT);
+}
+
+Variant::Type GDScriptUtilityFunctions::get_function_return_type(const StringName &p_function) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, Variant::NIL);
+ return info->info.return_val.type;
+}
+
+StringName GDScriptUtilityFunctions::get_function_return_class(const StringName &p_function) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, StringName());
+ return info->info.return_val.class_name;
+}
+
+Variant::Type GDScriptUtilityFunctions::get_function_argument_type(const StringName &p_function, int p_arg) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, Variant::NIL);
+ ERR_FAIL_COND_V(p_arg >= info->info.arguments.size(), Variant::NIL);
+ return info->info.arguments[p_arg].type;
+}
+
+int GDScriptUtilityFunctions::get_function_argument_count(const StringName &p_function, int p_arg) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, 0);
+ return info->info.arguments.size();
+}
+
+bool GDScriptUtilityFunctions::is_function_vararg(const StringName &p_function) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, false);
+ return (bool)(info->info.flags & METHOD_FLAG_VARARG);
+}
+
+bool GDScriptUtilityFunctions::is_function_constant(const StringName &p_function) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, false);
+ return info->is_constant;
+}
+
+bool GDScriptUtilityFunctions::function_exists(const StringName &p_function) {
+ return utility_function_table.has(p_function);
+}
+
+void GDScriptUtilityFunctions::get_function_list(List<StringName> *r_functions) {
+ for (const List<StringName>::Element *E = utility_function_name_table.front(); E; E = E->next()) {
+ r_functions->push_back(E->get());
+ }
+}
+
+MethodInfo GDScriptUtilityFunctions::get_function_info(const StringName &p_function) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, MethodInfo());
+ return info->info;
+}
diff --git a/modules/gdscript/gdscript_functions.h b/modules/gdscript/gdscript_utility_functions.h
index 005b49c5da..50867438d9 100644
--- a/modules/gdscript/gdscript_functions.h
+++ b/modules/gdscript/gdscript_utility_functions.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* gdscript_functions.h */
+/* gdscript_utility_functions.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,110 +28,31 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef GDSCRIPT_FUNCTIONS_H
-#define GDSCRIPT_FUNCTIONS_H
+#ifndef GDSCRIPT_UTILITY_FUNCTIONS_H
+#define GDSCRIPT_UTILITY_FUNCTIONS_H
+#include "core/string/string_name.h"
#include "core/variant/variant.h"
-class GDScriptFunctions {
+class GDScriptUtilityFunctions {
public:
- enum Function {
- MATH_SIN,
- MATH_COS,
- MATH_TAN,
- MATH_SINH,
- MATH_COSH,
- MATH_TANH,
- MATH_ASIN,
- MATH_ACOS,
- MATH_ATAN,
- MATH_ATAN2,
- MATH_SQRT,
- MATH_FMOD,
- MATH_FPOSMOD,
- MATH_POSMOD,
- MATH_FLOOR,
- MATH_CEIL,
- MATH_ROUND,
- MATH_ABS,
- MATH_SIGN,
- MATH_POW,
- MATH_LOG,
- MATH_EXP,
- MATH_ISNAN,
- MATH_ISINF,
- MATH_ISEQUALAPPROX,
- MATH_ISZEROAPPROX,
- MATH_EASE,
- MATH_STEP_DECIMALS,
- MATH_STEPIFY,
- MATH_LERP,
- MATH_LERP_ANGLE,
- MATH_INVERSE_LERP,
- MATH_RANGE_LERP,
- MATH_SMOOTHSTEP,
- MATH_MOVE_TOWARD,
- MATH_DECTIME,
- MATH_RANDOMIZE,
- MATH_RANDI,
- MATH_RANDF,
- MATH_RANDF_RANGE,
- MATH_RANDI_RANGE,
- MATH_SEED,
- MATH_RANDSEED,
- MATH_DEG2RAD,
- MATH_RAD2DEG,
- MATH_LINEAR2DB,
- MATH_DB2LINEAR,
- MATH_POLAR2CARTESIAN,
- MATH_CARTESIAN2POLAR,
- MATH_WRAP,
- MATH_WRAPF,
- LOGIC_MAX,
- LOGIC_MIN,
- LOGIC_CLAMP,
- LOGIC_NEAREST_PO2,
- OBJ_WEAKREF,
- TYPE_CONVERT,
- TYPE_OF,
- TYPE_EXISTS,
- TEXT_CHAR,
- TEXT_ORD,
- TEXT_STR,
- TEXT_PRINT,
- TEXT_PRINT_TABBED,
- TEXT_PRINT_SPACED,
- TEXT_PRINTERR,
- TEXT_PRINTRAW,
- TEXT_PRINT_DEBUG,
- PUSH_ERROR,
- PUSH_WARNING,
- VAR_TO_STR,
- STR_TO_VAR,
- VAR_TO_BYTES,
- BYTES_TO_VAR,
- GEN_RANGE,
- RESOURCE_LOAD,
- INST2DICT,
- DICT2INST,
- VALIDATE_JSON,
- PARSE_JSON,
- TO_JSON,
- HASH,
- COLOR8,
- COLORN,
- PRINT_STACK,
- GET_STACK,
- INSTANCE_FROM_ID,
- LEN,
- IS_INSTANCE_VALID,
- FUNC_MAX
- };
+ typedef void (*FunctionPtr)(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
- static const char *get_func_name(Function p_func);
- static void call(Function p_func, const Variant **p_args, int p_arg_count, Variant &r_ret, Callable::CallError &r_error);
- static bool is_deterministic(Function p_func);
- static MethodInfo get_info(Function p_func);
+ static FunctionPtr get_function(const StringName &p_function);
+ static bool has_function_return_value(const StringName &p_function);
+ static Variant::Type get_function_return_type(const StringName &p_function);
+ static StringName get_function_return_class(const StringName &p_function);
+ static Variant::Type get_function_argument_type(const StringName &p_function, int p_arg);
+ static int get_function_argument_count(const StringName &p_function, int p_arg);
+ static bool is_function_vararg(const StringName &p_function);
+ static bool is_function_constant(const StringName &p_function);
+
+ static bool function_exists(const StringName &p_function);
+ static void get_function_list(List<StringName> *r_functions);
+ static MethodInfo get_function_info(const StringName &p_function);
+
+ static void register_functions();
+ static void unregister_functions();
};
-#endif // GDSCRIPT_FUNCTIONS_H
+#endif // GDSCRIPT_UTILITY_FUNCTIONS_H
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index 7942ee8d97..b8e1791467 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -33,7 +33,6 @@
#include "core/core_string_names.h"
#include "core/os/os.h"
#include "gdscript.h"
-#include "gdscript_functions.h"
Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_instance, GDScript *p_script, Variant &self, Variant &static_ref, Variant *p_stack, String &r_error) const {
int address = p_address & ADDR_MASK;
@@ -220,7 +219,9 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
&&OPCODE_CALL, \
&&OPCODE_CALL_RETURN, \
&&OPCODE_CALL_ASYNC, \
- &&OPCODE_CALL_BUILT_IN, \
+ &&OPCODE_CALL_UTILITY, \
+ &&OPCODE_CALL_UTILITY_VALIDATED, \
+ &&OPCODE_CALL_GDSCRIPT_UTILITY, \
&&OPCODE_CALL_BUILTIN_TYPE_VALIDATED, \
&&OPCODE_CALL_SELF_BASE, \
&&OPCODE_CALL_METHOD_BIND, \
@@ -738,7 +739,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
const Variant::ValidatedKeyedSetter setter = _keyed_setters_ptr[index_setter];
bool valid;
- setter(dst, index, value, valid);
+ setter(dst, index, value, &valid);
#ifdef DEBUG_ENABLED
if (!valid) {
@@ -770,7 +771,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
int64_t int_index = *VariantInternal::get_int(index);
bool oob;
- setter(dst, int_index, value, oob);
+ setter(dst, int_index, value, &oob);
#ifdef DEBUG_ENABLED
if (oob) {
@@ -835,9 +836,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#ifdef DEBUG_ENABLED
// Allow better error message in cases where src and dst are the same stack position.
Variant ret;
- getter(src, key, &ret, valid);
+ getter(src, key, &ret, &valid);
#else
- getter(src, key, dst, valid);
+ getter(src, key, dst, &valid);
#endif
#ifdef DEBUG_ENABLED
if (!valid) {
@@ -870,7 +871,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
int64_t int_index = *VariantInternal::get_int(index);
bool oob;
- getter(src, int_index, dst, oob);
+ getter(src, int_index, dst, &oob);
#ifdef DEBUG_ENABLED
if (oob) {
@@ -1292,7 +1293,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
GET_INSTRUCTION_ARG(dst, argc);
- constructor(*dst, (const Variant **)argptrs);
+ constructor(dst, (const Variant **)argptrs);
ip += 3;
}
@@ -1749,7 +1750,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
DISPATCH_OPCODE;
- OPCODE(OPCODE_CALL_BUILT_IN) {
+ OPCODE(OPCODE_CALL_UTILITY) {
CHECK_SPACE(3 + instr_arg_count);
ip += instr_arg_count;
@@ -1757,22 +1758,80 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
int argc = _code_ptr[ip + 1];
GD_ERR_BREAK(argc < 0);
- GDScriptFunctions::Function func = GDScriptFunctions::Function(_code_ptr[ip + 2]);
+ GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _global_names_count);
+ StringName function = _global_names_ptr[_code_ptr[ip + 2]];
+
+ Variant **argptrs = instruction_args;
+
+ GET_INSTRUCTION_ARG(dst, argc);
+
+ Callable::CallError err;
+ Variant::call_utility_function(function, dst, (const Variant **)argptrs, argc, err);
+
+#ifdef DEBUG_ENABLED
+ if (err.error != Callable::CallError::CALL_OK) {
+ String methodstr = function;
+ if (dst->get_type() == Variant::STRING) {
+ // Call provided error string.
+ err_text = "Error calling utility function '" + methodstr + "': " + String(*dst);
+ } else {
+ err_text = _get_call_error(err, "utility function '" + methodstr + "'", (const Variant **)argptrs);
+ }
+ OPCODE_BREAK;
+ }
+#endif
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_CALL_UTILITY_VALIDATED) {
+ CHECK_SPACE(3 + instr_arg_count);
+
+ ip += instr_arg_count;
+
+ int argc = _code_ptr[ip + 1];
+ GD_ERR_BREAK(argc < 0);
+
+ GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _utilities_count);
+ Variant::ValidatedUtilityFunction function = _utilities_ptr[_code_ptr[ip + 2]];
+
+ Variant **argptrs = instruction_args;
+
+ GET_INSTRUCTION_ARG(dst, argc);
+
+ function(dst, (const Variant **)argptrs, argc);
+
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_CALL_GDSCRIPT_UTILITY) {
+ CHECK_SPACE(3 + instr_arg_count);
+
+ ip += instr_arg_count;
+
+ int argc = _code_ptr[ip + 1];
+ GD_ERR_BREAK(argc < 0);
+
+ GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _gds_utilities_count);
+ GDScriptUtilityFunctions::FunctionPtr function = _gds_utilities_ptr[_code_ptr[ip + 2]];
+
Variant **argptrs = instruction_args;
GET_INSTRUCTION_ARG(dst, argc);
Callable::CallError err;
- GDScriptFunctions::call(func, (const Variant **)argptrs, argc, *dst, err);
+ function(dst, (const Variant **)argptrs, argc, err);
#ifdef DEBUG_ENABLED
if (err.error != Callable::CallError::CALL_OK) {
- String methodstr = GDScriptFunctions::get_func_name(func);
+ // TODO: Add this information in debug.
+ String methodstr = "<unkown function>";
if (dst->get_type() == Variant::STRING) {
- //call provided error string
- err_text = "Error calling built-in function '" + methodstr + "': " + String(*dst);
+ // Call provided error string.
+ err_text = "Error calling GDScript utility function '" + methodstr + "': " + String(*dst);
} else {
- err_text = _get_call_error(err, "built-in function '" + methodstr + "'", (const Variant **)argptrs);
+ err_text = _get_call_error(err, "GDScript utility function '" + methodstr + "'", (const Variant **)argptrs);
}
OPCODE_BREAK;
}
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index 6c2af66c65..0c4996e9bb 100644
--- a/modules/gdscript/register_types.cpp
+++ b/modules/gdscript/register_types.cpp
@@ -38,6 +38,7 @@
#include "gdscript_analyzer.h"
#include "gdscript_cache.h"
#include "gdscript_tokenizer.h"
+#include "gdscript_utility_functions.h"
#ifdef TESTS_ENABLED
#include "tests/test_gdscript.h"
@@ -130,6 +131,8 @@ void register_gdscript_types() {
gdscript_translation_parser_plugin.instance();
EditorTranslationParser::get_singleton()->add_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD);
#endif // TOOLS_ENABLED
+
+ GDScriptUtilityFunctions::register_functions();
}
void unregister_gdscript_types() {
@@ -156,6 +159,7 @@ void unregister_gdscript_types() {
GDScriptParser::cleanup();
GDScriptAnalyzer::cleanup();
+ GDScriptUtilityFunctions::unregister_functions();
}
#ifdef TESTS_ENABLED
diff --git a/modules/glslang/SCsub b/modules/glslang/SCsub
index 58c033c75d..182272ffc7 100644
--- a/modules/glslang/SCsub
+++ b/modules/glslang/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_glslang = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_glslang"]:
thirdparty_dir = "#thirdparty/glslang/"
thirdparty_sources = [
@@ -70,7 +73,16 @@ if env["builtin_glslang"]:
env_thirdparty = env_glslang.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
+
+# Godot source files
+
+module_obj = []
+
+env_glslang.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-# Godot's own source files
-env_glslang.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/jpg/SCsub b/modules/jpg/SCsub
index 8ee8e6dd6e..7c6ceeea29 100644
--- a/modules/jpg/SCsub
+++ b/modules/jpg/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_jpg = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
# Not unbundled for now as they are not commonly available as shared library
thirdparty_dir = "#thirdparty/jpeg-compressor/"
thirdparty_sources = [
@@ -17,7 +20,15 @@ env_jpg.Prepend(CPPPATH=[thirdparty_dir])
env_thirdparty = env_jpg.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_jpg.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-# Godot's own source files
-env_jpg.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/mbedtls/SCsub b/modules/mbedtls/SCsub
index 3b1739c6ee..4fcbe8fb43 100755
--- a/modules/mbedtls/SCsub
+++ b/modules/mbedtls/SCsub
@@ -5,8 +5,11 @@ Import("env_modules")
env_mbed_tls = env_modules.Clone()
+# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_mbedtls"]:
- # Thirdparty source files
thirdparty_sources = [
"aes.c",
"aesni.c",
@@ -96,11 +99,21 @@ if env["builtin_mbedtls"]:
env_thirdparty = env_mbed_tls.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
+
+# Godot source files
-# Module sources
-env_mbed_tls.add_source_files(env.modules_sources, "*.cpp")
+module_obj = []
+
+env_mbed_tls.add_source_files(module_obj, "*.cpp")
if env["tests"]:
env_mbed_tls.Append(CPPDEFINES=["TESTS_ENABLED"])
- env_mbed_tls.add_source_files(env.modules_sources, "./tests/*.cpp")
+ env_mbed_tls.add_source_files(module_obj, "./tests/*.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/meshoptimizer/SCsub b/modules/meshoptimizer/SCsub
new file mode 100644
index 0000000000..3f86bb4f00
--- /dev/null
+++ b/modules/meshoptimizer/SCsub
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+Import("env")
+Import("env_modules")
+
+env_meshoptimizer = env_modules.Clone()
+
+# Thirdparty source files
+
+thirdparty_obj = []
+
+thirdparty_dir = "#thirdparty/meshoptimizer/"
+thirdparty_sources = [
+ "allocator.cpp",
+ "clusterizer.cpp",
+ "indexcodec.cpp",
+ "indexgenerator.cpp",
+ "overdrawanalyzer.cpp",
+ "overdrawoptimizer.cpp",
+ "simplifier.cpp",
+ "spatialorder.cpp",
+ "stripifier.cpp",
+ "vcacheanalyzer.cpp",
+ "vcacheoptimizer.cpp",
+ "vertexcodec.cpp",
+ "vertexfilter.cpp",
+ "vfetchanalyzer.cpp",
+ "vfetchoptimizer.cpp",
+]
+thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
+
+env_thirdparty = env_meshoptimizer.Clone()
+env_thirdparty.disable_warnings()
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_meshoptimizer.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/meshoptimizer/config.py b/modules/meshoptimizer/config.py
new file mode 100644
index 0000000000..82e4e43397
--- /dev/null
+++ b/modules/meshoptimizer/config.py
@@ -0,0 +1,7 @@
+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
+
+
+def configure(env):
+ pass
diff --git a/modules/meshoptimizer/register_types.cpp b/modules/meshoptimizer/register_types.cpp
new file mode 100644
index 0000000000..26c8c6ab72
--- /dev/null
+++ b/modules/meshoptimizer/register_types.cpp
@@ -0,0 +1,43 @@
+/*************************************************************************/
+/* register_types.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "register_types.h"
+#include "scene/resources/surface_tool.h"
+#include "thirdparty/meshoptimizer/meshoptimizer.h"
+
+void register_meshoptimizer_types() {
+ SurfaceTool::optimize_vertex_cache_func = meshopt_optimizeVertexCache;
+ SurfaceTool::simplify_func = meshopt_simplify;
+}
+
+void unregister_meshoptimizer_types() {
+ SurfaceTool::optimize_vertex_cache_func = nullptr;
+ SurfaceTool::simplify_func = nullptr;
+}
diff --git a/modules/meshoptimizer/register_types.h b/modules/meshoptimizer/register_types.h
new file mode 100644
index 0000000000..42b3a76a85
--- /dev/null
+++ b/modules/meshoptimizer/register_types.h
@@ -0,0 +1,37 @@
+/*************************************************************************/
+/* register_types.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef MESHOPTIMIZER_REGISTER_TYPES_H
+#define MESHOPTIMIZER_REGISTER_TYPES_H
+
+void register_meshoptimizer_types();
+void unregister_meshoptimizer_types();
+
+#endif // PVR_REGISTER_TYPES_H
diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py
index 9b10bac2f0..309abfbff7 100644
--- a/modules/mono/build_scripts/mono_configure.py
+++ b/modules/mono/build_scripts/mono_configure.py
@@ -263,7 +263,8 @@ def configure(env, env_mono):
env_mono.Append(CPPDEFINES=["_REENTRANT"])
if mono_static:
- env.Append(LINKFLAGS=["-rdynamic"])
+ if not is_javascript:
+ env.Append(LINKFLAGS=["-rdynamic"])
mono_lib_file = os.path.join(mono_lib_path, "lib" + mono_lib + ".a")
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
index e18ed7f107..e9bb701562 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
@@ -173,6 +173,8 @@ namespace GodotTools.Export
assemblies[projectDllName] = projectDllSrcPath;
+ string bclDir = DeterminePlatformBclDir(platform);
+
if (platform == OS.Platforms.Android)
{
string godotAndroidExtProfileDir = GetBclProfileDir("godot_android_ext");
@@ -183,8 +185,49 @@ namespace GodotTools.Export
assemblies["Mono.Android"] = monoAndroidAssemblyPath;
}
+ else if (platform == OS.Platforms.HTML5)
+ {
+ // Ideally these would be added automatically since they're referenced by the wasm BCL assemblies.
+ // However, at least in the case of 'WebAssembly.Net.Http' for some reason the BCL assemblies
+ // reference a different version even though the assembly is the same, for some weird reason.
- string bclDir = DeterminePlatformBclDir(platform);
+ var wasmFrameworkAssemblies = new[] {"WebAssembly.Bindings", "WebAssembly.Net.WebSockets"};
+
+ foreach (string thisWasmFrameworkAssemblyName in wasmFrameworkAssemblies)
+ {
+ string thisWasmFrameworkAssemblyPath = Path.Combine(bclDir, thisWasmFrameworkAssemblyName + ".dll");
+ if (!File.Exists(thisWasmFrameworkAssemblyPath))
+ throw new FileNotFoundException($"Assembly not found: '{thisWasmFrameworkAssemblyName}'", thisWasmFrameworkAssemblyPath);
+ assemblies[thisWasmFrameworkAssemblyName] = thisWasmFrameworkAssemblyPath;
+ }
+
+ // Assemblies that can have a different name in a newer version. Newer version must come first and it has priority.
+ (string newName, string oldName)[] wasmFrameworkAssembliesOneOf = new[]
+ {
+ ("System.Net.Http.WebAssemblyHttpHandler", "WebAssembly.Net.Http")
+ };
+
+ foreach (var thisWasmFrameworkAssemblyName in wasmFrameworkAssembliesOneOf)
+ {
+ string thisWasmFrameworkAssemblyPath = Path.Combine(bclDir, thisWasmFrameworkAssemblyName.newName + ".dll");
+ if (File.Exists(thisWasmFrameworkAssemblyPath))
+ {
+ assemblies[thisWasmFrameworkAssemblyName.newName] = thisWasmFrameworkAssemblyPath;
+ }
+ else
+ {
+ thisWasmFrameworkAssemblyPath = Path.Combine(bclDir, thisWasmFrameworkAssemblyName.oldName + ".dll");
+ if (!File.Exists(thisWasmFrameworkAssemblyPath))
+ {
+ throw new FileNotFoundException("Expected one of the following assemblies but none were found: " +
+ $"'{thisWasmFrameworkAssemblyName.newName}' / '{thisWasmFrameworkAssemblyName.oldName}'",
+ thisWasmFrameworkAssemblyPath);
+ }
+
+ assemblies[thisWasmFrameworkAssemblyName.oldName] = thisWasmFrameworkAssemblyPath;
+ }
+ }
+ }
var initialAssemblies = assemblies.Duplicate();
internal_GetExportedAssemblyDependencies(initialAssemblies, buildConfig, bclDir, assemblies);
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 968f9f29c7..ad7e5d4200 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -97,7 +97,7 @@
#define C_METHOD_MANAGED_TO_SIGNAL C_NS_MONOMARSHAL "::signal_info_to_callable"
#define C_METHOD_MANAGED_FROM_SIGNAL C_NS_MONOMARSHAL "::callable_to_signal_info"
-#define BINDINGS_GENERATOR_VERSION UINT32_C(12)
+#define BINDINGS_GENERATOR_VERSION UINT32_C(13)
const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN("\t%0 %1_in = %1;\n");
@@ -1999,12 +1999,12 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
#define ADD_INTERNAL_CALL_REGISTRATION(m_icall) \
{ \
- output.append("\tmono_add_internal_call("); \
+ output.append("\tGDMonoUtils::add_internal_call("); \
output.append("\"" BINDINGS_NAMESPACE "."); \
output.append(m_icall.editor_only ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS); \
output.append("::"); \
output.append(m_icall.name); \
- output.append("\", (void*)"); \
+ output.append("\", "); \
output.append(m_icall.name); \
output.append(");\n"); \
}
@@ -3100,44 +3100,11 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
INSERT_INT_TYPE("sbyte", int8_t, int64_t);
INSERT_INT_TYPE("short", int16_t, int64_t);
INSERT_INT_TYPE("int", int32_t, int64_t);
+ INSERT_INT_TYPE("long", int64_t, int64_t);
INSERT_INT_TYPE("byte", uint8_t, int64_t);
INSERT_INT_TYPE("ushort", uint16_t, int64_t);
INSERT_INT_TYPE("uint", uint32_t, int64_t);
-
- itype = TypeInterface::create_value_type(String("long"));
- {
- itype.c_out = "\treturn (%0)%1;\n";
- itype.c_in = "\t%0 %1_in = (%0)*%1;\n";
- itype.c_out = "\t*%3 = (%0)%1;\n";
- itype.c_type = "int64_t";
- itype.c_arg_in = "&%s_in";
- }
- itype.c_type_in = "int64_t*";
- itype.c_type_out = "int64_t";
- itype.im_type_in = "ref " + itype.name;
- itype.im_type_out = "out " + itype.name;
- itype.cs_in = "ref %0";
- /* in cs_out, im_type_out (%3) includes the 'out ' part */
- itype.cs_out = "%0(%1, %3 argRet); return argRet;";
- itype.ret_as_byref_arg = true;
- builtin_types.insert(itype.cname, itype);
-
- itype = TypeInterface::create_value_type(String("ulong"));
- {
- itype.c_in = "\t%0 %1_in = (%0)*%1;\n";
- itype.c_out = "\t*%3 = (%0)%1;\n";
- itype.c_type = "int64_t";
- itype.c_arg_in = "&%s_in";
- }
- itype.c_type_in = "uint64_t*";
- itype.c_type_out = "uint64_t";
- itype.im_type_in = "ref " + itype.name;
- itype.im_type_out = "out " + itype.name;
- itype.cs_in = "ref %0";
- /* in cs_out, im_type_out (%3) includes the 'out ' part */
- itype.cs_out = "%0(%1, %3 argRet); return argRet;";
- itype.ret_as_byref_arg = true;
- builtin_types.insert(itype.cname, itype);
+ INSERT_INT_TYPE("ulong", uint64_t, int64_t);
}
// Floating point types
@@ -3149,20 +3116,16 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.proxy_name = "float";
{
// The expected type for 'float' in ptrcall is 'double'
- itype.c_in = "\t%0 %1_in = (%0)*%1;\n";
- itype.c_out = "\t*%3 = (%0)%1;\n";
+ itype.c_in = "\t%0 %1_in = (%0)%1;\n";
+ itype.c_out = "\treturn (%0)%1;\n";
itype.c_type = "double";
- itype.c_type_in = "float*";
+ itype.c_type_in = "float";
itype.c_type_out = "float";
itype.c_arg_in = "&%s_in";
}
itype.cs_type = itype.proxy_name;
- itype.im_type_in = "ref " + itype.proxy_name;
- itype.im_type_out = "out " + itype.proxy_name;
- itype.cs_in = "ref %0";
- /* in cs_out, im_type_out (%3) includes the 'out ' part */
- itype.cs_out = "%0(%1, %3 argRet); return argRet;";
- itype.ret_as_byref_arg = true;
+ itype.im_type_in = itype.proxy_name;
+ itype.im_type_out = itype.proxy_name;
builtin_types.insert(itype.cname, itype);
// double
@@ -3171,20 +3134,14 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.cname = itype.name;
itype.proxy_name = "double";
{
- itype.c_in = "\t%0 %1_in = (%0)*%1;\n";
- itype.c_out = "\t*%3 = (%0)%1;\n";
itype.c_type = "double";
- itype.c_type_in = "double*";
+ itype.c_type_in = "double";
itype.c_type_out = "double";
- itype.c_arg_in = "&%s_in";
+ itype.c_arg_in = "&%s";
}
itype.cs_type = itype.proxy_name;
- itype.im_type_in = "ref " + itype.proxy_name;
- itype.im_type_out = "out " + itype.proxy_name;
- itype.cs_in = "ref %0";
- /* in cs_out, im_type_out (%3) includes the 'out ' part */
- itype.cs_out = "%0(%1, %3 argRet); return argRet;";
- itype.ret_as_byref_arg = true;
+ itype.im_type_in = itype.proxy_name;
+ itype.im_type_out = itype.proxy_name;
builtin_types.insert(itype.cname, itype);
}
diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp
index 68fc372959..f9be19bbe2 100644
--- a/modules/mono/editor/editor_internal_calls.cpp
+++ b/modules/mono/editor/editor_internal_calls.cpp
@@ -47,7 +47,6 @@
#include "../godotsharp_dirs.h"
#include "../mono_gd/gd_mono_marshal.h"
#include "../utils/osx_utils.h"
-#include "bindings_generator.h"
#include "code_completion.h"
#include "godotsharp_export.h"
#include "script_class_parser.h"
@@ -173,35 +172,6 @@ MonoBoolean godot_icall_EditorProgress_Step(MonoString *p_task, MonoString *p_st
return EditorNode::progress_task_step(task, state, p_step, (bool)p_force_refresh);
}
-BindingsGenerator *godot_icall_BindingsGenerator_Ctor() {
- return memnew(BindingsGenerator);
-}
-
-void godot_icall_BindingsGenerator_Dtor(BindingsGenerator *p_handle) {
- memdelete(p_handle);
-}
-
-MonoBoolean godot_icall_BindingsGenerator_LogPrintEnabled(BindingsGenerator *p_handle) {
- return p_handle->is_log_print_enabled();
-}
-
-void godot_icall_BindingsGenerator_SetLogPrintEnabled(BindingsGenerator p_handle, MonoBoolean p_enabled) {
- p_handle.set_log_print_enabled(p_enabled);
-}
-
-int32_t godot_icall_BindingsGenerator_GenerateCsApi(BindingsGenerator *p_handle, MonoString *p_output_dir) {
- String output_dir = GDMonoMarshal::mono_string_to_godot(p_output_dir);
- return p_handle->generate_cs_api(output_dir);
-}
-
-uint32_t godot_icall_BindingsGenerator_Version() {
- return BindingsGenerator::get_version();
-}
-
-uint32_t godot_icall_BindingsGenerator_CsGlueVersion() {
- return CS_GLUE_VERSION;
-}
-
int32_t godot_icall_ScriptClassParser_ParseFile(MonoString *p_filepath, MonoObject *p_classes, MonoString **r_error_str) {
*r_error_str = nullptr;
@@ -400,75 +370,66 @@ MonoBoolean godot_icall_Utils_OS_UnixFileHasExecutableAccess(MonoString *p_file_
void register_editor_internal_calls() {
// GodotSharpDirs
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResDataDir", (void *)godot_icall_GodotSharpDirs_ResDataDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResMetadataDir", (void *)godot_icall_GodotSharpDirs_ResMetadataDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResAssembliesBaseDir", (void *)godot_icall_GodotSharpDirs_ResAssembliesBaseDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResAssembliesDir", (void *)godot_icall_GodotSharpDirs_ResAssembliesDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResConfigDir", (void *)godot_icall_GodotSharpDirs_ResConfigDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempDir", (void *)godot_icall_GodotSharpDirs_ResTempDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempAssembliesBaseDir", (void *)godot_icall_GodotSharpDirs_ResTempAssembliesBaseDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempAssembliesDir", (void *)godot_icall_GodotSharpDirs_ResTempAssembliesDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoUserDir", (void *)godot_icall_GodotSharpDirs_MonoUserDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoLogsDir", (void *)godot_icall_GodotSharpDirs_MonoLogsDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoSolutionsDir", (void *)godot_icall_GodotSharpDirs_MonoSolutionsDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_BuildLogsDirs", (void *)godot_icall_GodotSharpDirs_BuildLogsDirs);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ProjectSlnPath", (void *)godot_icall_GodotSharpDirs_ProjectSlnPath);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ProjectCsProjPath", (void *)godot_icall_GodotSharpDirs_ProjectCsProjPath);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataEditorToolsDir", (void *)godot_icall_GodotSharpDirs_DataEditorToolsDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataEditorPrebuiltApiDir", (void *)godot_icall_GodotSharpDirs_DataEditorPrebuiltApiDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoEtcDir", (void *)godot_icall_GodotSharpDirs_DataMonoEtcDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoLibDir", (void *)godot_icall_GodotSharpDirs_DataMonoLibDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoBinDir", (void *)godot_icall_GodotSharpDirs_DataMonoBinDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResDataDir", godot_icall_GodotSharpDirs_ResDataDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResMetadataDir", godot_icall_GodotSharpDirs_ResMetadataDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResAssembliesBaseDir", godot_icall_GodotSharpDirs_ResAssembliesBaseDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResAssembliesDir", godot_icall_GodotSharpDirs_ResAssembliesDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResConfigDir", godot_icall_GodotSharpDirs_ResConfigDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempDir", godot_icall_GodotSharpDirs_ResTempDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempAssembliesBaseDir", godot_icall_GodotSharpDirs_ResTempAssembliesBaseDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempAssembliesDir", godot_icall_GodotSharpDirs_ResTempAssembliesDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoUserDir", godot_icall_GodotSharpDirs_MonoUserDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoLogsDir", godot_icall_GodotSharpDirs_MonoLogsDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoSolutionsDir", godot_icall_GodotSharpDirs_MonoSolutionsDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_BuildLogsDirs", godot_icall_GodotSharpDirs_BuildLogsDirs);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ProjectSlnPath", godot_icall_GodotSharpDirs_ProjectSlnPath);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ProjectCsProjPath", godot_icall_GodotSharpDirs_ProjectCsProjPath);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataEditorToolsDir", godot_icall_GodotSharpDirs_DataEditorToolsDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataEditorPrebuiltApiDir", godot_icall_GodotSharpDirs_DataEditorPrebuiltApiDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoEtcDir", godot_icall_GodotSharpDirs_DataMonoEtcDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoLibDir", godot_icall_GodotSharpDirs_DataMonoLibDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoBinDir", godot_icall_GodotSharpDirs_DataMonoBinDir);
// EditorProgress
- mono_add_internal_call("GodotTools.Internals.EditorProgress::internal_Create", (void *)godot_icall_EditorProgress_Create);
- mono_add_internal_call("GodotTools.Internals.EditorProgress::internal_Dispose", (void *)godot_icall_EditorProgress_Dispose);
- mono_add_internal_call("GodotTools.Internals.EditorProgress::internal_Step", (void *)godot_icall_EditorProgress_Step);
-
- // BiningsGenerator
- mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_Ctor", (void *)godot_icall_BindingsGenerator_Ctor);
- mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_Dtor", (void *)godot_icall_BindingsGenerator_Dtor);
- mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_LogPrintEnabled", (void *)godot_icall_BindingsGenerator_LogPrintEnabled);
- mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_SetLogPrintEnabled", (void *)godot_icall_BindingsGenerator_SetLogPrintEnabled);
- mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_GenerateCsApi", (void *)godot_icall_BindingsGenerator_GenerateCsApi);
- mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_Version", (void *)godot_icall_BindingsGenerator_Version);
- mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_CsGlueVersion", (void *)godot_icall_BindingsGenerator_CsGlueVersion);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.EditorProgress::internal_Create", godot_icall_EditorProgress_Create);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.EditorProgress::internal_Dispose", godot_icall_EditorProgress_Dispose);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.EditorProgress::internal_Step", godot_icall_EditorProgress_Step);
// ScriptClassParser
- mono_add_internal_call("GodotTools.Internals.ScriptClassParser::internal_ParseFile", (void *)godot_icall_ScriptClassParser_ParseFile);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.ScriptClassParser::internal_ParseFile", godot_icall_ScriptClassParser_ParseFile);
// ExportPlugin
- mono_add_internal_call("GodotTools.Export.ExportPlugin::internal_GetExportedAssemblyDependencies", (void *)godot_icall_ExportPlugin_GetExportedAssemblyDependencies);
+ GDMonoUtils::add_internal_call("GodotTools.Export.ExportPlugin::internal_GetExportedAssemblyDependencies", godot_icall_ExportPlugin_GetExportedAssemblyDependencies);
// Internals
- mono_add_internal_call("GodotTools.Internals.Internal::internal_UpdateApiAssembliesFromPrebuilt", (void *)godot_icall_Internal_UpdateApiAssembliesFromPrebuilt);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_FullTemplatesDir", (void *)godot_icall_Internal_FullTemplatesDir);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_SimplifyGodotPath", (void *)godot_icall_Internal_SimplifyGodotPath);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_IsOsxAppBundleInstalled", (void *)godot_icall_Internal_IsOsxAppBundleInstalled);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_GodotIs32Bits", (void *)godot_icall_Internal_GodotIs32Bits);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_GodotIsRealTDouble", (void *)godot_icall_Internal_GodotIsRealTDouble);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_GodotMainIteration", (void *)godot_icall_Internal_GodotMainIteration);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_GetCoreApiHash", (void *)godot_icall_Internal_GetCoreApiHash);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_GetEditorApiHash", (void *)godot_icall_Internal_GetEditorApiHash);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_IsAssembliesReloadingNeeded", (void *)godot_icall_Internal_IsAssembliesReloadingNeeded);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_ReloadAssemblies", (void *)godot_icall_Internal_ReloadAssemblies);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_EditorDebuggerNodeReloadScripts", (void *)godot_icall_Internal_EditorDebuggerNodeReloadScripts);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_ScriptEditorEdit", (void *)godot_icall_Internal_ScriptEditorEdit);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_EditorNodeShowScriptScreen", (void *)godot_icall_Internal_EditorNodeShowScriptScreen);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_GetScriptsMetadataOrNothing", (void *)godot_icall_Internal_GetScriptsMetadataOrNothing);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_MonoWindowsInstallRoot", (void *)godot_icall_Internal_MonoWindowsInstallRoot);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_EditorRunPlay", (void *)godot_icall_Internal_EditorRunPlay);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_EditorRunStop", (void *)godot_icall_Internal_EditorRunStop);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_ScriptEditorDebugger_ReloadScripts", (void *)godot_icall_Internal_ScriptEditorDebugger_ReloadScripts);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_CodeCompletionRequest", (void *)godot_icall_Internal_CodeCompletionRequest);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_UpdateApiAssembliesFromPrebuilt", godot_icall_Internal_UpdateApiAssembliesFromPrebuilt);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_FullTemplatesDir", godot_icall_Internal_FullTemplatesDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_SimplifyGodotPath", godot_icall_Internal_SimplifyGodotPath);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_IsOsxAppBundleInstalled", godot_icall_Internal_IsOsxAppBundleInstalled);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GodotIs32Bits", godot_icall_Internal_GodotIs32Bits);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GodotIsRealTDouble", godot_icall_Internal_GodotIsRealTDouble);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GodotMainIteration", godot_icall_Internal_GodotMainIteration);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GetCoreApiHash", godot_icall_Internal_GetCoreApiHash);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GetEditorApiHash", godot_icall_Internal_GetEditorApiHash);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_IsAssembliesReloadingNeeded", godot_icall_Internal_IsAssembliesReloadingNeeded);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_ReloadAssemblies", godot_icall_Internal_ReloadAssemblies);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_EditorDebuggerNodeReloadScripts", godot_icall_Internal_EditorDebuggerNodeReloadScripts);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_ScriptEditorEdit", godot_icall_Internal_ScriptEditorEdit);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_EditorNodeShowScriptScreen", godot_icall_Internal_EditorNodeShowScriptScreen);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GetScriptsMetadataOrNothing", godot_icall_Internal_GetScriptsMetadataOrNothing);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_MonoWindowsInstallRoot", godot_icall_Internal_MonoWindowsInstallRoot);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_EditorRunPlay", godot_icall_Internal_EditorRunPlay);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_EditorRunStop", godot_icall_Internal_EditorRunStop);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_ScriptEditorDebugger_ReloadScripts", godot_icall_Internal_ScriptEditorDebugger_ReloadScripts);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_CodeCompletionRequest", godot_icall_Internal_CodeCompletionRequest);
// Globals
- mono_add_internal_call("GodotTools.Internals.Globals::internal_EditorScale", (void *)godot_icall_Globals_EditorScale);
- mono_add_internal_call("GodotTools.Internals.Globals::internal_GlobalDef", (void *)godot_icall_Globals_GlobalDef);
- mono_add_internal_call("GodotTools.Internals.Globals::internal_EditorDef", (void *)godot_icall_Globals_EditorDef);
- mono_add_internal_call("GodotTools.Internals.Globals::internal_TTR", (void *)godot_icall_Globals_TTR);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_EditorScale", godot_icall_Globals_EditorScale);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_GlobalDef", godot_icall_Globals_GlobalDef);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_EditorDef", godot_icall_Globals_EditorDef);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_TTR", godot_icall_Globals_TTR);
// Utils.OS
- mono_add_internal_call("GodotTools.Utils.OS::GetPlatformName", (void *)godot_icall_Utils_OS_GetPlatformName);
- mono_add_internal_call("GodotTools.Utils.OS::UnixFileHasExecutableAccess", (void *)godot_icall_Utils_OS_UnixFileHasExecutableAccess);
+ GDMonoUtils::add_internal_call("GodotTools.Utils.OS::GetPlatformName", godot_icall_Utils_OS_GetPlatformName);
+ GDMonoUtils::add_internal_call("GodotTools.Utils.OS::UnixFileHasExecutableAccess", godot_icall_Utils_OS_UnixFileHasExecutableAccess);
}
diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp
index 544f414cba..afcc75395b 100644
--- a/modules/mono/glue/base_object_glue.cpp
+++ b/modules/mono/glue/base_object_glue.cpp
@@ -163,9 +163,9 @@ MonoObject *godot_icall_Object_weakref(Object *p_ptr) {
return GDMonoUtils::unmanaged_get_managed(wref.ptr());
}
-Error godot_icall_SignalAwaiter_connect(Object *p_source, StringName *p_signal, Object *p_target, MonoObject *p_awaiter) {
+int32_t godot_icall_SignalAwaiter_connect(Object *p_source, StringName *p_signal, Object *p_target, MonoObject *p_awaiter) {
StringName signal = p_signal ? *p_signal : StringName();
- return gd_mono_connect_signal_awaiter(p_source, signal, p_target, p_awaiter);
+ return (int32_t)gd_mono_connect_signal_awaiter(p_source, signal, p_target, p_awaiter);
}
MonoArray *godot_icall_DynamicGodotObject_SetMemberList(Object *p_ptr) {
@@ -240,18 +240,18 @@ MonoString *godot_icall_Object_ToString(Object *p_ptr) {
}
void godot_register_object_icalls() {
- mono_add_internal_call("Godot.Object::godot_icall_Object_Ctor", (void *)godot_icall_Object_Ctor);
- mono_add_internal_call("Godot.Object::godot_icall_Object_Disposed", (void *)godot_icall_Object_Disposed);
- mono_add_internal_call("Godot.Object::godot_icall_Reference_Disposed", (void *)godot_icall_Reference_Disposed);
- mono_add_internal_call("Godot.Object::godot_icall_Object_ConnectEventSignals", (void *)godot_icall_Object_ConnectEventSignals);
- mono_add_internal_call("Godot.Object::godot_icall_Object_ClassDB_get_method", (void *)godot_icall_Object_ClassDB_get_method);
- mono_add_internal_call("Godot.Object::godot_icall_Object_ToString", (void *)godot_icall_Object_ToString);
- mono_add_internal_call("Godot.Object::godot_icall_Object_weakref", (void *)godot_icall_Object_weakref);
- mono_add_internal_call("Godot.SignalAwaiter::godot_icall_SignalAwaiter_connect", (void *)godot_icall_SignalAwaiter_connect);
- mono_add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_SetMemberList", (void *)godot_icall_DynamicGodotObject_SetMemberList);
- mono_add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_InvokeMember", (void *)godot_icall_DynamicGodotObject_InvokeMember);
- mono_add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_GetMember", (void *)godot_icall_DynamicGodotObject_GetMember);
- mono_add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_SetMember", (void *)godot_icall_DynamicGodotObject_SetMember);
+ 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_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);
+ GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_weakref", godot_icall_Object_weakref);
+ GDMonoUtils::add_internal_call("Godot.SignalAwaiter::godot_icall_SignalAwaiter_connect", godot_icall_SignalAwaiter_connect);
+ GDMonoUtils::add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_SetMemberList", godot_icall_DynamicGodotObject_SetMemberList);
+ GDMonoUtils::add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_InvokeMember", godot_icall_DynamicGodotObject_InvokeMember);
+ GDMonoUtils::add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_GetMember", godot_icall_DynamicGodotObject_GetMember);
+ GDMonoUtils::add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_SetMember", godot_icall_DynamicGodotObject_SetMember);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp
index bb3ea0f730..dedb5b9f75 100644
--- a/modules/mono/glue/collections_glue.cpp
+++ b/modules/mono/glue/collections_glue.cpp
@@ -47,7 +47,7 @@ void godot_icall_Array_Dtor(Array *ptr) {
memdelete(ptr);
}
-MonoObject *godot_icall_Array_At(Array *ptr, int index) {
+MonoObject *godot_icall_Array_At(Array *ptr, int32_t index) {
if (index < 0 || index >= ptr->size()) {
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
return nullptr;
@@ -55,7 +55,7 @@ MonoObject *godot_icall_Array_At(Array *ptr, int index) {
return GDMonoMarshal::variant_to_mono_object(ptr->operator[](index));
}
-MonoObject *godot_icall_Array_At_Generic(Array *ptr, int index, uint32_t type_encoding, GDMonoClass *type_class) {
+MonoObject *godot_icall_Array_At_Generic(Array *ptr, int32_t index, uint32_t type_encoding, GDMonoClass *type_class) {
if (index < 0 || index >= ptr->size()) {
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
return nullptr;
@@ -63,7 +63,7 @@ MonoObject *godot_icall_Array_At_Generic(Array *ptr, int index, uint32_t type_en
return GDMonoMarshal::variant_to_mono_object(ptr->operator[](index), ManagedType(type_encoding, type_class));
}
-void godot_icall_Array_SetAt(Array *ptr, int index, MonoObject *value) {
+void godot_icall_Array_SetAt(Array *ptr, int32_t index, MonoObject *value) {
if (index < 0 || index >= ptr->size()) {
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
return;
@@ -71,11 +71,11 @@ void godot_icall_Array_SetAt(Array *ptr, int index, MonoObject *value) {
ptr->operator[](index) = GDMonoMarshal::mono_object_to_variant(value);
}
-int godot_icall_Array_Count(Array *ptr) {
+int32_t godot_icall_Array_Count(Array *ptr) {
return ptr->size();
}
-int godot_icall_Array_Add(Array *ptr, MonoObject *item) {
+int32_t godot_icall_Array_Add(Array *ptr, MonoObject *item) {
ptr->append(GDMonoMarshal::mono_object_to_variant(item));
return ptr->size();
}
@@ -88,7 +88,7 @@ MonoBoolean godot_icall_Array_Contains(Array *ptr, MonoObject *item) {
return ptr->find(GDMonoMarshal::mono_object_to_variant(item)) != -1;
}
-void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int array_index) {
+void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int32_t array_index) {
unsigned int count = ptr->size();
if (mono_array_length(array) < (array_index + count)) {
@@ -129,11 +129,11 @@ Array *godot_icall_Array_Concatenate(Array *left, Array *right) {
return new_array;
}
-int godot_icall_Array_IndexOf(Array *ptr, MonoObject *item) {
+int32_t godot_icall_Array_IndexOf(Array *ptr, MonoObject *item) {
return ptr->find(GDMonoMarshal::mono_object_to_variant(item));
}
-void godot_icall_Array_Insert(Array *ptr, int index, MonoObject *item) {
+void godot_icall_Array_Insert(Array *ptr, int32_t index, MonoObject *item) {
if (index < 0 || index > ptr->size()) {
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
return;
@@ -150,7 +150,7 @@ MonoBoolean godot_icall_Array_Remove(Array *ptr, MonoObject *item) {
return false;
}
-void godot_icall_Array_RemoveAt(Array *ptr, int index) {
+void godot_icall_Array_RemoveAt(Array *ptr, int32_t index) {
if (index < 0 || index >= ptr->size()) {
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
return;
@@ -158,8 +158,8 @@ void godot_icall_Array_RemoveAt(Array *ptr, int index) {
ptr->remove(index);
}
-Error godot_icall_Array_Resize(Array *ptr, int new_size) {
- return ptr->resize(new_size);
+int32_t godot_icall_Array_Resize(Array *ptr, int32_t new_size) {
+ return (int32_t)ptr->resize(new_size);
}
void godot_icall_Array_Shuffle(Array *ptr) {
@@ -226,7 +226,7 @@ Array *godot_icall_Dictionary_Values(Dictionary *ptr) {
return memnew(Array(ptr->values()));
}
-int godot_icall_Dictionary_Count(Dictionary *ptr) {
+int32_t godot_icall_Dictionary_Count(Dictionary *ptr) {
return ptr->size();
}
@@ -308,47 +308,47 @@ MonoString *godot_icall_Dictionary_ToString(Dictionary *ptr) {
}
void godot_register_collections_icalls() {
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor", (void *)godot_icall_Array_Ctor);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor_MonoArray", (void *)godot_icall_Array_Ctor_MonoArray);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Dtor", (void *)godot_icall_Array_Dtor);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_At", (void *)godot_icall_Array_At);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_At_Generic", (void *)godot_icall_Array_At_Generic);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_SetAt", (void *)godot_icall_Array_SetAt);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Count", (void *)godot_icall_Array_Count);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Add", (void *)godot_icall_Array_Add);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Clear", (void *)godot_icall_Array_Clear);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Concatenate", (void *)godot_icall_Array_Concatenate);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Contains", (void *)godot_icall_Array_Contains);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_CopyTo", (void *)godot_icall_Array_CopyTo);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Duplicate", (void *)godot_icall_Array_Duplicate);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_IndexOf", (void *)godot_icall_Array_IndexOf);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Insert", (void *)godot_icall_Array_Insert);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Remove", (void *)godot_icall_Array_Remove);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_RemoveAt", (void *)godot_icall_Array_RemoveAt);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Resize", (void *)godot_icall_Array_Resize);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Shuffle", (void *)godot_icall_Array_Shuffle);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Generic_GetElementTypeInfo", (void *)godot_icall_Array_Generic_GetElementTypeInfo);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_ToString", (void *)godot_icall_Array_ToString);
-
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Ctor", (void *)godot_icall_Dictionary_Ctor);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Dtor", (void *)godot_icall_Dictionary_Dtor);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue", (void *)godot_icall_Dictionary_GetValue);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue_Generic", (void *)godot_icall_Dictionary_GetValue_Generic);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_SetValue", (void *)godot_icall_Dictionary_SetValue);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Keys", (void *)godot_icall_Dictionary_Keys);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Values", (void *)godot_icall_Dictionary_Values);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Count", (void *)godot_icall_Dictionary_Count);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Add", (void *)godot_icall_Dictionary_Add);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Clear", (void *)godot_icall_Dictionary_Clear);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Contains", (void *)godot_icall_Dictionary_Contains);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_ContainsKey", (void *)godot_icall_Dictionary_ContainsKey);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Duplicate", (void *)godot_icall_Dictionary_Duplicate);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_RemoveKey", (void *)godot_icall_Dictionary_RemoveKey);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Remove", (void *)godot_icall_Dictionary_Remove);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue", (void *)godot_icall_Dictionary_TryGetValue);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue_Generic", (void *)godot_icall_Dictionary_TryGetValue_Generic);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Generic_GetValueTypeInfo", (void *)godot_icall_Dictionary_Generic_GetValueTypeInfo);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_ToString", (void *)godot_icall_Dictionary_ToString);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor", godot_icall_Array_Ctor);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor_MonoArray", godot_icall_Array_Ctor_MonoArray);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Dtor", godot_icall_Array_Dtor);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_At", godot_icall_Array_At);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_At_Generic", godot_icall_Array_At_Generic);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_SetAt", godot_icall_Array_SetAt);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Count", godot_icall_Array_Count);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Add", godot_icall_Array_Add);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Clear", godot_icall_Array_Clear);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Concatenate", godot_icall_Array_Concatenate);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Contains", godot_icall_Array_Contains);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_CopyTo", godot_icall_Array_CopyTo);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Duplicate", godot_icall_Array_Duplicate);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_IndexOf", godot_icall_Array_IndexOf);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Insert", godot_icall_Array_Insert);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Remove", godot_icall_Array_Remove);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_RemoveAt", godot_icall_Array_RemoveAt);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Resize", godot_icall_Array_Resize);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Shuffle", godot_icall_Array_Shuffle);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Generic_GetElementTypeInfo", godot_icall_Array_Generic_GetElementTypeInfo);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_ToString", godot_icall_Array_ToString);
+
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Ctor", godot_icall_Dictionary_Ctor);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Dtor", godot_icall_Dictionary_Dtor);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue", godot_icall_Dictionary_GetValue);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue_Generic", godot_icall_Dictionary_GetValue_Generic);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_SetValue", godot_icall_Dictionary_SetValue);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Keys", godot_icall_Dictionary_Keys);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Values", godot_icall_Dictionary_Values);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Count", godot_icall_Dictionary_Count);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Add", godot_icall_Dictionary_Add);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Clear", godot_icall_Dictionary_Clear);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Contains", godot_icall_Dictionary_Contains);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_ContainsKey", godot_icall_Dictionary_ContainsKey);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Duplicate", godot_icall_Dictionary_Duplicate);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_RemoveKey", godot_icall_Dictionary_RemoveKey);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Remove", godot_icall_Dictionary_Remove);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue", godot_icall_Dictionary_TryGetValue);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue_Generic", godot_icall_Dictionary_TryGetValue_Generic);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Generic_GetValueTypeInfo", godot_icall_Dictionary_Generic_GetValueTypeInfo);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_ToString", godot_icall_Dictionary_ToString);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/gd_glue.cpp b/modules/mono/glue/gd_glue.cpp
index 58d8dceb25..a4566b82fb 100644
--- a/modules/mono/glue/gd_glue.cpp
+++ b/modules/mono/glue/gd_glue.cpp
@@ -289,33 +289,33 @@ MonoObject *godot_icall_DefaultGodotTaskScheduler() {
}
void godot_register_gd_icalls() {
- mono_add_internal_call("Godot.GD::godot_icall_GD_bytes2var", (void *)godot_icall_GD_bytes2var);
- mono_add_internal_call("Godot.GD::godot_icall_GD_convert", (void *)godot_icall_GD_convert);
- mono_add_internal_call("Godot.GD::godot_icall_GD_hash", (void *)godot_icall_GD_hash);
- mono_add_internal_call("Godot.GD::godot_icall_GD_instance_from_id", (void *)godot_icall_GD_instance_from_id);
- mono_add_internal_call("Godot.GD::godot_icall_GD_pusherror", (void *)godot_icall_GD_pusherror);
- mono_add_internal_call("Godot.GD::godot_icall_GD_pushwarning", (void *)godot_icall_GD_pushwarning);
- mono_add_internal_call("Godot.GD::godot_icall_GD_print", (void *)godot_icall_GD_print);
- mono_add_internal_call("Godot.GD::godot_icall_GD_printerr", (void *)godot_icall_GD_printerr);
- mono_add_internal_call("Godot.GD::godot_icall_GD_printraw", (void *)godot_icall_GD_printraw);
- mono_add_internal_call("Godot.GD::godot_icall_GD_prints", (void *)godot_icall_GD_prints);
- mono_add_internal_call("Godot.GD::godot_icall_GD_printt", (void *)godot_icall_GD_printt);
- mono_add_internal_call("Godot.GD::godot_icall_GD_randf", (void *)godot_icall_GD_randf);
- mono_add_internal_call("Godot.GD::godot_icall_GD_randi", (void *)godot_icall_GD_randi);
- mono_add_internal_call("Godot.GD::godot_icall_GD_randomize", (void *)godot_icall_GD_randomize);
- mono_add_internal_call("Godot.GD::godot_icall_GD_randf_range", (void *)godot_icall_GD_randf_range);
- mono_add_internal_call("Godot.GD::godot_icall_GD_randi_range", (void *)godot_icall_GD_randi_range);
- mono_add_internal_call("Godot.GD::godot_icall_GD_rand_seed", (void *)godot_icall_GD_rand_seed);
- mono_add_internal_call("Godot.GD::godot_icall_GD_seed", (void *)godot_icall_GD_seed);
- mono_add_internal_call("Godot.GD::godot_icall_GD_str", (void *)godot_icall_GD_str);
- mono_add_internal_call("Godot.GD::godot_icall_GD_str2var", (void *)godot_icall_GD_str2var);
- mono_add_internal_call("Godot.GD::godot_icall_GD_type_exists", (void *)godot_icall_GD_type_exists);
- mono_add_internal_call("Godot.GD::godot_icall_GD_var2bytes", (void *)godot_icall_GD_var2bytes);
- mono_add_internal_call("Godot.GD::godot_icall_GD_var2str", (void *)godot_icall_GD_var2str);
- mono_add_internal_call("Godot.GD::godot_icall_TypeToVariantType", (void *)godot_icall_TypeToVariantType);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_bytes2var", godot_icall_GD_bytes2var);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_convert", godot_icall_GD_convert);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_hash", godot_icall_GD_hash);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_instance_from_id", godot_icall_GD_instance_from_id);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_pusherror", godot_icall_GD_pusherror);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_pushwarning", godot_icall_GD_pushwarning);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_print", godot_icall_GD_print);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_printerr", godot_icall_GD_printerr);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_printraw", godot_icall_GD_printraw);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_prints", godot_icall_GD_prints);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_printt", godot_icall_GD_printt);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randf", godot_icall_GD_randf);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randi", godot_icall_GD_randi);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randomize", godot_icall_GD_randomize);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randf_range", godot_icall_GD_randf_range);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randi_range", godot_icall_GD_randi_range);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_rand_seed", godot_icall_GD_rand_seed);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_seed", godot_icall_GD_seed);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_str", godot_icall_GD_str);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_str2var", godot_icall_GD_str2var);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_type_exists", godot_icall_GD_type_exists);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_var2bytes", godot_icall_GD_var2bytes);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_var2str", godot_icall_GD_var2str);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_TypeToVariantType", godot_icall_TypeToVariantType);
// Dispatcher
- mono_add_internal_call("Godot.Dispatcher::godot_icall_DefaultGodotTaskScheduler", (void *)godot_icall_DefaultGodotTaskScheduler);
+ GDMonoUtils::add_internal_call("Godot.Dispatcher::godot_icall_DefaultGodotTaskScheduler", godot_icall_DefaultGodotTaskScheduler);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/nodepath_glue.cpp b/modules/mono/glue/nodepath_glue.cpp
index 09c6d8f482..9405360c6c 100644
--- a/modules/mono/glue/nodepath_glue.cpp
+++ b/modules/mono/glue/nodepath_glue.cpp
@@ -81,17 +81,17 @@ MonoBoolean godot_icall_NodePath_is_empty(NodePath *p_ptr) {
}
void godot_register_nodepath_icalls() {
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_Ctor", (void *)godot_icall_NodePath_Ctor);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_Dtor", (void *)godot_icall_NodePath_Dtor);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_operator_String", (void *)godot_icall_NodePath_operator_String);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_get_as_property_path", (void *)godot_icall_NodePath_get_as_property_path);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_get_concatenated_subnames", (void *)godot_icall_NodePath_get_concatenated_subnames);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_get_name", (void *)godot_icall_NodePath_get_name);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_get_name_count", (void *)godot_icall_NodePath_get_name_count);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_get_subname", (void *)godot_icall_NodePath_get_subname);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_get_subname_count", (void *)godot_icall_NodePath_get_subname_count);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_is_absolute", (void *)godot_icall_NodePath_is_absolute);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_is_empty", (void *)godot_icall_NodePath_is_empty);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_Ctor", godot_icall_NodePath_Ctor);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_Dtor", godot_icall_NodePath_Dtor);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_operator_String", godot_icall_NodePath_operator_String);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_as_property_path", godot_icall_NodePath_get_as_property_path);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_concatenated_subnames", godot_icall_NodePath_get_concatenated_subnames);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_name", godot_icall_NodePath_get_name);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_name_count", godot_icall_NodePath_get_name_count);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_subname", godot_icall_NodePath_get_subname);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_subname_count", godot_icall_NodePath_get_subname_count);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_is_absolute", godot_icall_NodePath_is_absolute);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_is_empty", godot_icall_NodePath_is_empty);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/rid_glue.cpp b/modules/mono/glue/rid_glue.cpp
index cb4f26511f..410a98aa84 100644
--- a/modules/mono/glue/rid_glue.cpp
+++ b/modules/mono/glue/rid_glue.cpp
@@ -56,9 +56,9 @@ uint32_t godot_icall_RID_get_id(RID *p_ptr) {
}
void godot_register_rid_icalls() {
- mono_add_internal_call("Godot.RID::godot_icall_RID_Ctor", (void *)godot_icall_RID_Ctor);
- mono_add_internal_call("Godot.RID::godot_icall_RID_Dtor", (void *)godot_icall_RID_Dtor);
- mono_add_internal_call("Godot.RID::godot_icall_RID_get_id", (void *)godot_icall_RID_get_id);
+ GDMonoUtils::add_internal_call("Godot.RID::godot_icall_RID_Ctor", godot_icall_RID_Ctor);
+ GDMonoUtils::add_internal_call("Godot.RID::godot_icall_RID_Dtor", godot_icall_RID_Dtor);
+ GDMonoUtils::add_internal_call("Godot.RID::godot_icall_RID_get_id", godot_icall_RID_get_id);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/scene_tree_glue.cpp b/modules/mono/glue/scene_tree_glue.cpp
index 53d6c1436d..88695201a3 100644
--- a/modules/mono/glue/scene_tree_glue.cpp
+++ b/modules/mono/glue/scene_tree_glue.cpp
@@ -80,7 +80,7 @@ Array *godot_icall_SceneTree_get_nodes_in_group_Generic(SceneTree *ptr, StringNa
}
void godot_register_scene_tree_icalls() {
- mono_add_internal_call("Godot.SceneTree::godot_icall_SceneTree_get_nodes_in_group_Generic", (void *)godot_icall_SceneTree_get_nodes_in_group_Generic);
+ GDMonoUtils::add_internal_call("Godot.SceneTree::godot_icall_SceneTree_get_nodes_in_group_Generic", godot_icall_SceneTree_get_nodes_in_group_Generic);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/string_glue.cpp b/modules/mono/glue/string_glue.cpp
index 9271731573..d71d175418 100644
--- a/modules/mono/glue/string_glue.cpp
+++ b/modules/mono/glue/string_glue.cpp
@@ -68,12 +68,12 @@ MonoString *godot_icall_String_sha256_text(MonoString *p_str) {
}
void godot_register_string_icalls() {
- mono_add_internal_call("Godot.StringExtensions::godot_icall_String_md5_buffer", (void *)godot_icall_String_md5_buffer);
- mono_add_internal_call("Godot.StringExtensions::godot_icall_String_md5_text", (void *)godot_icall_String_md5_text);
- mono_add_internal_call("Godot.StringExtensions::godot_icall_String_rfind", (void *)godot_icall_String_rfind);
- mono_add_internal_call("Godot.StringExtensions::godot_icall_String_rfindn", (void *)godot_icall_String_rfindn);
- mono_add_internal_call("Godot.StringExtensions::godot_icall_String_sha256_buffer", (void *)godot_icall_String_sha256_buffer);
- mono_add_internal_call("Godot.StringExtensions::godot_icall_String_sha256_text", (void *)godot_icall_String_sha256_text);
+ GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_md5_buffer", godot_icall_String_md5_buffer);
+ GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_md5_text", godot_icall_String_md5_text);
+ GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_rfind", godot_icall_String_rfind);
+ GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_rfindn", godot_icall_String_rfindn);
+ GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_sha256_buffer", godot_icall_String_sha256_buffer);
+ GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_sha256_text", godot_icall_String_sha256_text);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/string_name_glue.cpp b/modules/mono/glue/string_name_glue.cpp
index 9323e3bbb3..fc2bf32b95 100644
--- a/modules/mono/glue/string_name_glue.cpp
+++ b/modules/mono/glue/string_name_glue.cpp
@@ -53,10 +53,10 @@ MonoBoolean godot_icall_StringName_is_empty(StringName *p_ptr) {
}
void godot_register_string_name_icalls() {
- mono_add_internal_call("Godot.StringName::godot_icall_StringName_Ctor", (void *)godot_icall_StringName_Ctor);
- mono_add_internal_call("Godot.StringName::godot_icall_StringName_Dtor", (void *)godot_icall_StringName_Dtor);
- mono_add_internal_call("Godot.StringName::godot_icall_StringName_operator_String", (void *)godot_icall_StringName_operator_String);
- mono_add_internal_call("Godot.StringName::godot_icall_StringName_is_empty", (void *)godot_icall_StringName_is_empty);
+ GDMonoUtils::add_internal_call("Godot.StringName::godot_icall_StringName_Ctor", godot_icall_StringName_Ctor);
+ GDMonoUtils::add_internal_call("Godot.StringName::godot_icall_StringName_Dtor", godot_icall_StringName_Dtor);
+ GDMonoUtils::add_internal_call("Godot.StringName::godot_icall_StringName_operator_String", godot_icall_StringName_operator_String);
+ GDMonoUtils::add_internal_call("Godot.StringName::godot_icall_StringName_is_empty", godot_icall_StringName_is_empty);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
index faa3d24eeb..5370b1c6fc 100644
--- a/modules/mono/mono_gd/gd_mono_utils.h
+++ b/modules/mono/mono_gd/gd_mono_utils.h
@@ -36,6 +36,9 @@
#include "../mono_gc_handle.h"
#include "../utils/macros.h"
#include "gd_mono_header.h"
+#ifdef JAVASCRIPT_ENABLED
+#include "gd_mono_wasm_m2n.h"
+#endif
#include "core/object/class_db.h"
#include "core/object/reference.h"
@@ -154,6 +157,22 @@ private:
};
StringName get_native_godot_class_name(GDMonoClass *p_class);
+
+template <typename... P>
+void add_internal_call(const char *p_name, void (*p_func)(P...)) {
+#ifdef JAVASCRIPT_ENABLED
+ GDMonoWasmM2n::ICallTrampolines<P...>::add();
+#endif
+ mono_add_internal_call(p_name, (void *)p_func);
+}
+
+template <typename R, typename... P>
+void add_internal_call(const char *p_name, R (*p_func)(P...)) {
+#ifdef JAVASCRIPT_ENABLED
+ GDMonoWasmM2n::ICallTrampolinesR<R, P...>::add();
+#endif
+ mono_add_internal_call(p_name, (void *)p_func);
+}
} // namespace GDMonoUtils
#define NATIVE_GDMONOCLASS_NAME(m_class) (GDMonoUtils::get_native_godot_class_name(m_class))
diff --git a/modules/mono/mono_gd/gd_mono_wasm_m2n.cpp b/modules/mono/mono_gd/gd_mono_wasm_m2n.cpp
new file mode 100644
index 0000000000..f4c964c6eb
--- /dev/null
+++ b/modules/mono/mono_gd/gd_mono_wasm_m2n.cpp
@@ -0,0 +1,79 @@
+/*************************************************************************/
+/* gd_mono_wasm_m2n.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gd_mono_wasm_m2n.h"
+
+#ifdef JAVASCRIPT_ENABLED
+
+#include "core/templates/oa_hash_map.h"
+
+typedef mono_bool (*GodotMonoM2nIcallTrampolineDispatch)(const char *cookie, void *target_func, Mono_InterpMethodArguments *margs);
+
+// This extern function is implemented in our patched version of Mono
+MONO_API void godot_mono_register_m2n_icall_trampoline_dispatch_hook(GodotMonoM2nIcallTrampolineDispatch hook);
+
+namespace GDMonoWasmM2n {
+
+struct HashMapCookieComparator {
+ static bool compare(const char *p_lhs, const char *p_rhs) {
+ return strcmp(p_lhs, p_rhs) == 0;
+ }
+};
+
+// The default hasher supports 'const char *' C Strings, but we need a custom comparator
+OAHashMap<const char *, TrampolineFunc, HashMapHasherDefault, HashMapCookieComparator> trampolines;
+
+void set_trampoline(const char *cookies, GDMonoWasmM2n::TrampolineFunc trampoline_func) {
+ trampolines.set(cookies, trampoline_func);
+}
+
+mono_bool trampoline_dispatch_hook(const char *cookie, void *target_func, Mono_InterpMethodArguments *margs) {
+ TrampolineFunc *trampoline_func = trampolines.lookup_ptr(cookie);
+
+ if (!trampoline_func) {
+ return false;
+ }
+
+ (*trampoline_func)(target_func, margs);
+ return true;
+}
+
+bool initialized = false;
+
+void lazy_initialize() {
+ // Doesn't need to be thread safe
+ if (!initialized) {
+ initialized = true;
+ godot_mono_register_m2n_icall_trampoline_dispatch_hook(&trampoline_dispatch_hook);
+ }
+}
+} // namespace GDMonoWasmM2n
+
+#endif
diff --git a/modules/mono/mono_gd/gd_mono_wasm_m2n.h b/modules/mono/mono_gd/gd_mono_wasm_m2n.h
new file mode 100644
index 0000000000..68a14f15f4
--- /dev/null
+++ b/modules/mono/mono_gd/gd_mono_wasm_m2n.h
@@ -0,0 +1,263 @@
+/*************************************************************************/
+/* gd_mono_wasm_m2n.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GD_MONO_WASM_M2N_H
+#define GD_MONO_WASM_M2N_H
+
+#ifdef JAVASCRIPT_ENABLED
+
+#include "core/string/ustring.h"
+#include "core/typedefs.h"
+
+#include <mono/metadata/loader.h>
+#include <mono/utils/mono-publib.h>
+#include <stdexcept>
+#include <type_traits>
+
+extern "C" {
+
+struct Mono_InterpMethodArguments {
+ size_t ilen;
+ void **iargs;
+ size_t flen;
+ double *fargs;
+ void **retval;
+ size_t is_float_ret;
+ //#ifdef TARGET_WASM
+ void *sig;
+ //#endif
+};
+} // extern "C"
+
+namespace GDMonoWasmM2n {
+
+template <typename T, size_t Size>
+struct array {
+ T elems[Size];
+};
+
+template <typename T>
+constexpr char get_m2n_cookie_impl() {
+#define M2N_REG_COOKIE(m_type, m_cookie) \
+ if constexpr (std::is_same_v<m_type, T>) { \
+ return m_cookie; \
+ }
+
+ M2N_REG_COOKIE(MonoBoolean, 'I');
+ M2N_REG_COOKIE(int8_t, 'I');
+ M2N_REG_COOKIE(uint8_t, 'I');
+ M2N_REG_COOKIE(int16_t, 'I');
+ M2N_REG_COOKIE(uint16_t, 'I');
+ M2N_REG_COOKIE(int32_t, 'I');
+ M2N_REG_COOKIE(uint32_t, 'I');
+ M2N_REG_COOKIE(int64_t, 'L');
+ M2N_REG_COOKIE(uint64_t, 'L');
+ M2N_REG_COOKIE(float, 'F');
+ M2N_REG_COOKIE(double, 'D');
+
+ if constexpr (std::is_pointer_v<T>) {
+ if constexpr (sizeof(void *) == 4) {
+ return 'I';
+ } else {
+ return 'L';
+ }
+ }
+
+ if constexpr (std::is_void_v<T>) {
+ return 'V';
+ }
+
+ return 'X';
+
+#undef M2N_REG_COOKIE
+}
+
+template <typename T>
+constexpr char get_m2n_cookie() {
+ constexpr char cookie = get_m2n_cookie_impl<T>();
+ static_assert(cookie != 'X', "Type not supported in internal call signature.");
+ return cookie;
+}
+
+template <typename... T>
+constexpr array<const char, sizeof...(T) + 2> get_m2n_cookies() {
+ return array<const char, sizeof...(T) + 2>{ 'V', get_m2n_cookie<T>()..., '\0' };
+}
+
+template <typename R, typename... T>
+constexpr array<const char, sizeof...(T) + 2> get_m2n_cookies_r() {
+ return array<const char, sizeof...(T) + 2>{ get_m2n_cookie<R>(), get_m2n_cookie<T>()..., '\0' };
+}
+
+template <typename T>
+constexpr size_t calc_m2n_index(size_t &r_int_idx, size_t &r_float_idx) {
+ constexpr char cookie = get_m2n_cookie<T>();
+
+ static_assert(cookie == 'I' || cookie == 'L' || cookie == 'F' || cookie == 'D');
+
+ if constexpr (cookie == 'I' || cookie == 'L') {
+ size_t ret = r_int_idx;
+ r_int_idx += cookie == 'I' ? 1 : 2;
+ return ret;
+ } else {
+ size_t ret = r_float_idx;
+ r_float_idx += cookie == 'F' ? 1 : 2;
+ return ret;
+ }
+}
+
+template <typename... P>
+constexpr array<size_t, sizeof...(P)> get_indices_for_type() {
+ size_t int_idx = 0;
+ size_t float_idx = 0;
+ return array<size_t, sizeof...(P)>{ calc_m2n_index<P>(int_idx, float_idx)... };
+}
+
+constexpr size_t fidx(size_t p_x) {
+ if constexpr (sizeof(void *) == 4) {
+ return p_x * 2;
+ } else {
+ return p_x;
+ }
+}
+
+template <typename T>
+T m2n_arg_cast(Mono_InterpMethodArguments *p_margs, size_t p_idx) {
+ constexpr char cookie = get_m2n_cookie<T>();
+
+ static_assert(cookie == 'I' || cookie == 'L' || cookie == 'F' || cookie == 'D');
+
+ if constexpr (cookie == 'I') {
+ return (T)(size_t)p_margs->iargs[p_idx];
+ } else if constexpr (cookie == 'L') {
+ static_assert(std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t> ||
+ (sizeof(void *) == 8 && std::is_pointer_v<T>),
+ "Invalid type for cookie 'L'.");
+
+ union {
+ T l;
+ struct {
+ int32_t lo;
+ int32_t hi;
+ } pair;
+ } p;
+
+ p.pair.lo = (int32_t)(size_t)p_margs->iargs[p_idx];
+ p.pair.hi = (int32_t)(size_t)p_margs->iargs[p_idx + 1];
+
+ return p.l;
+ } else if constexpr (cookie == 'F') {
+ return *reinterpret_cast<float *>(&p_margs->fargs[fidx(p_idx)]);
+ } else if constexpr (cookie == 'D') {
+ return (T)(size_t)p_margs->fargs[p_idx];
+ }
+}
+
+template <typename... P, size_t... Is>
+void m2n_trampoline_with_idx_seq(void *p_target_func, Mono_InterpMethodArguments *p_margs, IndexSequence<Is...>) {
+ constexpr array<size_t, sizeof...(P)> indices = get_indices_for_type<P...>();
+ typedef void (*Func)(P...);
+ Func func = (Func)p_target_func;
+ func(m2n_arg_cast<P>(p_margs, indices.elems[Is])...);
+}
+
+template <typename R, typename... P, size_t... Is>
+void m2n_trampoline_with_idx_seq_r(void *p_target_func, Mono_InterpMethodArguments *p_margs, IndexSequence<Is...>) {
+ constexpr array<size_t, sizeof...(P)> indices = get_indices_for_type<P...>();
+ typedef R (*Func)(P...);
+ Func func = (Func)p_target_func;
+ R res = func(m2n_arg_cast<P>(p_margs, indices.elems[Is])...);
+ *reinterpret_cast<R *>(p_margs->retval) = res;
+}
+
+inline void m2n_trampoline_with_idx_seq_0(void *p_target_func, Mono_InterpMethodArguments *p_margs) {
+ typedef void (*Func)();
+ Func func = (Func)p_target_func;
+ func();
+}
+
+template <typename R>
+void m2n_trampoline_with_idx_seq_r0(void *p_target_func, Mono_InterpMethodArguments *p_margs) {
+ typedef R (*Func)();
+ Func func = (Func)p_target_func;
+ R res = func();
+ *reinterpret_cast<R *>(p_margs->retval) = res;
+}
+
+template <typename... P>
+void m2n_trampoline(void *p_target_func, Mono_InterpMethodArguments *p_margs) {
+ if constexpr (sizeof...(P) == 0) {
+ m2n_trampoline_with_idx_seq_0(p_target_func, p_margs);
+ } else {
+ m2n_trampoline_with_idx_seq<P...>(p_target_func, p_margs, BuildIndexSequence<sizeof...(P)>{});
+ }
+}
+
+template <typename R, typename... P>
+void m2n_trampoline_r(void *p_target_func, Mono_InterpMethodArguments *p_margs) {
+ if constexpr (sizeof...(P) == 0) {
+ m2n_trampoline_with_idx_seq_r0<R>(p_target_func, p_margs);
+ } else {
+ m2n_trampoline_with_idx_seq_r<R, P...>(p_target_func, p_margs, BuildIndexSequence<sizeof...(P)>{});
+ }
+}
+
+typedef void (*TrampolineFunc)(void *p_target_func, Mono_InterpMethodArguments *p_margs);
+
+void set_trampoline(const char *cookies, TrampolineFunc trampoline_func);
+
+void lazy_initialize();
+
+template <typename... P>
+struct ICallTrampolines {
+ static constexpr auto cookies = get_m2n_cookies<P...>();
+
+ static void add() {
+ lazy_initialize();
+ set_trampoline(cookies.elems, &m2n_trampoline<P...>);
+ }
+};
+
+template <typename R, typename... P>
+struct ICallTrampolinesR {
+ static constexpr auto cookies = get_m2n_cookies_r<R, P...>();
+
+ static void add() {
+ lazy_initialize();
+ set_trampoline(cookies.elems, &m2n_trampoline_r<R, P...>);
+ }
+};
+
+void initialize();
+} // namespace GDMonoWasmM2n
+
+#endif
+
+#endif // GD_MONO_WASM_M2N_H
diff --git a/modules/mono/mono_gd/support/android_support.cpp b/modules/mono/mono_gd/support/android_support.cpp
index 18daf859b5..bc2ae03299 100644
--- a/modules/mono/mono_gd/support/android_support.cpp
+++ b/modules/mono/mono_gd/support/android_support.cpp
@@ -355,8 +355,8 @@ MonoArray *_gd_mono_android_cert_store_lookup(MonoString *p_alias) {
}
void register_internal_calls() {
- mono_add_internal_call("Android.Runtime.AndroidEnvironment::_gd_mono_init_cert_store", (void *)_gd_mono_init_cert_store);
- mono_add_internal_call("Android.Runtime.AndroidEnvironment::_gd_mono_android_cert_store_lookup", (void *)_gd_mono_android_cert_store_lookup);
+ GDMonoUtils::add_internal_call("Android.Runtime.AndroidEnvironment::_gd_mono_init_cert_store", _gd_mono_init_cert_store);
+ GDMonoUtils::add_internal_call("Android.Runtime.AndroidEnvironment::_gd_mono_android_cert_store_lookup", _gd_mono_android_cert_store_lookup);
}
void initialize() {
diff --git a/modules/ogg/SCsub b/modules/ogg/SCsub
index e768fb4ae8..e415d92498 100644
--- a/modules/ogg/SCsub
+++ b/modules/ogg/SCsub
@@ -9,6 +9,9 @@ Import("env_modules")
env_ogg = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_libogg"]:
thirdparty_dir = "#thirdparty/libogg/"
thirdparty_sources = [
@@ -21,7 +24,16 @@ if env["builtin_libogg"]:
env_thirdparty = env_ogg.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
# Godot source files
-env_ogg.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_ogg.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/opensimplex/SCsub b/modules/opensimplex/SCsub
index 52d8b145ef..86d77c3dfb 100644
--- a/modules/opensimplex/SCsub
+++ b/modules/opensimplex/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_opensimplex = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
thirdparty_dir = "#thirdparty/misc/"
thirdparty_sources = [
"open-simplex-noise.c",
@@ -16,7 +19,15 @@ env_opensimplex.Prepend(CPPPATH=[thirdparty_dir])
env_thirdparty = env_opensimplex.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_opensimplex.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-# Godot's own source files
-env_opensimplex.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/opus/SCsub b/modules/opus/SCsub
index 52c61fa708..1437cd86df 100644
--- a/modules/opus/SCsub
+++ b/modules/opus/SCsub
@@ -10,6 +10,10 @@ Import("env_modules")
env_opus = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
+# Thirdparty source files
if env["builtin_opus"]:
thirdparty_dir = "#thirdparty/opus/"
@@ -233,7 +237,16 @@ if env["builtin_opus"]:
env_thirdparty = env_opus.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
+
+# Godot source files
+
+module_obj = []
+
+env_opus.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-# Module files
-env_opus.add_source_files(env.modules_sources, "register_types.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/pvr/SCsub b/modules/pvr/SCsub
index e0baf851f1..36052cffed 100644
--- a/modules/pvr/SCsub
+++ b/modules/pvr/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_pvr = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
# Not unbundled so far since not widespread as shared library
thirdparty_dir = "#thirdparty/pvrtccompressor/"
thirdparty_sources = [
@@ -21,7 +24,15 @@ env_pvr.Prepend(CPPPATH=[thirdparty_dir])
env_thirdparty = env_pvr.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
# Godot source files
-env_pvr.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_pvr.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/pvr/image_compress_pvrtc.cpp b/modules/pvr/image_compress_pvrtc.cpp
new file mode 100644
index 0000000000..6695a539d0
--- /dev/null
+++ b/modules/pvr/image_compress_pvrtc.cpp
@@ -0,0 +1,84 @@
+/*************************************************************************/
+/* image_compress_pvrtc.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "image_compress_pvrtc.h"
+
+#include "core/io/image.h"
+#include "core/object/reference.h"
+
+#include <PvrTcEncoder.h>
+#include <RgbaBitmap.h>
+
+static void _compress_pvrtc1_4bpp(Image *p_img) {
+ Ref<Image> img = p_img->duplicate();
+
+ bool make_mipmaps = false;
+ if (!img->is_size_po2() || img->get_width() != img->get_height()) {
+ make_mipmaps = img->has_mipmaps();
+ img->resize_to_po2(true);
+ }
+ img->convert(Image::FORMAT_RGBA8);
+ if (!img->has_mipmaps() && make_mipmaps) {
+ img->generate_mipmaps();
+ }
+
+ bool use_alpha = img->detect_alpha();
+
+ Ref<Image> new_img;
+ new_img.instance();
+ new_img->create(img->get_width(), img->get_height(), img->has_mipmaps(), use_alpha ? Image::FORMAT_PVRTC1_4A : Image::FORMAT_PVRTC1_4);
+
+ Vector<uint8_t> data = new_img->get_data();
+ {
+ uint8_t *wr = data.ptrw();
+ const uint8_t *r = img->get_data().ptr();
+
+ for (int i = 0; i <= new_img->get_mipmap_count(); i++) {
+ int ofs, size, w, h;
+ 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);
+ Javelin::ColorRgba<unsigned char> *dp = bm.GetData();
+ for (int j = 0; j < size / 4; j++) {
+ // Red and blue colors are swapped.
+ SWAP(dp[j].r, dp[j].b);
+ }
+ new_img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h);
+ Javelin::PvrTcEncoder::EncodeRgba4Bpp(&wr[ofs], bm);
+ }
+ }
+
+ p_img->create(new_img->get_width(), new_img->get_height(), new_img->has_mipmaps(), new_img->get_format(), data);
+}
+
+void _register_pvrtc_compress_func() {
+ Image::_image_compress_pvrtc1_4bpp_func = _compress_pvrtc1_4bpp;
+}
diff --git a/editor/pvrtc_compress.h b/modules/pvr/image_compress_pvrtc.h
index 7b6c17d3c4..fde65f4bbe 100644
--- a/editor/pvrtc_compress.h
+++ b/modules/pvr/image_compress_pvrtc.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* pvrtc_compress.h */
+/* image_compress_pvrtc.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,11 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef PVRTC_COMPRESS_H
-#define PVRTC_COMPRESS_H
+#ifndef IMAGE_COMPRESS_PVRTC_H
+#define IMAGE_COMPRESS_PVRTC_H
-#include "core/io/image.h"
+void _register_pvrtc_compress_func();
-void _pvrtc_register_compressors();
-
-#endif // PVRTC_COMPRESS_H
+#endif // IMAGE_COMPRESS_PVRTC_H
diff --git a/modules/pvr/register_types.cpp b/modules/pvr/register_types.cpp
index 1eb697bba3..9bfc334d76 100644
--- a/modules/pvr/register_types.cpp
+++ b/modules/pvr/register_types.cpp
@@ -30,6 +30,7 @@
#include "register_types.h"
+#include "image_compress_pvrtc.h"
#include "texture_loader_pvr.h"
static Ref<ResourceFormatPVR> resource_loader_pvr;
@@ -37,6 +38,8 @@ static Ref<ResourceFormatPVR> resource_loader_pvr;
void register_pvr_types() {
resource_loader_pvr.instance();
ResourceLoader::add_resource_format_loader(resource_loader_pvr);
+
+ _register_pvrtc_compress_func();
}
void unregister_pvr_types() {
diff --git a/modules/pvr/texture_loader_pvr.cpp b/modules/pvr/texture_loader_pvr.cpp
index 0923714387..c9cbb1935a 100644
--- a/modules/pvr/texture_loader_pvr.cpp
+++ b/modules/pvr/texture_loader_pvr.cpp
@@ -29,11 +29,8 @@
/*************************************************************************/
#include "texture_loader_pvr.h"
-#include "PvrTcEncoder.h"
-#include "RgbaBitmap.h"
+
#include "core/os/file_access.h"
-#include <string.h>
-#include <new>
static void _pvrtc_decompress(Image *p_img);
@@ -111,11 +108,11 @@ RES ResourceFormatPVR::load(const String &p_path, const String &p_original_path,
switch (flags & 0xFF) {
case 0x18:
case 0xC:
- format = (flags & PVR_HAS_ALPHA) ? Image::FORMAT_PVRTC2A : Image::FORMAT_PVRTC2;
+ format = (flags & PVR_HAS_ALPHA) ? Image::FORMAT_PVRTC1_2A : Image::FORMAT_PVRTC1_2;
break;
case 0x19:
case 0xD:
- format = (flags & PVR_HAS_ALPHA) ? Image::FORMAT_PVRTC4A : Image::FORMAT_PVRTC4;
+ format = (flags & PVR_HAS_ALPHA) ? Image::FORMAT_PVRTC1_4A : Image::FORMAT_PVRTC1_4;
break;
case 0x16:
format = Image::FORMAT_L8;
@@ -183,53 +180,8 @@ String ResourceFormatPVR::get_resource_type(const String &p_path) const {
return "";
}
-static void _compress_pvrtc4(Image *p_img) {
- Ref<Image> img = p_img->duplicate();
-
- bool make_mipmaps = false;
- if (!img->is_size_po2() || img->get_width() != img->get_height()) {
- make_mipmaps = img->has_mipmaps();
- img->resize_to_po2(true);
- }
- img->convert(Image::FORMAT_RGBA8);
- if (!img->has_mipmaps() && make_mipmaps) {
- img->generate_mipmaps();
- }
-
- bool use_alpha = img->detect_alpha();
-
- Ref<Image> new_img;
- new_img.instance();
- new_img->create(img->get_width(), img->get_height(), img->has_mipmaps(), use_alpha ? Image::FORMAT_PVRTC4A : Image::FORMAT_PVRTC4);
-
- Vector<uint8_t> data = new_img->get_data();
- {
- uint8_t *wr = data.ptrw();
- const uint8_t *r = img->get_data().ptr();
-
- for (int i = 0; i <= new_img->get_mipmap_count(); i++) {
- int ofs, size, w, h;
- 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);
- Javelin::ColorRgba<unsigned char> *dp = bm.GetData();
- for (int j = 0; j < size / 4; j++) {
- /* red and blue colors are swapped. */
- SWAP(dp[j].r, dp[j].b);
- }
- new_img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h);
- Javelin::PvrTcEncoder::EncodeRgba4Bpp(&wr[ofs], bm);
- }
- }
-
- p_img->create(new_img->get_width(), new_img->get_height(), new_img->has_mipmaps(), new_img->get_format(), data);
-}
-
ResourceFormatPVR::ResourceFormatPVR() {
Image::_image_decompress_pvrtc = _pvrtc_decompress;
- Image::_image_compress_pvrtc4_func = _compress_pvrtc4;
- Image::_image_compress_pvrtc2_func = _compress_pvrtc4;
}
/////////////////////////////////////////////////////////
@@ -635,9 +587,9 @@ static void decompress_pvrtc(PVRTCBlock *p_comp_img, const int p_2bit, const int
}
static void _pvrtc_decompress(Image *p_img) {
- ERR_FAIL_COND(p_img->get_format() != Image::FORMAT_PVRTC2 && p_img->get_format() != Image::FORMAT_PVRTC2A && p_img->get_format() != Image::FORMAT_PVRTC4 && p_img->get_format() != Image::FORMAT_PVRTC4A);
+ ERR_FAIL_COND(p_img->get_format() != Image::FORMAT_PVRTC1_2 && p_img->get_format() != Image::FORMAT_PVRTC1_2A && p_img->get_format() != Image::FORMAT_PVRTC1_4 && p_img->get_format() != Image::FORMAT_PVRTC1_4A);
- bool _2bit = (p_img->get_format() == Image::FORMAT_PVRTC2 || p_img->get_format() == Image::FORMAT_PVRTC2A);
+ bool _2bit = (p_img->get_format() == Image::FORMAT_PVRTC1_2 || p_img->get_format() == Image::FORMAT_PVRTC1_2A);
Vector<uint8_t> data = p_img->get_data();
const uint8_t *r = data.ptr();
diff --git a/modules/regex/SCsub b/modules/regex/SCsub
index 2afacc1d9c..deb9db7591 100644
--- a/modules/regex/SCsub
+++ b/modules/regex/SCsub
@@ -5,6 +5,10 @@ Import("env_modules")
env_regex = env_modules.Clone()
+# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_pcre2"]:
thirdparty_dir = "#thirdparty/pcre2/src/"
thirdparty_flags = ["PCRE2_STATIC", "HAVE_CONFIG_H", "SUPPORT_UNICODE"]
@@ -52,11 +56,21 @@ if env["builtin_pcre2"]:
env_pcre2 = env_regex.Clone()
env_pcre2.disable_warnings()
env_pcre2["OBJSUFFIX"] = "_" + width + env_pcre2["OBJSUFFIX"]
- env_pcre2.add_source_files(env.modules_sources, thirdparty_sources)
env_pcre2.Append(CPPDEFINES=[("PCRE2_CODE_UNIT_WIDTH", width)])
+ env_pcre2.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
pcre2_builtin("16")
pcre2_builtin("32")
+
+# Godot source files
+
+module_obj = []
+
env_regex.Append(CPPDEFINES=[("PCRE2_CODE_UNIT_WIDTH", 0)])
-env_regex.add_source_files(env.modules_sources, "*.cpp")
+env_regex.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/squish/SCsub b/modules/squish/SCsub
index b31032403f..c9e29911d8 100644
--- a/modules/squish/SCsub
+++ b/modules/squish/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_squish = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_squish"]:
thirdparty_dir = "#thirdparty/squish/"
thirdparty_sources = [
@@ -26,7 +29,16 @@ if env["builtin_squish"]:
env_thirdparty = env_squish.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
# Godot source files
-env_squish.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_squish.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/stb_vorbis/SCsub b/modules/stb_vorbis/SCsub
index 266c87c802..8fddb23dc8 100644
--- a/modules/stb_vorbis/SCsub
+++ b/modules/stb_vorbis/SCsub
@@ -6,11 +6,22 @@ Import("env_modules")
env_stb_vorbis = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
thirdparty_sources = ["#thirdparty/misc/stb_vorbis.c"]
env_thirdparty = env_stb_vorbis.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_stb_vorbis.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-# Godot's own source files
-env_stb_vorbis.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/svg/SCsub b/modules/svg/SCsub
index 0bfba34fe5..c7228a8d0b 100644
--- a/modules/svg/SCsub
+++ b/modules/svg/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_svg = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
thirdparty_dir = "#thirdparty/nanosvg/"
thirdparty_sources = [
"nanosvg.cc",
@@ -16,7 +19,15 @@ env_svg.Prepend(CPPPATH=[thirdparty_dir])
env_thirdparty = env_svg.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_svg.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-# Godot's own source files
-env_svg.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub
index 7403b01a4c..3589c8546d 100644
--- a/modules/text_server_adv/SCsub
+++ b/modules/text_server_adv/SCsub
@@ -35,10 +35,14 @@ def make_icu_data(target, source, env):
g.write("#endif")
+# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_harfbuzz"]:
env_harfbuzz = env_modules.Clone()
+ env_harfbuzz.disable_warnings()
- # Thirdparty source files
thirdparty_dir = "#thirdparty/harfbuzz/"
thirdparty_sources = [
"src/hb-aat-layout.cc",
@@ -107,6 +111,15 @@ if env["builtin_harfbuzz"]:
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
+ env_harfbuzz.Append(
+ CPPPATH=[
+ "#thirdparty/harfbuzz/src",
+ "#thirdparty/freetype/include",
+ "#thirdparty/graphite/include",
+ "#thirdparty/icu4c/common/",
+ ]
+ )
+
if env["platform"] == "android" or env["platform"] == "linuxbsd" or env["platform"] == "server":
env_harfbuzz.Append(CCFLAGS=["-DHAVE_PTHREAD"])
@@ -117,14 +130,6 @@ if env["builtin_harfbuzz"]:
env_harfbuzz.Append(CCFLAGS=["-DHB_NO_MT"])
env_harfbuzz.Append(
- CPPPATH=[
- "#thirdparty/harfbuzz/src",
- "#thirdparty/freetype/include",
- "#thirdparty/graphite/include",
- "#thirdparty/icu4c/common/",
- ]
- )
- env_harfbuzz.Append(
CCFLAGS=[
"-DHAVE_ICU_BUILTIN",
"-DHAVE_ICU",
@@ -133,10 +138,9 @@ if env["builtin_harfbuzz"]:
"-DGRAPHITE2_STATIC",
]
)
- env_harfbuzz.disable_warnings()
- env_thirdparty = env_harfbuzz.Clone()
- env_thirdparty.disable_warnings()
- lib = env_thirdparty.add_library("harfbuzz_builtin", thirdparty_sources)
+
+ lib = env_harfbuzz.add_library("harfbuzz_builtin", thirdparty_sources)
+ thirdparty_obj += lib
# Needs to be appended to arrive after libscene in the linker call,
# but we don't want it to arrive *after* system libs, so manual hack
@@ -151,10 +155,11 @@ if env["builtin_harfbuzz"]:
if not inserted:
env.Append(LIBS=[lib])
+
if env["builtin_graphite"]:
env_graphite = env_modules.Clone()
+ env_graphite.disable_warnings()
- # Thirdparty source files
thirdparty_dir = "#thirdparty/graphite/"
thirdparty_sources = [
"src/gr_char_info.cpp",
@@ -203,10 +208,9 @@ if env["builtin_graphite"]:
"-DGRAPHITE2_NFILEFACE",
]
)
- env_graphite.disable_warnings()
- env_thirdparty = env_graphite.Clone()
- env_thirdparty.disable_warnings()
- lib = env_thirdparty.add_library("graphite_builtin", thirdparty_sources)
+
+ lib = env_graphite.add_library("graphite_builtin", thirdparty_sources)
+ thirdparty_obj += lib
# Needs to be appended to arrive after libscene in the linker call,
# but we don't want it to arrive *after* system libs, so manual hack
@@ -221,12 +225,12 @@ if env["builtin_graphite"]:
if not inserted:
env.Append(LIBS=[lib])
+
if env["builtin_icu"]:
env_icu = env_modules.Clone()
+ env_icu.disable_warnings()
- # Thirdparty source files
thirdparty_dir = "#thirdparty/icu4c/"
- # Thirdparty source files
thirdparty_sources = [
"common/appendable.cpp",
"common/bmpset.cpp",
@@ -457,10 +461,8 @@ if env["builtin_icu"]:
]
)
- env_icu.disable_warnings()
- env_thirdparty = env_icu.Clone()
- env_thirdparty.disable_warnings()
- lib = env_thirdparty.add_library("icu_builtin", thirdparty_sources)
+ lib = env_icu.add_library("icu_builtin", thirdparty_sources)
+ thirdparty_obj += lib
# Needs to be appended to arrive after libscene in the linker call,
# but we don't want it to arrive *after* system libs, so manual hack
@@ -475,6 +477,11 @@ if env["builtin_icu"]:
if not inserted:
env.Append(LIBS=[lib])
+
+# Godot source files
+
+module_obj = []
+
if env_text_server_adv["tools"]:
env_text_server_adv.Append(CXXFLAGS=["-DICU_STATIC_DATA"])
@@ -486,4 +493,9 @@ env_text_server_adv.Append(
"#thirdparty/icu4c/common/",
]
)
-env_text_server_adv.add_source_files(env.modules_sources, "*.cpp")
+
+env_text_server_adv.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/text_server_adv/dynamic_font_adv.cpp b/modules/text_server_adv/dynamic_font_adv.cpp
index 9c7c36ea5c..08c4ad2727 100644
--- a/modules/text_server_adv/dynamic_font_adv.cpp
+++ b/modules/text_server_adv/dynamic_font_adv.cpp
@@ -32,6 +32,7 @@
#include FT_STROKER_H
#include FT_ADVANCES_H
+#include FT_MULTIPLE_MASTERS_H
DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size(int p_size, int p_outline_size) {
ERR_FAIL_COND_V(!valid, nullptr);
@@ -134,16 +135,91 @@ DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size(
memdelete(fds);
ERR_FAIL_V_MSG(nullptr, "Error loading HB font.");
}
+
if (p_outline_size != 0) {
size_cache_outline[id] = fds;
} else {
size_cache[id] = fds;
}
- }
+ // Write variations.
+ if (fds->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
+ FT_MM_Var *amaster;
+
+ FT_Get_MM_Var(fds->face, &amaster);
+
+ Vector<hb_variation_t> hb_vars;
+ Vector<FT_Fixed> coords;
+ coords.resize(amaster->num_axis);
+
+ FT_Get_Var_Design_Coordinates(fds->face, coords.size(), coords.ptrw());
+
+ for (FT_UInt i = 0; i < amaster->num_axis; i++) {
+ hb_variation_t var;
+
+ // Reset to default.
+ var.tag = amaster->axis[i].tag;
+ var.value = (double)amaster->axis[i].def / 65536.f;
+ coords.write[i] = amaster->axis[i].def;
+
+ if (variations.has(var.tag)) {
+ var.value = variations[var.tag];
+ coords.write[i] = CLAMP(variations[var.tag] * 65536.f, amaster->axis[i].minimum, amaster->axis[i].maximum);
+ }
+
+ hb_vars.push_back(var);
+ }
+
+ FT_Set_Var_Design_Coordinates(fds->face, coords.size(), coords.ptrw());
+ hb_font_set_variations(fds->hb_handle, hb_vars.empty() ? nullptr : &hb_vars[0], hb_vars.size());
+
+ FT_Done_MM_Var(library, amaster);
+ }
+ }
return fds;
}
+Dictionary DynamicFontDataAdvanced::get_variation_list() const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(base_size);
+ if (fds == nullptr) {
+ return Dictionary();
+ }
+
+ Dictionary ret;
+ // Read variations.
+ if (fds->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
+ FT_MM_Var *amaster;
+
+ FT_Get_MM_Var(fds->face, &amaster);
+
+ for (FT_UInt i = 0; i < amaster->num_axis; i++) {
+ ret[(int32_t)amaster->axis[i].tag] = Vector3i(amaster->axis[i].minimum / 65536, amaster->axis[i].maximum / 65536, amaster->axis[i].def / 65536);
+ }
+
+ FT_Done_MM_Var(library, amaster);
+ }
+ return ret;
+}
+
+void DynamicFontDataAdvanced::set_variation(const String &p_name, double p_value) {
+ _THREAD_SAFE_METHOD_
+ int32_t tag = TS->name_to_tag(p_name);
+ if (!variations.has(tag) || (variations[tag] != p_value)) {
+ variations[tag] = p_value;
+ clear_cache();
+ }
+}
+
+double DynamicFontDataAdvanced::get_variation(const String &p_name) const {
+ _THREAD_SAFE_METHOD_
+ int32_t tag = TS->name_to_tag(p_name);
+ if (!variations.has(tag)) {
+ return 0.f;
+ }
+ return variations[tag];
+}
+
Dictionary DynamicFontDataAdvanced::get_feature_list() const {
_THREAD_SAFE_METHOD_
DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(base_size);
diff --git a/modules/text_server_adv/dynamic_font_adv.h b/modules/text_server_adv/dynamic_font_adv.h
index 4ba120f203..f9d6735c32 100644
--- a/modules/text_server_adv/dynamic_font_adv.h
+++ b/modules/text_server_adv/dynamic_font_adv.h
@@ -118,6 +118,8 @@ private:
String font_path;
Vector<uint8_t> font_mem_cache;
+ Map<int32_t, double> variations;
+
float rect_margin = 1.f;
int base_size = 16;
float oversampling = 1.f;
@@ -146,6 +148,10 @@ public:
virtual float get_descent(int p_size) const override;
virtual Dictionary get_feature_list() const override;
+ virtual Dictionary get_variation_list() const override;
+
+ virtual void set_variation(const String &p_name, double p_value) override;
+ virtual double get_variation(const String &p_name) const override;
virtual float get_underline_position(int p_size) const override;
virtual float get_underline_thickness(int p_size) const override;
diff --git a/modules/text_server_adv/font_adv.h b/modules/text_server_adv/font_adv.h
index 232d6d7d08..88b327f57b 100644
--- a/modules/text_server_adv/font_adv.h
+++ b/modules/text_server_adv/font_adv.h
@@ -50,6 +50,10 @@ struct FontDataAdvanced {
virtual float get_descent(int p_size) const = 0;
virtual Dictionary get_feature_list() const { return Dictionary(); };
+ virtual Dictionary get_variation_list() const { return Dictionary(); };
+
+ virtual void set_variation(const String &p_name, double p_value){};
+ virtual double get_variation(const String &p_name) const { return 0; };
virtual float get_underline_position(int p_size) const = 0;
virtual float get_underline_thickness(int p_size) const = 0;
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 95103c6ef6..3a706286e5 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -132,7 +132,7 @@ _FORCE_INLINE_ bool is_linebreak(char32_t p_char) {
/*************************************************************************/
String TextServerAdvanced::interface_name = "ICU / HarfBuzz / Graphite";
-uint32_t TextServerAdvanced::interface_features = FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_USE_SUPPORT_DATA;
+uint32_t TextServerAdvanced::interface_features = FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_USE_SUPPORT_DATA | FEATURE_FONT_VARIABLE;
bool TextServerAdvanced::has_feature(Feature p_feature) {
return (interface_features & p_feature) == p_feature;
@@ -622,6 +622,27 @@ bool TextServerAdvanced::font_get_antialiased(RID p_font) const {
return fd->get_antialiased();
}
+Dictionary TextServerAdvanced::font_get_variation_list(RID p_font) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, Dictionary());
+ return fd->get_variation_list();
+}
+
+void TextServerAdvanced::font_set_variation(RID p_font, const String &p_name, double p_value) {
+ _THREAD_SAFE_METHOD_
+ FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->set_variation(p_name, p_value);
+}
+
+double TextServerAdvanced::font_get_variation(RID p_font, const String &p_name) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, 0);
+ return fd->get_variation(p_name);
+}
+
void TextServerAdvanced::font_set_distance_field_hint(RID p_font, bool p_distance_field) {
_THREAD_SAFE_METHOD_
FontDataAdvanced *fd = font_owner.getornull(p_font);
@@ -1624,13 +1645,18 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
if (c == 0x0009 || c == 0x000b) {
sd_glyphs[i].flags |= GRAPHEME_IS_TAB;
}
+ if (is_whitespace(c)) {
+ sd_glyphs[i].flags |= GRAPHEME_IS_SPACE;
+ }
+ if (u_ispunct(c)) {
+ sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION;
+ }
if (breaks.has(sd->glyphs[i].start)) {
if (breaks[sd->glyphs[i].start]) {
sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_HARD;
} else {
if (is_whitespace(c)) {
sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT;
- sd_glyphs[i].flags |= GRAPHEME_IS_SPACE;
} else {
TextServer::Glyph gl;
gl.start = sd_glyphs[i].start;
@@ -1745,6 +1771,10 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
shaped_text_update_breaks(p_shaped);
}
+ if (sd->justification_ops_valid) {
+ return true; // Noting to do.
+ }
+
const UChar *data = sd->utf16.ptr();
int32_t data_size = sd->utf16.length();
@@ -1775,9 +1805,9 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
if (ubrk_getRuleStatus(bi) != UBRK_WORD_NONE) {
int i = _convert_pos(sd, ubrk_current(bi));
jstops[i + sd->start] = false;
- int ks = _generate_kashida_justification_opportunies(sd->text, limit, i) + sd->start;
+ int ks = _generate_kashida_justification_opportunies(sd->text, limit, i);
if (ks != -1) {
- jstops[ks] = true;
+ jstops[ks + sd->start] = true;
}
limit = i;
}
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index f26b87f67e..8c26554158 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -138,6 +138,10 @@ public:
virtual bool font_get_antialiased(RID p_font) const override;
virtual Dictionary font_get_feature_list(RID p_font) const override;
+ virtual Dictionary font_get_variation_list(RID p_font) const override;
+
+ virtual void font_set_variation(RID p_font, const String &p_name, double p_value) override;
+ virtual double font_get_variation(RID p_font, const String &p_name) const override;
virtual void font_set_hinting(RID p_font, Hinting p_hinting) override;
virtual Hinting font_get_hinting(RID p_font) const override;
diff --git a/modules/text_server_fb/SCsub b/modules/text_server_fb/SCsub
index 7650e27063..03eccbe7bd 100644
--- a/modules/text_server_fb/SCsub
+++ b/modules/text_server_fb/SCsub
@@ -9,4 +9,5 @@ env_text_server_fb.Append(
"#thirdparty/freetype/include",
]
)
+
env_text_server_fb.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 383250996d..675d0e5d4d 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -45,6 +45,10 @@ _FORCE_INLINE_ bool is_linebreak(char32_t p_char) {
return (p_char >= 0x000a && p_char <= 0x000d) || (p_char == 0x0085) || (p_char == 0x2028) || (p_char == 0x2029);
}
+_FORCE_INLINE_ bool is_punct(char32_t p_char) {
+ return (p_char >= 0x0020 && p_char <= 0x002F) || (p_char >= 0x003A && p_char <= 0x0040) || (p_char >= 0x005B && p_char <= 0x0060) || (p_char >= 0x007B && p_char <= 0x007E) || (p_char >= 0x2000 && p_char <= 0x206F) || (p_char >= 0x3000 && p_char <= 0x303F);
+}
+
/*************************************************************************/
String TextServerFallback::interface_name = "Fallback";
@@ -1029,6 +1033,9 @@ bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) {
for (int i = 0; i < sd_size; i++) {
if (sd->glyphs[i].count > 0) {
char32_t c = sd->text[sd->glyphs[i].start];
+ if (is_punct(c)) {
+ sd->glyphs.write[i].flags |= GRAPHEME_IS_PUNCTUATION;
+ }
if (is_whitespace(c) && !is_linebreak(c)) {
sd->glyphs.write[i].flags |= GRAPHEME_IS_SPACE;
sd->glyphs.write[i].flags |= GRAPHEME_IS_BREAK_SOFT;
diff --git a/modules/theora/SCsub b/modules/theora/SCsub
index a01e65b4b0..6038ea086a 100644
--- a/modules/theora/SCsub
+++ b/modules/theora/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_theora = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_libtheora"]:
thirdparty_dir = "#thirdparty/libtheora/"
thirdparty_sources = [
@@ -80,7 +83,16 @@ if env["builtin_libtheora"]:
env_thirdparty = env_theora.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
# Godot source files
-env_theora.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_theora.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/tinyexr/SCsub b/modules/tinyexr/SCsub
index 84b3b4015b..30bde96fb4 100644
--- a/modules/tinyexr/SCsub
+++ b/modules/tinyexr/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_tinyexr = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
# Not unbundled for now as they are not commonly available as shared library
thirdparty_dir = "#thirdparty/tinyexr/"
thirdparty_sources = [
@@ -20,7 +23,15 @@ env_tinyexr.Append(CPPDEFINES=["TINYEXR_USE_THREAD"])
env_thirdparty = env_tinyexr.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_tinyexr.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-# Godot's own source files
-env_tinyexr.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/upnp/SCsub b/modules/upnp/SCsub
index 2e129e15ca..bc0b215be3 100644
--- a/modules/upnp/SCsub
+++ b/modules/upnp/SCsub
@@ -7,6 +7,8 @@ env_upnp = env_modules.Clone()
# Thirdparty source files
+thirdparty_obj = []
+
if env["builtin_miniupnpc"]:
thirdparty_dir = "#thirdparty/miniupnpc/"
thirdparty_sources = [
@@ -31,7 +33,16 @@ if env["builtin_miniupnpc"]:
env_thirdparty = env_upnp.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
# Godot source files
-env_upnp.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_upnp.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/vhacd/SCsub b/modules/vhacd/SCsub
index ecd432b275..1ff4122114 100644
--- a/modules/vhacd/SCsub
+++ b/modules/vhacd/SCsub
@@ -7,6 +7,8 @@ env_vhacd = env_modules.Clone()
# Thirdparty source files
+thirdparty_obj = []
+
thirdparty_dir = "#thirdparty/vhacd/"
thirdparty_sources = [
@@ -24,10 +26,19 @@ thirdparty_sources = [
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
-env_vhacd.Prepend(CPPPATH=[thirdparty_dir + "/inc"])
+env_vhacd.Prepend(CPPPATH=[thirdparty_dir + "inc"])
env_thirdparty = env_vhacd.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_vhacd.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-env_vhacd.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index 64abd3dd84..1bd88a2a19 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -2547,7 +2547,7 @@ void VisualScriptEditor::set_edited_resource(const RES &p_res) {
}
_update_graph();
- _update_members();
+ call_deferred("_update_members");
}
void VisualScriptEditor::enable_editor() {
@@ -4858,8 +4858,8 @@ VisualScriptEditor::VisualScriptEditor() {
function_create_dialog = memnew(ConfirmationDialog);
function_create_dialog->set_title(TTR("Create Function"));
function_create_dialog->add_child(function_vb);
- function_create_dialog->get_ok()->set_text(TTR("Create"));
- function_create_dialog->get_ok()->connect("pressed", callable_mp(this, &VisualScriptEditor::_create_function));
+ function_create_dialog->get_ok_button()->set_text(TTR("Create"));
+ function_create_dialog->get_ok_button()->connect("pressed", callable_mp(this, &VisualScriptEditor::_create_function));
add_child(function_create_dialog);
select_func_text = memnew(Label);
@@ -4902,7 +4902,7 @@ VisualScriptEditor::VisualScriptEditor() {
graph->connect("connection_to_empty", callable_mp(this, &VisualScriptEditor::_graph_connect_to_empty));
edit_signal_dialog = memnew(AcceptDialog);
- edit_signal_dialog->get_ok()->set_text(TTR("Close"));
+ edit_signal_dialog->get_ok_button()->set_text(TTR("Close"));
add_child(edit_signal_dialog);
signal_editor = memnew(VisualScriptEditorSignalEdit);
@@ -4912,7 +4912,7 @@ VisualScriptEditor::VisualScriptEditor() {
edit_signal_edit->edit(signal_editor);
edit_variable_dialog = memnew(AcceptDialog);
- edit_variable_dialog->get_ok()->set_text(TTR("Close"));
+ edit_variable_dialog->get_ok_button()->set_text(TTR("Close"));
add_child(edit_variable_dialog);
variable_editor = memnew(VisualScriptEditorVariableEdit);
@@ -4944,7 +4944,7 @@ VisualScriptEditor::VisualScriptEditor() {
new_connect_node_select = memnew(VisualScriptPropertySelector);
add_child(new_connect_node_select);
new_connect_node_select->connect("selected", callable_mp(this, &VisualScriptEditor::_selected_connect_node));
- new_connect_node_select->get_cancel()->connect("pressed", callable_mp(this, &VisualScriptEditor::_cancel_connect_node));
+ new_connect_node_select->get_cancel_button()->connect("pressed", callable_mp(this, &VisualScriptEditor::_cancel_connect_node));
new_virtual_method_select = memnew(VisualScriptPropertySelector);
add_child(new_virtual_method_select);
diff --git a/modules/visual_script/visual_script_property_selector.cpp b/modules/visual_script/visual_script_property_selector.cpp
index 54d86d5a9c..dbb76e19ac 100644
--- a/modules/visual_script/visual_script_property_selector.cpp
+++ b/modules/visual_script/visual_script_property_selector.cpp
@@ -310,7 +310,7 @@ void VisualScriptPropertySelector::_update_search() {
found = true;
}
- get_ok()->set_disabled(root->get_children() == nullptr);
+ get_ok_button()->set_disabled(root->get_children() == nullptr);
}
void VisualScriptPropertySelector::create_visualscript_item(const String &name, TreeItem *const root, const String &search_input, const String &text) {
@@ -705,8 +705,8 @@ VisualScriptPropertySelector::VisualScriptPropertySelector() {
search_box->connect("gui_input", callable_mp(this, &VisualScriptPropertySelector::_sbox_input));
search_options = memnew(Tree);
vbc->add_margin_child(TTR("Matches:"), search_options, true);
- get_ok()->set_text(TTR("Open"));
- get_ok()->set_disabled(true);
+ get_ok_button()->set_text(TTR("Open"));
+ get_ok_button()->set_disabled(true);
register_text_enter(search_box);
set_hide_on_ok(false);
search_options->connect("item_activated", callable_mp(this, &VisualScriptPropertySelector::_confirmed));
diff --git a/modules/vorbis/SCsub b/modules/vorbis/SCsub
index 05d46757d3..bc31fff066 100644
--- a/modules/vorbis/SCsub
+++ b/modules/vorbis/SCsub
@@ -8,9 +8,10 @@ Import("env_modules")
env_vorbis = env_modules.Clone()
-stub = True
-
# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_libvorbis"]:
thirdparty_dir = "#thirdparty/libvorbis/"
thirdparty_sources = [
@@ -51,7 +52,16 @@ if env["builtin_libvorbis"]:
env_thirdparty = env_vorbis.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
+
+# Godot source files
+
+module_obj = []
+
+env_vorbis.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-# Module files
-env_vorbis.add_source_files(env.modules_sources, "register_types.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/webm/SCsub b/modules/webm/SCsub
index 247b4ead37..44e80e2870 100644
--- a/modules/webm/SCsub
+++ b/modules/webm/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_webm = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
thirdparty_dir = "#thirdparty/libsimplewebm/"
thirdparty_sources = [
"libwebm/mkvparser/mkvparser.cc",
@@ -31,7 +34,15 @@ if env["builtin_libvpx"]:
env_thirdparty = env_webm.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
# Godot source files
-env_webm.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_webm.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/webm/libvpx/SCsub b/modules/webm/libvpx/SCsub
index d0744fa313..67d3f1bebd 100644
--- a/modules/webm/libvpx/SCsub
+++ b/modules/webm/libvpx/SCsub
@@ -278,7 +278,7 @@ if webm_cpu_x86:
try:
yasm_found = True
subprocess.Popen([yasm_path, "--version"], stdout=devnull, stderr=devnull).communicate()
- except:
+ except Exception:
yasm_found = False
if yasm_found:
break
diff --git a/modules/webp/SCsub b/modules/webp/SCsub
index 58f2bb35e6..4c0c2f7893 100644
--- a/modules/webp/SCsub
+++ b/modules/webp/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_webp = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_libwebp"]:
thirdparty_dir = "#thirdparty/libwebp/"
thirdparty_sources = [
@@ -130,7 +133,16 @@ if env["builtin_libwebp"]:
env_thirdparty = env_webp.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
# Godot source files
-env_webp.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_webp.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/webrtc/SCsub b/modules/webrtc/SCsub
index 4f870ddb2f..31b8a73bf2 100644
--- a/modules/webrtc/SCsub
+++ b/modules/webrtc/SCsub
@@ -3,8 +3,6 @@
Import("env")
Import("env_modules")
-# Thirdparty source files
-
env_webrtc = env_modules.Clone()
use_gdnative = env_webrtc["module_gdnative_enabled"]
diff --git a/modules/websocket/SCsub b/modules/websocket/SCsub
index 13e51a39c0..4c022c43cf 100644
--- a/modules/websocket/SCsub
+++ b/modules/websocket/SCsub
@@ -5,28 +5,44 @@ Import("env_modules")
env_ws = env_modules.Clone()
+thirdparty_obj = []
+
if env["platform"] == "javascript":
# Our JavaScript/C++ interface.
env.AddJSLibraries(["library_godot_websocket.js"])
+
elif env["builtin_wslay"]:
# Thirdparty source files
- wslay_dir = "#thirdparty/wslay/"
- wslay_sources = [
+ thirdparty_dir = "#thirdparty/wslay/"
+ thirdparty_sources = [
"wslay_net.c",
"wslay_event.c",
"wslay_queue.c",
"wslay_stack.c",
"wslay_frame.c",
]
- wslay_sources = [wslay_dir + s for s in wslay_sources]
- env_ws.Prepend(CPPPATH=[wslay_dir + "includes/"])
+ thirdparty_sources = [thirdparty_dir + s for s in thirdparty_sources]
+
+ env_ws.Prepend(CPPPATH=[thirdparty_dir + "includes/"])
env_ws.Append(CPPDEFINES=["HAVE_CONFIG_H"])
+
if env["platform"] == "windows" or env["platform"] == "uwp":
env_ws.Append(CPPDEFINES=["HAVE_WINSOCK2_H"])
else:
env_ws.Append(CPPDEFINES=["HAVE_NETINET_IN_H"])
- env_wslay = env_ws.Clone()
- env_wslay.disable_warnings()
- env_wslay.add_source_files(env.modules_sources, wslay_sources)
-env_ws.add_source_files(env.modules_sources, "*.cpp")
+ env_thirdparty = env_ws.Clone()
+ env_thirdparty.disable_warnings()
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
+
+# Godot source files
+
+module_obj = []
+
+env_ws.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/xatlas_unwrap/SCsub b/modules/xatlas_unwrap/SCsub
index c659349d05..aa6bdaea33 100644
--- a/modules/xatlas_unwrap/SCsub
+++ b/modules/xatlas_unwrap/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_xatlas_unwrap = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_xatlas"]:
thirdparty_dir = "#thirdparty/xatlas/"
thirdparty_sources = [
@@ -17,7 +20,16 @@ if env["builtin_xatlas"]:
env_thirdparty = env_xatlas_unwrap.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
# Godot source files
-env_xatlas_unwrap.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_xatlas_unwrap.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/platform/android/SCsub b/platform/android/SCsub
index d8013b0baf..7e9dac926c 100644
--- a/platform/android/SCsub
+++ b/platform/android/SCsub
@@ -29,10 +29,14 @@ for x in android_files:
env_thirdparty = env_android.Clone()
env_thirdparty.disable_warnings()
-android_objects.append(env_thirdparty.SharedObject("#thirdparty/misc/ifaddrs-android.cc"))
+thirdparty_obj = env_thirdparty.SharedObject("#thirdparty/misc/ifaddrs-android.cc")
+android_objects.append(thirdparty_obj)
lib = env_android.add_shared_library("#bin/libgodot", [android_objects], SHLIBSUFFIX=env["SHLIBSUFFIX"])
+# Needed to force rebuilding the platform files when the thirdparty code is updated.
+env.Depends(lib, thirdparty_obj)
+
lib_arch_dir = ""
if env["android_arch"] == "armv7":
lib_arch_dir = "armeabi-v7a"
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 60d4146712..650606ff8b 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -334,6 +334,6 @@ def get_ndk_version(path):
key_value = list(map(lambda x: x.strip(), line.split("=")))
if key_value[0] == "Pkg.Revision":
return key_value[1]
- except:
+ except Exception:
print("Could not read source prop file '%s'" % prop_file_path)
return None
diff --git a/platform/android/os_android.h b/platform/android/os_android.h
index cac7efaa88..d9a07411ad 100644
--- a/platform/android/os_android.h
+++ b/platform/android/os_android.h
@@ -68,15 +68,15 @@ private:
GodotIOJavaWrapper *godot_io_java;
public:
- virtual void initialize_core();
- virtual void initialize();
+ virtual void initialize_core() override;
+ virtual void initialize() override;
- virtual void initialize_joypads();
+ virtual void initialize_joypads() override;
- virtual void set_main_loop(MainLoop *p_main_loop);
- virtual void delete_main_loop();
+ virtual void set_main_loop(MainLoop *p_main_loop) override;
+ virtual void delete_main_loop() override;
- virtual void finalize();
+ virtual void finalize() override;
typedef int64_t ProcessID;
@@ -84,14 +84,14 @@ public:
GodotJavaWrapper *get_godot_java();
GodotIOJavaWrapper *get_godot_io_java();
- virtual bool request_permission(const String &p_name);
- virtual bool request_permissions();
- virtual Vector<String> get_granted_permissions() const;
+ virtual bool request_permission(const String &p_name) override;
+ virtual bool request_permissions() override;
+ virtual Vector<String> get_granted_permissions() const override;
- virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false);
+ virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false) override;
- virtual String get_name() const;
- virtual MainLoop *get_main_loop() const;
+ virtual String get_name() const override;
+ virtual MainLoop *get_main_loop() const override;
void main_loop_begin();
bool main_loop_iterate();
@@ -109,19 +109,19 @@ public:
void set_native_window(ANativeWindow *p_native_window);
ANativeWindow *get_native_window() const;
- virtual Error shell_open(String p_uri);
- virtual String get_user_data_dir() const;
- virtual String get_resource_dir() const;
- virtual String get_locale() const;
- virtual String get_model_name() const;
+ virtual Error shell_open(String p_uri) override;
+ virtual String get_user_data_dir() const override;
+ virtual String get_resource_dir() const override;
+ virtual String get_locale() const override;
+ virtual String get_model_name() const override;
- virtual String get_unique_id() const;
+ virtual String get_unique_id() const override;
- virtual String get_system_dir(SystemDir p_dir) const;
+ virtual String get_system_dir(SystemDir p_dir) const override;
- void vibrate_handheld(int p_duration_ms);
+ void vibrate_handheld(int p_duration_ms) override;
- virtual bool _check_internal_feature_support(const String &p_feature);
+ virtual bool _check_internal_feature_support(const String &p_feature) override;
OS_Android(GodotJavaWrapper *p_godot_java, GodotIOJavaWrapper *p_godot_io_java, bool p_use_apk_expansion);
~OS_Android();
};
diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py
index 0456458326..ad4af9ba6a 100644
--- a/platform/iphone/detect.py
+++ b/platform/iphone/detect.py
@@ -12,7 +12,6 @@ def get_name():
def can_build():
-
if sys.platform == "darwin" or ("OSXCROSS_IOS" in os.environ):
return True
@@ -41,14 +40,12 @@ def get_opts():
def get_flags():
-
return [
("tools", False),
]
def configure(env):
-
## Build type
if env["target"].startswith("release"):
diff --git a/platform/javascript/api/javascript_tools_editor_plugin.cpp b/platform/javascript/api/javascript_tools_editor_plugin.cpp
index 8d781703ed..a063718a0c 100644
--- a/platform/javascript/api/javascript_tools_editor_plugin.cpp
+++ b/platform/javascript/api/javascript_tools_editor_plugin.cpp
@@ -53,8 +53,7 @@ void JavaScriptToolsEditorPlugin::initialize() {
}
JavaScriptToolsEditorPlugin::JavaScriptToolsEditorPlugin(EditorNode *p_editor) {
- Variant v;
- add_tool_menu_item("Download Project Source", this, "_download_zip", v);
+ add_tool_menu_item("Download Project Source", callable_mp(this, &JavaScriptToolsEditorPlugin::_download_zip));
}
void JavaScriptToolsEditorPlugin::_download_zip(Variant p_v) {
@@ -73,10 +72,6 @@ void JavaScriptToolsEditorPlugin::_download_zip(Variant p_v) {
godot_js_editor_download_file("/tmp/project.zip", "project.zip", "application/zip");
}
-void JavaScriptToolsEditorPlugin::_bind_methods() {
- ClassDB::bind_method("_download_zip", &JavaScriptToolsEditorPlugin::_download_zip);
-}
-
void JavaScriptToolsEditorPlugin::_zip_file(String p_path, String p_base_path, zipFile p_zip) {
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
if (!f) {
diff --git a/platform/javascript/api/javascript_tools_editor_plugin.h b/platform/javascript/api/javascript_tools_editor_plugin.h
index cc09fa4cd3..df1197139c 100644
--- a/platform/javascript/api/javascript_tools_editor_plugin.h
+++ b/platform/javascript/api/javascript_tools_editor_plugin.h
@@ -41,10 +41,6 @@ class JavaScriptToolsEditorPlugin : public EditorPlugin {
private:
void _zip_file(String p_path, String p_base_path, zipFile p_zip);
void _zip_recursive(String p_path, String p_base_path, zipFile p_zip);
-
-protected:
- static void _bind_methods();
-
void _download_zip(Variant p_v);
public:
diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py
index 178088e234..d53c774e77 100644
--- a/platform/javascript/detect.py
+++ b/platform/javascript/detect.py
@@ -23,12 +23,12 @@ def get_opts():
return [
("initial_memory", "Initial WASM memory (in MiB)", 16),
- BoolVariable("use_assertions", "Use emscripten runtime assertions", False),
+ BoolVariable("use_assertions", "Use Emscripten runtime assertions", False),
BoolVariable("use_thinlto", "Use ThinLTO", 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_safe_heap", "Use emscripten SAFE_HEAP sanitizer", False),
+ BoolVariable("use_ubsan", "Use Emscripten undefined behavior sanitizer (UBSAN)", False),
+ BoolVariable("use_asan", "Use Emscripten address sanitizer (ASAN)", False),
+ BoolVariable("use_lsan", "Use Emscripten leak sanitizer (LSAN)", False),
+ BoolVariable("use_safe_heap", "Use Emscripten SAFE_HEAP sanitizer", False),
# eval() can be a security concern, so it can be disabled.
BoolVariable("javascript_eval", "Enable JavaScript eval interface", True),
BoolVariable("threads_enabled", "Enable WebAssembly Threads support (limited browser support)", False),
@@ -50,9 +50,7 @@ def get_flags():
def configure(env):
- try:
- env["initial_memory"] = int(env["initial_memory"])
- except:
+ if not isinstance(env["initial_memory"], int):
print("Initial memory must be a valid integer")
sys.exit(255)
diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp
index f77bf6ab97..37681b2484 100644
--- a/platform/javascript/export/export.cpp
+++ b/platform/javascript/export/export.cpp
@@ -37,16 +37,13 @@
#include "platform/javascript/logo.gen.h"
#include "platform/javascript/run_icon.gen.h"
-#define EXPORT_TEMPLATE_WEBASSEMBLY_RELEASE "webassembly_release.zip"
-#define EXPORT_TEMPLATE_WEBASSEMBLY_DEBUG "webassembly_debug.zip"
-
class EditorHTTPServer : public Reference {
private:
Ref<TCP_Server> server;
Ref<StreamPeerTCP> connection;
- uint64_t time;
+ uint64_t time = 0;
uint8_t req_buf[4096];
- int req_pos;
+ int req_pos = 0;
void _clear_client() {
connection = Ref<StreamPeerTCP>();
@@ -211,7 +208,12 @@ class EditorExportPlatformJavaScript : public EditorExportPlatform {
Ref<ImageTexture> logo;
Ref<ImageTexture> run_icon;
Ref<ImageTexture> stop_icon;
- int menu_options;
+ int menu_options = 0;
+
+ Ref<EditorHTTPServer> server;
+ bool server_quit = false;
+ Mutex server_lock;
+ Thread *server_thread = nullptr;
enum ExportMode {
EXPORT_MODE_NORMAL = 0,
@@ -241,12 +243,6 @@ class EditorExportPlatformJavaScript : public EditorExportPlatform {
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);
-private:
- Ref<EditorHTTPServer> server;
- bool server_quit;
- Mutex server_lock;
- Thread *server_thread;
-
static void _server_thread_poll(void *data);
public:
@@ -685,7 +681,6 @@ void EditorExportPlatformJavaScript::_server_thread_poll(void *data) {
EditorExportPlatformJavaScript::EditorExportPlatformJavaScript() {
server.instance();
- server_quit = false;
server_thread = Thread::create(_server_thread_poll, this);
Ref<Image> img = memnew(Image(_javascript_logo));
@@ -702,8 +697,6 @@ EditorExportPlatformJavaScript::EditorExportPlatformJavaScript() {
} else {
stop_icon.instance();
}
-
- menu_options = 0;
}
EditorExportPlatformJavaScript::~EditorExportPlatformJavaScript() {
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index 277aafc107..a819731328 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -12,7 +12,6 @@ def get_name():
def can_build():
-
if os.name != "posix" or sys.platform == "darwin":
return False
@@ -81,12 +80,10 @@ def get_opts():
def get_flags():
-
return []
def configure(env):
-
## Build type
if env["target"] == "release":
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index 136bee68e3..7e58272208 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -95,6 +95,15 @@
static const double abs_resolution_mult = 10000.0;
static const double abs_resolution_range_mult = 10.0;
+// Hints for X11 fullscreen
+struct Hints {
+ unsigned long flags = 0;
+ unsigned long functions = 0;
+ unsigned long decorations = 0;
+ long inputMode = 0;
+ unsigned long status = 0;
+};
+
bool DisplayServerX11::has_feature(Feature p_feature) const {
switch (p_feature) {
case FEATURE_SUBWINDOWS:
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
index 0507ef3fff..6f437f3be9 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/display_server_x11.h
@@ -61,15 +61,6 @@
#include <X11/extensions/Xrandr.h>
#include <X11/keysym.h>
-// Hints for X11 fullscreen
-typedef struct {
- unsigned long flags = 0;
- unsigned long functions = 0;
- unsigned long decorations = 0;
- long inputMode = 0;
- unsigned long status = 0;
-} Hints;
-
typedef struct _xrr_monitor_info {
Atom name;
Bool primary = false;
diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h
index 6e93bf6ef2..89d0bcd0f2 100644
--- a/platform/linuxbsd/os_linuxbsd.h
+++ b/platform/linuxbsd/os_linuxbsd.h
@@ -43,7 +43,7 @@
#include "servers/rendering_server.h"
class OS_LinuxBSD : public OS_Unix {
- virtual void delete_main_loop();
+ virtual void delete_main_loop() override;
bool force_quit;
@@ -68,36 +68,36 @@ class OS_LinuxBSD : public OS_Unix {
MainLoop *main_loop;
protected:
- virtual void initialize();
- virtual void finalize();
+ virtual void initialize() override;
+ virtual void finalize() override;
- virtual void initialize_joypads();
+ virtual void initialize_joypads() override;
- virtual void set_main_loop(MainLoop *p_main_loop);
+ virtual void set_main_loop(MainLoop *p_main_loop) override;
public:
- virtual String get_name() const;
+ virtual String get_name() const override;
- virtual MainLoop *get_main_loop() const;
+ virtual MainLoop *get_main_loop() const override;
- virtual String get_config_path() const;
- virtual String get_data_path() const;
- virtual String get_cache_path() const;
+ virtual String get_config_path() const override;
+ virtual String get_data_path() const override;
+ virtual String get_cache_path() const override;
- virtual String get_system_dir(SystemDir p_dir) const;
+ virtual String get_system_dir(SystemDir p_dir) const override;
- virtual Error shell_open(String p_uri);
+ virtual Error shell_open(String p_uri) override;
- virtual String get_unique_id() const;
+ virtual String get_unique_id() const override;
- virtual bool _check_internal_feature_support(const String &p_feature);
+ virtual bool _check_internal_feature_support(const String &p_feature) override;
void run();
- void disable_crash_handler();
- bool is_disable_crash_handler() const;
+ virtual void disable_crash_handler() override;
+ virtual bool is_disable_crash_handler() const override;
- virtual Error move_to_trash(const String &p_path);
+ virtual Error move_to_trash(const String &p_path) override;
OS_LinuxBSD();
};
diff --git a/platform/osx/detect.py b/platform/osx/detect.py
index ea41479bb0..466f68d269 100644
--- a/platform/osx/detect.py
+++ b/platform/osx/detect.py
@@ -12,7 +12,6 @@ def get_name():
def can_build():
-
if sys.platform == "darwin" or ("OSXCROSS_ROOT" in os.environ):
return True
@@ -31,6 +30,7 @@ def get_opts():
" validation layers)",
False,
),
+ EnumVariable("macports_clang", "Build using Clang from MacPorts", "no", ("no", "5.0", "devel")),
EnumVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", "yes", ("yes", "no")),
BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False),
BoolVariable("use_ubsan", "Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)", False),
@@ -40,12 +40,10 @@ def get_opts():
def get_flags():
-
return []
def configure(env):
-
## Build type
if env["target"] == "release":
diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h
index 5a9e43450f..f6eee31a6a 100644
--- a/platform/osx/os_osx.h
+++ b/platform/osx/os_osx.h
@@ -40,7 +40,7 @@
#include "servers/audio_server.h"
class OS_OSX : public OS_Unix {
- virtual void delete_main_loop();
+ virtual void delete_main_loop() override;
bool force_quit;
@@ -61,45 +61,45 @@ public:
String open_with_filename;
protected:
- virtual void initialize_core();
- virtual void initialize();
- virtual void finalize();
+ virtual void initialize_core() override;
+ virtual void initialize() override;
+ virtual void finalize() override;
- virtual void initialize_joypads();
+ virtual void initialize_joypads() override;
- virtual void set_main_loop(MainLoop *p_main_loop);
+ virtual void set_main_loop(MainLoop *p_main_loop) override;
public:
- virtual String get_name() const;
+ virtual String get_name() const override;
- virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false);
+ virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false) override;
- virtual MainLoop *get_main_loop() const;
+ virtual MainLoop *get_main_loop() const override;
- virtual String get_config_path() const;
- virtual String get_data_path() const;
- virtual String get_cache_path() const;
- virtual String get_bundle_resource_dir() const;
- virtual String get_godot_dir_name() const;
+ virtual String get_config_path() const override;
+ virtual String get_data_path() const override;
+ virtual String get_cache_path() const override;
+ virtual String get_bundle_resource_dir() const override;
+ virtual String get_godot_dir_name() const override;
- virtual String get_system_dir(SystemDir p_dir) const;
+ virtual String get_system_dir(SystemDir p_dir) const override;
- Error shell_open(String p_uri);
+ Error shell_open(String p_uri) override;
- String get_locale() const;
+ String get_locale() const override;
- virtual String get_executable_path() const;
+ virtual String get_executable_path() const override;
- virtual String get_unique_id() const; //++
+ virtual String get_unique_id() const override; //++
- virtual bool _check_internal_feature_support(const String &p_feature);
+ virtual bool _check_internal_feature_support(const String &p_feature) override;
void run();
- void disable_crash_handler();
- bool is_disable_crash_handler() const;
+ virtual void disable_crash_handler() override;
+ virtual bool is_disable_crash_handler() const override;
- virtual Error move_to_trash(const String &p_path);
+ virtual Error move_to_trash(const String &p_path) override;
OS_OSX();
};
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index 399a29cbe0..ed03e953a5 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -286,7 +286,7 @@ Error OS_OSX::shell_open(String p_uri) {
String OS_OSX::get_locale() const {
NSString *locale_code = [[NSLocale preferredLanguages] objectAtIndex:0];
- return [locale_code UTF8String];
+ return String([locale_code UTF8String]).replace("-", "_");
}
String OS_OSX::get_executable_path() const {
diff --git a/platform/server/detect.py b/platform/server/detect.py
index bf4744a234..db503584d3 100644
--- a/platform/server/detect.py
+++ b/platform/server/detect.py
@@ -21,7 +21,6 @@ def get_program_suffix():
def can_build():
-
if os.name != "posix":
return False
@@ -46,7 +45,6 @@ def get_opts():
def get_flags():
-
return []
diff --git a/platform/server/os_server.cpp b/platform/server/os_server.cpp
index f8b420b1c8..77cf15c489 100644
--- a/platform/server/os_server.cpp
+++ b/platform/server/os_server.cpp
@@ -150,10 +150,6 @@ void OS_Server::set_main_loop(MainLoop *p_main_loop) {
input->set_main_loop(p_main_loop);
}
-bool OS_Server::can_draw() const {
- return false; //can never draw
-};
-
String OS_Server::get_name() const {
return "Server";
}
diff --git a/platform/server/os_server.h b/platform/server/os_server.h
index 95b6b5143b..b707549b17 100644
--- a/platform/server/os_server.h
+++ b/platform/server/os_server.h
@@ -89,8 +89,6 @@ public:
virtual MainLoop *get_main_loop() const;
- virtual bool can_draw() 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;
diff --git a/platform/uwp/detect.py b/platform/uwp/detect.py
index 2af7803749..fda8fdec66 100644
--- a/platform/uwp/detect.py
+++ b/platform/uwp/detect.py
@@ -30,7 +30,6 @@ def get_opts():
def get_flags():
-
return [
("tools", False),
("xaudio2", True),
@@ -39,7 +38,6 @@ def get_flags():
def configure(env):
-
env.msvc = True
if env["bits"] != "default":
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index 780eba8407..693d8a69f1 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -156,10 +156,6 @@ void OS_UWP::initialize_core() {
cursor_shape = CURSOR_ARROW;
}
-bool OS_UWP::can_draw() const {
- return !minimized;
-};
-
void OS_UWP::set_window(Windows::UI::Core::CoreWindow ^ p_window) {
window = p_window;
}
diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h
index fd25cefe2b..bf3c31f867 100644
--- a/platform/uwp/os_uwp.h
+++ b/platform/uwp/os_uwp.h
@@ -194,7 +194,6 @@ public:
virtual TimeZoneInfo get_time_zone_info() const;
virtual uint64_t get_unix_time() const;
- virtual bool can_draw() const;
virtual Error set_cwd(const String &p_cwd);
virtual void delay_usec(uint32_t p_usec) const;
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index ee13e3c774..5216fca2ca 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -68,7 +68,7 @@ def get_opts():
EnumVariable("windows_subsystem", "Windows subsystem", "default", ("default", "console", "gui")),
BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False),
("msvc_version", "MSVC version to use. Ignored if VCINSTALLDIR is set in shell env.", None),
- BoolVariable("use_mingw", "Use the Mingw compiler, even if MSVC is installed. Only used on Windows.", False),
+ BoolVariable("use_mingw", "Use the Mingw compiler, even if MSVC is installed.", False),
BoolVariable("use_llvm", "Use the LLVM compiler", False),
BoolVariable("use_thinlto", "Use ThinLTO", False),
BoolVariable("use_static_cpp", "Link MinGW/MSVC C++ runtime libraries statically", True),
@@ -76,12 +76,10 @@ def get_opts():
def get_flags():
-
return []
def build_res_file(target, source, env):
-
if env["bits"] == "32":
cmdbase = env["mingw_prefix_32"]
else:
@@ -95,7 +93,7 @@ def build_res_file(target, source, env):
out = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate()
if len(out[1]):
return 1
- except:
+ except Exception:
return 1
return 0
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 62fcd20f61..520b43f963 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -2956,7 +2956,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
Rect2i r;
r.position = screen_get_position(i);
r.size = screen_get_size(i);
- Rect2 inters = r.clip(p_rect);
+ Rect2 inters = r.intersection(p_rect);
int area = inters.size.width * inters.size.height;
if (area >= nearest_area) {
screen_rect = r;
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 633a5091de..451f3bf18c 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -561,21 +561,21 @@ String OS_Windows::get_locale() const {
LANGID langid = GetUserDefaultUILanguage();
String neutral;
- int lang = langid & ((1 << 9) - 1);
- int sublang = langid & ~((1 << 9) - 1);
+ int lang = PRIMARYLANGID(langid);
+ int sublang = SUBLANGID(langid);
while (wl->locale) {
if (wl->main_lang == lang && wl->sublang == SUBLANG_NEUTRAL)
neutral = wl->locale;
if (lang == wl->main_lang && sublang == wl->sublang)
- return wl->locale;
+ return String(wl->locale).replace("-", "_");
wl++;
}
if (neutral != "")
- return neutral;
+ return String(neutral).replace("-", "_");
return "en";
}
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 5451e15d36..14d09d2b35 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -93,14 +93,14 @@ class OS_Windows : public OS {
// functions used by main to initialize/deinitialize the OS
protected:
- virtual void initialize();
+ virtual void initialize() override;
- virtual void set_main_loop(MainLoop *p_main_loop);
- virtual void delete_main_loop();
+ virtual void set_main_loop(MainLoop *p_main_loop) override;
+ virtual void delete_main_loop() override;
- virtual void finalize();
- virtual void finalize_core();
- virtual String get_stdin_string(bool p_block);
+ virtual void finalize() override;
+ virtual void finalize_core() override;
+ virtual String get_stdin_string(bool p_block) override;
String _quote_command_line_argument(const String &p_text) const;
@@ -111,66 +111,66 @@ protected:
Map<ProcessID, ProcessInfo> *process_map;
public:
- virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false);
- virtual Error close_dynamic_library(void *p_library_handle);
- virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false);
+ virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false) override;
+ virtual Error close_dynamic_library(void *p_library_handle) override;
+ virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false) override;
- virtual MainLoop *get_main_loop() const;
+ virtual MainLoop *get_main_loop() const override;
- virtual String get_name() const;
+ virtual String get_name() const override;
- virtual int get_tablet_driver_count() const;
- virtual String get_tablet_driver_name(int p_driver) const;
- virtual String get_current_tablet_driver() const;
- virtual void set_current_tablet_driver(const String &p_driver);
+ virtual int get_tablet_driver_count() const override;
+ virtual String get_tablet_driver_name(int p_driver) const override;
+ virtual String get_current_tablet_driver() const override;
+ virtual void set_current_tablet_driver(const String &p_driver) override;
- virtual void initialize_joypads() {}
+ virtual void initialize_joypads() override {}
- virtual Date get_date(bool utc) const;
- virtual Time get_time(bool utc) const;
- virtual TimeZoneInfo get_time_zone_info() const;
- virtual double get_unix_time() const;
+ virtual Date get_date(bool utc) const override;
+ virtual Time get_time(bool utc) const override;
+ virtual TimeZoneInfo get_time_zone_info() const override;
+ virtual double get_unix_time() const override;
- virtual Error set_cwd(const String &p_cwd);
+ virtual Error set_cwd(const String &p_cwd) override;
- virtual void delay_usec(uint32_t p_usec) const;
- virtual uint64_t get_ticks_usec() const;
+ virtual void delay_usec(uint32_t p_usec) const override;
+ virtual uint64_t get_ticks_usec() const override;
- virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr);
- virtual Error kill(const ProcessID &p_pid);
- virtual int get_process_id() const;
+ virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) override;
+ virtual Error kill(const ProcessID &p_pid) override;
+ virtual int get_process_id() const override;
- virtual bool has_environment(const String &p_var) const;
- virtual String get_environment(const String &p_var) const;
- virtual bool set_environment(const String &p_var, const String &p_value) const;
+ virtual bool has_environment(const String &p_var) const override;
+ virtual String get_environment(const String &p_var) const override;
+ virtual bool set_environment(const String &p_var, const String &p_value) const override;
- virtual String get_executable_path() const;
+ virtual String get_executable_path() const override;
- virtual String get_locale() const;
+ virtual String get_locale() const override;
- virtual int get_processor_count() const;
+ virtual int get_processor_count() const override;
- virtual String get_config_path() const;
- virtual String get_data_path() const;
- virtual String get_cache_path() const;
- virtual String get_godot_dir_name() const;
+ virtual String get_config_path() const override;
+ virtual String get_data_path() const override;
+ virtual String get_cache_path() const override;
+ virtual String get_godot_dir_name() const override;
- virtual String get_system_dir(SystemDir p_dir) const;
- virtual String get_user_data_dir() const;
+ virtual String get_system_dir(SystemDir p_dir) const override;
+ virtual String get_user_data_dir() const override;
- virtual String get_unique_id() const;
+ virtual String get_unique_id() const override;
- virtual Error shell_open(String p_uri);
+ virtual Error shell_open(String p_uri) override;
void run();
- virtual bool _check_internal_feature_support(const String &p_feature);
+ virtual bool _check_internal_feature_support(const String &p_feature) override;
- void disable_crash_handler();
- bool is_disable_crash_handler() const;
- virtual void initialize_debugging();
+ virtual void disable_crash_handler() override;
+ virtual bool is_disable_crash_handler() const override;
+ virtual void initialize_debugging() override;
- virtual Error move_to_trash(const String &p_path);
+ virtual Error move_to_trash(const String &p_path) override;
void set_main_window(HWND p_main_window) { main_window = p_main_window; }
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index 79b0b64efb..0d09d21a71 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -77,6 +77,9 @@ void Camera2D::_update_process_mode() {
}
void Camera2D::set_zoom(const Vector2 &p_zoom) {
+ // Setting zoom to zero causes 'affine_invert' issues
+ ERR_FAIL_COND_MSG(Math::is_zero_approx(p_zoom.x) || Math::is_zero_approx(p_zoom.y), "Zoom level must be different from 0 (can be negative).");
+
zoom = p_zoom;
Point2 old_smoothed_camera_pos = smoothed_camera_pos;
_update_scroll();
diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp
index b1ffe76662..b1adb0e88e 100644
--- a/scene/3d/area_3d.cpp
+++ b/scene/3d/area_3d.cpp
@@ -505,11 +505,11 @@ bool Area3D::is_overriding_audio_bus() const {
return audio_bus_override;
}
-void Area3D::set_audio_bus(const StringName &p_audio_bus) {
+void Area3D::set_audio_bus_name(const StringName &p_audio_bus) {
audio_bus = p_audio_bus;
}
-StringName Area3D::get_audio_bus() const {
+StringName Area3D::get_audio_bus_name() const {
for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
if (AudioServer::get_singleton()->get_bus_name(i) == audio_bus) {
return audio_bus;
@@ -625,8 +625,8 @@ void Area3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_audio_bus_override", "enable"), &Area3D::set_audio_bus_override);
ClassDB::bind_method(D_METHOD("is_overriding_audio_bus"), &Area3D::is_overriding_audio_bus);
- ClassDB::bind_method(D_METHOD("set_audio_bus", "name"), &Area3D::set_audio_bus);
- ClassDB::bind_method(D_METHOD("get_audio_bus"), &Area3D::get_audio_bus);
+ ClassDB::bind_method(D_METHOD("set_audio_bus_name", "name"), &Area3D::set_audio_bus_name);
+ ClassDB::bind_method(D_METHOD("get_audio_bus_name"), &Area3D::get_audio_bus_name);
ClassDB::bind_method(D_METHOD("set_use_reverb_bus", "enable"), &Area3D::set_use_reverb_bus);
ClassDB::bind_method(D_METHOD("is_using_reverb_bus"), &Area3D::is_using_reverb_bus);
@@ -665,7 +665,7 @@ void Area3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
ADD_GROUP("Audio Bus", "audio_bus_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_bus_override"), "set_audio_bus_override", "is_overriding_audio_bus");
- ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "audio_bus_name", PROPERTY_HINT_ENUM, ""), "set_audio_bus", "get_audio_bus");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "audio_bus_name", PROPERTY_HINT_ENUM, ""), "set_audio_bus_name", "get_audio_bus_name");
ADD_GROUP("Reverb Bus", "reverb_bus_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reverb_bus_enable"), "set_use_reverb_bus", "is_using_reverb_bus");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "reverb_bus_name", PROPERTY_HINT_ENUM, ""), "set_reverb_bus", "get_reverb_bus");
diff --git a/scene/3d/area_3d.h b/scene/3d/area_3d.h
index 7d1f030baf..51f6317517 100644
--- a/scene/3d/area_3d.h
+++ b/scene/3d/area_3d.h
@@ -190,8 +190,8 @@ public:
void set_audio_bus_override(bool p_override);
bool is_overriding_audio_bus() const;
- void set_audio_bus(const StringName &p_audio_bus);
- StringName get_audio_bus() const;
+ void set_audio_bus_name(const StringName &p_audio_bus);
+ StringName get_audio_bus_name() const;
void set_use_reverb_bus(bool p_enable);
bool is_using_reverb_bus() const;
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 37bc032356..2907eb3c7e 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -484,7 +484,7 @@ void AudioStreamPlayer3D::_notification(int p_what) {
if (area) {
if (area->is_overriding_audio_bus()) {
//override audio bus
- StringName bus_name = area->get_audio_bus();
+ StringName bus_name = area->get_audio_bus_name();
output.bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus_name);
}
diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp
index 191159448a..178c5c8ff8 100644
--- a/scene/3d/camera_3d.cpp
+++ b/scene/3d/camera_3d.cpp
@@ -519,8 +519,8 @@ void Camera3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fov", PROPERTY_HINT_RANGE, "1,179,0.1"), "set_fov", "get_fov");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size", PROPERTY_HINT_RANGE, "0.1,16384,0.01"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frustum_offset"), "set_frustum_offset", "get_frustum_offset");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "near", PROPERTY_HINT_EXP_RANGE, "0.001,8192,0.001,or_greater"), "set_znear", "get_znear");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "far", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01,or_greater"), "set_zfar", "get_zfar");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "near", PROPERTY_HINT_EXP_RANGE, "0.001,10,0.001,or_greater"), "set_znear", "get_znear");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "far", PROPERTY_HINT_EXP_RANGE, "0.01,4000,0.01,or_greater"), "set_zfar", "get_zfar");
BIND_ENUM_CONSTANT(PROJECTION_PERSPECTIVE);
BIND_ENUM_CONSTANT(PROJECTION_ORTHOGONAL);
@@ -662,7 +662,7 @@ Camera3D::Camera3D() {
viewport = nullptr;
force_change = false;
mode = PROJECTION_PERSPECTIVE;
- set_perspective(75.0, 0.05, 100.0);
+ set_perspective(75.0, 0.05, 4000.0);
keep_aspect = KEEP_HEIGHT;
layers = 0xfffff;
v_offset = 0;
diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp
index f25a64c567..ae6bbad8bf 100644
--- a/scene/3d/path_3d.cpp
+++ b/scene/3d/path_3d.cpp
@@ -94,10 +94,6 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) {
return;
}
- if (delta_offset == 0) {
- return;
- }
-
float bl = c->get_baked_length();
if (bl == 0.0) {
return;
@@ -156,7 +152,7 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) {
t.origin = pos;
- if (p_update_xyz_rot) { // Only update rotation if some parameter has changed - i.e. not on addition to scene tree
+ if (p_update_xyz_rot && delta_offset != 0) { // Only update rotation if some parameter has changed - i.e. not on addition to scene tree.
Vector3 t_prev = (pos - c->interpolate_baked(offset - delta_offset, cubic)).normalized();
Vector3 t_cur = (c->interpolate_baked(offset + delta_offset, cubic) - pos).normalized();
diff --git a/scene/3d/physics_joint_3d.cpp b/scene/3d/physics_joint_3d.cpp
index ab9cdb9fd8..06de5ad0ae 100644
--- a/scene/3d/physics_joint_3d.cpp
+++ b/scene/3d/physics_joint_3d.cpp
@@ -710,9 +710,6 @@ void Generic6DOFJoint3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_flag_z", "flag", "value"), &Generic6DOFJoint3D::set_flag_z);
ClassDB::bind_method(D_METHOD("get_flag_z", "flag"), &Generic6DOFJoint3D::get_flag_z);
- ClassDB::bind_method(D_METHOD("set_precision", "precision"), &Generic6DOFJoint3D::set_precision);
- ClassDB::bind_method(D_METHOD("get_precision"), &Generic6DOFJoint3D::get_precision);
-
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_limit_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_LINEAR_LIMIT);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_x/upper_distance"), "set_param_x", "get_param_x", PARAM_LINEAR_UPPER_LIMIT);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_x/lower_distance"), "set_param_x", "get_param_x", PARAM_LINEAR_LOWER_LIMIT);
@@ -801,8 +798,6 @@ void Generic6DOFJoint3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_z/damping"), "set_param_z", "get_param_z", PARAM_ANGULAR_SPRING_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_z/equilibrium_point"), "set_param_z", "get_param_z", PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "precision", PROPERTY_HINT_RANGE, "1,99999,1"), "set_precision", "get_precision");
-
BIND_ENUM_CONSTANT(PARAM_LINEAR_LOWER_LIMIT);
BIND_ENUM_CONSTANT(PARAM_LINEAR_UPPER_LIMIT);
BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_SOFTNESS);
@@ -921,14 +916,6 @@ bool Generic6DOFJoint3D::get_flag_z(Flag p_flag) const {
return flags_z[p_flag];
}
-void Generic6DOFJoint3D::set_precision(int p_precision) {
- precision = p_precision;
-
- PhysicsServer3D::get_singleton()->generic_6dof_joint_set_precision(
- get_joint(),
- precision);
-}
-
RID Generic6DOFJoint3D::_configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
Transform gt = get_global_transform();
//Vector3 cone_twistpos = gt.origin;
diff --git a/scene/3d/physics_joint_3d.h b/scene/3d/physics_joint_3d.h
index a65f6db3bf..250ae8bf52 100644
--- a/scene/3d/physics_joint_3d.h
+++ b/scene/3d/physics_joint_3d.h
@@ -300,8 +300,6 @@ protected:
float params_z[PARAM_MAX];
bool flags_z[FLAG_MAX];
- int precision = 1;
-
virtual RID _configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) override;
static void _bind_methods();
@@ -324,11 +322,6 @@ public:
void set_flag_z(Flag p_flag, bool p_enabled);
bool get_flag_z(Flag p_flag) const;
- void set_precision(int p_precision);
- int get_precision() const {
- return precision;
- }
-
Generic6DOFJoint3D();
};
diff --git a/scene/3d/proximity_group_3d.cpp b/scene/3d/proximity_group_3d.cpp
index 1a0677c603..7e25255885 100644
--- a/scene/3d/proximity_group_3d.cpp
+++ b/scene/3d/proximity_group_3d.cpp
@@ -32,7 +32,7 @@
#include "core/math/math_funcs.h"
-void ProximityGroup3D::clear_groups() {
+void ProximityGroup3D::_clear_groups() {
Map<StringName, uint32_t>::Element *E;
{
@@ -43,21 +43,21 @@ void ProximityGroup3D::clear_groups() {
while (E && num < size) {
if (E->get() != group_version) {
remove_list[num++] = E->key();
- };
+ }
E = E->next();
- };
+ }
for (int i = 0; i < num; i++) {
groups.erase(remove_list[i]);
- };
- };
+ }
+ }
if (E) {
- clear_groups(); // call until we go through the whole list
- };
-};
+ _clear_groups(); // call until we go through the whole list
+ }
+}
-void ProximityGroup3D::update_groups() {
+void ProximityGroup3D::_update_groups() {
if (grid_radius == Vector3(0, 0, 0)) {
return;
}
@@ -68,20 +68,20 @@ void ProximityGroup3D::update_groups() {
Vector3 vcell = pos / cell_size;
int cell[3] = { Math::fast_ftoi(vcell.x), Math::fast_ftoi(vcell.y), Math::fast_ftoi(vcell.z) };
- add_groups(cell, group_name, 0);
+ _add_groups(cell, group_name, 0);
- clear_groups();
-};
+ _clear_groups();
+}
-void ProximityGroup3D::add_groups(int *p_cell, String p_base, int p_depth) {
+void ProximityGroup3D::_add_groups(int *p_cell, String p_base, int p_depth) {
p_base = p_base + "|";
if (grid_radius[p_depth] == 0) {
if (p_depth == 2) {
_new_group(p_base);
} else {
- add_groups(p_cell, p_base, p_depth + 1);
- };
- };
+ _add_groups(p_cell, p_base, p_depth + 1);
+ }
+ }
int start = p_cell[p_depth] - grid_radius[p_depth];
int end = p_cell[p_depth] + grid_radius[p_depth];
@@ -91,72 +91,72 @@ void ProximityGroup3D::add_groups(int *p_cell, String p_base, int p_depth) {
if (p_depth == 2) {
_new_group(gname);
} else {
- add_groups(p_cell, gname, p_depth + 1);
- };
- };
-};
+ _add_groups(p_cell, gname, p_depth + 1);
+ }
+ }
+}
void ProximityGroup3D::_new_group(StringName p_name) {
const Map<StringName, uint32_t>::Element *E = groups.find(p_name);
if (!E) {
add_to_group(p_name);
- };
+ }
groups[p_name] = group_version;
-};
+}
void ProximityGroup3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_EXIT_TREE:
++group_version;
- clear_groups();
+ _clear_groups();
break;
case NOTIFICATION_TRANSFORM_CHANGED:
- update_groups();
+ _update_groups();
break;
- };
-};
+ }
+}
-void ProximityGroup3D::broadcast(String p_name, Variant p_params) {
+void ProximityGroup3D::broadcast(String p_method, Variant p_parameters) {
Map<StringName, uint32_t>::Element *E;
E = groups.front();
while (E) {
- get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFAULT, E->key(), "_proximity_group_broadcast", p_name, p_params);
+ get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFAULT, E->key(), "_proximity_group_broadcast", p_method, p_parameters);
E = E->next();
- };
-};
+ }
+}
-void ProximityGroup3D::_proximity_group_broadcast(String p_name, Variant p_params) {
+void ProximityGroup3D::_proximity_group_broadcast(String p_method, Variant p_parameters) {
if (dispatch_mode == MODE_PROXY) {
- get_parent()->call(p_name, p_params);
+ get_parent()->call(p_method, p_parameters);
} else {
- emit_signal("broadcast", p_name, p_params);
- };
-};
+ emit_signal("broadcast", p_method, p_parameters);
+ }
+}
void ProximityGroup3D::set_group_name(const String &p_group_name) {
group_name = p_group_name;
-};
+}
String ProximityGroup3D::get_group_name() const {
return group_name;
-};
+}
void ProximityGroup3D::set_dispatch_mode(DispatchMode p_mode) {
dispatch_mode = p_mode;
-};
+}
ProximityGroup3D::DispatchMode ProximityGroup3D::get_dispatch_mode() const {
return dispatch_mode;
-};
+}
void ProximityGroup3D::set_grid_radius(const Vector3 &p_radius) {
grid_radius = p_radius;
-};
+}
Vector3 ProximityGroup3D::get_grid_radius() const {
return grid_radius;
-};
+}
void ProximityGroup3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_group_name", "name"), &ProximityGroup3D::set_group_name);
@@ -165,19 +165,21 @@ void ProximityGroup3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_dispatch_mode"), &ProximityGroup3D::get_dispatch_mode);
ClassDB::bind_method(D_METHOD("set_grid_radius", "radius"), &ProximityGroup3D::set_grid_radius);
ClassDB::bind_method(D_METHOD("get_grid_radius"), &ProximityGroup3D::get_grid_radius);
- ClassDB::bind_method(D_METHOD("broadcast", "name", "parameters"), &ProximityGroup3D::broadcast);
- ClassDB::bind_method(D_METHOD("_proximity_group_broadcast", "name", "params"), &ProximityGroup3D::_proximity_group_broadcast);
+
+ ClassDB::bind_method(D_METHOD("broadcast", "method", "parameters"), &ProximityGroup3D::broadcast);
+
+ ClassDB::bind_method(D_METHOD("_proximity_group_broadcast", "method", "parameters"), &ProximityGroup3D::_proximity_group_broadcast);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "group_name"), "set_group_name", "get_group_name");
ADD_PROPERTY(PropertyInfo(Variant::INT, "dispatch_mode", PROPERTY_HINT_ENUM, "Proxy,Signal"), "set_dispatch_mode", "get_dispatch_mode");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "grid_radius"), "set_grid_radius", "get_grid_radius");
- ADD_SIGNAL(MethodInfo("broadcast", PropertyInfo(Variant::STRING, "group_name"), PropertyInfo(Variant::ARRAY, "parameters")));
+ ADD_SIGNAL(MethodInfo("broadcast", PropertyInfo(Variant::STRING, "method"), PropertyInfo(Variant::ARRAY, "parameters")));
BIND_ENUM_CONSTANT(MODE_PROXY);
BIND_ENUM_CONSTANT(MODE_SIGNAL);
-};
+}
ProximityGroup3D::ProximityGroup3D() {
set_notify_transform(true);
-};
+}
diff --git a/scene/3d/proximity_group_3d.h b/scene/3d/proximity_group_3d.h
index dd3a2f0a87..d52843e9a2 100644
--- a/scene/3d/proximity_group_3d.h
+++ b/scene/3d/proximity_group_3d.h
@@ -35,7 +35,6 @@
class ProximityGroup3D : public Node3D {
GDCLASS(ProximityGroup3D, Node3D);
- OBJ_CATEGORY("3D");
public:
enum DispatchMode {
@@ -43,25 +42,25 @@ public:
MODE_SIGNAL,
};
-public:
- void clear_groups();
- void update_groups();
-
- void _notification(int p_what);
-
- DispatchMode dispatch_mode = MODE_PROXY;
-
+private:
Map<StringName, uint32_t> groups;
+
String group_name;
+ DispatchMode dispatch_mode = MODE_PROXY;
+ Vector3 grid_radius = Vector3(1, 1, 1);
float cell_size = 1.0;
- Vector3 grid_radius = Vector3(1, 1, 1);
uint32_t group_version = 0;
- void add_groups(int *p_cell, String p_base, int p_depth);
+ void _clear_groups();
+ void _update_groups();
+ void _add_groups(int *p_cell, String p_base, int p_depth);
void _new_group(StringName p_name);
- void _proximity_group_broadcast(String p_name, Variant p_params);
+ void _proximity_group_broadcast(String p_method, Variant p_parameters);
+
+protected:
+ void _notification(int p_what);
static void _bind_methods();
@@ -75,7 +74,7 @@ public:
void set_grid_radius(const Vector3 &p_radius);
Vector3 get_grid_radius() const;
- void broadcast(String p_name, Variant p_params);
+ void broadcast(String p_method, Variant p_parameters);
ProximityGroup3D();
~ProximityGroup3D() {}
@@ -83,4 +82,4 @@ public:
VARIANT_ENUM_CAST(ProximityGroup3D::DispatchMode);
-#endif
+#endif // PROXIMITY_GROUP_H
diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp
index c7948395d3..c82ed423a7 100644
--- a/scene/3d/reflection_probe.cpp
+++ b/scene/3d/reflection_probe.cpp
@@ -76,6 +76,15 @@ float ReflectionProbe::get_max_distance() const {
return max_distance;
}
+void ReflectionProbe::set_lod_threshold(float p_pixels) {
+ lod_threshold = p_pixels;
+ RS::get_singleton()->reflection_probe_set_lod_threshold(probe, p_pixels);
+}
+
+float ReflectionProbe::get_lod_threshold() const {
+ return lod_threshold;
+}
+
void ReflectionProbe::set_extents(const Vector3 &p_extents) {
extents = p_extents;
@@ -199,6 +208,9 @@ void ReflectionProbe::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_max_distance", "max_distance"), &ReflectionProbe::set_max_distance);
ClassDB::bind_method(D_METHOD("get_max_distance"), &ReflectionProbe::get_max_distance);
+ ClassDB::bind_method(D_METHOD("set_lod_threshold", "ratio"), &ReflectionProbe::set_lod_threshold);
+ ClassDB::bind_method(D_METHOD("get_lod_threshold"), &ReflectionProbe::get_lod_threshold);
+
ClassDB::bind_method(D_METHOD("set_extents", "extents"), &ReflectionProbe::set_extents);
ClassDB::bind_method(D_METHOD("get_extents"), &ReflectionProbe::get_extents);
@@ -229,6 +241,7 @@ void ReflectionProbe::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior"), "set_as_interior", "is_set_as_interior");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enable_shadows"), "set_enable_shadows", "are_shadows_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask");
+ 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");
@@ -256,6 +269,7 @@ ReflectionProbe::ReflectionProbe() {
enable_shadows = false;
cull_mask = (1 << 20) - 1;
update_mode = UPDATE_ONCE;
+ lod_threshold = 1.0;
probe = RenderingServer::get_singleton()->reflection_probe_create();
RS::get_singleton()->instance_set_base(get_instance(), probe);
diff --git a/scene/3d/reflection_probe.h b/scene/3d/reflection_probe.h
index 56177d0f95..4bff2f8bf9 100644
--- a/scene/3d/reflection_probe.h
+++ b/scene/3d/reflection_probe.h
@@ -63,6 +63,7 @@ private:
AmbientMode ambient_mode;
Color ambient_color;
float ambient_color_energy;
+ float lod_threshold;
uint32_t cull_mask;
UpdateMode update_mode;
@@ -90,6 +91,9 @@ public:
void set_max_distance(float p_distance);
float get_max_distance() const;
+ void set_lod_threshold(float p_pixels);
+ float get_lod_threshold() const;
+
void set_extents(const Vector3 &p_extents);
Vector3 get_extents() const;
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index a1c498e8ab..0b70b0f920 100644
--- a/scene/3d/visual_instance_3d.cpp
+++ b/scene/3d/visual_instance_3d.cpp
@@ -278,6 +278,16 @@ float GeometryInstance3D::get_extra_cull_margin() const {
return extra_cull_margin;
}
+void GeometryInstance3D::set_lod_bias(float p_bias) {
+ ERR_FAIL_COND(p_bias < 0.0);
+ lod_bias = p_bias;
+ RS::get_singleton()->instance_geometry_set_lod_bias(get_instance(), lod_bias);
+}
+
+float GeometryInstance3D::get_lod_bias() const {
+ return lod_bias;
+}
+
void GeometryInstance3D::set_shader_instance_uniform(const StringName &p_uniform, const Variant &p_value) {
if (p_value.get_type() == Variant::NIL) {
Variant def_value = RS::get_singleton()->instance_geometry_get_shader_parameter_default_value(get_instance(), p_uniform);
@@ -361,6 +371,9 @@ 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", "p_bias"), &GeometryInstance3D::set_lod_bias);
+ ClassDB::bind_method(D_METHOD("get_lod_bias"), &GeometryInstance3D::get_lod_bias);
+
ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &GeometryInstance3D::set_custom_aabb);
ClassDB::bind_method(D_METHOD("get_aabb"), &GeometryInstance3D::get_aabb);
@@ -369,6 +382,7 @@ void GeometryInstance3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material_override", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,StandardMaterial3D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE), "set_material_override", "get_material_override");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cast_shadow", PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"), "set_cast_shadows_setting", "get_cast_shadows_setting");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "extra_cull_margin", PROPERTY_HINT_RANGE, "0,16384,0.01"), "set_extra_cull_margin", "get_extra_cull_margin");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lod_bias", PROPERTY_HINT_RANGE, "0.001,128,0.001"), "set_lod_bias", "get_lod_bias");
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");
@@ -403,6 +417,8 @@ GeometryInstance3D::GeometryInstance3D() {
lod_min_hysteresis = 0;
lod_max_hysteresis = 0;
+ lod_bias = 1.0;
+
gi_mode = GI_MODE_DISABLED;
lightmap_scale = LIGHTMAP_SCALE_1X;
diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h
index 51bcb411da..0810b7b4ce 100644
--- a/scene/3d/visual_instance_3d.h
+++ b/scene/3d/visual_instance_3d.h
@@ -112,6 +112,8 @@ private:
float lod_min_hysteresis;
float lod_max_hysteresis;
+ float lod_bias;
+
mutable HashMap<StringName, Variant> instance_uniforms;
mutable HashMap<StringName, StringName> instance_uniform_property_remap;
@@ -151,6 +153,9 @@ public:
void set_extra_cull_margin(float p_margin);
float get_extra_cull_margin() const;
+ void set_lod_bias(float p_bias);
+ float get_lod_bias() const;
+
void set_gi_mode(GIMode p_mode);
GIMode get_gi_mode() const;
diff --git a/scene/SCsub b/scene/SCsub
index f9fc00f3f2..ccd2bab8ff 100644
--- a/scene/SCsub
+++ b/scene/SCsub
@@ -4,24 +4,9 @@ Import("env")
env.scene_sources = []
-# Thirdparty code
-thirdparty_dir = "#thirdparty/misc/"
-thirdparty_sources = [
- # C++ sources
- "easing_equations.cpp",
- # C sources
- "mikktspace.c",
-]
-thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
-
-env_thirdparty = env.Clone()
-env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.scene_sources, thirdparty_sources)
-
-# Godot's own sources
+# Godot source files
env.add_source_files(env.scene_sources, "*.cpp")
-
# Chain load SCsubs
SConscript("main/SCsub")
SConscript("gui/SCsub")
@@ -32,7 +17,6 @@ SConscript("audio/SCsub")
SConscript("resources/SCsub")
SConscript("debugger/SCsub")
-
# Build it all as a library
lib = env.add_library("scene", env.scene_sources)
env.Prepend(LIBS=[lib])
diff --git a/scene/animation/SCsub b/scene/animation/SCsub
index fc61250247..cc33a5af84 100644
--- a/scene/animation/SCsub
+++ b/scene/animation/SCsub
@@ -2,4 +2,23 @@
Import("env")
-env.add_source_files(env.scene_sources, "*.cpp")
+# Thirdparty code
+
+thirdparty_obj = []
+
+thirdparty_sources = "#thirdparty/misc/easing_equations.cpp"
+
+env_thirdparty = env.Clone()
+env_thirdparty.disable_warnings()
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.scene_sources += thirdparty_obj
+
+# Godot source files
+
+scene_obj = []
+
+env.add_source_files(scene_obj, "*.cpp")
+env.scene_sources += scene_obj
+
+# Needed to force rebuilding the scene files when the thirdparty code is updated.
+env.Depends(scene_obj, thirdparty_obj)
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index e9e17148d6..159ccae130 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -36,6 +36,7 @@
#include "servers/audio/audio_stream.h"
#ifdef TOOLS_ENABLED
+#include "editor/editor_node.h"
#include "editor/editor_settings.h"
#include "scene/2d/skeleton_2d.h"
@@ -53,6 +54,21 @@ void AnimatedValuesBackup::update_skeletons() {
}
}
}
+
+void AnimatedValuesBackup::restore() const {
+ for (int i = 0; i < entries.size(); i++) {
+ const AnimatedValuesBackup::Entry *entry = &entries[i];
+ if (entry->bone_idx == -1) {
+ entry->object->set_indexed(entry->subpath, entry->value);
+ } else {
+ Object::cast_to<Skeleton3D>(entry->object)->set_bone_pose(entry->bone_idx, entry->value);
+ }
+ }
+}
+
+void AnimatedValuesBackup::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("restore"), &AnimatedValuesBackup::restore);
+}
#endif
bool AnimationPlayer::_set(const StringName &p_name, const Variant &p_value) {
@@ -1379,6 +1395,14 @@ String AnimationPlayer::get_autoplay() const {
return autoplay;
}
+void AnimationPlayer::set_reset_on_save_enabled(bool p_enabled) {
+ reset_on_save = p_enabled;
+}
+
+bool AnimationPlayer::is_reset_on_save_enabled() const {
+ return reset_on_save;
+}
+
void AnimationPlayer::set_animation_process_mode(AnimationProcessMode p_mode) {
if (animation_process_mode == p_mode) {
return;
@@ -1473,15 +1497,15 @@ void AnimationPlayer::get_argument_options(const StringName &p_function, int p_i
}
#ifdef TOOLS_ENABLED
-AnimatedValuesBackup AnimationPlayer::backup_animated_values() {
+Ref<AnimatedValuesBackup> AnimationPlayer::backup_animated_values() {
+ Ref<AnimatedValuesBackup> backup;
if (!playback.current.from) {
- return AnimatedValuesBackup();
+ return backup;
}
_ensure_node_caches(playback.current.from);
- AnimatedValuesBackup backup;
-
+ backup.instance();
for (int i = 0; i < playback.current.from->node_cache.size(); i++) {
TrackNodeCache *nc = playback.current.from->node_cache[i];
if (!nc) {
@@ -1497,7 +1521,7 @@ AnimatedValuesBackup AnimationPlayer::backup_animated_values() {
entry.object = nc->skeleton;
entry.bone_idx = nc->bone_idx;
entry.value = nc->skeleton->get_bone_pose(nc->bone_idx);
- backup.entries.push_back(entry);
+ backup->entries.push_back(entry);
} else {
if (nc->spatial) {
AnimatedValuesBackup::Entry entry;
@@ -1505,7 +1529,7 @@ AnimatedValuesBackup AnimationPlayer::backup_animated_values() {
entry.subpath.push_back("transform");
entry.value = nc->spatial->get_transform();
entry.bone_idx = -1;
- backup.entries.push_back(entry);
+ backup->entries.push_back(entry);
} else {
for (Map<StringName, TrackNodeCache::PropertyAnim>::Element *E = nc->property_anim.front(); E; E = E->next()) {
AnimatedValuesBackup::Entry entry;
@@ -1515,7 +1539,7 @@ AnimatedValuesBackup AnimationPlayer::backup_animated_values() {
entry.value = E->value().object->get_indexed(E->value().subpath, &valid);
entry.bone_idx = -1;
if (valid) {
- backup.entries.push_back(entry);
+ backup->entries.push_back(entry);
}
}
}
@@ -1525,15 +1549,40 @@ AnimatedValuesBackup AnimationPlayer::backup_animated_values() {
return backup;
}
-void AnimationPlayer::restore_animated_values(const AnimatedValuesBackup &p_backup) {
- for (int i = 0; i < p_backup.entries.size(); i++) {
- const AnimatedValuesBackup::Entry *entry = &p_backup.entries[i];
- if (entry->bone_idx == -1) {
- entry->object->set_indexed(entry->subpath, entry->value);
- } else {
- Object::cast_to<Skeleton3D>(entry->object)->set_bone_pose(entry->bone_idx, entry->value);
- }
+Ref<AnimatedValuesBackup> AnimationPlayer::apply_reset(bool p_user_initiated) {
+ ERR_FAIL_COND_V(!can_apply_reset(), Ref<AnimatedValuesBackup>());
+
+ Ref<Animation> reset_anim = animation_set["RESET"].animation;
+ ERR_FAIL_COND_V(reset_anim.is_null(), Ref<AnimatedValuesBackup>());
+
+ Node *root_node = get_node_or_null(root);
+ ERR_FAIL_COND_V(!root_node, Ref<AnimatedValuesBackup>());
+
+ AnimationPlayer *aux_player = memnew(AnimationPlayer);
+ EditorNode::get_singleton()->add_child(aux_player);
+ aux_player->set_root(aux_player->get_path_to(root_node));
+ aux_player->add_animation("RESET", reset_anim);
+ aux_player->set_assigned_animation("RESET");
+ Ref<AnimatedValuesBackup> old_values = aux_player->backup_animated_values();
+ aux_player->seek(0.0f, true);
+ aux_player->queue_delete();
+
+ if (p_user_initiated) {
+ Ref<AnimatedValuesBackup> new_values = aux_player->backup_animated_values();
+ old_values->restore();
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Anim Apply Reset"));
+ ur->add_do_method(new_values.ptr(), "restore");
+ ur->add_undo_method(old_values.ptr(), "restore");
+ ur->commit_action();
}
+
+ return old_values;
+}
+
+bool AnimationPlayer::can_apply_reset() const {
+ return has_animation("RESET") && playback.assigned != StringName("RESET");
}
#endif
@@ -1577,6 +1626,9 @@ void AnimationPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_autoplay", "name"), &AnimationPlayer::set_autoplay);
ClassDB::bind_method(D_METHOD("get_autoplay"), &AnimationPlayer::get_autoplay);
+ ClassDB::bind_method(D_METHOD("set_reset_on_save_enabled", "enabled"), &AnimationPlayer::set_reset_on_save_enabled);
+ ClassDB::bind_method(D_METHOD("is_reset_on_save_enabled"), &AnimationPlayer::is_reset_on_save_enabled);
+
ClassDB::bind_method(D_METHOD("set_root", "path"), &AnimationPlayer::set_root);
ClassDB::bind_method(D_METHOD("get_root"), &AnimationPlayer::get_root);
@@ -1600,6 +1652,7 @@ void AnimationPlayer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "current_animation", PROPERTY_HINT_ENUM, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ANIMATE_AS_TRIGGER), "set_current_animation", "get_current_animation");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "assigned_animation", PROPERTY_HINT_NONE, "", 0), "set_assigned_animation", "get_assigned_animation");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "autoplay", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_autoplay", "get_autoplay");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reset_on_save", PROPERTY_HINT_NONE, ""), "set_reset_on_save_enabled", "is_reset_on_save_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "current_animation_length", PROPERTY_HINT_NONE, "", 0), "", "get_current_animation_length");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "current_animation_position", PROPERTY_HINT_NONE, "", 0), "", "get_current_animation_position");
@@ -1631,6 +1684,7 @@ AnimationPlayer::AnimationPlayer() {
speed_scale = 1;
end_reached = false;
end_notify = false;
+ reset_on_save = true;
animation_process_mode = ANIMATION_PROCESS_IDLE;
method_call_mode = ANIMATION_METHOD_CALL_DEFERRED;
processing = false;
diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h
index dbce5643c7..7f0d5630e1 100644
--- a/scene/animation/animation_player.h
+++ b/scene/animation/animation_player.h
@@ -37,8 +37,9 @@
#include "scene/resources/animation.h"
#ifdef TOOLS_ENABLED
-// To save/restore animated values
-class AnimatedValuesBackup {
+class AnimatedValuesBackup : public Reference {
+ GDCLASS(AnimatedValuesBackup, Reference);
+
struct Entry {
Object *object;
Vector<StringName> subpath; // Unused if bone
@@ -49,8 +50,12 @@ class AnimatedValuesBackup {
friend class AnimationPlayer;
+protected:
+ static void _bind_methods();
+
public:
void update_skeletons();
+ void restore() const;
};
#endif
@@ -215,6 +220,7 @@ private:
bool end_notify;
String autoplay;
+ bool reset_on_save;
AnimationProcessMode animation_process_mode;
AnimationMethodCallMode method_call_mode;
bool processing;
@@ -304,6 +310,9 @@ public:
void set_autoplay(const String &p_name);
String get_autoplay() const;
+ void set_reset_on_save_enabled(bool p_enabled);
+ bool is_reset_on_save_enabled() const;
+
void set_animation_process_mode(AnimationProcessMode p_mode);
AnimationProcessMode get_animation_process_mode() const;
@@ -325,9 +334,9 @@ public:
void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
#ifdef TOOLS_ENABLED
- // These may be interesting for games, but are too dangerous for general use
- AnimatedValuesBackup backup_animated_values();
- void restore_animated_values(const AnimatedValuesBackup &p_backup);
+ Ref<AnimatedValuesBackup> backup_animated_values();
+ Ref<AnimatedValuesBackup> apply_reset(bool p_user_initiated = false);
+ bool can_apply_reset() const;
#endif
AnimationPlayer();
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index b471bb9d4e..bdbb0d4684 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -2206,14 +2206,14 @@ String Control::_get_tooltip() const {
return data.tooltip;
}
-void Control::set_focus_neighbour(Margin p_margin, const NodePath &p_neighbour) {
+void Control::set_focus_neighbor(Margin p_margin, const NodePath &p_neighbor) {
ERR_FAIL_INDEX((int)p_margin, 4);
- data.focus_neighbour[p_margin] = p_neighbour;
+ data.focus_neighbor[p_margin] = p_neighbor;
}
-NodePath Control::get_focus_neighbour(Margin p_margin) const {
+NodePath Control::get_focus_neighbor(Margin p_margin) const {
ERR_FAIL_INDEX_V((int)p_margin, 4, NodePath());
- return data.focus_neighbour[p_margin];
+ return data.focus_neighbor[p_margin];
}
void Control::set_focus_next(const NodePath &p_next) {
@@ -2232,17 +2232,17 @@ NodePath Control::get_focus_previous() const {
return data.focus_prev;
}
-#define MAX_NEIGHBOUR_SEARCH_COUNT 512
+#define MAX_NEIGHBOR_SEARCH_COUNT 512
-Control *Control::_get_focus_neighbour(Margin p_margin, int p_count) {
+Control *Control::_get_focus_neighbor(Margin p_margin, int p_count) {
ERR_FAIL_INDEX_V((int)p_margin, 4, nullptr);
- if (p_count >= MAX_NEIGHBOUR_SEARCH_COUNT) {
+ if (p_count >= MAX_NEIGHBOR_SEARCH_COUNT) {
return nullptr;
}
- if (!data.focus_neighbour[p_margin].is_empty()) {
+ if (!data.focus_neighbor[p_margin].is_empty()) {
Control *c = nullptr;
- Node *n = get_node(data.focus_neighbour[p_margin]);
+ Node *n = get_node(data.focus_neighbor[p_margin]);
if (n) {
c = Object::cast_to<Control>(n);
ERR_FAIL_COND_V_MSG(!c, nullptr, "Neighbor focus node is not a control: " + n->get_name() + ".");
@@ -2260,7 +2260,7 @@ Control *Control::_get_focus_neighbour(Margin p_margin, int p_count) {
return c;
}
- c = c->_get_focus_neighbour(p_margin, p_count + 1);
+ c = c->_get_focus_neighbor(p_margin, p_count + 1);
return c;
}
@@ -2310,12 +2310,12 @@ Control *Control::_get_focus_neighbour(Margin p_margin, int p_count) {
return nullptr;
}
- _window_find_focus_neighbour(vdir, base, points, maxd, dist, &result);
+ _window_find_focus_neighbor(vdir, base, points, maxd, dist, &result);
return result;
}
-void Control::_window_find_focus_neighbour(const Vector2 &p_dir, Node *p_at, const Point2 *p_points, float p_min, float &r_closest_dist, Control **r_closest) {
+void Control::_window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, const Point2 *p_points, float p_min, float &r_closest_dist, Control **r_closest) {
if (Object::cast_to<Viewport>(p_at)) {
return; //bye
}
@@ -2368,7 +2368,7 @@ void Control::_window_find_focus_neighbour(const Vector2 &p_dir, Node *p_at, con
if (childc && childc->data.RI) {
continue; //subwindow, ignore
}
- _window_find_focus_neighbour(p_dir, p_at->get_child(i), p_points, p_min, r_closest_dist, r_closest);
+ _window_find_focus_neighbor(p_dir, p_at->get_child(i), p_points, p_min, r_closest_dist, r_closest);
}
}
@@ -2843,8 +2843,8 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_default_cursor_shape"), &Control::get_default_cursor_shape);
ClassDB::bind_method(D_METHOD("get_cursor_shape", "position"), &Control::get_cursor_shape, DEFVAL(Point2()));
- ClassDB::bind_method(D_METHOD("set_focus_neighbour", "margin", "neighbour"), &Control::set_focus_neighbour);
- ClassDB::bind_method(D_METHOD("get_focus_neighbour", "margin"), &Control::get_focus_neighbour);
+ ClassDB::bind_method(D_METHOD("set_focus_neighbor", "margin", "neighbor"), &Control::set_focus_neighbor);
+ ClassDB::bind_method(D_METHOD("get_focus_neighbor", "margin"), &Control::get_focus_neighbor);
ClassDB::bind_method(D_METHOD("set_focus_next", "next"), &Control::set_focus_next);
ClassDB::bind_method(D_METHOD("get_focus_next"), &Control::get_focus_next);
@@ -2922,10 +2922,10 @@ void Control::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "hint_tooltip", PROPERTY_HINT_MULTILINE_TEXT), "set_tooltip", "_get_tooltip");
ADD_GROUP("Focus", "focus_");
- ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_left", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_top", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_right", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_bottom", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_BOTTOM);
+ ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbor_left", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbor", "get_focus_neighbor", MARGIN_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbor_top", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbor", "get_focus_neighbor", MARGIN_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbor_right", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbor", "get_focus_neighbor", MARGIN_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbor_bottom", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbor", "get_focus_neighbor", MARGIN_BOTTOM);
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "focus_next", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_next", "get_focus_next");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "focus_previous", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_previous", "get_focus_previous");
ADD_PROPERTY(PropertyInfo(Variant::INT, "focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_focus_mode", "get_focus_mode");
diff --git a/scene/gui/control.h b/scene/gui/control.h
index 8496729f05..d314c7357b 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -207,7 +207,7 @@ private:
CanvasItem *parent_canvas_item;
- NodePath focus_neighbour[4];
+ NodePath focus_neighbor[4];
NodePath focus_next;
NodePath focus_prev;
@@ -223,8 +223,8 @@ private:
// used internally
Control *_find_control_at_pos(CanvasItem *p_node, const Point2 &p_pos, const Transform2D &p_xform, Transform2D &r_inv_xform);
- void _window_find_focus_neighbour(const Vector2 &p_dir, Node *p_at, const Point2 *p_points, float p_min, float &r_closest_dist, Control **r_closest);
- Control *_get_focus_neighbour(Margin p_margin, int p_count = 0);
+ void _window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, const Point2 *p_points, float p_min, float &r_closest_dist, Control **r_closest);
+ Control *_get_focus_neighbor(Margin p_margin, int p_count = 0);
void _set_anchor(Margin p_margin, float p_anchor);
void _set_position(const Point2 &p_point);
@@ -436,8 +436,8 @@ public:
Control *find_next_valid_focus() const;
Control *find_prev_valid_focus() const;
- void set_focus_neighbour(Margin p_margin, const NodePath &p_neighbour);
- NodePath get_focus_neighbour(Margin p_margin) const;
+ void set_focus_neighbor(Margin p_margin, const NodePath &p_neighbor);
+ NodePath get_focus_neighbor(Margin p_margin) const;
void set_focus_next(const NodePath &p_next);
NodePath get_focus_next() const;
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index 4f59f4a36a..4e80498108 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -60,7 +60,7 @@ void AcceptDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
if (is_visible()) {
- get_ok()->grab_focus();
+ get_ok_button()->grab_focus();
_update_child_rects();
parent_visible = get_parent_visible_window();
if (parent_visible) {
@@ -253,7 +253,7 @@ Button *AcceptDialog::add_button(const String &p_text, bool p_right, const Strin
return button;
}
-Button *AcceptDialog::add_cancel(const String &p_cancel) {
+Button *AcceptDialog::add_cancel_button(const String &p_cancel) {
String c = p_cancel;
if (p_cancel == "") {
c = RTR("Cancel");
@@ -264,12 +264,12 @@ Button *AcceptDialog::add_cancel(const String &p_cancel) {
}
void AcceptDialog::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_ok"), &AcceptDialog::get_ok);
+ ClassDB::bind_method(D_METHOD("get_ok_button"), &AcceptDialog::get_ok_button);
ClassDB::bind_method(D_METHOD("get_label"), &AcceptDialog::get_label);
ClassDB::bind_method(D_METHOD("set_hide_on_ok", "enabled"), &AcceptDialog::set_hide_on_ok);
ClassDB::bind_method(D_METHOD("get_hide_on_ok"), &AcceptDialog::get_hide_on_ok);
ClassDB::bind_method(D_METHOD("add_button", "text", "right", "action"), &AcceptDialog::add_button, DEFVAL(false), DEFVAL(""));
- ClassDB::bind_method(D_METHOD("add_cancel", "name"), &AcceptDialog::add_cancel);
+ ClassDB::bind_method(D_METHOD("add_cancel_button", "name"), &AcceptDialog::add_cancel_button);
ClassDB::bind_method(D_METHOD("register_text_enter", "line_edit"), &AcceptDialog::register_text_enter);
ClassDB::bind_method(D_METHOD("set_text", "text"), &AcceptDialog::set_text);
ClassDB::bind_method(D_METHOD("get_text"), &AcceptDialog::get_text);
@@ -337,10 +337,10 @@ AcceptDialog::~AcceptDialog() {
// ConfirmationDialog
void ConfirmationDialog::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_cancel"), &ConfirmationDialog::get_cancel);
+ ClassDB::bind_method(D_METHOD("get_cancel_button"), &ConfirmationDialog::get_cancel_button);
}
-Button *ConfirmationDialog::get_cancel() {
+Button *ConfirmationDialog::get_cancel_button() {
return cancel;
}
@@ -349,5 +349,5 @@ ConfirmationDialog::ConfirmationDialog() {
#ifdef TOOLS_ENABLED
set_min_size(Size2(200, 70) * EDSCALE);
#endif
- cancel = add_cancel();
+ cancel = add_cancel_button();
}
diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h
index de08685ce2..8f6e0e86f9 100644
--- a/scene/gui/dialogs.h
+++ b/scene/gui/dialogs.h
@@ -79,9 +79,9 @@ public:
void register_text_enter(Node *p_line_edit);
- Button *get_ok() { return ok; }
+ Button *get_ok_button() { return ok; }
Button *add_button(const String &p_text, bool p_right = false, const String &p_action = "");
- Button *add_cancel(const String &p_cancel = "");
+ Button *add_cancel_button(const String &p_cancel = "");
void set_hide_on_ok(bool p_hide);
bool get_hide_on_ok() const;
@@ -104,7 +104,7 @@ protected:
static void _bind_methods();
public:
- Button *get_cancel();
+ Button *get_cancel_button();
ConfirmationDialog();
};
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index eb3d5d5c6d..041b8ef174 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -324,15 +324,15 @@ void FileDialog::deselect_items() {
// And change get_ok title.
if (!tree->is_anything_selected()) {
- get_ok()->set_disabled(_is_open_should_be_disabled());
+ get_ok_button()->set_disabled(_is_open_should_be_disabled());
switch (mode) {
case FILE_MODE_OPEN_FILE:
case FILE_MODE_OPEN_FILES:
- get_ok()->set_text(RTR("Open"));
+ get_ok_button()->set_text(RTR("Open"));
break;
case FILE_MODE_OPEN_DIR:
- get_ok()->set_text(RTR("Select Current Folder"));
+ get_ok_button()->set_text(RTR("Select Current Folder"));
break;
case FILE_MODE_OPEN_ANY:
case FILE_MODE_SAVE_FILE:
@@ -356,10 +356,10 @@ void FileDialog::_tree_selected() {
if (!d["dir"]) {
file->set_text(d["name"]);
} else if (mode == FILE_MODE_OPEN_DIR) {
- get_ok()->set_text(RTR("Select This Folder"));
+ get_ok_button()->set_text(RTR("Select This Folder"));
}
- get_ok()->set_disabled(_is_open_should_be_disabled());
+ get_ok_button()->set_disabled(_is_open_should_be_disabled());
}
void FileDialog::_tree_item_activated() {
@@ -646,35 +646,35 @@ void FileDialog::set_file_mode(FileMode p_mode) {
mode = p_mode;
switch (mode) {
case FILE_MODE_OPEN_FILE:
- get_ok()->set_text(RTR("Open"));
+ get_ok_button()->set_text(RTR("Open"));
if (mode_overrides_title) {
set_title(RTR("Open a File"));
}
makedir->hide();
break;
case FILE_MODE_OPEN_FILES:
- get_ok()->set_text(RTR("Open"));
+ get_ok_button()->set_text(RTR("Open"));
if (mode_overrides_title) {
set_title(RTR("Open File(s)"));
}
makedir->hide();
break;
case FILE_MODE_OPEN_DIR:
- get_ok()->set_text(RTR("Select Current Folder"));
+ get_ok_button()->set_text(RTR("Select Current Folder"));
if (mode_overrides_title) {
set_title(RTR("Open a Directory"));
}
makedir->show();
break;
case FILE_MODE_OPEN_ANY:
- get_ok()->set_text(RTR("Open"));
+ get_ok_button()->set_text(RTR("Open"));
if (mode_overrides_title) {
set_title(RTR("Open a File or Directory"));
}
makedir->show();
break;
case FILE_MODE_SAVE_FILE:
- get_ok()->set_text(RTR("Save"));
+ get_ok_button()->set_text(RTR("Save"));
if (mode_overrides_title) {
set_title(RTR("Save a File"));
}
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 96810e8707..2bcc1890fe 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -31,6 +31,7 @@
#include "graph_edit.h"
#include "core/input/input.h"
+#include "core/math/math_funcs.h"
#include "core/os/keyboard.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
@@ -44,6 +45,9 @@
#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
+
bool GraphEditFilter::has_point(const Point2 &p_point) const {
return ge->_filter_input(p_point);
}
@@ -52,6 +56,141 @@ GraphEditFilter::GraphEditFilter(GraphEdit *p_edit) {
ge = p_edit;
}
+void GraphEditMinimap::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_gui_input"), &GraphEditMinimap::_gui_input);
+}
+
+GraphEditMinimap::GraphEditMinimap(GraphEdit *p_edit) {
+ ge = p_edit;
+
+ graph_proportions = Vector2(1, 1);
+ graph_padding = Vector2(0, 0);
+ camera_position = Vector2(100, 50);
+ camera_size = Vector2(200, 200);
+ minimap_padding = Vector2(MINIMAP_PADDING, MINIMAP_PADDING);
+ minimap_offset = minimap_padding + _convert_from_graph_position(graph_padding);
+
+ is_pressing = false;
+ is_resizing = false;
+}
+
+void GraphEditMinimap::update_minimap() {
+ Vector2 graph_offset = _get_graph_offset();
+ Vector2 graph_size = _get_graph_size();
+
+ camera_position = ge->get_scroll_ofs() - graph_offset;
+ camera_size = ge->get_size();
+
+ Vector2 render_size = _get_render_size();
+ float target_ratio = render_size.x / render_size.y;
+ float graph_ratio = graph_size.x / graph_size.y;
+
+ graph_proportions = graph_size;
+ graph_padding = Vector2(0, 0);
+ if (graph_ratio > target_ratio) {
+ graph_proportions.x = graph_size.x;
+ graph_proportions.y = graph_size.x / target_ratio;
+ graph_padding.y = Math::abs(graph_size.y - graph_proportions.y) / 2;
+ } else {
+ graph_proportions.x = graph_size.y * target_ratio;
+ graph_proportions.y = graph_size.y;
+ graph_padding.x = Math::abs(graph_size.x - graph_proportions.x) / 2;
+ }
+
+ // This centers minimap inside the minimap rectangle.
+ minimap_offset = minimap_padding + _convert_from_graph_position(graph_padding);
+}
+
+Rect2 GraphEditMinimap::get_camera_rect() {
+ Vector2 camera_center = _convert_from_graph_position(camera_position + camera_size / 2) + minimap_offset;
+ Vector2 camera_viewport = _convert_from_graph_position(camera_size);
+ Vector2 camera_position = (camera_center - camera_viewport / 2);
+ return Rect2(camera_position, camera_viewport);
+}
+
+Vector2 GraphEditMinimap::_get_render_size() {
+ if (!is_inside_tree()) {
+ return Vector2(0, 0);
+ }
+
+ return get_size() - 2 * minimap_padding;
+}
+
+Vector2 GraphEditMinimap::_get_graph_offset() {
+ return Vector2(ge->h_scroll->get_min(), ge->v_scroll->get_min());
+}
+
+Vector2 GraphEditMinimap::_get_graph_size() {
+ Vector2 graph_size = Vector2(ge->h_scroll->get_max(), ge->v_scroll->get_max()) - Vector2(ge->h_scroll->get_min(), ge->v_scroll->get_min());
+
+ if (graph_size.x == 0) {
+ graph_size.x = 1;
+ }
+ if (graph_size.y == 0) {
+ graph_size.y = 1;
+ }
+
+ return graph_size;
+}
+
+Vector2 GraphEditMinimap::_convert_from_graph_position(const Vector2 &p_position) {
+ Vector2 map_position = Vector2(0, 0);
+ Vector2 render_size = _get_render_size();
+
+ map_position.x = p_position.x * render_size.x / graph_proportions.x;
+ map_position.y = p_position.y * render_size.y / graph_proportions.y;
+
+ return map_position;
+}
+
+Vector2 GraphEditMinimap::_convert_to_graph_position(const Vector2 &p_position) {
+ Vector2 graph_position = Vector2(0, 0);
+ Vector2 render_size = _get_render_size();
+
+ graph_position.x = p_position.x * graph_proportions.x / render_size.x;
+ graph_position.y = p_position.y * graph_proportions.y / render_size.y;
+
+ return graph_position;
+}
+
+void GraphEditMinimap::_gui_input(const Ref<InputEvent> &p_ev) {
+ Ref<InputEventMouseButton> mb = p_ev;
+ Ref<InputEventMouseMotion> mm = p_ev;
+
+ if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->is_pressed()) {
+ is_pressing = true;
+
+ Ref<Texture2D> resizer = get_theme_icon("resizer");
+ Rect2 resizer_hitbox = Rect2(Point2(), resizer->get_size());
+ if (resizer_hitbox.has_point(mb->get_position())) {
+ is_resizing = true;
+ } else {
+ Vector2 click_position = _convert_to_graph_position(mb->get_position() - minimap_padding) - graph_padding;
+ _adjust_graph_scroll(click_position);
+ }
+ } else {
+ is_pressing = false;
+ is_resizing = false;
+ }
+ accept_event();
+ } else if (mm.is_valid() && is_pressing) {
+ if (is_resizing) {
+ ge->set_minimap_size(ge->get_minimap_size() - mm->get_relative());
+ update();
+ } else {
+ Vector2 click_position = _convert_to_graph_position(mm->get_position() - minimap_padding) - graph_padding;
+ _adjust_graph_scroll(click_position);
+ }
+ accept_event();
+ }
+}
+
+void GraphEditMinimap::_adjust_graph_scroll(const Vector2 &p_offset) {
+ Vector2 graph_offset = _get_graph_offset();
+ ge->set_scroll_ofs(p_offset + graph_offset - camera_size / 2);
+}
+
Error GraphEdit::connect_node(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port) {
if (is_node_connected(p_from, p_from_port, p_to, p_to_port)) {
return OK;
@@ -64,6 +203,7 @@ Error GraphEdit::connect_node(const StringName &p_from, int p_from_port, const S
c.activity = 0;
connections.push_back(c);
top_layer->update();
+ minimap->update();
update();
connections_layer->update();
@@ -85,6 +225,7 @@ void GraphEdit::disconnect_node(const StringName &p_from, int p_from_port, const
if (E->get().from == p_from && E->get().from_port == p_from_port && E->get().to == p_to && E->get().to_port == p_to_port) {
connections.erase(E);
top_layer->update();
+ minimap->update();
update();
connections_layer->update();
return;
@@ -118,6 +259,7 @@ void GraphEdit::_scroll_moved(double) {
awaiting_scroll_offset_update = true;
}
top_layer->update();
+ minimap->update();
update();
if (!setting_scroll_ofs) { //in godot, signals on change value are avoided as a convention
@@ -234,6 +376,7 @@ void GraphEdit::_graph_node_moved(Node *p_gn) {
GraphNode *gn = Object::cast_to<GraphNode>(p_gn);
ERR_FAIL_COND(!gn);
top_layer->update();
+ minimap->update();
update();
connections_layer->update();
}
@@ -241,13 +384,15 @@ void GraphEdit::_graph_node_moved(Node *p_gn) {
void GraphEdit::add_child_notify(Node *p_child) {
Control::add_child_notify(p_child);
- top_layer->call_deferred("raise"); //top layer always on top!
+ top_layer->call_deferred("raise"); // Top layer always on top!
+
GraphNode *gn = Object::cast_to<GraphNode>(p_child);
if (gn) {
gn->set_scale(Vector2(zoom, zoom));
gn->connect("offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved), varray(gn));
gn->connect("raise_request", callable_mp(this, &GraphEdit::_graph_node_raised), varray(gn));
gn->connect("item_rect_changed", callable_mp((CanvasItem *)connections_layer, &CanvasItem::update));
+ gn->connect("item_rect_changed", callable_mp((CanvasItem *)minimap, &GraphEditMinimap::update));
_graph_node_moved(gn);
gn->set_mouse_filter(MOUSE_FILTER_PASS);
}
@@ -255,14 +400,17 @@ void GraphEdit::add_child_notify(Node *p_child) {
void GraphEdit::remove_child_notify(Node *p_child) {
Control::remove_child_notify(p_child);
+
if (is_inside_tree()) {
- top_layer->call_deferred("raise"); //top layer always on top!
+ top_layer->call_deferred("raise"); // Top layer always on top!
}
+
GraphNode *gn = Object::cast_to<GraphNode>(p_child);
if (gn) {
gn->disconnect("offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved));
gn->disconnect("raise_request", callable_mp(this, &GraphEdit::_graph_node_raised));
gn->disconnect("item_rect_changed", callable_mp((CanvasItem *)connections_layer, &CanvasItem::update));
+ gn->disconnect("item_rect_changed", callable_mp((CanvasItem *)minimap, &GraphEditMinimap::update));
}
}
@@ -275,6 +423,7 @@ void GraphEdit::_notification(int p_what) {
zoom_reset->set_icon(get_theme_icon("reset"));
zoom_plus->set_icon(get_theme_icon("more"));
snap_button->set_icon(get_theme_icon("snap"));
+ minimap_button->set_icon(get_theme_icon("minimap"));
}
if (p_what == NOTIFICATION_READY) {
Size2 hmin = h_scroll->get_combined_minimum_size();
@@ -338,6 +487,7 @@ void GraphEdit::_notification(int p_what) {
if (p_what == NOTIFICATION_RESIZED) {
_update_scroll();
top_layer->update();
+ minimap->update();
}
}
@@ -472,6 +622,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_to = mm->get_position();
connecting_target = false;
top_layer->update();
+ minimap->update();
connecting_valid = just_disconnected || click_pos.distance_to(connecting_to) > 20.0 * zoom;
if (connecting_valid) {
@@ -541,6 +692,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting = false;
top_layer->update();
+ minimap->update();
update();
connections_layer->update();
}
@@ -632,12 +784,12 @@ 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) {
+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) {
//cubic bezier code
float diff = p_to.x - p_from.x;
float cp_offset;
- int cp_len = get_theme_constant("bezier_len_pos");
- int cp_neg_len = get_theme_constant("bezier_len_neg");
+ int cp_len = get_theme_constant("bezier_len_pos") * p_bezier_ratio;
+ int cp_neg_len = get_theme_constant("bezier_len_neg") * p_bezier_ratio;
if (diff > 0) {
cp_offset = MIN(cp_len, diff * 0.5);
@@ -659,9 +811,9 @@ void GraphEdit::_draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const
colors.push_back(p_to_color);
#ifdef TOOLS_ENABLED
- p_where->draw_polyline_colors(points, colors, Math::floor(2 * EDSCALE), true);
+ p_where->draw_polyline_colors(points, colors, Math::floor(p_width * EDSCALE), lines_antialiased);
#else
- p_where->draw_polyline_colors(points, colors, 2, true);
+ p_where->draw_polyline_colors(points, colors, p_width, lines_antialiased);
#endif
}
@@ -708,7 +860,7 @@ void GraphEdit::_connections_layer_draw() {
color = color.lerp(activity_color, E->get().activity);
tocolor = tocolor.lerp(activity_color, E->get().activity);
}
- _draw_cos_line(connections_layer, frompos, topos, color, tocolor);
+ _draw_cos_line(connections_layer, frompos, topos, color, tocolor, lines_thickness);
}
while (to_erase.size()) {
@@ -747,7 +899,7 @@ void GraphEdit::_top_layer_draw() {
if (!connecting_out) {
SWAP(pos, topos);
}
- _draw_cos_line(top_layer, pos, topos, col, col);
+ _draw_cos_line(top_layer, pos, topos, col, col, lines_thickness);
}
if (box_selecting) {
@@ -756,6 +908,114 @@ void GraphEdit::_top_layer_draw() {
}
}
+void GraphEdit::_minimap_draw() {
+ if (!is_minimap_enabled()) {
+ return;
+ }
+
+ minimap->update_minimap();
+
+ // Draw the minimap background.
+ Rect2 minimap_rect = Rect2(Point2(), minimap->get_size());
+ minimap->draw_style_box(minimap->get_theme_stylebox("bg"), minimap_rect);
+
+ Vector2 graph_offset = minimap->_get_graph_offset();
+ Vector2 minimap_offset = minimap->minimap_offset;
+
+ // Draw comment graph nodes.
+ for (int i = get_child_count() - 1; i >= 0; i--) {
+ GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
+ if (!gn || !gn->is_comment()) {
+ continue;
+ }
+
+ Vector2 node_position = minimap->_convert_from_graph_position(gn->get_offset() * zoom - graph_offset) + minimap_offset;
+ Vector2 node_size = minimap->_convert_from_graph_position(gn->get_size() * zoom);
+ Rect2 node_rect = Rect2(node_position, node_size);
+
+ Ref<StyleBoxFlat> sb_minimap = minimap->get_theme_stylebox("node")->duplicate();
+
+ // Override default values with colors provided by the GraphNode's stylebox, if possible.
+ Ref<StyleBoxFlat> sbf = gn->get_theme_stylebox(gn->is_selected() ? "commentfocus" : "comment");
+ if (sbf.is_valid()) {
+ Color node_color = sbf->get_bg_color();
+ sb_minimap->set_bg_color(node_color);
+ }
+
+ minimap->draw_style_box(sb_minimap, node_rect);
+ }
+
+ // Draw regular graph nodes.
+ for (int i = get_child_count() - 1; i >= 0; i--) {
+ GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
+ if (!gn || gn->is_comment()) {
+ continue;
+ }
+
+ Vector2 node_position = minimap->_convert_from_graph_position(gn->get_offset() * zoom - graph_offset) + minimap_offset;
+ Vector2 node_size = minimap->_convert_from_graph_position(gn->get_size() * zoom);
+ Rect2 node_rect = Rect2(node_position, node_size);
+
+ Ref<StyleBoxFlat> sb_minimap = minimap->get_theme_stylebox("node")->duplicate();
+
+ // Override default values with colors provided by the GraphNode's stylebox, if possible.
+ Ref<StyleBoxFlat> sbf = gn->get_theme_stylebox(gn->is_selected() ? "selectedframe" : "frame");
+ if (sbf.is_valid()) {
+ Color node_color = sbf->get_border_color();
+ sb_minimap->set_bg_color(node_color);
+ }
+
+ minimap->draw_style_box(sb_minimap, node_rect);
+ }
+
+ // Draw node connections.
+ Color activity_color = get_theme_color("activity");
+ for (List<Connection>::Element *E = connections.front(); E; E = E->next()) {
+ NodePath fromnp(E->get().from);
+
+ Node *from = get_node(fromnp);
+ if (!from) {
+ continue;
+ }
+ GraphNode *gfrom = Object::cast_to<GraphNode>(from);
+ if (!gfrom) {
+ continue;
+ }
+
+ NodePath tonp(E->get().to);
+ Node *to = get_node(tonp);
+ if (!to) {
+ continue;
+ }
+ GraphNode *gto = Object::cast_to<GraphNode>(to);
+ if (!gto) {
+ continue;
+ }
+
+ Vector2 from_slot_position = gfrom->get_offset() * zoom + gfrom->get_connection_output_position(E->get().from_port);
+ Vector2 from_position = minimap->_convert_from_graph_position(from_slot_position - graph_offset) + minimap_offset;
+ Color from_color = gfrom->get_connection_output_color(E->get().from_port);
+ Vector2 to_slot_position = gto->get_offset() * zoom + gto->get_connection_input_position(E->get().to_port);
+ Vector2 to_position = minimap->_convert_from_graph_position(to_slot_position - graph_offset) + minimap_offset;
+ Color to_color = gto->get_connection_input_color(E->get().to_port);
+
+ if (E->get().activity > 0) {
+ from_color = from_color.lerp(activity_color, E->get().activity);
+ to_color = to_color.lerp(activity_color, E->get().activity);
+ }
+ _draw_cos_line(minimap, from_position, to_position, from_color, to_color, 1.0, 0.5);
+ }
+
+ // Draw the "camera" viewport.
+ Rect2 camera_rect = minimap->get_camera_rect();
+ minimap->draw_style_box(minimap->get_theme_stylebox("camera"), camera_rect);
+
+ // Draw the resizer control.
+ Ref<Texture2D> resizer = minimap->get_theme_icon("resizer");
+ Color resizer_color = minimap->get_theme_color("resizer_color");
+ minimap->draw_texture(resizer, Point2(), resizer_color);
+}
+
void GraphEdit::set_selected(Node *p_child) {
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
@@ -836,6 +1096,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
}
top_layer->update();
+ minimap->update();
}
Ref<InputEventMouseButton> b = p_ev;
@@ -858,10 +1119,12 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
gn->set_selected(select);
}
top_layer->update();
+ minimap->update();
} else {
if (connecting) {
connecting = false;
top_layer->update();
+ minimap->update();
} else {
emit_signal("popup_request", b->get_global_position());
}
@@ -902,6 +1165,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
dragging = false;
top_layer->update();
+ minimap->update();
update();
connections_layer->update();
}
@@ -1012,6 +1276,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
box_selecting = false;
previus_selected.clear();
top_layer->update();
+ minimap->update();
}
if (b->get_button_index() == BUTTON_WHEEL_UP && b->is_pressed()) {
@@ -1079,6 +1344,7 @@ void GraphEdit::set_connection_activity(const StringName &p_from, int p_from_por
if (Math::is_equal_approx(E->get().activity, p_activity)) {
//update only if changed
top_layer->update();
+ minimap->update();
connections_layer->update();
}
E->get().activity = p_activity;
@@ -1089,6 +1355,7 @@ void GraphEdit::set_connection_activity(const StringName &p_from, int p_from_por
void GraphEdit::clear_connections() {
connections.clear();
+ minimap->update();
update();
connections_layer->update();
}
@@ -1112,6 +1379,7 @@ void GraphEdit::set_zoom_custom(float p_zoom, const Vector2 &p_center) {
top_layer->update();
_update_scroll();
+ minimap->update();
connections_layer->update();
if (is_visible_in_tree()) {
@@ -1229,6 +1497,63 @@ void GraphEdit::_snap_value_changed(double) {
update();
}
+void GraphEdit::set_minimap_size(Vector2 p_size) {
+ minimap->set_size(p_size);
+ Vector2 minimap_size = minimap->get_size(); // The size might've been adjusted by the minimum size.
+
+ minimap->set_anchors_preset(Control::PRESET_BOTTOM_RIGHT);
+ minimap->set_margin(Margin::MARGIN_LEFT, -minimap_size.x - MINIMAP_OFFSET);
+ minimap->set_margin(Margin::MARGIN_TOP, -minimap_size.y - MINIMAP_OFFSET);
+ minimap->set_margin(Margin::MARGIN_RIGHT, -MINIMAP_OFFSET);
+ minimap->set_margin(Margin::MARGIN_BOTTOM, -MINIMAP_OFFSET);
+ minimap->update();
+}
+
+Vector2 GraphEdit::get_minimap_size() const {
+ return minimap->get_size();
+}
+
+void GraphEdit::set_minimap_opacity(float p_opacity) {
+ minimap->set_modulate(Color(1, 1, 1, p_opacity));
+ minimap->update();
+}
+
+float GraphEdit::get_minimap_opacity() const {
+ Color minimap_modulate = minimap->get_modulate();
+ return minimap_modulate.a;
+}
+
+void GraphEdit::set_minimap_enabled(bool p_enable) {
+ minimap_button->set_pressed(p_enable);
+ minimap->update();
+}
+
+bool GraphEdit::is_minimap_enabled() const {
+ return minimap_button->is_pressed();
+}
+
+void GraphEdit::_minimap_toggled() {
+ minimap->update();
+}
+
+void GraphEdit::set_connection_lines_thickness(float p_thickness) {
+ lines_thickness = p_thickness;
+ update();
+}
+
+float GraphEdit::get_connection_lines_thickness() const {
+ return lines_thickness;
+}
+
+void GraphEdit::set_connection_lines_antialiased(bool p_antialiased) {
+ lines_antialiased = p_antialiased;
+ update();
+}
+
+bool GraphEdit::is_connection_lines_antialiased() const {
+ return lines_antialiased;
+}
+
HBoxContainer *GraphEdit::get_zoom_hbox() {
return zoom_hb;
}
@@ -1260,6 +1585,20 @@ void GraphEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_snap", "enable"), &GraphEdit::set_use_snap);
ClassDB::bind_method(D_METHOD("is_using_snap"), &GraphEdit::is_using_snap);
+ ClassDB::bind_method(D_METHOD("set_connection_lines_thickness", "pixels"), &GraphEdit::set_connection_lines_thickness);
+ ClassDB::bind_method(D_METHOD("get_connection_lines_thickness"), &GraphEdit::get_connection_lines_thickness);
+
+ ClassDB::bind_method(D_METHOD("set_connection_lines_antialiased", "pixels"), &GraphEdit::set_connection_lines_antialiased);
+ ClassDB::bind_method(D_METHOD("is_connection_lines_antialiased"), &GraphEdit::is_connection_lines_antialiased);
+
+ ClassDB::bind_method(D_METHOD("set_minimap_size", "p_size"), &GraphEdit::set_minimap_size);
+ ClassDB::bind_method(D_METHOD("get_minimap_size"), &GraphEdit::get_minimap_size);
+ ClassDB::bind_method(D_METHOD("set_minimap_opacity", "p_opacity"), &GraphEdit::set_minimap_opacity);
+ ClassDB::bind_method(D_METHOD("get_minimap_opacity"), &GraphEdit::get_minimap_opacity);
+
+ ClassDB::bind_method(D_METHOD("set_minimap_enabled", "enable"), &GraphEdit::set_minimap_enabled);
+ ClassDB::bind_method(D_METHOD("is_minimap_enabled"), &GraphEdit::is_minimap_enabled);
+
ClassDB::bind_method(D_METHOD("set_right_disconnects", "enable"), &GraphEdit::set_right_disconnects);
ClassDB::bind_method(D_METHOD("is_right_disconnects_enabled"), &GraphEdit::is_right_disconnects_enabled);
@@ -1275,6 +1614,12 @@ void GraphEdit::_bind_methods() {
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_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("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");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "minimap_opacity"), "set_minimap_opacity", "get_minimap_opacity");
ADD_SIGNAL(MethodInfo("connection_request", PropertyInfo(Variant::STRING_NAME, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::STRING_NAME, "to"), PropertyInfo(Variant::INT, "to_slot")));
ADD_SIGNAL(MethodInfo("disconnection_request", PropertyInfo(Variant::STRING_NAME, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::STRING_NAME, "to"), PropertyInfo(Variant::INT, "to_slot")));
@@ -1380,6 +1725,32 @@ GraphEdit::GraphEdit() {
snap_amount->connect("value_changed", callable_mp(this, &GraphEdit::_snap_value_changed));
zoom_hb->add_child(snap_amount);
+ minimap_button = memnew(Button);
+ minimap_button->set_flat(true);
+ minimap_button->set_toggle_mode(true);
+ minimap_button->set_tooltip(RTR("Enable grid minimap."));
+ minimap_button->connect("pressed", callable_mp(this, &GraphEdit::_minimap_toggled));
+ minimap_button->set_pressed(true);
+ minimap_button->set_focus_mode(FOCUS_NONE);
+ zoom_hb->add_child(minimap_button);
+
+ Vector2 minimap_size = Vector2(240, 160);
+ float minimap_opacity = 0.65;
+
+ minimap = memnew(GraphEditMinimap(this));
+ top_layer->add_child(minimap);
+ minimap->set_name("_minimap");
+ minimap->set_modulate(Color(1, 1, 1, minimap_opacity));
+ minimap->set_mouse_filter(MOUSE_FILTER_STOP);
+ minimap->set_custom_minimum_size(Vector2(50, 50));
+ minimap->set_size(minimap_size);
+ minimap->set_anchors_preset(Control::PRESET_BOTTOM_RIGHT);
+ minimap->set_margin(Margin::MARGIN_LEFT, -minimap_size.x - MINIMAP_OFFSET);
+ minimap->set_margin(Margin::MARGIN_TOP, -minimap_size.y - MINIMAP_OFFSET);
+ minimap->set_margin(Margin::MARGIN_RIGHT, -MINIMAP_OFFSET);
+ minimap->set_margin(Margin::MARGIN_BOTTOM, -MINIMAP_OFFSET);
+ minimap->connect("draw", callable_mp(this, &GraphEdit::_minimap_draw));
+
setting_scroll_ofs = false;
just_disconnected = false;
set_clip_contents(true);
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index d87bd41f27..d081789784 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -45,6 +45,7 @@ class GraphEditFilter : public Control {
GDCLASS(GraphEditFilter, Control);
friend class GraphEdit;
+ friend class GraphEditMinimap;
GraphEdit *ge;
virtual bool has_point(const Point2 &p_point) const override;
@@ -52,6 +53,45 @@ public:
GraphEditFilter(GraphEdit *p_edit);
};
+class GraphEditMinimap : public Control {
+ GDCLASS(GraphEditMinimap, Control);
+
+ friend class GraphEdit;
+ friend class GraphEditFilter;
+ GraphEdit *ge;
+
+protected:
+ static void _bind_methods();
+
+public:
+ GraphEditMinimap(GraphEdit *p_edit);
+
+ void update_minimap();
+ Rect2 get_camera_rect();
+
+private:
+ Vector2 minimap_padding;
+ Vector2 minimap_offset;
+ Vector2 graph_proportions;
+ Vector2 graph_padding;
+ Vector2 camera_position;
+ Vector2 camera_size;
+
+ bool is_pressing;
+ bool is_resizing;
+
+ Vector2 _get_render_size();
+ Vector2 _get_graph_offset();
+ Vector2 _get_graph_size();
+
+ Vector2 _convert_from_graph_position(const Vector2 &p_position);
+ Vector2 _convert_to_graph_position(const Vector2 &p_position);
+
+ void _gui_input(const Ref<InputEvent> &p_ev);
+
+ void _adjust_graph_scroll(const Vector2 &p_offset);
+};
+
class GraphEdit : public Control {
GDCLASS(GraphEdit, Control);
@@ -72,6 +112,8 @@ private:
Button *snap_button;
SpinBox *snap_amount;
+ Button *minimap_button;
+
void _zoom_minus();
void _zoom_reset();
void _zoom_plus();
@@ -116,9 +158,12 @@ private:
bool awaiting_scroll_offset_update;
List<Connection> connections;
+ float lines_thickness = 2.0f;
+ bool lines_antialiased = true;
+
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);
+ 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 _graph_node_raised(Node *p_gn);
void _graph_node_moved(Node *p_gn);
@@ -129,12 +174,14 @@ private:
Control *connections_layer;
GraphEditFilter *top_layer;
+ GraphEditMinimap *minimap;
void _top_layer_input(const Ref<InputEvent> &p_ev);
bool is_in_hot_zone(const Vector2 &pos, const Vector2 &p_mouse_pos);
void _top_layer_draw();
void _connections_layer_draw();
+ void _minimap_draw();
void _update_scroll_offset();
Array _get_connection_list() const;
@@ -171,6 +218,9 @@ private:
void _snap_toggled();
void _snap_value_changed(double);
+ friend class GraphEditMinimap;
+ void _minimap_toggled();
+
bool _check_clickable_control(Control *p_control, const Vector2 &pos);
protected:
@@ -196,7 +246,16 @@ public:
void set_zoom_custom(float p_zoom, const Vector2 &p_center);
float get_zoom() const;
+ void set_minimap_size(Vector2 p_size);
+ Vector2 get_minimap_size() const;
+ void set_minimap_opacity(float p_opacity);
+ float get_minimap_opacity() const;
+
+ void set_minimap_enabled(bool p_enable);
+ bool is_minimap_enabled() const;
+
GraphEditFilter *get_top_layer() const { return top_layer; }
+ GraphEditMinimap *get_minimap() const { return minimap; }
void get_connection_list(List<Connection> *r_connections) const;
void set_right_disconnects(bool p_enable);
@@ -219,6 +278,12 @@ public:
int get_snap() const;
void set_snap(int p_snap);
+ void set_connection_lines_thickness(float p_thickness);
+ float get_connection_lines_thickness() const;
+
+ void set_connection_lines_antialiased(bool p_antialiased);
+ bool is_connection_lines_antialiased() const;
+
HBoxContainer *get_zoom_hbox();
GraphEdit();
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index bfbb3cb3f3..07f03ad40e 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -238,6 +238,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
search_from = 0;
}
+ bool match_found = false;
for (int i = search_from; i < items.size(); i++) {
if (!items[i].separator && !items[i].disabled) {
mouse_over = i;
@@ -245,15 +246,31 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
_scroll_to_item(i);
control->update();
set_input_as_handled();
+ match_found = true;
break;
}
}
+
+ if (!match_found) {
+ // If the last item is not selectable, try re-searching from the start.
+ for (int i = 0; i < search_from; i++) {
+ if (!items[i].separator && !items[i].disabled) {
+ mouse_over = i;
+ emit_signal("id_focused", i);
+ _scroll_to_item(i);
+ control->update();
+ set_input_as_handled();
+ break;
+ }
+ }
+ }
} else if (p_event->is_action("ui_up") && p_event->is_pressed()) {
int search_from = mouse_over - 1;
if (search_from < 0) {
search_from = items.size() - 1;
}
+ bool match_found = false;
for (int i = search_from; i >= 0; i--) {
if (!items[i].separator && !items[i].disabled) {
mouse_over = i;
@@ -261,9 +278,24 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
_scroll_to_item(i);
control->update();
set_input_as_handled();
+ match_found = true;
break;
}
}
+
+ if (!match_found) {
+ // If the first item is not selectable, try re-searching from the end.
+ for (int i = items.size() - 1; i >= search_from; i--) {
+ if (!items[i].separator && !items[i].disabled) {
+ mouse_over = i;
+ emit_signal("id_focused", i);
+ _scroll_to_item(i);
+ control->update();
+ set_input_as_handled();
+ break;
+ }
+ }
+ }
} else if (p_event->is_action("ui_left") && p_event->is_pressed()) {
Node *n = get_parent();
if (n && Object::cast_to<PopupMenu>(n)) {
diff --git a/scene/gui/rich_text_effect.cpp b/scene/gui/rich_text_effect.cpp
index 76ca8abcc7..5b201f45d3 100644
--- a/scene/gui/rich_text_effect.cpp
+++ b/scene/gui/rich_text_effect.cpp
@@ -64,11 +64,8 @@ RichTextEffect::RichTextEffect() {
}
void CharFXTransform::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_relative_index"), &CharFXTransform::get_relative_index);
- ClassDB::bind_method(D_METHOD("set_relative_index", "index"), &CharFXTransform::set_relative_index);
-
- ClassDB::bind_method(D_METHOD("get_absolute_index"), &CharFXTransform::get_absolute_index);
- ClassDB::bind_method(D_METHOD("set_absolute_index", "index"), &CharFXTransform::set_absolute_index);
+ ClassDB::bind_method(D_METHOD("get_range"), &CharFXTransform::get_range);
+ ClassDB::bind_method(D_METHOD("set_range", "range"), &CharFXTransform::set_range);
ClassDB::bind_method(D_METHOD("get_elapsed_time"), &CharFXTransform::get_elapsed_time);
ClassDB::bind_method(D_METHOD("set_elapsed_time", "time"), &CharFXTransform::set_elapsed_time);
@@ -76,6 +73,9 @@ void CharFXTransform::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_visible"), &CharFXTransform::is_visible);
ClassDB::bind_method(D_METHOD("set_visibility", "visibility"), &CharFXTransform::set_visibility);
+ ClassDB::bind_method(D_METHOD("is_outline"), &CharFXTransform::is_outline);
+ ClassDB::bind_method(D_METHOD("set_outline", "outline"), &CharFXTransform::set_outline);
+
ClassDB::bind_method(D_METHOD("get_offset"), &CharFXTransform::get_offset);
ClassDB::bind_method(D_METHOD("set_offset", "offset"), &CharFXTransform::set_offset);
@@ -85,27 +85,24 @@ void CharFXTransform::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_environment"), &CharFXTransform::get_environment);
ClassDB::bind_method(D_METHOD("set_environment", "environment"), &CharFXTransform::set_environment);
- ClassDB::bind_method(D_METHOD("get_character"), &CharFXTransform::get_character);
- ClassDB::bind_method(D_METHOD("set_character", "character"), &CharFXTransform::set_character);
+ ClassDB::bind_method(D_METHOD("get_glyph_index"), &CharFXTransform::get_glyph_index);
+ ClassDB::bind_method(D_METHOD("set_glyph_index", "glyph_index"), &CharFXTransform::set_glyph_index);
+
+ ClassDB::bind_method(D_METHOD("get_font"), &CharFXTransform::get_font);
+ ClassDB::bind_method(D_METHOD("set_font", "font"), &CharFXTransform::set_font);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "relative_index"), "set_relative_index", "get_relative_index");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "absolute_index"), "set_absolute_index", "get_absolute_index");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "range"), "set_range", "get_range");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "elapsed_time"), "set_elapsed_time", "get_elapsed_time");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visibility", "is_visible");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "outline"), "set_outline", "is_outline");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "env"), "set_environment", "get_environment");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "character"), "set_character", "get_character");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "glyph_index"), "set_glyph_index", "get_glyph_index");
+ ADD_PROPERTY(PropertyInfo(Variant::RID, "font"), "set_font", "get_font");
}
CharFXTransform::CharFXTransform() {
- relative_index = 0;
- absolute_index = 0;
- visibility = true;
- offset = Point2();
- color = Color();
- character = 0;
- elapsed_time = 0.0f;
}
CharFXTransform::~CharFXTransform() {
diff --git a/scene/gui/rich_text_effect.h b/scene/gui/rich_text_effect.h
index e6b9f09e4d..1aa62c1c83 100644
--- a/scene/gui/rich_text_effect.h
+++ b/scene/gui/rich_text_effect.h
@@ -54,32 +54,37 @@ protected:
static void _bind_methods();
public:
- uint64_t relative_index;
- uint64_t absolute_index;
- bool visibility;
+ Vector2i range;
+ bool visibility = true;
+ bool outline = false;
Point2 offset;
Color color;
- char32_t character;
- float elapsed_time;
+ float elapsed_time = 0.0f;
Dictionary environment;
+ uint32_t glpyh_index = 0;
+ RID font;
CharFXTransform();
~CharFXTransform();
- uint64_t get_relative_index() { return relative_index; }
- void set_relative_index(uint64_t p_index) { relative_index = p_index; }
- uint64_t get_absolute_index() { return absolute_index; }
- void set_absolute_index(uint64_t p_index) { absolute_index = p_index; }
+ Vector2i get_range() { return range; }
+ void set_range(const Vector2i &p_range) { range = p_range; }
float get_elapsed_time() { return elapsed_time; }
void set_elapsed_time(float p_elapsed_time) { elapsed_time = p_elapsed_time; }
bool is_visible() { return visibility; }
- void set_visibility(bool p_vis) { visibility = p_vis; }
+ void set_visibility(bool p_visibility) { visibility = p_visibility; }
+ bool is_outline() { return outline; }
+ void set_outline(bool p_outline) { outline = p_outline; }
Point2 get_offset() { return offset; }
void set_offset(Point2 p_offset) { offset = p_offset; }
Color get_color() { return color; }
void set_color(Color p_color) { color = p_color; }
- int get_character() { return (int)character; }
- void set_character(int p_char) { character = (char32_t)p_char; }
+
+ uint32_t get_glyph_index() const { return glpyh_index; };
+ void set_glyph_index(uint32_t p_glpyh_index) { glpyh_index = p_glpyh_index; };
+ RID get_font() const { return font; };
+ void set_font(RID p_font) { font = p_font; };
+
Dictionary get_environment() { return environment; }
void set_environment(Dictionary p_environment) { environment = p_environment; }
};
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index e3b645591c..244d90ca6b 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -140,741 +140,1088 @@ Rect2 RichTextLabel::_get_text_rect() {
return Rect2(style->get_offset(), get_size() - style->get_minimum_size());
}
-int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &y, int p_width, int p_line, ProcessMode p_mode, const Ref<Font> &p_base_font, const Color &p_base_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &shadow_ofs, const Point2i &p_click_pos, Item **r_click_item, int *r_click_char, bool *r_outside, int p_char_count) {
- ERR_FAIL_INDEX_V((int)p_mode, 3, 0);
-
- RID ci;
- if (r_outside) {
- *r_outside = false;
+RichTextLabel::Item *RichTextLabel::_get_item_at_pos(RichTextLabel::Item *p_item_from, RichTextLabel::Item *p_item_to, int p_position) {
+ int offset = 0;
+ for (Item *it = p_item_from; it && it != p_item_to; it = _get_next_item(it)) {
+ switch (it->type) {
+ case ITEM_TEXT: {
+ ItemText *t = (ItemText *)it;
+ offset += t->text.length();
+ if (offset > p_position) {
+ return it;
+ }
+ } break;
+ case ITEM_NEWLINE:
+ case ITEM_IMAGE:
+ case ITEM_TABLE: {
+ offset += 1;
+ } break;
+ default:
+ break;
+ }
}
- if (p_mode == PROCESS_DRAW) {
- ci = get_canvas_item();
+ return p_item_from;
+}
- if (r_click_item) {
- *r_click_item = nullptr;
- }
+String RichTextLabel::_roman(int p_num, bool p_capitalize) const {
+ if (p_num > 3999) {
+ return "ERR";
+ };
+ String s;
+ if (p_capitalize) {
+ String M[] = { "", "M", "MM", "MMM" };
+ String C[] = { "", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM" };
+ String X[] = { "", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC" };
+ String I[] = { "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" };
+ s = M[p_num / 1000] + C[(p_num % 1000) / 100] + X[(p_num % 100) / 10] + I[p_num % 10];
+ } else {
+ String M[] = { "", "m", "mm", "mmm" };
+ String C[] = { "", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm" };
+ String X[] = { "", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc" };
+ String I[] = { "", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix" };
+ s = M[p_num / 1000] + C[(p_num % 1000) / 100] + X[(p_num % 100) / 10] + I[p_num % 10];
}
- Line &l = p_frame->lines.write[p_line];
- Item *it = l.from;
+ return s;
+}
- int line_ofs = 0;
- int margin = _find_margin(it, p_base_font);
- Align align = _find_align(it);
- int line = 0;
- int spaces = 0;
+String RichTextLabel::_letters(int p_num, bool p_capitalize) const {
+ int64_t n = p_num;
- int height = get_size().y;
+ int chars = 0;
+ do {
+ n /= 24;
+ chars++;
+ } while (n);
- if (p_mode != PROCESS_CACHE) {
- ERR_FAIL_INDEX_V(line, l.offset_caches.size(), 0);
- line_ofs = l.offset_caches[line];
- }
+ String s;
+ s.resize(chars + 1);
+ char32_t *c = s.ptrw();
+ c[chars] = 0;
+ n = p_num;
+ do {
+ int mod = ABS(n % 24);
+ char a = (p_capitalize ? 'A' : 'a');
+ c[--chars] = a + mod - 1;
- if (p_mode == PROCESS_CACHE) {
- l.offset_caches.clear();
- l.height_caches.clear();
- l.ascent_caches.clear();
- l.descent_caches.clear();
- l.char_count = 0;
- l.minimum_width = 0;
- l.maximum_width = 0;
- }
+ n /= 24;
+ } while (n);
- int wofs = margin;
- int spaces_size = 0;
- int align_ofs = 0;
+ return s;
+}
- if (p_mode != PROCESS_CACHE && align != ALIGN_FILL) {
- wofs += line_ofs;
- }
+void RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width) {
+ ERR_FAIL_COND(p_frame == nullptr);
+ ERR_FAIL_COND(p_line < 0 || p_line >= p_frame->lines.size());
+
+ Line &l = p_frame->lines.write[p_line];
- int begin = margin;
+ l.offset.x = _find_margin(l.from, p_base_font, p_base_font_size);
+ l.text_buf->set_width(p_width - l.offset.x);
- Ref<Font> cfont = _find_font(it);
- if (cfont.is_null()) {
- cfont = p_base_font;
+ if (tab_size > 0) { // Align inline tabs.
+ Vector<float> tabs;
+ tabs.push_back(tab_size * p_base_font->get_char_size('m', 0, p_base_font_size).width);
+ l.text_buf->tab_align(tabs);
}
- //line height should be the font height for the first time, this ensures that an empty line will never have zero height and successive newlines are displayed
- int line_height = cfont->get_height();
- int line_ascent = cfont->get_ascent();
- int line_descent = cfont->get_descent();
+ Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr;
+ for (Item *it = l.from; it && it != it_to; it = _get_next_item(it)) {
+ switch (it->type) {
+ case ITEM_TABLE: {
+ ItemTable *table = static_cast<ItemTable *>(it);
+ int hseparation = get_theme_constant("table_hseparation");
+ int vseparation = get_theme_constant("table_vseparation");
+ int col_count = table->columns.size();
- int backtrack = 0; // for dynamic hidden content.
+ for (int i = 0; i < col_count; i++) {
+ table->columns.write[i].width = 0;
+ }
- int nonblank_line_count = 0; //number of nonblank lines as counted during PROCESS_DRAW
+ 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++) {
+ _resize_line(frame, i, p_base_font, p_base_font_size, 1);
+ }
+ idx++;
+ }
- Variant meta;
+ // Compute minimum width for each cell.
+ const int available_width = p_width - hseparation * (col_count - 1);
-#define RETURN return nonblank_line_count
-
-#define NEW_LINE \
- { \
- if (p_mode != PROCESS_CACHE) { \
- line++; \
- backtrack = 0; \
- if (!line_is_blank) { \
- nonblank_line_count++; \
- } \
- line_is_blank = true; \
- if (line < l.offset_caches.size()) \
- line_ofs = l.offset_caches[line]; \
- wofs = margin; \
- if (align != ALIGN_FILL) \
- wofs += line_ofs; \
- } else { \
- int used = wofs - margin; \
- switch (align) { \
- case ALIGN_LEFT: \
- l.offset_caches.push_back(0); \
- break; \
- case ALIGN_CENTER: \
- l.offset_caches.push_back(((p_width - margin) - used) / 2); \
- break; \
- case ALIGN_RIGHT: \
- l.offset_caches.push_back(((p_width - margin) - used)); \
- break; \
- case ALIGN_FILL: \
- l.offset_caches.push_back(line_wrapped ? ((p_width - margin) - used) : 0); \
- break; \
- } \
- l.height_caches.push_back(line_height); \
- l.ascent_caches.push_back(line_ascent); \
- l.descent_caches.push_back(line_descent); \
- l.space_caches.push_back(spaces); \
- } \
- line_wrapped = false; \
- y += line_height + get_theme_constant(SceneStringNames::get_singleton()->line_separation); \
- line_height = 0; \
- line_ascent = 0; \
- line_descent = 0; \
- spaces = 0; \
- spaces_size = 0; \
- wofs = begin; \
- align_ofs = 0; \
- if (p_mode != PROCESS_CACHE) { \
- lh = line < l.height_caches.size() ? l.height_caches[line] : 1; \
- line_ascent = line < l.ascent_caches.size() ? l.ascent_caches[line] : 1; \
- line_descent = line < l.descent_caches.size() ? l.descent_caches[line] : 1; \
- if (align != ALIGN_FILL) { \
- if (line < l.offset_caches.size()) { \
- wofs = l.offset_caches[line]; \
- } \
- } \
- } \
- if (p_mode == PROCESS_POINTER && r_click_item && p_click_pos.y >= p_ofs.y + y && p_click_pos.y <= p_ofs.y + y + lh && p_click_pos.x < p_ofs.x + wofs) { \
- if (r_outside) \
- *r_outside = true; \
- *r_click_item = it; \
- *r_click_char = rchar; \
- RETURN; \
- } \
- }
-
-#define ENSURE_WIDTH(m_width) \
- if (p_mode == PROCESS_CACHE) { \
- l.maximum_width = MAX(l.maximum_width, MIN(p_width, wofs + m_width)); \
- l.minimum_width = MAX(l.minimum_width, m_width); \
- } \
- if (wofs - backtrack + m_width > p_width) { \
- line_wrapped = true; \
- if (p_mode == PROCESS_CACHE) { \
- if (spaces > 0) \
- spaces -= 1; \
- } \
- const bool x_in_range = (p_click_pos.x > p_ofs.x + wofs) && (!p_frame->cell || p_click_pos.x < p_ofs.x + p_width); \
- if (p_mode == PROCESS_POINTER && r_click_item && p_click_pos.y >= p_ofs.y + y && p_click_pos.y <= p_ofs.y + y + lh && x_in_range) { \
- if (r_outside) \
- *r_outside = true; \
- *r_click_item = it; \
- *r_click_char = rchar; \
- RETURN; \
- } \
- NEW_LINE \
- }
-
-#define ADVANCE(m_width) \
- { \
- if (p_mode == PROCESS_POINTER && r_click_item && p_click_pos.y >= p_ofs.y + y && p_click_pos.y <= p_ofs.y + y + lh && p_click_pos.x >= p_ofs.x + wofs && p_click_pos.x < p_ofs.x + wofs + m_width) { \
- if (r_outside) \
- *r_outside = false; \
- *r_click_item = it; \
- *r_click_char = rchar; \
- RETURN; \
- } \
- wofs += m_width; \
- }
-
-#define CHECK_HEIGHT(m_height) \
- if (m_height > line_height) { \
- line_height = m_height; \
- }
-
-#define YRANGE_VISIBLE(m_top, m_height) \
- (m_height > 0 && ((m_top >= 0 && m_top < height) || ((m_top + m_height - 1) >= 0 && (m_top + m_height - 1) < height)))
-
- Color selection_fg;
- Color selection_bg;
-
- if (p_mode == PROCESS_DRAW) {
- selection_fg = get_theme_color("font_color_selected");
- selection_bg = get_theme_color("selection_color");
- }
-
- int rchar = 0;
- int lh = 0;
- bool line_is_blank = true;
- bool line_wrapped = false;
- int fh = 0;
+ // Compute available width and total ratio (for expanders).
+ int total_ratio = 0;
+ int remaining_width = available_width;
+ table->total_width = hseparation;
- while (it) {
- switch (it->type) {
- case ITEM_ALIGN: {
- ItemAlign *align_it = static_cast<ItemAlign *>(it);
+ for (int i = 0; i < col_count; i++) {
+ remaining_width -= table->columns[i].min_width;
+ if (table->columns[i].max_width > table->columns[i].min_width) {
+ table->columns.write[i].expand = true;
+ }
+ if (table->columns[i].expand) {
+ total_ratio += table->columns[i].expand_ratio;
+ }
+ }
- align = align_it->align;
+ // Assign actual widths.
+ for (int i = 0; i < col_count; i++) {
+ table->columns.write[i].width = table->columns[i].min_width;
+ if (table->columns[i].expand && total_ratio > 0) {
+ table->columns.write[i].width += table->columns[i].expand_ratio * remaining_width / total_ratio;
+ }
+ table->total_width += table->columns[i].width + hseparation;
+ }
- } break;
- case ITEM_INDENT: {
- if (it != l.from) {
- ItemIndent *indent_it = static_cast<ItemIndent *>(it);
-
- int indent = indent_it->level * tab_size * cfont->get_char_size(' ').width;
- margin += indent;
- begin += indent;
- wofs += indent;
+ // Resize to max_width if needed and distribute the remaining space.
+ bool table_need_fit = true;
+ while (table_need_fit) {
+ table_need_fit = false;
+ // Fit slim.
+ for (int i = 0; i < col_count; i++) {
+ if (!table->columns[i].expand) {
+ continue;
+ }
+ int dif = table->columns[i].width - table->columns[i].max_width;
+ if (dif > 0) {
+ table_need_fit = true;
+ table->columns.write[i].width = table->columns[i].max_width;
+ table->total_width -= dif;
+ total_ratio -= table->columns[i].expand_ratio;
+ }
+ }
+ // Grow.
+ remaining_width = available_width - table->total_width;
+ if (remaining_width > 0 && total_ratio > 0) {
+ for (int i = 0; i < col_count; i++) {
+ if (table->columns[i].expand) {
+ int dif = table->columns[i].max_width - table->columns[i].width;
+ if (dif > 0) {
+ int slice = table->columns[i].expand_ratio * remaining_width / total_ratio;
+ int incr = MIN(dif, slice);
+ table->columns.write[i].width += incr;
+ table->total_width += incr;
+ }
+ }
+ }
+ }
}
+ // Update line width and get total height.
+ idx = 0;
+ table->total_height = 0;
+ table->rows.clear();
+
+ Vector2 offset;
+ float row_height = 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());
+
+ int column = idx % col_count;
+
+ offset.x += frame->padding.position.x;
+ float yofs = frame->padding.position.y;
+ for (int i = 0; i < frame->lines.size(); i++) {
+ frame->lines.write[i].text_buf->set_width(table->columns[column].width);
+ table->columns.write[column].width = MAX(table->columns.write[column].width, ceil(frame->lines[i].text_buf->get_size().x));
+
+ if (i > 0) {
+ frame->lines.write[i].offset.y = frame->lines[i - 1].offset.y + frame->lines[i - 1].text_buf->get_size().y;
+ } else {
+ frame->lines.write[i].offset.y = 0;
+ }
+ frame->lines.write[i].offset += Vector2(offset.x, offset.y);
+
+ float h = frame->lines[i].text_buf->get_size().y;
+ if (frame->min_size_over.y > 0) {
+ h = MAX(h, frame->min_size_over.y);
+ }
+ if (frame->max_size_over.y > 0) {
+ h = MIN(h, frame->max_size_over.y);
+ }
+ yofs += h;
+ }
+ yofs += frame->padding.size.y;
+ offset.x += table->columns[column].width + hseparation + frame->padding.size.x;
+
+ row_height = MAX(yofs, row_height);
+ if (column == col_count - 1) {
+ offset.x = 0;
+ row_height += vseparation;
+ table->total_height += row_height;
+ offset.y += row_height;
+ table->rows.push_back(row_height);
+ row_height = 0;
+ }
+ idx++;
+ }
+ l.text_buf->resize_object((uint64_t)it, Size2(table->total_width, table->total_height), table->inline_align);
} break;
- case ITEM_TEXT: {
- ItemText *text = static_cast<ItemText *>(it);
+ default:
+ break;
+ }
+ }
+ if (p_line > 0) {
+ l.offset.y = p_frame->lines[p_line - 1].offset.y + p_frame->lines[p_line - 1].text_buf->get_size().y;
+ } else {
+ l.offset.y = 0;
+ }
+}
+
+void RichTextLabel::_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) {
+ ERR_FAIL_COND(p_frame == nullptr);
+ ERR_FAIL_COND(p_line < 0 || p_line >= p_frame->lines.size());
+
+ Line &l = p_frame->lines.write[p_line];
+
+ // Clear cache.
+ l.text_buf->clear();
+ l.text_buf->set_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_TRIM_EDGE_SPACES);
+ l.char_offset = *r_char_offset;
+ l.char_count = 0;
+
+ // Add indent.
+ l.offset.x = _find_margin(l.from, p_base_font, p_base_font_size);
+ l.text_buf->set_width(p_width - l.offset.x);
+ l.text_buf->set_align((HAlign)_find_align(l.from));
+ l.text_buf->set_direction(_find_direction(l.from));
+
+ if (tab_size > 0) { // Align inline tabs.
+ Vector<float> tabs;
+ tabs.push_back(tab_size * p_base_font->get_char_size('m', 0, p_base_font_size).width);
+ l.text_buf->tab_align(tabs);
+ }
+
+ // Shape current paragraph.
+ String text;
+ Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr;
+ for (Item *it = l.from; it && it != it_to; it = _get_next_item(it)) {
+ if (visible_characters >= 0 && l.char_offset + l.char_count > visible_characters) {
+ break;
+ }
+ switch (it->type) {
+ case ITEM_NEWLINE: {
Ref<Font> font = _find_font(it);
if (font.is_null()) {
font = p_base_font;
}
+ int font_size = _find_font_size(it);
+ if (font_size == -1) {
+ font_size = p_base_font_size;
+ }
+ l.text_buf->add_string("\n", font, font_size, Dictionary(), "");
+ text += "\n";
+ l.char_count += 1;
+ } break;
+ case ITEM_TEXT: {
+ ItemText *t = (ItemText *)it;
+ Ref<Font> font = _find_font(it);
+ if (font.is_null()) {
+ font = p_base_font;
+ }
+ int font_size = _find_font_size(it);
+ if (font_size == -1) {
+ font_size = p_base_font_size;
+ }
+ Dictionary font_ftr = _find_font_features(it);
+ String lang = _find_language(it);
+ String tx = t->text;
+ if (visible_characters >= 0 && l.char_offset + l.char_count + tx.length() > visible_characters) {
+ tx = tx.substr(0, l.char_offset + l.char_count + tx.length() - visible_characters);
+ }
- const char32_t *c = text->text.get_data();
- const char32_t *cf = c;
- int ascent = font->get_ascent();
- int descent = font->get_descent();
-
- Color color;
- Color font_color_shadow;
- bool underline = false;
- bool strikethrough = false;
- ItemFade *fade = nullptr;
- int it_char_start = p_char_count;
-
- Vector<ItemFX *> fx_stack = Vector<ItemFX *>();
- _fetch_item_fx_stack(text, fx_stack);
- bool custom_fx_ok = true;
-
- if (p_mode == PROCESS_DRAW) {
- color = _find_color(text, p_base_color);
- font_color_shadow = _find_color(text, p_font_color_shadow);
- if (_find_underline(text) || (_find_meta(text, &meta) && underline_meta)) {
- underline = true;
- } else if (_find_strikethrough(text)) {
- strikethrough = true;
- }
+ l.text_buf->add_string(tx, font, font_size, font_ftr, lang);
+ text += tx;
+ l.char_count += tx.length();
+ } break;
+ case ITEM_IMAGE: {
+ ItemImage *img = (ItemImage *)it;
+ l.text_buf->add_object((uint64_t)it, img->image->get_size(), img->inline_align, 1);
+ text += String::chr(0xfffc);
+ } break;
+ case ITEM_TABLE: {
+ ItemTable *table = static_cast<ItemTable *>(it);
+ int hseparation = get_theme_constant("table_hseparation");
+ int vseparation = get_theme_constant("table_vseparation");
+ int col_count = table->columns.size();
+ int t_char_count = 0;
+ // Set minimums to zero.
+ for (int i = 0; i < col_count; i++) {
+ table->columns.write[i].min_width = 0;
+ table->columns.write[i].max_width = 0;
+ table->columns.write[i].width = 0;
+ }
+ // Compute minimum width for each cell.
+ const int available_width = p_width - hseparation * (col_count - 1);
- Item *fade_item = it;
- while (fade_item) {
- if (fade_item->type == ITEM_FADE) {
- fade = static_cast<ItemFade *>(fade_item);
- break;
- }
- fade_item = fade_item->parent;
- }
+ 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());
- } else if (p_mode == PROCESS_CACHE) {
- l.char_count += text->text.length();
+ int column = idx % col_count;
+ for (int i = 0; i < frame->lines.size(); i++) {
+ int char_offset = l.char_offset + l.char_count;
+ _shape_line(frame, i, p_base_font, p_base_font_size, 1, &char_offset);
+ int cell_ch = (char_offset - (l.char_offset + l.char_count));
+ l.char_count += cell_ch;
+ t_char_count += cell_ch;
+
+ table->columns.write[column].min_width = MAX(table->columns[column].min_width, ceil(frame->lines[i].text_buf->get_size().x));
+ table->columns.write[column].max_width = MAX(table->columns[column].max_width, ceil(frame->lines[i].text_buf->get_non_wraped_size().x));
+ }
+ idx++;
}
- rchar = 0;
- //FontDrawer drawer(font, Color(1, 1, 1));
- while (*c) {
- int end = 0;
- int w = 0;
- int fw = 0;
+ // Compute available width and total ratio (for expanders).
+ int total_ratio = 0;
+ int remaining_width = available_width;
+ table->total_width = hseparation;
- lh = 0;
+ for (int i = 0; i < col_count; i++) {
+ remaining_width -= table->columns[i].min_width;
+ if (table->columns[i].max_width > table->columns[i].min_width) {
+ table->columns.write[i].expand = true;
+ }
+ if (table->columns[i].expand) {
+ total_ratio += table->columns[i].expand_ratio;
+ }
+ }
- if (p_mode != PROCESS_CACHE) {
- lh = line < l.height_caches.size() ? l.height_caches[line] : 1;
- line_ascent = line < l.ascent_caches.size() ? l.ascent_caches[line] : 1;
- line_descent = line < l.descent_caches.size() ? l.descent_caches[line] : 1;
+ // Assign actual widths.
+ for (int i = 0; i < col_count; i++) {
+ table->columns.write[i].width = table->columns[i].min_width;
+ if (table->columns[i].expand && total_ratio > 0) {
+ table->columns.write[i].width += table->columns[i].expand_ratio * remaining_width / total_ratio;
}
- while (c[end] != 0 && !(end && c[end - 1] == ' ' && c[end] != ' ')) {
- int cw = font->get_char_size(c[end], c[end + 1]).width;
- if (c[end] == '\t') {
- cw = tab_size * font->get_char_size(' ').width;
- }
+ table->total_width += table->columns[i].width + hseparation;
+ }
- if (end > 0 && fw + cw + begin > p_width) {
- break; //don't allow lines longer than assigned width
+ // Resize to max_width if needed and distribute the remaining space.
+ bool table_need_fit = true;
+ while (table_need_fit) {
+ table_need_fit = false;
+ // Fit slim.
+ for (int i = 0; i < col_count; i++) {
+ if (!table->columns[i].expand) {
+ continue;
+ }
+ int dif = table->columns[i].width - table->columns[i].max_width;
+ if (dif > 0) {
+ table_need_fit = true;
+ table->columns.write[i].width = table->columns[i].max_width;
+ table->total_width -= dif;
+ total_ratio -= table->columns[i].expand_ratio;
}
-
- fw += cw;
-
- end++;
}
- CHECK_HEIGHT(fh);
- ENSURE_WIDTH(fw);
-
- line_ascent = MAX(line_ascent, ascent);
- line_descent = MAX(line_descent, descent);
- fh = line_ascent + line_descent;
-
- if (end && c[end - 1] == ' ') {
- if (p_mode == PROCESS_CACHE) {
- spaces_size += font->get_char_size(' ').width;
- } else if (align == ALIGN_FILL) {
- int ln = MIN(l.offset_caches.size() - 1, line);
- if (l.space_caches[ln]) {
- align_ofs = spaces * l.offset_caches[ln] / l.space_caches[ln];
+ // Grow.
+ remaining_width = available_width - table->total_width;
+ if (remaining_width > 0 && total_ratio > 0) {
+ for (int i = 0; i < col_count; i++) {
+ if (table->columns[i].expand) {
+ int dif = table->columns[i].max_width - table->columns[i].width;
+ if (dif > 0) {
+ int slice = table->columns[i].expand_ratio * remaining_width / total_ratio;
+ int incr = MIN(dif, slice);
+ table->columns.write[i].width += incr;
+ table->total_width += incr;
+ }
}
}
- spaces++;
}
+ }
- {
- int ofs = 0 - backtrack;
+ // Update line width and get total height.
+ idx = 0;
+ table->total_height = 0;
+ table->rows.clear();
- for (int i = 0; i < end; i++) {
- int pofs = wofs + ofs;
+ Vector2 offset;
+ float row_height = 0;
- if (p_mode == PROCESS_POINTER && r_click_char && p_click_pos.y >= p_ofs.y + y && p_click_pos.y <= p_ofs.y + y + lh) {
- int cw = font->get_char_size(c[i], c[i + 1]).x;
+ 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());
- if (c[i] == '\t') {
- cw = tab_size * font->get_char_size(' ').width;
- }
+ int column = idx % col_count;
- if (p_click_pos.x - cw / 2 > p_ofs.x + align_ofs + pofs) {
- rchar = int((&c[i]) - cf);
- }
+ offset.x += frame->padding.position.x;
+ float yofs = frame->padding.position.y;
+ for (int i = 0; i < frame->lines.size(); i++) {
+ frame->lines.write[i].text_buf->set_width(table->columns[column].width);
+ table->columns.write[column].width = MAX(table->columns.write[column].width, ceil(frame->lines[i].text_buf->get_size().x));
- ofs += cw;
- } else if (p_mode == PROCESS_DRAW) {
- bool selected = false;
- Color fx_color = Color(color);
- Point2 fx_offset;
- char32_t fx_char = c[i];
-
- if (selection.active) {
- int cofs = (&c[i]) - cf;
- if ((text->index > selection.from->index || (text->index == selection.from->index && cofs >= selection.from_char)) && (text->index < selection.to->index || (text->index == selection.to->index && cofs <= selection.to_char))) {
- selected = true;
- }
- }
+ if (i > 0) {
+ frame->lines.write[i].offset.y = frame->lines[i - 1].offset.y + frame->lines[i - 1].text_buf->get_size().y;
+ } else {
+ frame->lines.write[i].offset.y = 0;
+ }
+ frame->lines.write[i].offset += Vector2(offset.x, offset.y);
- int cw = 0;
- int c_item_offset = p_char_count - it_char_start;
+ float h = frame->lines[i].text_buf->get_size().y;
+ if (frame->min_size_over.y > 0) {
+ h = MAX(h, frame->min_size_over.y);
+ }
+ if (frame->max_size_over.y > 0) {
+ h = MIN(h, frame->max_size_over.y);
+ }
+ yofs += h;
+ }
+ yofs += frame->padding.size.y;
+ offset.x += table->columns[column].width + hseparation + frame->padding.size.x;
- float faded_visibility = 1.0f;
- if (fade) {
- if (c_item_offset >= fade->starting_index) {
- faded_visibility -= (float)(c_item_offset - fade->starting_index) / (float)fade->length;
- faded_visibility = faded_visibility < 0.0f ? 0.0f : faded_visibility;
- }
- fx_color.a = faded_visibility;
- }
+ row_height = MAX(yofs, row_height);
+ if (column == col_count - 1) {
+ offset.x = 0;
+ row_height += vseparation;
+ table->total_height += row_height;
+ offset.y += row_height;
+ table->rows.push_back(row_height);
+ row_height = 0;
+ }
+ idx++;
+ }
+
+ l.text_buf->add_object((uint64_t)it, Size2(table->total_width, table->total_height), table->inline_align, t_char_count);
+ text += String::chr(0xfffc).repeat(t_char_count);
+ } break;
+ default:
+ break;
+ }
+ }
- bool visible = visible_characters < 0 || ((p_char_count < visible_characters && YRANGE_VISIBLE(y + lh - line_descent - line_ascent, line_ascent + line_descent)) &&
- faded_visibility > 0.0f);
+ //Apply BiDi override.
+ l.text_buf->set_bidi_override(structured_text_parser(_find_stt(l.from), st_args, text));
- const bool previously_visible = visible;
+ *r_char_offset = l.char_offset + l.char_count;
- for (int j = 0; j < fx_stack.size(); j++) {
- ItemFX *item_fx = fx_stack[j];
+ if (p_line > 0) {
+ l.offset.y = p_frame->lines[p_line - 1].offset.y + p_frame->lines[p_line - 1].text_buf->get_size().y;
+ } else {
+ l.offset.y = 0;
+ }
+}
- if (item_fx->type == ITEM_CUSTOMFX && custom_fx_ok) {
- ItemCustomFX *item_custom = static_cast<ItemCustomFX *>(item_fx);
+float RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &p_shadow_ofs) {
+ Vector2 off;
- Ref<CharFXTransform> charfx = item_custom->char_fx_transform;
- Ref<RichTextEffect> custom_effect = item_custom->custom_effect;
+ ERR_FAIL_COND_V(p_frame == nullptr, off.y);
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= p_frame->lines.size(), off.y);
- if (!custom_effect.is_null()) {
- charfx->elapsed_time = item_custom->elapsed_time;
- charfx->relative_index = c_item_offset;
- charfx->absolute_index = p_char_count;
- charfx->visibility = visible;
- charfx->offset = fx_offset;
- charfx->color = fx_color;
- charfx->character = fx_char;
+ Line &l = p_frame->lines.write[p_line];
- bool effect_status = custom_effect->_process_effect_impl(charfx);
- custom_fx_ok = effect_status;
+ Item *it_from = l.from;
+ Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr;
+ Variant meta;
- fx_offset += charfx->offset;
- fx_color = charfx->color;
- visible &= charfx->visibility;
- fx_char = charfx->character;
- }
- } else if (item_fx->type == ITEM_SHAKE) {
- ItemShake *item_shake = static_cast<ItemShake *>(item_fx);
-
- uint64_t char_current_rand = item_shake->offset_random(c_item_offset);
- uint64_t char_previous_rand = item_shake->offset_previous_random(c_item_offset);
- uint64_t max_rand = 2147483647;
- double current_offset = Math::range_lerp(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
- double previous_offset = Math::range_lerp(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
- double n_time = (double)(item_shake->elapsed_time / (0.5f / item_shake->rate));
- n_time = (n_time > 1.0) ? 1.0 : n_time;
- fx_offset += Point2(Math::lerp(Math::sin(previous_offset),
- Math::sin(current_offset),
- n_time),
- Math::lerp(Math::cos(previous_offset),
- Math::cos(current_offset),
- n_time)) *
- (float)item_shake->strength / 10.0f;
- } else if (item_fx->type == ITEM_WAVE) {
- ItemWave *item_wave = static_cast<ItemWave *>(item_fx);
-
- double value = Math::sin(item_wave->frequency * item_wave->elapsed_time + ((p_ofs.x + pofs) / 50)) * (item_wave->amplitude / 10.0f);
- fx_offset += Point2(0, 1) * value;
- } else if (item_fx->type == ITEM_TORNADO) {
- ItemTornado *item_tornado = static_cast<ItemTornado *>(item_fx);
-
- double torn_x = Math::sin(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + pofs) / 50)) * (item_tornado->radius);
- double torn_y = Math::cos(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + pofs) / 50)) * (item_tornado->radius);
- fx_offset += Point2(torn_x, torn_y);
- } else if (item_fx->type == ITEM_RAINBOW) {
- ItemRainbow *item_rainbow = static_cast<ItemRainbow *>(item_fx);
-
- fx_color = fx_color.from_hsv(item_rainbow->frequency * (item_rainbow->elapsed_time + ((p_ofs.x + pofs) / 50)),
- item_rainbow->saturation,
- item_rainbow->value,
- fx_color.a);
- }
- }
+ if (it_from == nullptr) {
+ return off.y;
+ }
- if (visible) {
- line_is_blank = false;
- w += font->get_char_size(c[i], c[i + 1]).x;
- }
+ RID ci = get_canvas_item();
+ bool rtl = (l.text_buf->get_direction() == TextServer::DIRECTION_RTL);
+ bool lrtl = is_layout_rtl();
- if (c[i] == '\t') {
- visible = false;
- }
+ Vector<int> list_index;
+ Vector<ItemList *> list_items;
+ _find_list(l.from, list_index, list_items);
- if (visible) {
- if (selected) {
- cw = font->get_char_size(fx_char, c[i + 1]).x;
- draw_rect(Rect2(p_ofs.x + pofs, p_ofs.y + y, cw, lh), selection_bg);
- }
+ String prefix;
+ for (int i = 0; i < list_index.size(); i++) {
+ if (rtl) {
+ prefix = prefix + ".";
+ } else {
+ prefix = "." + prefix;
+ }
+ String segment;
+ if (list_items[i]->list_type == LIST_DOTS) {
+ static const char32_t _prefix[2] = { 0x25CF, 0 };
+ prefix = _prefix;
+ break;
+ } else if (list_items[i]->list_type == LIST_NUMBERS) {
+ segment = TS->format_number(itos(list_index[i]), _find_language(l.from));
+ } else if (list_items[i]->list_type == LIST_LETTERS) {
+ segment = _letters(list_index[i], list_items[i]->capitalize);
+ } else if (list_items[i]->list_type == LIST_ROMAN) {
+ segment = _roman(list_index[i], list_items[i]->capitalize);
+ }
+ if (rtl) {
+ prefix = prefix + segment;
+ } else {
+ prefix = segment + prefix;
+ }
+ }
+ if (prefix != "") {
+ Ref<Font> font = _find_font(l.from);
+ if (font.is_null()) {
+ font = get_theme_font("normal_font");
+ }
+ int font_size = _find_font_size(l.from);
+ if (font_size == -1) {
+ font_size = get_theme_font_size("normal_font_size");
+ }
+ if (rtl) {
+ float offx = 0.0f;
+ if (!lrtl && p_frame == main) { // Skip Scrollbar.
+ offx -= scroll_w;
+ }
+ font->draw_string(ci, p_ofs + Vector2(p_width - l.offset.x + offx, l.text_buf->get_line_ascent(0)), " " + prefix, HALIGN_LEFT, l.offset.x, font_size, _find_color(l.from, p_base_color));
+ } else {
+ float offx = 0.0f;
+ if (lrtl && p_frame == main) { // Skip Scrollbar.
+ offx += scroll_w;
+ }
+ font->draw_string(ci, p_ofs + Vector2(offx, l.text_buf->get_line_ascent(0)), prefix + " ", HALIGN_RIGHT, l.offset.x, font_size, _find_color(l.from, p_base_color));
+ }
+ }
- if (p_font_color_shadow.a > 0) {
- float x_ofs_shadow = align_ofs + pofs;
- float y_ofs_shadow = y + lh - line_descent;
- font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + shadow_ofs + fx_offset, fx_char, c[i + 1], -1, p_font_color_shadow);
+ // Draw text.
+ for (int line = 0; line < l.text_buf->get_line_count(); line++) {
+ RID rid = l.text_buf->get_line_rid(line);
- if (p_shadow_as_outline) {
- font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(-shadow_ofs.x, shadow_ofs.y) + fx_offset, fx_char, c[i + 1], -1, p_font_color_shadow);
- font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(shadow_ofs.x, -shadow_ofs.y) + fx_offset, fx_char, c[i + 1], -1, p_font_color_shadow);
- font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(-shadow_ofs.x, -shadow_ofs.y) + fx_offset, fx_char, c[i + 1], -1, p_font_color_shadow);
- }
- }
+ float width = l.text_buf->get_width();
+ float length = TS->shaped_text_get_width(rid);
- if (selected) {
- font->draw_char(ci, p_ofs + Point2(align_ofs + pofs, y + lh - line_descent), fx_char, c[i + 1], -1, override_selected_font_color ? selection_fg : fx_color);
- } else {
- cw = font->draw_char(ci, p_ofs + Point2(align_ofs + pofs, y + lh - line_descent) + fx_offset, fx_char, c[i + 1], -1, fx_color);
- }
- } else if (previously_visible && c[i] != '\t') {
- backtrack += font->get_char_size(fx_char, c[i + 1]).x;
- }
+ // Draw line.
- p_char_count++;
- if (c[i] == '\t') {
- cw = tab_size * font->get_char_size(' ').width;
- backtrack = MAX(0, backtrack - cw);
+ if (rtl) {
+ off.x = p_width - l.offset.x - width;
+ if (!lrtl && p_frame == main) { // Skip Scrollbar.
+ off.x -= scroll_w;
+ }
+ } else {
+ off.x = l.offset.x;
+ if (lrtl && p_frame == main) { // Skip Scrollbar.
+ off.x += scroll_w;
+ }
+ }
+
+ // Draw text.
+ switch (l.text_buf->get_align()) {
+ case HALIGN_FILL:
+ case HALIGN_LEFT: {
+ if (rtl) {
+ off.x += width - length;
+ }
+ } break;
+ case HALIGN_CENTER: {
+ off.x += Math::floor((width - length) / 2.0);
+ } break;
+ case HALIGN_RIGHT: {
+ if (!rtl) {
+ off.x += width - length;
+ }
+ } break;
+ }
+
+ //draw_rect(Rect2(p_ofs + off, TS->shaped_text_get_size(rid)), Color(1,0,0), false, 2); //DEBUG_RECTS
+
+ off.y += TS->shaped_text_get_ascent(rid);
+ // Draw inlined objects.
+ Array objects = TS->shaped_text_get_objects(rid);
+ for (int i = 0; i < objects.size(); i++) {
+ Item *it = (Item *)(uint64_t)objects[i];
+ if (it != nullptr) {
+ Rect2 rect = TS->shaped_text_get_object_rect(rid, objects[i]);
+ //draw_rect(rect, Color(1,0,0), false, 2); //DEBUG_RECTS
+ switch (it->type) {
+ case ITEM_IMAGE: {
+ ItemImage *img = static_cast<ItemImage *>(it);
+ img->image->draw_rect(ci, Rect2(p_ofs + rect.position + off, rect.size), false, img->color);
+ } break;
+ case ITEM_TABLE: {
+ ItemTable *table = static_cast<ItemTable *>(it);
+ Color odd_row_bg = get_theme_color("table_odd_row_bg");
+ Color even_row_bg = get_theme_color("table_even_row_bg");
+ Color border = get_theme_color("table_border");
+ int col_count = table->columns.size();
+ int row_count = table->rows.size();
+
+ int idx = 0;
+ for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) {
+ ItemFrame *frame = static_cast<ItemFrame *>(E->get());
+
+ int col = idx % col_count;
+ int row = idx / col_count;
+
+ if (frame->lines.size() != 0 && row < row_count) {
+ Vector2 coff = frame->lines[0].offset;
+ if (rtl) {
+ coff.x = rect.size.width - table->columns[col].width - coff.x;
+ }
+ if (row % 2 == 0) {
+ draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width, table->rows[row])), (frame->odd_row_bg != Color(0, 0, 0, 0) ? frame->odd_row_bg : odd_row_bg), true);
+ } else {
+ draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width, table->rows[row])), (frame->even_row_bg != Color(0, 0, 0, 0) ? frame->even_row_bg : even_row_bg), true);
}
+ draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width, table->rows[row])), (frame->border != Color(0, 0, 0, 0) ? frame->border : border), false);
+ }
- ofs += cw;
+ for (int j = 0; j < frame->lines.size(); j++) {
+ _draw_line(frame, j, p_ofs + rect.position + off + Vector2(0, frame->lines[j].offset.y), rect.size.x, p_base_color, p_outline_size, p_outline_color, p_font_color_shadow, p_shadow_as_outline, p_shadow_ofs);
}
+ idx++;
}
+ } break;
+ default:
+ break;
+ }
+ }
+ }
- if (underline) {
- Color uc = color;
- uc.a *= 0.5;
- int uy = y + lh - line_descent + font->get_underline_position();
- float underline_width = font->get_underline_thickness();
-#ifdef TOOLS_ENABLED
- underline_width *= EDSCALE;
-#endif
- RS::get_singleton()->canvas_item_add_line(ci, p_ofs + Point2(align_ofs + wofs, uy), p_ofs + Point2(align_ofs + wofs + w, uy), uc, underline_width);
- } else if (strikethrough) {
- Color uc = color;
- uc.a *= 0.5;
- int uy = y + lh - (line_ascent + line_descent) / 2;
- float strikethrough_width = font->get_underline_thickness();
-#ifdef TOOLS_ENABLED
- strikethrough_width *= EDSCALE;
-#endif
- RS::get_singleton()->canvas_item_add_line(ci, p_ofs + Point2(align_ofs + wofs, uy), p_ofs + Point2(align_ofs + wofs + w, uy), uc, strikethrough_width);
- }
- }
+ const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(rid);
+ const TextServer::Glyph *glyphs = visual.ptr();
+ int gl_size = visual.size();
- ADVANCE(fw);
- CHECK_HEIGHT(fh); //must be done somewhere
- c = &c[end];
- }
+ Vector2 gloff = off;
+ // Draw oulines and shadow.
+ for (int i = 0; i < gl_size; i++) {
+ Item *it = _get_item_at_pos(it_from, it_to, glyphs[i].start);
+ int size = _find_outline_size(it);
+ Color font_color = _find_outline_color(it, Color(0, 0, 0, 0));
+ if (size <= 0) {
+ gloff.x += glyphs[i].advance;
+ continue;
+ }
- } break;
- case ITEM_IMAGE: {
- lh = 0;
- if (p_mode != PROCESS_CACHE) {
- lh = line < l.height_caches.size() ? l.height_caches[line] : 1;
- } else {
- l.char_count += 1; //images count as chars too
+ // Get FX.
+ ItemFade *fade = nullptr;
+ Item *fade_item = it;
+ while (fade_item) {
+ if (fade_item->type == ITEM_FADE) {
+ fade = static_cast<ItemFade *>(fade_item);
+ break;
}
+ fade_item = fade_item->parent;
+ }
- ItemImage *img = static_cast<ItemImage *>(it);
+ Vector<ItemFX *> fx_stack;
+ _fetch_item_fx_stack(it, fx_stack);
+ bool custom_fx_ok = true;
- Ref<Font> font = _find_font(it);
- if (font.is_null()) {
- font = p_base_font;
+ Point2 fx_offset = Vector2(glyphs[i].x_off, glyphs[i].y_off);
+ RID frid = glyphs[i].font_rid;
+ uint32_t gl = glyphs[i].index;
+
+ //Apply fx.
+ float faded_visibility = 1.0f;
+ if (fade) {
+ if (glyphs[i].start >= fade->starting_index) {
+ faded_visibility -= (float)(glyphs[i].start - fade->starting_index) / (float)fade->length;
+ faded_visibility = faded_visibility < 0.0f ? 0.0f : faded_visibility;
}
+ font_color.a = faded_visibility;
+ }
- if (p_mode == PROCESS_POINTER && r_click_char) {
- *r_click_char = 0;
+ bool visible = (font_color.a != 0);
+
+ for (int j = 0; j < fx_stack.size(); j++) {
+ ItemFX *item_fx = fx_stack[j];
+ if (item_fx->type == ITEM_CUSTOMFX && custom_fx_ok) {
+ ItemCustomFX *item_custom = static_cast<ItemCustomFX *>(item_fx);
+
+ Ref<CharFXTransform> charfx = item_custom->char_fx_transform;
+ Ref<RichTextEffect> custom_effect = item_custom->custom_effect;
+
+ if (!custom_effect.is_null()) {
+ charfx->elapsed_time = item_custom->elapsed_time;
+ charfx->range = Vector2i(l.char_offset + glyphs[i].start, l.char_offset + glyphs[i].end);
+ charfx->visibility = visible;
+ charfx->outline = true;
+ charfx->font = frid;
+ charfx->glpyh_index = gl;
+ charfx->offset = fx_offset;
+ charfx->color = font_color;
+
+ bool effect_status = custom_effect->_process_effect_impl(charfx);
+ custom_fx_ok = effect_status;
+
+ fx_offset += charfx->offset;
+ font_color = charfx->color;
+ frid = charfx->font;
+ gl = charfx->glpyh_index;
+ visible &= charfx->visibility;
+ }
+ } else if (item_fx->type == ITEM_SHAKE) {
+ ItemShake *item_shake = static_cast<ItemShake *>(item_fx);
+
+ uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start);
+ uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start);
+ uint64_t max_rand = 2147483647;
+ double current_offset = Math::range_lerp(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
+ double previous_offset = Math::range_lerp(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
+ double n_time = (double)(item_shake->elapsed_time / (0.5f / item_shake->rate));
+ n_time = (n_time > 1.0) ? 1.0 : n_time;
+ fx_offset += Point2(Math::lerp(Math::sin(previous_offset), Math::sin(current_offset), n_time), Math::lerp(Math::cos(previous_offset), Math::cos(current_offset), n_time)) * (float)item_shake->strength / 10.0f;
+ } else if (item_fx->type == ITEM_WAVE) {
+ ItemWave *item_wave = static_cast<ItemWave *>(item_fx);
+
+ double value = Math::sin(item_wave->frequency * item_wave->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_wave->amplitude / 10.0f);
+ fx_offset += Point2(0, 1) * value;
+ } else if (item_fx->type == ITEM_TORNADO) {
+ ItemTornado *item_tornado = static_cast<ItemTornado *>(item_fx);
+
+ double torn_x = Math::sin(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + gloff.x) / 50)) * (item_tornado->radius);
+ double torn_y = Math::cos(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + gloff.x) / 50)) * (item_tornado->radius);
+ fx_offset += Point2(torn_x, torn_y);
+ } else if (item_fx->type == ITEM_RAINBOW) {
+ ItemRainbow *item_rainbow = static_cast<ItemRainbow *>(item_fx);
+
+ font_color = font_color.from_hsv(item_rainbow->frequency * (item_rainbow->elapsed_time + ((p_ofs.x + gloff.x) / 50)), item_rainbow->saturation, item_rainbow->value, font_color.a);
}
+ }
- ENSURE_WIDTH(img->size.width);
+ Point2 shadow_ofs(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y"));
- bool visible = visible_characters < 0 || (p_char_count < visible_characters && YRANGE_VISIBLE(y + lh - font->get_descent() - img->size.height, img->size.height));
+ // Draw glyph outlines.
+ for (int j = 0; j < glyphs[i].repeat; j++) {
if (visible) {
- line_is_blank = false;
- }
-
- if (p_mode == PROCESS_DRAW && visible) {
- img->image->draw_rect(ci, Rect2(p_ofs + Point2(align_ofs + wofs, y + lh - font->get_descent() - img->size.height), img->size), false, img->color);
+ if (frid != RID()) {
+ if (p_shadow_as_outline) {
+ TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, size, p_ofs + fx_offset + gloff + Vector2(-shadow_ofs.x, shadow_ofs.y), gl, p_font_color_shadow);
+ TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, size, p_ofs + fx_offset + gloff + Vector2(shadow_ofs.x, -shadow_ofs.y), gl, p_font_color_shadow);
+ TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, size, p_ofs + fx_offset + gloff + Vector2(-shadow_ofs.x, -shadow_ofs.y), gl, p_font_color_shadow);
+ }
+ TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, size, p_ofs + fx_offset + gloff, gl, font_color);
+ }
}
- p_char_count++;
+ gloff.x += glyphs[i].advance;
+ }
+ }
- ADVANCE(img->size.width);
- CHECK_HEIGHT((img->size.height + font->get_descent()));
+ // Draw main text.
+ Color selection_fg = get_theme_color("font_color_selected");
+ Color selection_bg = get_theme_color("selection_color");
- } break;
- case ITEM_NEWLINE: {
- lh = 0;
+ int sel_start = -1;
+ int sel_end = -1;
- if (p_mode != PROCESS_CACHE) {
- lh = line < l.height_caches.size() ? l.height_caches[line] : 1;
- line_is_blank = true;
- }
+ if (selection.active && (selection.from_frame->lines[selection.from_line].char_offset + selection.from_char) <= (l.char_offset + TS->shaped_text_get_range(rid).y) && (selection.to_frame->lines[selection.to_line].char_offset + selection.to_char) >= (l.char_offset + TS->shaped_text_get_range(rid).x)) {
+ sel_start = MAX(TS->shaped_text_get_range(rid).x, (selection.from_frame->lines[selection.from_line].char_offset + selection.from_char) - l.char_offset);
+ sel_end = MIN(TS->shaped_text_get_range(rid).y, (selection.to_frame->lines[selection.to_line].char_offset + selection.to_char) - l.char_offset);
- } break;
- case ITEM_TABLE: {
- lh = 0;
- ItemTable *table = static_cast<ItemTable *>(it);
- int hseparation = get_theme_constant("table_hseparation");
- int vseparation = get_theme_constant("table_vseparation");
- Color ccolor = _find_color(table, p_base_color);
- Vector2 draw_ofs = Point2(wofs, y);
- Color font_color_shadow = get_theme_color("font_color_shadow");
- bool use_outline = get_theme_constant("shadow_as_outline");
- Point2 shadow_ofs2(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y"));
-
- if (p_mode == PROCESS_CACHE) {
- int idx = 0;
- //set minimums to zero
- for (int i = 0; i < table->columns.size(); i++) {
- table->columns.write[i].min_width = 0;
- table->columns.write[i].max_width = 0;
- table->columns.write[i].width = 0;
- }
- //compute minimum width for each cell
- const int available_width = p_width - hseparation * (table->columns.size() - 1) - wofs;
-
- 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());
+ Vector<Vector2> sel = TS->shaped_text_get_selection(rid, sel_start, sel_end);
+ for (int i = 0; i < sel.size(); i++) {
+ Rect2 rect = Rect2(sel[i].x + p_ofs.x + off.x, p_ofs.y + off.y - TS->shaped_text_get_ascent(rid), sel[i].y - sel[i].x, TS->shaped_text_get_size(rid).y);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, selection_bg);
+ }
+ }
- int column = idx % table->columns.size();
+ for (int i = 0; i < gl_size; i++) {
+ bool selected = selection.active && (sel_start != -1) && (glyphs[i].start >= sel_start) && (glyphs[i].end <= sel_end);
+ Item *it = _get_item_at_pos(it_from, it_to, glyphs[i].start);
+ Color font_color = _find_color(it, p_base_color);
+ if (_find_underline(it) || (_find_meta(it, &meta) && underline_meta)) {
+ Color uc = font_color;
+ uc.a *= 0.5;
+ float y_off = TS->shaped_text_get_underline_position(rid);
+ float underline_width = TS->shaped_text_get_underline_thickness(rid);
+#ifdef TOOLS_ENABLED
+ underline_width *= EDSCALE;
+#endif
+ draw_line(p_ofs + Vector2(off.x, off.y + y_off), p_ofs + Vector2(off.x + glyphs[i].advance * glyphs[i].repeat, off.y + y_off), uc, underline_width);
+ } else if (_find_strikethrough(it)) {
+ Color uc = font_color;
+ uc.a *= 0.5;
+ float y_off = -TS->shaped_text_get_ascent(rid) + TS->shaped_text_get_size(rid).y / 2;
+ float underline_width = TS->shaped_text_get_underline_thickness(rid);
+#ifdef TOOLS_ENABLED
+ underline_width *= EDSCALE;
+#endif
+ draw_line(p_ofs + Vector2(off.x, off.y + y_off), p_ofs + Vector2(off.x + glyphs[i].advance * glyphs[i].repeat, off.y + y_off), uc, underline_width);
+ }
- int ly = 0;
+ // Get FX.
+ ItemFade *fade = nullptr;
+ Item *fade_item = it;
+ while (fade_item) {
+ if (fade_item->type == ITEM_FADE) {
+ fade = static_cast<ItemFade *>(fade_item);
+ break;
+ }
+ fade_item = fade_item->parent;
+ }
- for (int i = 0; i < frame->lines.size(); i++) {
- _process_line(frame, Point2(), ly, available_width, i, PROCESS_CACHE, cfont, Color(), font_color_shadow, use_outline, shadow_ofs2);
- table->columns.write[column].min_width = MAX(table->columns[column].min_width, frame->lines[i].minimum_width);
- table->columns.write[column].max_width = MAX(table->columns[column].max_width, frame->lines[i].maximum_width);
- }
- idx++;
- }
+ Vector<ItemFX *> fx_stack;
+ _fetch_item_fx_stack(it, fx_stack);
+ bool custom_fx_ok = true;
- //compute available width and total ratio (for expanders)
+ Point2 fx_offset = Vector2(glyphs[i].x_off, glyphs[i].y_off);
+ RID frid = glyphs[i].font_rid;
+ uint32_t gl = glyphs[i].index;
- int total_ratio = 0;
- int remaining_width = available_width;
- table->total_width = hseparation;
+ //Apply fx.
+ float faded_visibility = 1.0f;
+ if (fade) {
+ if (glyphs[i].start >= fade->starting_index) {
+ faded_visibility -= (float)(glyphs[i].start - fade->starting_index) / (float)fade->length;
+ faded_visibility = faded_visibility < 0.0f ? 0.0f : faded_visibility;
+ }
+ font_color.a = faded_visibility;
+ }
- for (int i = 0; i < table->columns.size(); i++) {
- remaining_width -= table->columns[i].min_width;
- if (table->columns[i].max_width > table->columns[i].min_width) {
- table->columns.write[i].expand = true;
- }
- if (table->columns[i].expand) {
- total_ratio += table->columns[i].expand_ratio;
- }
+ bool visible = (font_color.a != 0);
+
+ for (int j = 0; j < fx_stack.size(); j++) {
+ ItemFX *item_fx = fx_stack[j];
+ if (item_fx->type == ITEM_CUSTOMFX && custom_fx_ok) {
+ ItemCustomFX *item_custom = static_cast<ItemCustomFX *>(item_fx);
+
+ Ref<CharFXTransform> charfx = item_custom->char_fx_transform;
+ Ref<RichTextEffect> custom_effect = item_custom->custom_effect;
+
+ if (!custom_effect.is_null()) {
+ charfx->elapsed_time = item_custom->elapsed_time;
+ charfx->range = Vector2i(l.char_offset + glyphs[i].start, l.char_offset + glyphs[i].end);
+ charfx->visibility = visible;
+ charfx->outline = false;
+ charfx->font = frid;
+ charfx->glpyh_index = gl;
+ charfx->offset = fx_offset;
+ charfx->color = font_color;
+
+ bool effect_status = custom_effect->_process_effect_impl(charfx);
+ custom_fx_ok = effect_status;
+
+ fx_offset += charfx->offset;
+ font_color = charfx->color;
+ frid = charfx->font;
+ gl = charfx->glpyh_index;
+ visible &= charfx->visibility;
}
+ } else if (item_fx->type == ITEM_SHAKE) {
+ ItemShake *item_shake = static_cast<ItemShake *>(item_fx);
+
+ uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start);
+ uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start);
+ uint64_t max_rand = 2147483647;
+ double current_offset = Math::range_lerp(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
+ double previous_offset = Math::range_lerp(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
+ double n_time = (double)(item_shake->elapsed_time / (0.5f / item_shake->rate));
+ n_time = (n_time > 1.0) ? 1.0 : n_time;
+ fx_offset += Point2(Math::lerp(Math::sin(previous_offset), Math::sin(current_offset), n_time), Math::lerp(Math::cos(previous_offset), Math::cos(current_offset), n_time)) * (float)item_shake->strength / 10.0f;
+ } else if (item_fx->type == ITEM_WAVE) {
+ ItemWave *item_wave = static_cast<ItemWave *>(item_fx);
+
+ double value = Math::sin(item_wave->frequency * item_wave->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_wave->amplitude / 10.0f);
+ fx_offset += Point2(0, 1) * value;
+ } else if (item_fx->type == ITEM_TORNADO) {
+ ItemTornado *item_tornado = static_cast<ItemTornado *>(item_fx);
+
+ double torn_x = Math::sin(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_tornado->radius);
+ double torn_y = Math::cos(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_tornado->radius);
+ fx_offset += Point2(torn_x, torn_y);
+ } else if (item_fx->type == ITEM_RAINBOW) {
+ ItemRainbow *item_rainbow = static_cast<ItemRainbow *>(item_fx);
+
+ font_color = font_color.from_hsv(item_rainbow->frequency * (item_rainbow->elapsed_time + ((p_ofs.x + off.x) / 50)), item_rainbow->saturation, item_rainbow->value, font_color.a);
+ }
+ }
- //assign actual widths
- for (int i = 0; i < table->columns.size(); i++) {
- table->columns.write[i].width = table->columns[i].min_width;
- if (table->columns[i].expand && total_ratio > 0) {
- table->columns.write[i].width += table->columns[i].expand_ratio * remaining_width / total_ratio;
- }
- table->total_width += table->columns[i].width + hseparation;
- }
+ if (selected) {
+ font_color = override_selected_font_color ? selection_fg : font_color;
+ }
- //resize to max_width if needed and distribute the remaining space
- bool table_need_fit = true;
- while (table_need_fit) {
- table_need_fit = false;
- //fit slim
- for (int i = 0; i < table->columns.size(); i++) {
- if (!table->columns[i].expand) {
- continue;
- }
- int dif = table->columns[i].width - table->columns[i].max_width;
- if (dif > 0) {
- table_need_fit = true;
- table->columns.write[i].width = table->columns[i].max_width;
- table->total_width -= dif;
- total_ratio -= table->columns[i].expand_ratio;
- }
- }
- //grow
- remaining_width = available_width - table->total_width;
- if (remaining_width > 0 && total_ratio > 0) {
- for (int i = 0; i < table->columns.size(); i++) {
- if (table->columns[i].expand) {
- int dif = table->columns[i].max_width - table->columns[i].width;
- if (dif > 0) {
- int slice = table->columns[i].expand_ratio * remaining_width / total_ratio;
- int incr = MIN(dif, slice);
- table->columns.write[i].width += incr;
- table->total_width += incr;
- }
- }
- }
- }
+ // Draw glyphs.
+ for (int j = 0; j < glyphs[i].repeat; j++) {
+ if (visible) {
+ if (frid != RID()) {
+ TS->font_draw_glyph(frid, ci, glyphs[i].font_size, p_ofs + fx_offset + off, gl, selected ? selection_fg : font_color);
+ } else if ((glyphs[i].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
+ TS->draw_hex_code_box(ci, glyphs[i].font_size, p_ofs + fx_offset + off, gl, selected ? selection_fg : font_color);
}
+ }
+ off.x += glyphs[i].advance;
+ }
+ }
+ off.y += TS->shaped_text_get_descent(rid);
+ }
- //compute caches properly again with the right width
- 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());
+ return off.y;
+}
- int column = idx % table->columns.size();
+void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, ItemFrame **r_click_frame, int *r_click_line, Item **r_click_item, int *r_click_char, bool *r_outside) {
+ if (r_click_item) {
+ *r_click_item = nullptr;
+ }
+ if (r_click_char != nullptr) {
+ *r_click_char = 0;
+ }
+ if (r_outside != nullptr) {
+ *r_outside = true;
+ }
- for (int i = 0; i < frame->lines.size(); i++) {
- int ly = 0;
- _process_line(frame, Point2(), ly, table->columns[column].width, i, PROCESS_CACHE, cfont, Color(), font_color_shadow, use_outline, shadow_ofs2);
- frame->lines.write[i].height_cache = ly; //actual height
- frame->lines.write[i].height_accum_cache = ly; //actual height
- }
- idx++;
- }
- }
+ Size2 size = get_size();
+ Rect2 text_rect = _get_text_rect();
- Point2 offset(align_ofs + hseparation, vseparation);
+ int vofs = vscroll->get_value();
- int row_height = 0;
- //draw using computed caches
- 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());
+ // Search for the first line.
+ int from_line = 0;
- int column = idx % table->columns.size();
+ //TODO, change to binary search ?
+ while (from_line < main->lines.size()) {
+ if (main->lines[from_line].offset.y + main->lines[from_line].text_buf->get_size().y + _get_text_rect().get_position().y >= vofs) {
+ break;
+ }
+ from_line++;
+ }
+
+ if (from_line >= main->lines.size()) {
+ return;
+ }
- int ly = 0;
- int yofs = 0;
+ Point2 ofs = text_rect.get_position() + Vector2(0, main->lines[from_line].offset.y - vofs);
+ while (ofs.y < size.height && from_line < main->lines.size()) {
+ ofs.y += _find_click_in_line(p_frame, from_line, ofs, text_rect.size.x, p_click, r_click_frame, r_click_line, r_click_item, r_click_char);
+ if (((r_click_item != nullptr) && ((*r_click_item) != nullptr)) || ((r_click_frame != nullptr) && ((*r_click_frame) != nullptr))) {
+ if (r_outside != nullptr) {
+ *r_outside = false;
+ }
+ return;
+ }
+ from_line++;
+ }
+}
- int lines_h = frame->lines[frame->lines.size() - 1].height_accum_cache - (frame->lines[0].height_accum_cache - frame->lines[0].height_cache);
- int lines_ofs = p_ofs.y + offset.y + draw_ofs.y;
+float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Point2i &p_click, ItemFrame **r_click_frame, int *r_click_line, Item **r_click_item, int *r_click_char) {
+ Vector2 off;
- bool visible = lines_ofs < get_size().height && lines_ofs + lines_h >= 0;
- if (visible) {
- line_is_blank = false;
- }
+ int char_pos = -1;
+ Line &l = p_frame->lines.write[p_line];
+ bool rtl = (l.text_buf->get_direction() == TextServer::DIRECTION_RTL);
+ bool lrtl = is_layout_rtl();
+ bool table_hit = false;
- for (int i = 0; i < frame->lines.size(); i++) {
- if (visible) {
- if (p_mode == PROCESS_DRAW) {
- nonblank_line_count += _process_line(frame, p_ofs + offset + draw_ofs + Vector2(0, yofs), ly, table->columns[column].width, i, PROCESS_DRAW, cfont, ccolor, font_color_shadow, use_outline, shadow_ofs2);
- } else if (p_mode == PROCESS_POINTER) {
- _process_line(frame, p_ofs + offset + draw_ofs + Vector2(0, yofs), ly, table->columns[column].width, i, PROCESS_POINTER, cfont, ccolor, font_color_shadow, use_outline, shadow_ofs2, p_click_pos, r_click_item, r_click_char, r_outside);
- if (r_click_item && *r_click_item) {
- RETURN; // exit early
- }
- }
- }
+ for (int line = 0; line < l.text_buf->get_line_count(); line++) {
+ RID rid = l.text_buf->get_line_rid(line);
- yofs += frame->lines[i].height_cache;
- if (p_mode == PROCESS_CACHE) {
- frame->lines.write[i].height_accum_cache = offset.y + draw_ofs.y + frame->lines[i].height_cache;
- }
- }
+ float width = l.text_buf->get_width();
+ float length = TS->shaped_text_get_width(rid);
- row_height = MAX(yofs, row_height);
- offset.x += table->columns[column].width + hseparation;
+ if (rtl) {
+ off.x = p_width - l.offset.x - width;
+ if (!lrtl && p_frame == main) { // Skip Scrollbar.
+ off.x -= scroll_w;
+ }
+ } else {
+ off.x = l.offset.x;
+ if (lrtl && p_frame == main) { // Skip Scrollbar.
+ off.x += scroll_w;
+ }
+ }
- if (column == table->columns.size() - 1) {
- offset.y += row_height + vseparation;
- offset.x = hseparation;
- row_height = 0;
- }
- idx++;
+ switch (l.text_buf->get_align()) {
+ case HALIGN_FILL:
+ case HALIGN_LEFT: {
+ if (rtl) {
+ off.x += width - length;
}
-
- int total_height = offset.y;
- if (row_height) {
- total_height = row_height + vseparation;
+ } break;
+ case HALIGN_CENTER: {
+ off.x += Math::floor((width - length) / 2.0);
+ } break;
+ case HALIGN_RIGHT: {
+ if (!rtl) {
+ off.x += width - length;
}
+ } break;
+ }
- ADVANCE(table->total_width);
- CHECK_HEIGHT(total_height);
+ off.y += TS->shaped_text_get_ascent(rid);
- } break;
+ Array objects = TS->shaped_text_get_objects(rid);
+ for (int i = 0; i < objects.size(); i++) {
+ Item *it = (Item *)(uint64_t)objects[i];
+ if (it != nullptr) {
+ Rect2 rect = TS->shaped_text_get_object_rect(rid, objects[i]);
+ if (rect.has_point(p_click - p_ofs - off)) {
+ switch (it->type) {
+ case ITEM_TABLE: {
+ int hseparation = get_theme_constant("table_hseparation");
+ int vseparation = get_theme_constant("table_vseparation");
- default: {
- }
- }
+ ItemTable *table = static_cast<ItemTable *>(it);
+
+ table_hit = true;
+
+ int idx = 0;
+ int col_count = table->columns.size();
+ int row_count = table->rows.size();
- Item *itp = it;
+ for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) {
+ ItemFrame *frame = static_cast<ItemFrame *>(E->get());
- it = _get_next_item(it);
+ int col = idx % col_count;
+ int row = idx / col_count;
- if (it && (p_line + 1 < p_frame->lines.size()) && p_frame->lines[p_line + 1].from == it) {
- if (p_mode == PROCESS_POINTER && r_click_item && p_click_pos.y >= p_ofs.y + y && p_click_pos.y <= p_ofs.y + y + lh) {
- //went to next line, but pointer was on the previous one
- if (r_outside) {
- *r_outside = true;
+ if (frame->lines.size() != 0 && row < row_count) {
+ Vector2 coff = frame->lines[0].offset;
+ if (rtl) {
+ coff.x = rect.size.width - table->columns[col].width - coff.x;
+ }
+ Rect2 crect = Rect2(p_ofs + off + rect.position + coff - frame->padding.position, Size2(table->columns[col].width + hseparation, table->rows[row] + vseparation) + frame->padding.position + frame->padding.size);
+ if (col == col_count - 1) {
+ if (rtl) {
+ crect.size.x = crect.position.x + crect.size.x;
+ crect.position.x = 0;
+ } else {
+ crect.size.x = get_size().x;
+ }
+ }
+ if (crect.has_point(p_click)) {
+ for (int j = 0; j < frame->lines.size(); j++) {
+ _find_click_in_line(frame, j, p_ofs + off + rect.position + Vector2(0, frame->lines[j].offset.y), rect.size.x, p_click, r_click_frame, r_click_line, r_click_item, r_click_char);
+ if (((r_click_item != nullptr) && ((*r_click_item) != nullptr)) || ((r_click_frame != nullptr) && ((*r_click_frame) != nullptr))) {
+ return off.y;
+ }
+ }
+ }
+ }
+ idx++;
+ }
+ } break;
+ default:
+ break;
+ }
}
- *r_click_item = itp;
- *r_click_char = rchar;
- RETURN;
}
+ }
+ Rect2 rect = Rect2(p_ofs + off - Vector2(0, TS->shaped_text_get_ascent(rid)), Size2(get_size().x, TS->shaped_text_get_size(rid).y));
- break;
+ if (rect.has_point(p_click) && !table_hit) {
+ char_pos = TS->shaped_text_hit_test_position(rid, p_click.x - rect.position.x);
}
+ off.y += TS->shaped_text_get_descent(rid);
}
- NEW_LINE;
- RETURN;
+ if (char_pos >= 0) {
+ // Find item.
+ if (r_click_item != nullptr) {
+ Item *it = p_frame->lines[p_line].from;
+ Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr;
+ it = _get_item_at_pos(it, it_to, char_pos);
+ *r_click_item = it;
+ }
+
+ if (r_click_frame != nullptr) {
+ *r_click_frame = p_frame;
+ }
+
+ if (r_click_line != nullptr) {
+ *r_click_line = p_line;
+ }
+
+ if (r_click_char != nullptr) {
+ *r_click_char = char_pos;
+ }
+ }
-#undef RETURN
-#undef NEW_LINE
-#undef ENSURE_WIDTH
-#undef ADVANCE
-#undef CHECK_HEIGHT
+ return off.y;
}
void RichTextLabel::_scroll_changed(double) {
@@ -910,7 +1257,7 @@ void RichTextLabel::_update_scroll() {
vscroll->hide();
}
- main->first_invalid_line = 0; //invalidate ALL
+ main->first_resized_line = 0; //invalidate ALL
_validate_line_caches(main);
}
}
@@ -960,10 +1307,11 @@ void RichTextLabel::_notification(int p_what) {
}
} break;
case NOTIFICATION_RESIZED: {
- main->first_invalid_line = 0; //invalidate ALL
+ main->first_resized_line = 0; //invalidate ALL
update();
} break;
+ case NOTIFICATION_THEME_CHANGED:
case NOTIFICATION_ENTER_TREE: {
if (bbcode != "") {
set_bbcode(bbcode);
@@ -971,11 +1319,11 @@ void RichTextLabel::_notification(int p_what) {
main->first_invalid_line = 0; //invalidate ALL
update();
-
} break;
- case NOTIFICATION_THEME_CHANGED: {
+ case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
+ case NOTIFICATION_TRANSLATION_CHANGED: {
+ main->first_invalid_line = 0; //invalidate ALL
update();
-
} break;
case NOTIFICATION_DRAW: {
_validate_line_caches(main);
@@ -994,36 +1342,37 @@ void RichTextLabel::_notification(int p_what) {
RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, false);
}
- int ofs = vscroll->get_value();
-
- //todo, change to binary search
+ float vofs = vscroll->get_value();
+ // Search for the first line.
int from_line = 0;
- int total_chars = 0;
+
+ //TODO, change to binary search ?
while (from_line < main->lines.size()) {
- if (main->lines[from_line].height_accum_cache + _get_text_rect().get_position().y >= ofs) {
+ if (main->lines[from_line].offset.y + main->lines[from_line].text_buf->get_size().y + _get_text_rect().get_position().y >= vofs) {
break;
}
- total_chars += main->lines[from_line].char_count;
from_line++;
}
if (from_line >= main->lines.size()) {
break; //nothing to draw
}
- int y = (main->lines[from_line].height_accum_cache - main->lines[from_line].height_cache) - ofs;
Ref<Font> base_font = get_theme_font("normal_font");
Color base_color = get_theme_color("default_color");
+ Color outline_color = get_theme_color("outline_color");
+ int outline_size = get_theme_constant("outline_size");
Color font_color_shadow = get_theme_color("font_color_shadow");
bool use_outline = get_theme_constant("shadow_as_outline");
Point2 shadow_ofs(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y"));
visible_line_count = 0;
- while (y < size.height && from_line < main->lines.size()) {
- visible_line_count++;
- _process_line(main, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, from_line, PROCESS_DRAW, base_font, base_color, font_color_shadow, use_outline, shadow_ofs, Point2i(), nullptr, nullptr, nullptr, total_chars);
- total_chars += main->lines[from_line].char_count;
+ // New cache draw.
+ Point2 ofs = text_rect.get_position() + Vector2(0, main->lines[from_line].offset.y - vofs);
+ while (ofs.y < size.height && from_line < main->lines.size()) {
+ visible_line_count++;
+ ofs.y += _draw_line(main, from_line, ofs, text_rect.size.x, base_color, outline_size, outline_color, font_color_shadow, use_outline, shadow_ofs);
from_line++;
}
} break;
@@ -1036,50 +1385,12 @@ void RichTextLabel::_notification(int p_what) {
}
}
-void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item **r_click_item, int *r_click_char, bool *r_outside) {
- if (r_click_item) {
- *r_click_item = nullptr;
- }
-
- Rect2 text_rect = _get_text_rect();
- int ofs = vscroll->get_value();
- Color font_color_shadow = get_theme_color("font_color_shadow");
- bool use_outline = get_theme_constant("shadow_as_outline");
- Point2 shadow_ofs(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y"));
-
- //todo, change to binary search
- int from_line = 0;
-
- while (from_line < p_frame->lines.size()) {
- if (p_frame->lines[from_line].height_accum_cache >= ofs) {
- break;
- }
- from_line++;
- }
-
- if (from_line >= p_frame->lines.size()) {
- return;
- }
-
- int y = (p_frame->lines[from_line].height_accum_cache - p_frame->lines[from_line].height_cache) - ofs;
- Ref<Font> base_font = get_theme_font("normal_font");
- Color base_color = get_theme_color("default_color");
-
- while (y < text_rect.get_size().height && from_line < p_frame->lines.size()) {
- _process_line(p_frame, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, from_line, PROCESS_POINTER, base_font, base_color, font_color_shadow, use_outline, shadow_ofs, p_click, r_click_item, r_click_char, r_outside);
- if (r_click_item && *r_click_item) {
- return;
- }
- from_line++;
- }
-}
-
Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const {
if (!underline_meta) {
return CURSOR_ARROW;
}
- if (selection.click) {
+ if (selection.click_item) {
return CURSOR_IBEAM;
}
@@ -1087,10 +1398,13 @@ Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const
return CURSOR_ARROW; //invalid
}
- int line = 0;
+ if (main->first_resized_line < main->lines.size()) {
+ return CURSOR_ARROW; //invalid
+ }
+
Item *item = nullptr;
- bool outside;
- ((RichTextLabel *)(this))->_find_click(main, p_pos, &item, &line, &outside);
+ bool outside = true;
+ ((RichTextLabel *)(this))->_find_click(main, p_pos, nullptr, nullptr, &item, nullptr, &outside);
if (item && !outside && ((RichTextLabel *)(this))->_find_meta(item, nullptr)) {
return CURSOR_POINTING_HAND;
@@ -1106,27 +1420,37 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
if (main->first_invalid_line < main->lines.size()) {
return;
}
+ if (main->first_resized_line < main->lines.size()) {
+ return;
+ }
if (b->get_button_index() == BUTTON_LEFT) {
if (b->is_pressed() && !b->is_doubleclick()) {
scroll_updated = false;
- int line = 0;
- Item *item = nullptr;
-
+ ItemFrame *c_frame = nullptr;
+ int c_line = 0;
+ Item *c_item = nullptr;
+ int c_index = 0;
bool outside;
- _find_click(main, b->get_position(), &item, &line, &outside);
- if (item) {
+ _find_click(main, b->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside);
+ if (c_item != nullptr) {
if (selection.enabled) {
- selection.click = item;
- selection.click_char = line;
+ selection.click_frame = c_frame;
+ selection.click_item = c_item;
+ selection.click_line = c_line;
+ selection.click_char = c_index;
// Erase previous selection.
if (selection.active) {
- selection.from = nullptr;
- selection.from_char = '\0';
- selection.to = nullptr;
- selection.to_char = '\0';
+ selection.from_frame = nullptr;
+ selection.from_line = 0;
+ selection.from_item = nullptr;
+ selection.from_char = 0;
+ selection.to_frame = nullptr;
+ selection.to_line = 0;
+ selection.to_item = nullptr;
+ selection.to_char = 0;
selection.active = false;
update();
@@ -1135,44 +1459,49 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
}
} else if (b->is_pressed() && b->is_doubleclick() && selection.enabled) {
//doubleclick: select word
- int line = 0;
- Item *item = nullptr;
+
+ ItemFrame *c_frame = nullptr;
+ int c_line = 0;
+ Item *c_item = nullptr;
+ int c_index = 0;
bool outside;
- _find_click(main, b->get_position(), &item, &line, &outside);
+ _find_click(main, b->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside);
- while (item && item->type != ITEM_TEXT) {
- item = _get_next_item(item, true);
- }
+ if (c_frame) {
+ const Line &l = c_frame->lines[c_line];
+ Vector<Vector2i> words = TS->shaped_text_get_word_breaks(l.text_buf->get_rid());
+ for (int i = 0; i < words.size(); i++) {
+ if (c_index >= words[i].x && c_index < words[i].y) {
+ selection.from_frame = c_frame;
+ selection.from_line = c_line;
+ selection.from_item = c_item;
+ selection.from_char = words[i].x;
- if (item && item->type == ITEM_TEXT) {
- String itext = static_cast<ItemText *>(item)->text;
-
- int beg, end;
- if (select_word(itext, line, beg, end)) {
- selection.from = item;
- selection.to = item;
- selection.from_char = beg;
- selection.to_char = end - 1;
- selection.active = true;
- update();
+ selection.to_frame = c_frame;
+ selection.to_line = c_line;
+ selection.to_item = c_item;
+ selection.to_char = words[i].y;
+
+ selection.active = true;
+ update();
+ break;
+ }
}
}
} else if (!b->is_pressed()) {
- selection.click = nullptr;
+ selection.click_item = nullptr;
if (!b->is_doubleclick() && !scroll_updated) {
- int line = 0;
- Item *item = nullptr;
+ Item *c_item = nullptr;
- bool outside;
- _find_click(main, b->get_position(), &item, &line, &outside);
+ bool outside = true;
+ _find_click(main, b->get_position(), nullptr, nullptr, &c_item, nullptr, &outside);
- if (item) {
+ if (c_item) {
Variant meta;
- if (!outside && _find_meta(item, &meta)) {
+ if (!outside && _find_meta(c_item, &meta)) {
//meta clicked
-
emit_signal("meta_clicked", meta);
}
}
@@ -1221,13 +1550,13 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
} break;
case KEY_UP: {
if (vscroll->is_visible_in_tree()) {
- vscroll->set_value(vscroll->get_value() - get_theme_font("normal_font")->get_height());
+ vscroll->set_value(vscroll->get_value() - get_theme_font("normal_font")->get_height(get_theme_font_size("normal_font_size")));
handled = true;
}
} break;
case KEY_DOWN: {
if (vscroll->is_visible_in_tree()) {
- vscroll->set_value(vscroll->get_value() + get_theme_font("normal_font")->get_height());
+ vscroll->set_value(vscroll->get_value() + get_theme_font("normal_font")->get_height(get_theme_font_size("normal_font_size")));
handled = true;
}
} break;
@@ -1265,27 +1594,32 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
if (main->first_invalid_line < main->lines.size()) {
return;
}
+ if (main->first_resized_line < main->lines.size()) {
+ return;
+ }
- int line = 0;
- Item *item = nullptr;
+ ItemFrame *c_frame = nullptr;
+ int c_line = 0;
+ Item *c_item = nullptr;
+ int c_index = 0;
bool outside;
- _find_click(main, m->get_position(), &item, &line, &outside);
-
- if (selection.click) {
- if (!item) {
- return; // do not update
- }
- selection.from = selection.click;
+ _find_click(main, m->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside);
+ if (selection.click_item && c_item) {
+ selection.from_frame = selection.click_frame;
+ selection.from_line = selection.click_line;
+ selection.from_item = selection.click_item;
selection.from_char = selection.click_char;
- selection.to = item;
- selection.to_char = line;
+ selection.to_frame = c_frame;
+ selection.to_line = c_line;
+ selection.to_item = c_item;
+ selection.to_char = c_index;
bool swap = false;
- if (selection.from->index > selection.to->index) {
+ if (selection.from_item->index > selection.to_item->index) {
swap = true;
- } else if (selection.from->index == selection.to->index) {
+ } else if (selection.from_item->index == selection.to_item->index) {
if (selection.from_char > selection.to_char) {
swap = true;
} else if (selection.from_char == selection.to_char) {
@@ -1295,7 +1629,9 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
}
if (swap) {
- SWAP(selection.from, selection.to);
+ SWAP(selection.from_frame, selection.to_frame);
+ SWAP(selection.from_line, selection.to_line);
+ SWAP(selection.from_item, selection.to_item);
SWAP(selection.from_char, selection.to_char);
}
@@ -1305,7 +1641,7 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
Variant meta;
ItemMeta *item_meta;
- if (item && !outside && _find_meta(item, &meta, &item_meta)) {
+ if (c_item && !outside && _find_meta(c_item, &meta, &item_meta)) {
if (meta_hovering != item_meta) {
if (meta_hovering) {
emit_signal("meta_hover_ended", current_meta);
@@ -1322,6 +1658,31 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
}
}
+void RichTextLabel::_find_frame(Item *p_item, ItemFrame **r_frame, int *r_line) {
+ if (r_frame != nullptr) {
+ *r_frame = nullptr;
+ }
+ if (r_line != nullptr) {
+ *r_line = 0;
+ }
+
+ Item *item = p_item;
+
+ while (item) {
+ if (item->parent != nullptr && item->parent->type == ITEM_FRAME) {
+ if (r_frame != nullptr) {
+ *r_frame = (ItemFrame *)item->parent;
+ }
+ if (r_line != nullptr) {
+ *r_line = item->line;
+ }
+ return;
+ }
+
+ item = item->parent;
+ }
+}
+
Ref<Font> RichTextLabel::_find_font(Item *p_item) {
Item *fontitem = p_item;
@@ -1337,10 +1698,103 @@ Ref<Font> RichTextLabel::_find_font(Item *p_item) {
return Ref<Font>();
}
-int RichTextLabel::_find_margin(Item *p_item, const Ref<Font> &p_base_font) {
+int RichTextLabel::_find_font_size(Item *p_item) {
+ Item *sizeitem = p_item;
+
+ while (sizeitem) {
+ if (sizeitem->type == ITEM_FONT_SIZE) {
+ ItemFontSize *fi = static_cast<ItemFontSize *>(sizeitem);
+ return fi->font_size;
+ }
+
+ sizeitem = sizeitem->parent;
+ }
+
+ return -1;
+}
+
+int RichTextLabel::_find_outline_size(Item *p_item) {
+ Item *sizeitem = p_item;
+
+ while (sizeitem) {
+ if (sizeitem->type == ITEM_OUTLINE_SIZE) {
+ ItemOutlineSize *fi = static_cast<ItemOutlineSize *>(sizeitem);
+ return fi->outline_size;
+ }
+
+ sizeitem = sizeitem->parent;
+ }
+
+ return 0;
+}
+
+Dictionary RichTextLabel::_find_font_features(Item *p_item) {
+ Item *ffitem = p_item;
+
+ while (ffitem) {
+ if (ffitem->type == ITEM_FONT_FEATURES) {
+ ItemFontFeatures *fi = static_cast<ItemFontFeatures *>(ffitem);
+ return fi->opentype_features;
+ }
+
+ ffitem = ffitem->parent;
+ }
+
+ return Dictionary();
+}
+
+RichTextLabel::ItemList *RichTextLabel::_find_list_item(Item *p_item) {
+ Item *item = p_item;
+
+ while (item) {
+ if (item->type == ITEM_LIST) {
+ return static_cast<ItemList *>(item);
+ }
+ item = item->parent;
+ }
+
+ return nullptr;
+}
+
+int RichTextLabel::_find_list(Item *p_item, Vector<int> &r_index, Vector<ItemList *> &r_list) {
+ Item *item = p_item;
+ Item *prev_item = p_item;
+
+ int level = 0;
+
+ while (item) {
+ if (item->type == ITEM_LIST) {
+ ItemList *list = static_cast<ItemList *>(item);
+
+ ItemFrame *frame = nullptr;
+ int line = -1;
+ _find_frame(list, &frame, &line);
+
+ int index = 1;
+ if (frame != nullptr) {
+ for (int i = list->line + 1; i <= prev_item->line; i++) {
+ if (_find_list_item(frame->lines[i].from) == list) {
+ index++;
+ }
+ }
+ }
+
+ r_index.push_back(index);
+ r_list.push_back(list);
+
+ prev_item = item;
+ }
+ level++;
+ item = item->parent;
+ }
+
+ return level;
+}
+
+int RichTextLabel::_find_margin(Item *p_item, const Ref<Font> &p_base_font, int p_base_font_size) {
Item *item = p_item;
- int margin = 0;
+ float margin = 0;
while (item) {
if (item->type == ITEM_INDENT) {
@@ -1348,16 +1802,22 @@ int RichTextLabel::_find_margin(Item *p_item, const Ref<Font> &p_base_font) {
if (font.is_null()) {
font = p_base_font;
}
-
- ItemIndent *indent = static_cast<ItemIndent *>(item);
-
- margin += indent->level * tab_size * font->get_char_size(' ').width;
+ int font_size = _find_font_size(item);
+ if (font_size == -1) {
+ font_size = p_base_font_size;
+ }
+ margin += tab_size * font->get_char_size('m', 0, font_size).width;
} else if (item->type == ITEM_LIST) {
Ref<Font> font = _find_font(item);
if (font.is_null()) {
font = p_base_font;
}
+ int font_size = _find_font_size(item);
+ if (font_size == -1) {
+ font_size = p_base_font_size;
+ }
+ margin += tab_size * font->get_char_size('m', 0, font_size).width;
}
item = item->parent;
@@ -1370,9 +1830,9 @@ RichTextLabel::Align RichTextLabel::_find_align(Item *p_item) {
Item *item = p_item;
while (item) {
- if (item->type == ITEM_ALIGN) {
- ItemAlign *align = static_cast<ItemAlign *>(item);
- return align->align;
+ if (item->type == ITEM_PARAGRAPH) {
+ ItemParagraph *p = static_cast<ItemParagraph *>(item);
+ return p->align;
}
item = item->parent;
@@ -1381,6 +1841,57 @@ RichTextLabel::Align RichTextLabel::_find_align(Item *p_item) {
return default_align;
}
+TextServer::Direction RichTextLabel::_find_direction(Item *p_item) {
+ Item *item = p_item;
+
+ while (item) {
+ if (item->type == ITEM_PARAGRAPH) {
+ ItemParagraph *p = static_cast<ItemParagraph *>(item);
+ if (p->direction != Control::TEXT_DIRECTION_INHERITED) {
+ return (TextServer::Direction)p->direction;
+ }
+ }
+
+ item = item->parent;
+ }
+
+ if (text_direction == Control::TEXT_DIRECTION_INHERITED) {
+ return is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR;
+ } else {
+ return (TextServer::Direction)text_direction;
+ }
+}
+
+Control::StructuredTextParser RichTextLabel::_find_stt(Item *p_item) {
+ Item *item = p_item;
+
+ while (item) {
+ if (item->type == ITEM_PARAGRAPH) {
+ ItemParagraph *p = static_cast<ItemParagraph *>(item);
+ return p->st_parser;
+ }
+
+ item = item->parent;
+ }
+
+ return st_parser;
+}
+
+String RichTextLabel::_find_language(Item *p_item) {
+ Item *item = p_item;
+
+ while (item) {
+ if (item->type == ITEM_PARAGRAPH) {
+ ItemParagraph *p = static_cast<ItemParagraph *>(item);
+ return p->language;
+ }
+
+ item = item->parent;
+ }
+
+ return language;
+}
+
Color RichTextLabel::_find_color(Item *p_item, const Color &p_default_color) {
Item *item = p_item;
@@ -1396,6 +1907,21 @@ Color RichTextLabel::_find_color(Item *p_item, const Color &p_default_color) {
return p_default_color;
}
+Color RichTextLabel::_find_outline_color(Item *p_item, const Color &p_default_color) {
+ Item *item = p_item;
+
+ while (item) {
+ if (item->type == ITEM_OUTLINE_COLOR) {
+ ItemOutlineColor *color = static_cast<ItemOutlineColor *>(item);
+ return color->color;
+ }
+
+ item = item->parent;
+ }
+
+ return p_default_color;
+}
+
bool RichTextLabel::_find_underline(Item *p_item) {
Item *item = p_item;
@@ -1516,38 +2042,67 @@ bool RichTextLabel::_find_layout_subitem(Item *from, Item *to) {
void RichTextLabel::_validate_line_caches(ItemFrame *p_frame) {
if (p_frame->first_invalid_line == p_frame->lines.size()) {
+ if (p_frame->first_resized_line == p_frame->lines.size()) {
+ return;
+ }
+
+ // Resize lines without reshaping.
+ Size2 size = get_size();
+ if (fixed_width != -1) {
+ size.width = fixed_width;
+ }
+ Rect2 text_rect = _get_text_rect();
+
+ Ref<Font> base_font = get_theme_font("normal_font");
+ int base_font_size = get_theme_font_size("normal_font_size");
+
+ for (int i = p_frame->first_resized_line; i < p_frame->lines.size(); i++) {
+ _resize_line(p_frame, i, base_font, base_font_size, text_rect.get_size().width - scroll_w);
+ }
+
+ int total_height = 0;
+ if (p_frame->lines.size()) {
+ total_height = p_frame->lines[p_frame->lines.size() - 1].offset.y + p_frame->lines[p_frame->lines.size() - 1].text_buf->get_size().y + get_theme_stylebox("normal")->get_minimum_size().height;
+ }
+
+ p_frame->first_resized_line = p_frame->lines.size();
+
+ updating_scroll = true;
+ vscroll->set_max(total_height);
+ vscroll->set_page(size.height);
+ if (scroll_follow && scroll_following) {
+ vscroll->set_value(total_height - size.height);
+ }
+ updating_scroll = false;
+
+ if (fit_content_height) {
+ minimum_size_changed();
+ }
return;
}
- //validate invalid lines
+ // Shape invalid lines.
Size2 size = get_size();
if (fixed_width != -1) {
size.width = fixed_width;
}
Rect2 text_rect = _get_text_rect();
- Color font_color_shadow = get_theme_color("font_color_shadow");
- bool use_outline = get_theme_constant("shadow_as_outline");
- Point2 shadow_ofs(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y"));
Ref<Font> base_font = get_theme_font("normal_font");
+ int base_font_size = get_theme_font_size("normal_font_size");
+ int total_chars = (p_frame->first_invalid_line == 0) ? 0 : (p_frame->lines[p_frame->first_invalid_line].char_offset + p_frame->lines[p_frame->first_invalid_line].char_count);
for (int i = p_frame->first_invalid_line; i < p_frame->lines.size(); i++) {
- int y = 0;
- _process_line(p_frame, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, i, PROCESS_CACHE, base_font, Color(), font_color_shadow, use_outline, shadow_ofs);
- p_frame->lines.write[i].height_cache = y;
- p_frame->lines.write[i].height_accum_cache = y;
-
- if (i > 0) {
- p_frame->lines.write[i].height_accum_cache += p_frame->lines[i - 1].height_accum_cache;
- }
+ _shape_line(p_frame, i, base_font, base_font_size, text_rect.get_size().width - scroll_w, &total_chars);
}
int total_height = 0;
if (p_frame->lines.size()) {
- total_height = p_frame->lines[p_frame->lines.size() - 1].height_accum_cache + get_theme_stylebox("normal")->get_minimum_size().height;
+ total_height = p_frame->lines[p_frame->lines.size() - 1].offset.y + p_frame->lines[p_frame->lines.size() - 1].text_buf->get_size().y + get_theme_stylebox("normal")->get_minimum_size().height;
}
- main->first_invalid_line = p_frame->lines.size();
+ p_frame->first_invalid_line = p_frame->lines.size();
+ p_frame->first_resized_line = p_frame->lines.size();
updating_scroll = true;
vscroll->set_max(total_height);
@@ -1555,7 +2110,6 @@ void RichTextLabel::_validate_line_caches(ItemFrame *p_frame) {
if (scroll_follow && scroll_following) {
vscroll->set_value(total_height - size.height);
}
-
updating_scroll = false;
if (fit_content_height) {
@@ -1627,6 +2181,13 @@ void RichTextLabel::_add_item(Item *p_item, bool p_enter, bool p_ensure_newline)
p_item->parent = current;
p_item->E = current->subitems.push_back(p_item);
p_item->index = current_idx++;
+ p_item->char_ofs = current_char_ofs;
+ if (p_item->type == ITEM_TEXT) {
+ ItemText *t = (ItemText *)p_item;
+ current_char_ofs += t->text.length();
+ } else if (p_item->type == ITEM_IMAGE) {
+ current_char_ofs++;
+ }
if (p_enter) {
current = p_item;
@@ -1672,7 +2233,7 @@ void RichTextLabel::_remove_item(Item *p_item, const int p_line, const int p_sub
}
}
-void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width, const int p_height, const Color &p_color) {
+void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width, const int p_height, const Color &p_color, VAlign p_align) {
if (current->type == ITEM_TABLE) {
return;
}
@@ -1682,6 +2243,7 @@ void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width,
item->image = p_image;
item->color = p_color;
+ item->inline_align = p_align;
if (p_width > 0) {
// custom width
@@ -1750,7 +2312,7 @@ bool RichTextLabel::remove_line(const int p_line) {
main->lines.write[0].from = main;
}
- main->first_invalid_line = 0;
+ main->first_invalid_line = 0; // p_line ???
return true;
}
@@ -1799,6 +2361,30 @@ void RichTextLabel::push_mono() {
push_font(mono_font);
}
+void RichTextLabel::push_font_size(int p_font_size) {
+ ERR_FAIL_COND(current->type == ITEM_TABLE);
+ ItemFontSize *item = memnew(ItemFontSize);
+
+ item->font_size = p_font_size;
+ _add_item(item, true);
+}
+
+void RichTextLabel::push_font_features(const Dictionary &p_features) {
+ ERR_FAIL_COND(current->type == ITEM_TABLE);
+ ItemFontFeatures *item = memnew(ItemFontFeatures);
+
+ item->opentype_features = p_features;
+ _add_item(item, true);
+}
+
+void RichTextLabel::push_outline_size(int p_font_size) {
+ ERR_FAIL_COND(current->type == ITEM_TABLE);
+ ItemOutlineSize *item = memnew(ItemOutlineSize);
+
+ item->outline_size = p_font_size;
+ _add_item(item, true);
+}
+
void RichTextLabel::push_color(const Color &p_color) {
ERR_FAIL_COND(current->type == ITEM_TABLE);
ItemColor *item = memnew(ItemColor);
@@ -1807,6 +2393,14 @@ void RichTextLabel::push_color(const Color &p_color) {
_add_item(item, true);
}
+void RichTextLabel::push_outline_color(const Color &p_color) {
+ ERR_FAIL_COND(current->type == ITEM_TABLE);
+ ItemOutlineColor *item = memnew(ItemOutlineColor);
+
+ item->color = p_color;
+ _add_item(item, true);
+}
+
void RichTextLabel::push_underline() {
ERR_FAIL_COND(current->type == ITEM_TABLE);
ItemUnderline *item = memnew(ItemUnderline);
@@ -1821,11 +2415,14 @@ void RichTextLabel::push_strikethrough() {
_add_item(item, true);
}
-void RichTextLabel::push_align(Align p_align) {
+void RichTextLabel::push_paragraph(Align p_align, Control::TextDirection p_direction, const String &p_language, Control::StructuredTextParser p_st_parser) {
ERR_FAIL_COND(current->type == ITEM_TABLE);
- ItemAlign *item = memnew(ItemAlign);
+ ItemParagraph *item = memnew(ItemParagraph);
item->align = p_align;
+ item->direction = p_direction;
+ item->language = p_language;
+ item->st_parser = p_st_parser;
_add_item(item, true, true);
}
@@ -1838,13 +2435,15 @@ void RichTextLabel::push_indent(int p_level) {
_add_item(item, true, true);
}
-void RichTextLabel::push_list(ListType p_list) {
+void RichTextLabel::push_list(int p_level, ListType p_list, bool p_capitalize) {
ERR_FAIL_COND(current->type == ITEM_TABLE);
- ERR_FAIL_INDEX(p_list, 3);
+ ERR_FAIL_COND(p_level < 0);
ItemList *item = memnew(ItemList);
item->list_type = p_list;
+ item->level = p_level;
+ item->capitalize = p_capitalize;
_add_item(item, true, true);
}
@@ -1856,17 +2455,18 @@ void RichTextLabel::push_meta(const Variant &p_meta) {
_add_item(item, true);
}
-void RichTextLabel::push_table(int p_columns) {
+void RichTextLabel::push_table(int p_columns, VAlign p_align) {
ERR_FAIL_COND(p_columns < 1);
ItemTable *item = memnew(ItemTable);
item->columns.resize(p_columns);
item->total_width = 0;
+ item->inline_align = p_align;
for (int i = 0; i < item->columns.size(); i++) {
item->columns.write[i].expand = false;
item->columns.write[i].expand_ratio = 1;
}
- _add_item(item, true, true);
+ _add_item(item, true, false);
}
void RichTextLabel::push_fade(int p_start_index, int p_length) {
@@ -1920,6 +2520,36 @@ void RichTextLabel::set_table_column_expand(int p_column, bool p_expand, int p_r
table->columns.write[p_column].expand_ratio = p_ratio;
}
+void RichTextLabel::set_cell_row_background_color(const Color &p_odd_row_bg, const Color &p_even_row_bg) {
+ ERR_FAIL_COND(current->type != ITEM_FRAME);
+ ItemFrame *cell = static_cast<ItemFrame *>(current);
+ ERR_FAIL_COND(!cell->cell);
+ cell->odd_row_bg = p_odd_row_bg;
+ cell->even_row_bg = p_even_row_bg;
+}
+
+void RichTextLabel::set_cell_border_color(const Color &p_color) {
+ ERR_FAIL_COND(current->type != ITEM_FRAME);
+ ItemFrame *cell = static_cast<ItemFrame *>(current);
+ ERR_FAIL_COND(!cell->cell);
+ cell->border = p_color;
+}
+
+void RichTextLabel::set_cell_size_override(const Size2 &p_min_size, const Size2 &p_max_size) {
+ ERR_FAIL_COND(current->type != ITEM_FRAME);
+ ItemFrame *cell = static_cast<ItemFrame *>(current);
+ ERR_FAIL_COND(!cell->cell);
+ cell->min_size_over = p_min_size;
+ cell->max_size_over = p_max_size;
+}
+
+void RichTextLabel::set_cell_padding(const Rect2 &p_padding) {
+ ERR_FAIL_COND(current->type != ITEM_FRAME);
+ ItemFrame *cell = static_cast<ItemFrame *>(current);
+ ERR_FAIL_COND(!cell->cell);
+ cell->padding = p_padding;
+}
+
void RichTextLabel::push_cell() {
ERR_FAIL_COND(current->type != ITEM_TABLE);
@@ -1928,10 +2558,9 @@ void RichTextLabel::push_cell() {
_add_item(item, true);
current_frame = item;
item->cell = true;
- item->parent_line = item->parent_frame->lines.size() - 1;
item->lines.resize(1);
item->lines.write[0].from = nullptr;
- item->first_invalid_line = 0;
+ item->first_invalid_line = 0; // parent frame last line ???
}
int RichTextLabel::get_current_table_column() const {
@@ -1958,9 +2587,13 @@ void RichTextLabel::clear() {
main->lines.resize(1);
main->first_invalid_line = 0;
update();
- selection.click = nullptr;
+
+ selection.click_frame = nullptr;
+ selection.click_item = nullptr;
selection.active = false;
+
current_idx = 1;
+ current_char_ofs = 0;
if (scroll_follow) {
scroll_following = true;
}
@@ -1972,7 +2605,7 @@ void RichTextLabel::clear() {
void RichTextLabel::set_tab_size(int p_spaces) {
tab_size = p_spaces;
- main->first_invalid_line = 0;
+ main->first_resized_line = 0;
update();
}
@@ -2121,7 +2754,7 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
if (tag_stack.front()->get() == "i") {
in_italics = false;
}
- if (tag_stack.front()->get() == "indent") {
+ if ((tag_stack.front()->get() == "indent") || (tag_stack.front()->get() == "ol") || (tag_stack.front()->get() == "ul")) {
indent_level--;
}
@@ -2163,12 +2796,24 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag.begins_with("table=")) {
- int columns = tag.substr(6, tag.length()).to_int();
+ Vector<String> subtag = tag.substr(6, tag.length()).split(",");
+ int columns = subtag[0].to_int();
if (columns < 1) {
columns = 1;
}
- push_table(columns);
+ VAlign align = VALIGN_TOP;
+ if (subtag.size() > 1) {
+ if (subtag[1] == "top" || subtag[1] == "t") {
+ align = VALIGN_TOP;
+ } else if (subtag[1] == "center" || subtag[1] == "c") {
+ align = VALIGN_CENTER;
+ } else if (subtag[1] == "bottom" || subtag[1] == "b") {
+ align = VALIGN_BOTTOM;
+ }
+ }
+
+ push_table(columns, align);
pos = brk_end + 1;
tag_stack.push_front("table");
} else if (tag == "cell") {
@@ -2183,6 +2828,42 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
set_table_column_expand(get_current_table_column(), true, ratio);
push_cell();
+
+ pos = brk_end + 1;
+ tag_stack.push_front("cell");
+ } else if (tag.begins_with("cell ")) {
+ Vector<String> subtag = tag.substr(5, tag.length()).split(" ");
+
+ for (int i = 0; i < subtag.size(); i++) {
+ Vector<String> subtag_a = subtag[i].split("=");
+ if (subtag_a.size() == 2) {
+ if (subtag_a[0] == "expand") {
+ int ratio = subtag_a[1].to_int();
+ if (ratio < 1) {
+ ratio = 1;
+ }
+ set_table_column_expand(get_current_table_column(), true, ratio);
+ }
+ }
+ }
+ push_cell();
+ for (int i = 0; i < subtag.size(); i++) {
+ Vector<String> subtag_a = subtag[i].split("=");
+ if (subtag_a.size() == 2) {
+ if (subtag_a[0] == "border") {
+ Color color = _get_color_from_string(subtag_a[1], Color(0, 0, 0, 0));
+ set_cell_border_color(color);
+ } else if (subtag_a[0] == "bg") {
+ Vector<String> subtag_b = subtag_a[1].split(",");
+ if (subtag_b.size() == 2) {
+ Color color1 = _get_color_from_string(subtag_b[0], Color(0, 0, 0, 0));
+ Color color2 = _get_color_from_string(subtag_b[1], Color(0, 0, 0, 0));
+ set_cell_row_background_color(color1, color2);
+ }
+ }
+ }
+ }
+
pos = brk_end + 1;
tag_stack.push_front("cell");
} else if (tag == "u") {
@@ -2195,32 +2876,156 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
push_strikethrough();
pos = brk_end + 1;
tag_stack.push_front(tag);
+ } else if (tag == "lrm") {
+ add_text(String::chr(0x200E));
+ pos = brk_end + 1;
+ } else if (tag == "rlm") {
+ add_text(String::chr(0x200F));
+ pos = brk_end + 1;
+ } else if (tag == "lre") {
+ add_text(String::chr(0x202A));
+ pos = brk_end + 1;
+ } else if (tag == "rle") {
+ add_text(String::chr(0x202B));
+ pos = brk_end + 1;
+ } else if (tag == "lro") {
+ add_text(String::chr(0x202D));
+ pos = brk_end + 1;
+ } else if (tag == "rlo") {
+ add_text(String::chr(0x202E));
+ pos = brk_end + 1;
+ } else if (tag == "pdf") {
+ add_text(String::chr(0x202C));
+ pos = brk_end + 1;
+ } else if (tag == "alm") {
+ add_text(String::chr(0x061c));
+ pos = brk_end + 1;
+ } else if (tag == "lri") {
+ add_text(String::chr(0x2066));
+ pos = brk_end + 1;
+ } else if (tag == "rli") {
+ add_text(String::chr(0x2027));
+ pos = brk_end + 1;
+ } else if (tag == "fsi") {
+ add_text(String::chr(0x2068));
+ pos = brk_end + 1;
+ } else if (tag == "pdi") {
+ add_text(String::chr(0x2069));
+ pos = brk_end + 1;
+ } else if (tag == "zwj") {
+ add_text(String::chr(0x200D));
+ pos = brk_end + 1;
+ } else if (tag == "zwnj") {
+ add_text(String::chr(0x200C));
+ pos = brk_end + 1;
+ } else if (tag == "wj") {
+ add_text(String::chr(0x2060));
+ pos = brk_end + 1;
+ } else if (tag == "shy") {
+ add_text(String::chr(0x00AD));
+ pos = brk_end + 1;
} else if (tag == "center") {
- push_align(ALIGN_CENTER);
+ push_paragraph(ALIGN_CENTER);
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "fill") {
- push_align(ALIGN_FILL);
+ push_paragraph(ALIGN_FILL);
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "right") {
- push_align(ALIGN_RIGHT);
+ push_paragraph(ALIGN_RIGHT);
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "ul") {
- push_list(LIST_DOTS);
+ indent_level++;
+ push_list(indent_level, LIST_DOTS, false);
pos = brk_end + 1;
tag_stack.push_front(tag);
- } else if (tag == "ol") {
- push_list(LIST_NUMBERS);
+ } else if ((tag == "ol") || (tag == "ol type=1")) {
+ indent_level++;
+ push_list(indent_level, LIST_NUMBERS, false);
pos = brk_end + 1;
tag_stack.push_front(tag);
+ } else if (tag == "ol type=a") {
+ indent_level++;
+ push_list(indent_level, LIST_LETTERS, false);
+ pos = brk_end + 1;
+ tag_stack.push_front("ol");
+ } else if (tag == "ol type=A") {
+ indent_level++;
+ push_list(indent_level, LIST_LETTERS, true);
+ pos = brk_end + 1;
+ tag_stack.push_front("ol");
+ } else if (tag == "ol type=i") {
+ indent_level++;
+ push_list(indent_level, LIST_ROMAN, false);
+ pos = brk_end + 1;
+ tag_stack.push_front("ol");
+ } else if (tag == "ol type=I") {
+ indent_level++;
+ push_list(indent_level, LIST_ROMAN, true);
+ pos = brk_end + 1;
+ tag_stack.push_front("ol");
} else if (tag == "indent") {
indent_level++;
push_indent(indent_level);
pos = brk_end + 1;
tag_stack.push_front(tag);
-
+ } else if (tag == "p") {
+ push_paragraph(ALIGN_LEFT);
+ pos = brk_end + 1;
+ tag_stack.push_front("p");
+ } else if (tag.begins_with("p ")) {
+ Vector<String> subtag = tag.substr(2, tag.length()).split(" ");
+ Align align = ALIGN_LEFT;
+ Control::TextDirection dir = Control::TEXT_DIRECTION_INHERITED;
+ String lang;
+ Control::StructuredTextParser st_parser = STRUCTURED_TEXT_DEFAULT;
+ for (int i = 0; i < subtag.size(); i++) {
+ Vector<String> subtag_a = subtag[i].split("=");
+ if (subtag_a.size() == 2) {
+ if (subtag_a[0] == "align") {
+ if (subtag_a[1] == "l" || subtag_a[1] == "left") {
+ align = ALIGN_LEFT;
+ } else if (subtag_a[1] == "c" || subtag_a[1] == "center") {
+ align = ALIGN_CENTER;
+ } else if (subtag_a[1] == "r" || subtag_a[1] == "right") {
+ align = ALIGN_RIGHT;
+ } else if (subtag_a[1] == "f" || subtag_a[1] == "fill") {
+ align = ALIGN_FILL;
+ }
+ } else if (subtag_a[0] == "dir" || subtag_a[0] == "direction") {
+ if (subtag_a[1] == "a" || subtag_a[1] == "auto") {
+ dir = Control::TEXT_DIRECTION_AUTO;
+ } else if (subtag_a[1] == "l" || subtag_a[1] == "ltr") {
+ dir = Control::TEXT_DIRECTION_LTR;
+ } else if (subtag_a[1] == "r" || subtag_a[1] == "rtl") {
+ dir = Control::TEXT_DIRECTION_RTL;
+ }
+ } else if (subtag_a[0] == "lang" || subtag_a[0] == "language") {
+ lang = subtag_a[1];
+ } else if (subtag_a[0] == "st" || subtag_a[0] == "bidi_override") {
+ if (subtag_a[1] == "d" || subtag_a[1] == "default") {
+ st_parser = STRUCTURED_TEXT_DEFAULT;
+ } else if (subtag_a[1] == "u" || subtag_a[1] == "uri") {
+ st_parser = STRUCTURED_TEXT_URI;
+ } else if (subtag_a[1] == "f" || subtag_a[1] == "file") {
+ st_parser = STRUCTURED_TEXT_FILE;
+ } else if (subtag_a[1] == "e" || subtag_a[1] == "email") {
+ st_parser = STRUCTURED_TEXT_EMAIL;
+ } else if (subtag_a[1] == "l" || subtag_a[1] == "list") {
+ st_parser = STRUCTURED_TEXT_LIST;
+ } else if (subtag_a[1] == "n" || subtag_a[1] == "none") {
+ st_parser = STRUCTURED_TEXT_NONE;
+ } else if (subtag_a[1] == "c" || subtag_a[1] == "custom") {
+ st_parser = STRUCTURED_TEXT_CUSTOM;
+ }
+ }
+ }
+ }
+ push_paragraph(align, dir, lang, st_parser);
+ pos = brk_end + 1;
+ tag_stack.push_front("p");
} else if (tag == "url") {
int end = p_bbcode.find("[", brk_end);
if (end == -1) {
@@ -2237,7 +3042,19 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
push_meta(url);
pos = brk_end + 1;
tag_stack.push_front("url");
- } else if (bbcode_name == "img") {
+ } else if (tag.begins_with("img")) {
+ VAlign align = VALIGN_TOP;
+ if (tag.begins_with("img=")) {
+ String al = tag.substr(4, tag.length());
+ if (al == "top" || al == "t") {
+ align = VALIGN_TOP;
+ } else if (al == "center" || al == "c") {
+ align = VALIGN_CENTER;
+ } else if (al == "bottom" || al == "b") {
+ align = VALIGN_BOTTOM;
+ }
+ }
+
int end = p_bbcode.find("[", brk_end);
if (end == -1) {
end = p_bbcode.length();
@@ -2275,7 +3092,7 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
}
}
- add_image(texture, width, height, color);
+ add_image(texture, width, height, color, align);
}
pos = end;
@@ -2287,6 +3104,13 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
pos = brk_end + 1;
tag_stack.push_front("color");
+ } else if (tag.begins_with("outline_color=")) {
+ String color_str = tag.substr(14, tag.length());
+ Color color = _get_color_from_string(color_str, base_color);
+ push_outline_color(color);
+ pos = brk_end + 1;
+ tag_stack.push_front("outline_color");
+
} else if (tag.begins_with("font=")) {
String fnt = tag.substr(5, tag.length());
@@ -2299,6 +3123,54 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
pos = brk_end + 1;
tag_stack.push_front("font");
+ } else if (tag.begins_with("font_size=")) {
+ int fnt_size = tag.substr(10, tag.length()).to_int();
+ push_font_size(fnt_size);
+ pos = brk_end + 1;
+ tag_stack.push_front("font_size");
+ } else if (tag.begins_with("opentype_features=")) {
+ String fnt_ftr = tag.substr(18, tag.length());
+ Vector<String> subtag = fnt_ftr.split(",");
+ Dictionary ftrs;
+ for (int i = 0; i < subtag.size(); i++) {
+ Vector<String> subtag_a = subtag[i].split("=");
+ if (subtag_a.size() == 2) {
+ ftrs[TS->name_to_tag(subtag_a[0])] = subtag_a[1].to_int();
+ } else if (subtag_a.size() == 1) {
+ ftrs[TS->name_to_tag(subtag_a[0])] = 1;
+ }
+ }
+ push_font_features(ftrs);
+ pos = brk_end + 1;
+ tag_stack.push_front("opentype_features");
+ } else if (tag.begins_with("font ")) {
+ Vector<String> subtag = tag.substr(2, tag.length()).split(" ");
+
+ for (int i = 1; i < subtag.size(); i++) {
+ Vector<String> subtag_a = subtag[i].split("=", true, 2);
+ if (subtag_a.size() == 2) {
+ if (subtag_a[0] == "name" || subtag_a[0] == "n") {
+ String fnt = subtag_a[1];
+ Ref<Font> font = ResourceLoader::load(fnt, "Font");
+ if (font.is_valid()) {
+ push_font(font);
+ } else {
+ push_font(normal_font);
+ }
+ } else if (subtag_a[0] == "size" || subtag_a[0] == "s") {
+ int fnt_size = subtag_a[1].to_int();
+ push_font_size(fnt_size);
+ }
+ }
+ }
+
+ pos = brk_end + 1;
+ tag_stack.push_front("font");
+ } else if (tag.begins_with("outline_size=")) {
+ int fnt_size = tag.substr(13, tag.length()).to_int();
+ push_outline_size(fnt_size);
+ pos = brk_end + 1;
+ tag_stack.push_front("outline_size");
} else if (bbcode_name == "fade") {
int start_index = 0;
@@ -2431,7 +3303,7 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
void RichTextLabel::scroll_to_line(int p_line) {
ERR_FAIL_INDEX(p_line, main->lines.size());
_validate_line_caches(main);
- vscroll->set_value(main->lines[p_line].height_accum_cache - main->lines[p_line].height_cache);
+ vscroll->set_value(main->lines[p_line].offset.y);
}
int RichTextLabel::get_line_count() const {
@@ -2458,95 +3330,160 @@ void RichTextLabel::set_selection_enabled(bool p_enabled) {
}
}
-bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p_search_previous) {
- ERR_FAIL_COND_V(!selection.enabled, false);
- Item *it = main;
- int charidx = 0;
-
- if (p_from_selection && selection.active) {
- it = selection.to;
- charidx = selection.to_char + 1;
- }
-
- while (it) {
- if (it->type == ITEM_TEXT) {
- ItemText *t = static_cast<ItemText *>(it);
- int sp = t->text.findn(p_string, charidx);
- if (sp != -1) {
- selection.from = it;
- selection.from_char = sp;
- selection.to = it;
- selection.to_char = sp + p_string.length() - 1;
- selection.active = true;
- update();
-
- _validate_line_caches(main);
+bool RichTextLabel::_search_line(ItemFrame *p_frame, int p_line, const String &p_string, Item *p_from, Item *p_to) {
+ ERR_FAIL_COND_V(p_frame == nullptr, false);
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= p_frame->lines.size(), false);
- int fh = _find_font(t).is_valid() ? _find_font(t)->get_height() : get_theme_font("normal_font")->get_height();
+ Line &l = p_frame->lines.write[p_line];
- float offset = 0;
+ String text;
+ Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr;
+ for (Item *it = l.from; it && it != it_to; it = _get_next_item(it)) {
+ switch (it->type) {
+ case ITEM_NEWLINE: {
+ text += "\n";
+ } break;
+ case ITEM_TEXT: {
+ ItemText *t = (ItemText *)it;
+ text += t->text;
+ } break;
+ case ITEM_IMAGE: {
+ text += " ";
+ } 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());
- int line = t->line;
- Item *item = t;
- while (item) {
- if (item->type == ITEM_FRAME) {
- ItemFrame *frame = static_cast<ItemFrame *>(item);
- if (line >= 0 && line < frame->lines.size()) {
- offset += frame->lines[line].height_accum_cache - frame->lines[line].height_cache;
- line = frame->line;
+ for (int i = 0; i < frame->lines.size(); i++) {
+ if (_search_line(frame, i, p_string, p_from, p_to)) {
+ return true;
}
}
- item = item->parent;
+ idx++;
}
- vscroll->set_value(offset - fh);
+ } break;
+ default:
+ break;
+ }
+ }
+ int sp = text.findn(p_string, 0);
+ if (sp != -1) {
+ selection.from_frame = p_frame;
+ selection.from_line = p_line;
+ selection.from_item = _get_item_at_pos(l.from, it_to, sp);
+ 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.active = true;
+ return true;
+ }
+
+ return false;
+}
+bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p_search_previous) {
+ ERR_FAIL_COND_V(!selection.enabled, false);
+
+ 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;
}
}
-
- if (p_search_previous) {
- it = _get_prev_item(it, true);
- } else {
- it = _get_next_item(it, true);
+ } else {
+ for (int i = 0; i < main->lines.size(); i++) {
+ if (_search_line(main, i, p_string, nullptr, nullptr)) {
+ update();
+ return true;
+ }
}
- charidx = 0;
}
return false;
}
-String RichTextLabel::get_selected_text() {
- if (!selection.active || !selection.enabled) {
- return "";
- }
-
+String RichTextLabel::_get_line_text(ItemFrame *p_frame, int p_line, Selection p_selection) {
String text;
+ ERR_FAIL_COND_V(p_frame == nullptr, text);
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= p_frame->lines.size(), text);
- RichTextLabel::Item *item = selection.from;
-
- while (item) {
- if (item->type == ITEM_TEXT) {
- String itext = static_cast<ItemText *>(item)->text;
- if (item == selection.from && item == selection.to) {
- text += itext.substr(selection.from_char, selection.to_char - selection.from_char + 1);
- } else if (item == selection.from) {
- text += itext.substr(selection.from_char, itext.size());
- } else if (item == selection.to) {
- text += itext.substr(0, selection.to_char + 1);
- } else {
- text += itext;
- }
+ Line &l = p_frame->lines.write[p_line];
- } else if (item->type == ITEM_NEWLINE) {
- text += "\n";
+ Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr;
+ int end_idx = 0;
+ if (it_to != nullptr) {
+ end_idx = it_to->index;
+ } else {
+ for (Item *it = l.from; it && it != it_to; it = _get_next_item(it)) {
+ end_idx = it->index + 1;
+ }
+ }
+ for (Item *it = l.from; it && it != it_to; it = _get_next_item(it)) {
+ if ((p_selection.to_item != nullptr) && (p_selection.to_item->index < l.from->index)) {
+ break;
}
- if (item == selection.to) {
+ if ((p_selection.from_item != nullptr) && (p_selection.from_item->index >= end_idx)) {
break;
}
+ switch (it->type) {
+ case ITEM_NEWLINE: {
+ text += "\n";
+ } break;
+ case ITEM_TEXT: {
+ ItemText *t = (ItemText *)it;
+ text += t->text;
+ } break;
+ case ITEM_IMAGE: {
+ text += " ";
+ } break;
+ case ITEM_TABLE: {
+ ItemTable *table = static_cast<ItemTable *>(it);
+ int idx = 0;
+ int col_count = table->columns.size();
+ 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());
+ int column = idx % col_count;
+
+ for (int i = 0; i < frame->lines.size(); i++) {
+ text += _get_line_text(frame, i, p_selection);
+ }
+ if (column == col_count - 1) {
+ text += "\n";
+ } else {
+ text += " ";
+ }
+ idx++;
+ }
+ } break;
+ default:
+ break;
+ }
+ }
+ if ((l.from != nullptr) && (p_frame == p_selection.to_frame) && (p_selection.to_item != nullptr) && (p_selection.to_item->index >= l.from->index) && (p_selection.to_item->index < end_idx)) {
+ text = text.substr(0, p_selection.to_char);
+ }
+ if ((l.from != nullptr) && (p_frame == p_selection.from_frame) && (p_selection.from_item != nullptr) && (p_selection.from_item->index >= l.from->index) && (p_selection.from_item->index < end_idx)) {
+ text = text.substr(p_selection.from_char, -1);
+ }
+ return text;
+}
- item = _get_next_item(item, true);
+String RichTextLabel::get_selected_text() {
+ if (!selection.active || !selection.enabled) {
+ return "";
}
+ String text;
+ for (int i = 0; i < main->lines.size(); i++) {
+ text += _get_line_text(main, i, selection);
+ }
return text;
}
@@ -2597,7 +3534,7 @@ String RichTextLabel::get_text() {
text += t->text;
} else if (it->type == ITEM_NEWLINE) {
text += "\n";
- } else if (it->type == ITEM_INDENT) {
+ } else if (it->type == ITEM_INDENT || it->type == ITEM_LIST) {
text += "\t";
}
it = _get_next_item(it, true);
@@ -2610,18 +3547,73 @@ void RichTextLabel::set_text(const String &p_string) {
add_text(p_string);
}
-void RichTextLabel::set_percent_visible(float p_percent) {
- if (p_percent < 0 || p_percent >= 1) {
- visible_characters = -1;
- percent_visible = 1;
+void RichTextLabel::set_text_direction(Control::TextDirection p_text_direction) {
+ ERR_FAIL_COND((int)p_text_direction < -1 || (int)p_text_direction > 3);
+ if (text_direction != p_text_direction) {
+ text_direction = p_text_direction;
+ main->first_invalid_line = 0; //invalidate ALL
+ _validate_line_caches(main);
+ update();
+ }
+}
- } else {
- visible_characters = get_total_character_count() * p_percent;
- percent_visible = p_percent;
+void RichTextLabel::set_structured_text_bidi_override(Control::StructuredTextParser p_parser) {
+ if (st_parser != p_parser) {
+ st_parser = p_parser;
+ main->first_invalid_line = 0; //invalidate ALL
+ _validate_line_caches(main);
+ update();
}
+}
+
+Control::StructuredTextParser RichTextLabel::get_structured_text_bidi_override() const {
+ return st_parser;
+}
+
+void RichTextLabel::set_structured_text_bidi_override_options(Array p_args) {
+ st_args = p_args;
+ main->first_invalid_line = 0; //invalidate ALL
+ _validate_line_caches(main);
update();
}
+Array RichTextLabel::get_structured_text_bidi_override_options() const {
+ return st_args;
+}
+
+Control::TextDirection RichTextLabel::get_text_direction() const {
+ return text_direction;
+}
+
+void RichTextLabel::set_language(const String &p_language) {
+ if (language != p_language) {
+ language = p_language;
+ main->first_invalid_line = 0; //invalidate ALL
+ _validate_line_caches(main);
+ update();
+ }
+}
+
+String RichTextLabel::get_language() const {
+ return language;
+}
+
+void RichTextLabel::set_percent_visible(float p_percent) {
+ if (percent_visible != p_percent) {
+ if (p_percent < 0 || p_percent >= 1) {
+ visible_characters = -1;
+ percent_visible = 1;
+
+ } else {
+ visible_characters = get_total_character_count() * p_percent;
+ percent_visible = p_percent;
+ }
+ main->first_invalid_line = 0; //invalidate ALL
+ _validate_line_caches(main);
+ update();
+ }
+}
+
float RichTextLabel::get_percent_visible() const {
return percent_visible;
}
@@ -2657,7 +3649,7 @@ void RichTextLabel::install_effect(const Variant effect) {
int RichTextLabel::get_content_height() const {
int total_height = 0;
if (main->lines.size()) {
- total_height = main->lines[main->lines.size() - 1].height_accum_cache + get_theme_stylebox("normal")->get_minimum_size().height;
+ total_height = main->lines[main->lines.size() - 1].offset.y + main->lines[main->lines.size() - 1].text_buf->get_size().y + get_theme_stylebox("normal")->get_minimum_size().height;
}
return total_height;
}
@@ -2667,29 +3659,46 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_text"), &RichTextLabel::get_text);
ClassDB::bind_method(D_METHOD("add_text", "text"), &RichTextLabel::add_text);
ClassDB::bind_method(D_METHOD("set_text", "text"), &RichTextLabel::set_text);
- ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height", "color"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0), DEFVAL(Color(1.0, 1.0, 1.0)));
+ ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height", "color", "inline_align"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(VALIGN_TOP));
ClassDB::bind_method(D_METHOD("newline"), &RichTextLabel::add_newline);
ClassDB::bind_method(D_METHOD("remove_line", "line"), &RichTextLabel::remove_line);
ClassDB::bind_method(D_METHOD("push_font", "font"), &RichTextLabel::push_font);
+ ClassDB::bind_method(D_METHOD("push_font_size", "font_size"), &RichTextLabel::push_font_size);
+ ClassDB::bind_method(D_METHOD("push_font_features", "opentype_features"), &RichTextLabel::push_font_features);
ClassDB::bind_method(D_METHOD("push_normal"), &RichTextLabel::push_normal);
ClassDB::bind_method(D_METHOD("push_bold"), &RichTextLabel::push_bold);
ClassDB::bind_method(D_METHOD("push_bold_italics"), &RichTextLabel::push_bold_italics);
ClassDB::bind_method(D_METHOD("push_italics"), &RichTextLabel::push_italics);
ClassDB::bind_method(D_METHOD("push_mono"), &RichTextLabel::push_mono);
ClassDB::bind_method(D_METHOD("push_color", "color"), &RichTextLabel::push_color);
- ClassDB::bind_method(D_METHOD("push_align", "align"), &RichTextLabel::push_align);
+ ClassDB::bind_method(D_METHOD("push_outline_size", "outline_size"), &RichTextLabel::push_outline_size);
+ ClassDB::bind_method(D_METHOD("push_outline_color", "color"), &RichTextLabel::push_outline_color);
+ ClassDB::bind_method(D_METHOD("push_paragraph", "align", "base_direction", "language", "st_parser"), &RichTextLabel::push_paragraph, DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(""), DEFVAL(STRUCTURED_TEXT_DEFAULT));
ClassDB::bind_method(D_METHOD("push_indent", "level"), &RichTextLabel::push_indent);
- ClassDB::bind_method(D_METHOD("push_list", "type"), &RichTextLabel::push_list);
+ ClassDB::bind_method(D_METHOD("push_list", "level", "type", "capitalize"), &RichTextLabel::push_list);
ClassDB::bind_method(D_METHOD("push_meta", "data"), &RichTextLabel::push_meta);
ClassDB::bind_method(D_METHOD("push_underline"), &RichTextLabel::push_underline);
ClassDB::bind_method(D_METHOD("push_strikethrough"), &RichTextLabel::push_strikethrough);
- ClassDB::bind_method(D_METHOD("push_table", "columns"), &RichTextLabel::push_table);
+ ClassDB::bind_method(D_METHOD("push_table", "columns", "inline_align"), &RichTextLabel::push_table, DEFVAL(VALIGN_TOP));
ClassDB::bind_method(D_METHOD("set_table_column_expand", "column", "expand", "ratio"), &RichTextLabel::set_table_column_expand);
+ ClassDB::bind_method(D_METHOD("set_cell_row_background_color", "odd_row_bg", "even_row_bg"), &RichTextLabel::set_cell_row_background_color);
+ ClassDB::bind_method(D_METHOD("set_cell_border_color", "color"), &RichTextLabel::set_cell_border_color);
+ ClassDB::bind_method(D_METHOD("set_cell_size_override", "min_size", "max_size"), &RichTextLabel::set_cell_size_override);
+ ClassDB::bind_method(D_METHOD("set_cell_padding", "padding"), &RichTextLabel::set_cell_padding);
ClassDB::bind_method(D_METHOD("push_cell"), &RichTextLabel::push_cell);
ClassDB::bind_method(D_METHOD("pop"), &RichTextLabel::pop);
ClassDB::bind_method(D_METHOD("clear"), &RichTextLabel::clear);
+ ClassDB::bind_method(D_METHOD("set_structured_text_bidi_override", "parser"), &RichTextLabel::set_structured_text_bidi_override);
+ ClassDB::bind_method(D_METHOD("get_structured_text_bidi_override"), &RichTextLabel::get_structured_text_bidi_override);
+ ClassDB::bind_method(D_METHOD("set_structured_text_bidi_override_options", "args"), &RichTextLabel::set_structured_text_bidi_override_options);
+ ClassDB::bind_method(D_METHOD("get_structured_text_bidi_override_options"), &RichTextLabel::get_structured_text_bidi_override_options);
+ ClassDB::bind_method(D_METHOD("set_text_direction", "direction"), &RichTextLabel::set_text_direction);
+ ClassDB::bind_method(D_METHOD("get_text_direction"), &RichTextLabel::get_text_direction);
+ ClassDB::bind_method(D_METHOD("set_language", "language"), &RichTextLabel::set_language);
+ ClassDB::bind_method(D_METHOD("get_language"), &RichTextLabel::get_language);
+
ClassDB::bind_method(D_METHOD("set_meta_underline", "enable"), &RichTextLabel::set_meta_underline);
ClassDB::bind_method(D_METHOD("is_meta_underlined"), &RichTextLabel::is_meta_underlined);
@@ -2764,6 +3773,13 @@ 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::STRING, "language"), "set_language", "get_language");
+
+ ADD_GROUP("Structured Text", "structured_text_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "structured_text_bidi_override", PROPERTY_HINT_ENUM, "Default,URI,File,Email,List,None,Custom"), "set_structured_text_bidi_override", "get_structured_text_bidi_override");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "structured_text_bidi_override_options"), "set_structured_text_bidi_override_options", "get_structured_text_bidi_override_options");
+
ADD_SIGNAL(MethodInfo("meta_clicked", PropertyInfo(Variant::NIL, "meta", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT)));
ADD_SIGNAL(MethodInfo("meta_hover_started", PropertyInfo(Variant::NIL, "meta", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT)));
ADD_SIGNAL(MethodInfo("meta_hover_ended", PropertyInfo(Variant::NIL, "meta", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT)));
@@ -2775,6 +3791,7 @@ void RichTextLabel::_bind_methods() {
BIND_ENUM_CONSTANT(LIST_NUMBERS);
BIND_ENUM_CONSTANT(LIST_LETTERS);
+ BIND_ENUM_CONSTANT(LIST_ROMAN);
BIND_ENUM_CONSTANT(LIST_DOTS);
BIND_ENUM_CONSTANT(ITEM_FRAME);
@@ -2782,10 +3799,14 @@ void RichTextLabel::_bind_methods() {
BIND_ENUM_CONSTANT(ITEM_IMAGE);
BIND_ENUM_CONSTANT(ITEM_NEWLINE);
BIND_ENUM_CONSTANT(ITEM_FONT);
+ BIND_ENUM_CONSTANT(ITEM_FONT_SIZE);
+ BIND_ENUM_CONSTANT(ITEM_FONT_FEATURES);
BIND_ENUM_CONSTANT(ITEM_COLOR);
+ BIND_ENUM_CONSTANT(ITEM_OUTLINE_SIZE);
+ BIND_ENUM_CONSTANT(ITEM_OUTLINE_COLOR);
BIND_ENUM_CONSTANT(ITEM_UNDERLINE);
BIND_ENUM_CONSTANT(ITEM_STRIKETHROUGH);
- BIND_ENUM_CONSTANT(ITEM_ALIGN);
+ BIND_ENUM_CONSTANT(ITEM_PARAGRAPH);
BIND_ENUM_CONSTANT(ITEM_INDENT);
BIND_ENUM_CONSTANT(ITEM_LIST);
BIND_ENUM_CONSTANT(ITEM_TABLE);
@@ -2915,6 +3936,7 @@ RichTextLabel::RichTextLabel() {
main->lines.resize(1);
main->lines.write[0].from = main;
main->first_invalid_line = 0;
+ main->first_resized_line = 0;
current_frame = main;
tab_size = 4;
default_align = ALIGN_LEFT;
@@ -2940,10 +3962,10 @@ RichTextLabel::RichTextLabel() {
vscroll->connect("value_changed", callable_mp(this, &RichTextLabel::_scroll_changed));
vscroll->set_step(1);
vscroll->hide();
- current_idx = 1;
use_bbcode = false;
- selection.click = nullptr;
+ selection.click_frame = nullptr;
+ selection.click_item = nullptr;
selection.active = false;
selection.enabled = false;
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index 2c74eb741d..93e48dd449 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -33,6 +33,7 @@
#include "rich_text_effect.h"
#include "scene/gui/scroll_bar.h"
+#include "scene/resources/text_paragraph.h"
class RichTextLabel : public Control {
GDCLASS(RichTextLabel, Control);
@@ -48,6 +49,7 @@ public:
enum ListType {
LIST_NUMBERS,
LIST_LETTERS,
+ LIST_ROMAN,
LIST_DOTS
};
@@ -57,10 +59,14 @@ public:
ITEM_IMAGE,
ITEM_NEWLINE,
ITEM_FONT,
+ ITEM_FONT_SIZE,
+ ITEM_FONT_FEATURES,
ITEM_COLOR,
+ ITEM_OUTLINE_SIZE,
+ ITEM_OUTLINE_COLOR,
ITEM_UNDERLINE,
ITEM_STRIKETHROUGH,
- ITEM_ALIGN,
+ ITEM_PARAGRAPH,
ITEM_INDENT,
ITEM_LIST,
ITEM_TABLE,
@@ -80,31 +86,25 @@ private:
struct Item;
struct Line {
- Item *from;
- Vector<int> offset_caches;
- Vector<int> height_caches;
- Vector<int> ascent_caches;
- Vector<int> descent_caches;
- Vector<int> space_caches;
- int height_cache;
- int height_accum_cache;
- int char_count;
- int minimum_width;
- int maximum_width;
-
- Line() {
- from = nullptr;
- char_count = 0;
- }
+ Item *from = nullptr;
+
+ Ref<TextParagraph> text_buf;
+
+ Vector2 offset;
+ int char_offset = 0;
+ int char_count = 0;
+
+ Line() { text_buf.instance(); }
};
struct Item {
- int index;
- Item *parent;
- ItemType type;
+ int index = 0;
+ int char_ofs = 0;
+ Item *parent = nullptr;
+ ItemType type = ITEM_FRAME;
List<Item *> subitems;
- List<Item *>::Element *E;
- int line;
+ List<Item *>::Element *E = nullptr;
+ int line = 0;
void _clear_children() {
while (subitems.size()) {
@@ -113,29 +113,26 @@ private:
}
}
- Item() {
- parent = nullptr;
- E = nullptr;
- line = 0;
- index = 0;
- type = ITEM_FRAME;
- }
virtual ~Item() { _clear_children(); }
};
struct ItemFrame : public Item {
- int parent_line;
- bool cell;
+ bool cell = false;
+
Vector<Line> lines;
- int first_invalid_line;
- ItemFrame *parent_frame;
-
- ItemFrame() {
- type = ITEM_FRAME;
- parent_frame = nullptr;
- cell = false;
- parent_line = 0;
- }
+ int first_invalid_line = 0;
+ int first_resized_line = 0;
+
+ ItemFrame *parent_frame = nullptr;
+
+ Color odd_row_bg = Color(0, 0, 0, 0);
+ Color even_row_bg = Color(0, 0, 0, 0);
+ Color border = Color(0, 0, 0, 0);
+ Size2 min_size_over = Size2(-1, -1);
+ Size2 max_size_over = Size2(-1, -1);
+ Rect2 padding;
+
+ ItemFrame() { type = ITEM_FRAME; }
};
struct ItemText : public Item {
@@ -145,6 +142,7 @@ private:
struct ItemImage : public Item {
Ref<Texture2D> image;
+ VAlign inline_align = VALIGN_TOP;
Size2 size;
Color color;
ItemImage() { type = ITEM_IMAGE; }
@@ -155,11 +153,31 @@ private:
ItemFont() { type = ITEM_FONT; }
};
+ struct ItemFontSize : public Item {
+ int font_size = 16;
+ ItemFontSize() { type = ITEM_FONT_SIZE; }
+ };
+
+ struct ItemFontFeatures : public Item {
+ Dictionary opentype_features;
+ ItemFontFeatures() { type = ITEM_FONT_FEATURES; }
+ };
+
struct ItemColor : public Item {
Color color;
ItemColor() { type = ITEM_COLOR; }
};
+ struct ItemOutlineSize : public Item {
+ int outline_size = 0;
+ ItemOutlineSize() { type = ITEM_OUTLINE_SIZE; }
+ };
+
+ struct ItemOutlineColor : public Item {
+ Color color;
+ ItemOutlineColor() { type = ITEM_OUTLINE_COLOR; }
+ };
+
struct ItemUnderline : public Item {
ItemUnderline() { type = ITEM_UNDERLINE; }
};
@@ -173,18 +191,23 @@ private:
ItemMeta() { type = ITEM_META; }
};
- struct ItemAlign : public Item {
- Align align;
- ItemAlign() { type = ITEM_ALIGN; }
+ struct ItemParagraph : public Item {
+ Align align = ALIGN_LEFT;
+ String language;
+ Control::TextDirection direction = Control::TEXT_DIRECTION_AUTO;
+ Control::StructuredTextParser st_parser = STRUCTURED_TEXT_DEFAULT;
+ ItemParagraph() { type = ITEM_PARAGRAPH; }
};
struct ItemIndent : public Item {
- int level;
+ int level = 0;
ItemIndent() { type = ITEM_INDENT; }
};
struct ItemList : public Item {
- ListType list_type;
+ ListType list_type = LIST_DOTS;
+ bool capitalize = false;
+ int level = 0;
ItemList() { type = ITEM_LIST; }
};
@@ -202,37 +225,32 @@ private:
};
Vector<Column> columns;
- int total_width;
+ Vector<float> rows;
+
+ int total_width = 0;
+ int total_height = 0;
+ VAlign inline_align = VALIGN_TOP;
ItemTable() { type = ITEM_TABLE; }
};
struct ItemFade : public Item {
- int starting_index;
- int length;
+ int starting_index = 0;
+ int length = 0;
ItemFade() { type = ITEM_FADE; }
};
struct ItemFX : public Item {
- float elapsed_time;
-
- ItemFX() {
- elapsed_time = 0.0f;
- }
+ float elapsed_time = 0.f;
};
struct ItemShake : public ItemFX {
- int strength;
- float rate;
- uint64_t _current_rng;
- uint64_t _previous_rng;
-
- ItemShake() {
- strength = 0;
- rate = 0.0f;
- _current_rng = 0;
- type = ITEM_SHAKE;
- }
+ int strength = 0;
+ float rate = 0.0f;
+ uint64_t _current_rng = 0;
+ uint64_t _previous_rng = 0;
+
+ ItemShake() { type = ITEM_SHAKE; }
void reroll_random() {
_previous_rng = _current_rng;
@@ -251,38 +269,25 @@ private:
};
struct ItemWave : public ItemFX {
- float frequency;
- float amplitude;
+ float frequency = 1.0f;
+ float amplitude = 1.0f;
- ItemWave() {
- frequency = 1.0f;
- amplitude = 1.0f;
- type = ITEM_WAVE;
- }
+ ItemWave() { type = ITEM_WAVE; }
};
struct ItemTornado : public ItemFX {
- float radius;
- float frequency;
+ float radius = 1.0f;
+ float frequency = 1.0f;
- ItemTornado() {
- radius = 1.0f;
- frequency = 1.0f;
- type = ITEM_TORNADO;
- }
+ ItemTornado() { type = ITEM_TORNADO; }
};
struct ItemRainbow : public ItemFX {
- float saturation;
- float value;
- float frequency;
-
- ItemRainbow() {
- saturation = 0.8f;
- value = 0.8f;
- frequency = 1.0f;
- type = ITEM_RAINBOW;
- }
+ float saturation = 0.8f;
+ float value = 0.8f;
+ float frequency = 1.0f;
+
+ ItemRainbow() { type = ITEM_RAINBOW; }
};
struct ItemCustomFX : public ItemFX {
@@ -291,7 +296,6 @@ private:
ItemCustomFX() {
type = ITEM_CUSTOMFX;
-
char_fx_transform.instance();
}
@@ -316,7 +320,8 @@ private:
int scroll_w;
bool scroll_updated;
bool updating_scroll;
- int current_idx;
+ int current_idx = 1;
+ int current_char_ofs = 0;
int visible_line_count;
int tab_size;
@@ -336,23 +341,25 @@ private:
void _add_item(Item *p_item, bool p_enter = false, bool p_ensure_newline = false);
void _remove_item(Item *p_item, const int p_line, const int p_subitem_line);
- struct ProcessState {
- int line_width;
- };
-
- enum ProcessMode {
- PROCESS_CACHE,
- PROCESS_DRAW,
- PROCESS_POINTER
- };
+ String language;
+ TextDirection text_direction = TEXT_DIRECTION_AUTO;
+ Control::StructuredTextParser st_parser = STRUCTURED_TEXT_DEFAULT;
+ Array st_args;
struct Selection {
- Item *click;
+ ItemFrame *click_frame;
+ int click_line;
+ Item *click_item;
int click_char;
- Item *from;
+ ItemFrame *from_frame;
+ int from_line;
+ Item *from_item;
int from_char;
- Item *to;
+
+ ItemFrame *to_frame;
+ int to_line;
+ Item *to_item;
int to_char;
bool active; // anything selected? i.e. from, to, etc. valid?
@@ -364,13 +371,34 @@ private:
int visible_characters;
float percent_visible;
- int _process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &y, int p_width, int p_line, ProcessMode p_mode, const Ref<Font> &p_base_font, const Color &p_base_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &shadow_ofs, const Point2i &p_click_pos = Point2i(), Item **r_click_item = nullptr, int *r_click_char = nullptr, bool *r_outside = nullptr, int p_char_count = 0);
- void _find_click(ItemFrame *p_frame, const Point2i &p_click, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool *r_outside = nullptr);
+ 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);
+ bool _search_line(ItemFrame *p_frame, int p_line, const String &p_string, Item *p_from, Item *p_to);
+
+ void _shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width, int *r_char_offset);
+ void _resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width);
+ float _draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &shadow_ofs);
+ float _find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr);
+
+ String _roman(int p_num, bool p_capitalize) const;
+ String _letters(int p_num, bool p_capitalize) const;
+ Item *_get_item_at_pos(Item *p_item_from, Item *p_item_to, int p_position);
+ void _find_frame(Item *p_item, ItemFrame **r_frame, int *r_line);
Ref<Font> _find_font(Item *p_item);
- int _find_margin(Item *p_item, const Ref<Font> &p_base_font);
+ int _find_font_size(Item *p_item);
+ Dictionary _find_font_features(Item *p_item);
+ int _find_outline_size(Item *p_item);
+ ItemList *_find_list_item(Item *p_item);
+ int _find_list(Item *p_item, Vector<int> &r_index, Vector<ItemList *> &r_list);
+ int _find_margin(Item *p_item, const Ref<Font> &p_base_font, int p_base_font_size);
Align _find_align(Item *p_item);
+ TextServer::Direction _find_direction(Item *p_item);
+ Control::StructuredTextParser _find_stt(Item *p_item);
+ String _find_language(Item *p_item);
Color _find_color(Item *p_item, const Color &p_default_color);
+ Color _find_outline_color(Item *p_item, const Color &p_default_color);
bool _find_underline(Item *p_item);
bool _find_strikethrough(Item *p_item);
bool _find_meta(Item *p_item, Variant *r_meta, ItemMeta **r_item = nullptr);
@@ -394,8 +422,6 @@ private:
bool use_bbcode;
String bbcode;
- void _update_all_lines();
-
int fixed_width;
bool fit_content_height;
@@ -406,23 +432,27 @@ protected:
public:
String get_text();
void add_text(const String &p_text);
- void add_image(const Ref<Texture2D> &p_image, const int p_width = 0, const int p_height = 0, const Color &p_color = Color(1.0, 1.0, 1.0));
+ void add_image(const Ref<Texture2D> &p_image, const int p_width = 0, const int p_height = 0, const Color &p_color = Color(1.0, 1.0, 1.0), VAlign p_align = VALIGN_TOP);
void add_newline();
bool remove_line(const int p_line);
void push_font(const Ref<Font> &p_font);
+ void push_font_size(int p_font_size);
+ void push_font_features(const Dictionary &p_features);
+ void push_outline_size(int p_font_size);
void push_normal();
void push_bold();
void push_bold_italics();
void push_italics();
void push_mono();
void push_color(const Color &p_color);
+ void push_outline_color(const Color &p_color);
void push_underline();
void push_strikethrough();
- void push_align(Align p_align);
+ void push_paragraph(Align p_align, Control::TextDirection p_direction = Control::TEXT_DIRECTION_INHERITED, const String &p_language = "", Control::StructuredTextParser p_st_parser = STRUCTURED_TEXT_DEFAULT);
void push_indent(int p_level);
- void push_list(ListType p_list);
+ void push_list(int p_level, ListType p_list, bool p_capitalize);
void push_meta(const Variant &p_meta);
- void push_table(int p_columns);
+ void push_table(int p_columns, VAlign p_align = VALIGN_TOP);
void push_fade(int p_start_index, int p_length);
void push_shake(int p_strength, float p_rate);
void push_wave(float p_frequency, float p_amplitude);
@@ -430,6 +460,10 @@ public:
void push_rainbow(float p_saturation, float p_value, float p_frequency);
void push_customfx(Ref<RichTextEffect> p_custom_effect, Dictionary p_environment);
void set_table_column_expand(int p_column, bool p_expand, int p_ratio = 1);
+ void set_cell_row_background_color(const Color &p_odd_row_bg, const Color &p_even_row_bg);
+ void set_cell_border_color(const Color &p_color);
+ void set_cell_size_override(const Size2 &p_min_size, const Size2 &p_max_size);
+ void set_cell_padding(const Rect2 &p_padding);
int get_current_table_column() const;
void push_cell();
void pop();
@@ -484,6 +518,18 @@ public:
void set_text(const String &p_string);
+ void set_text_direction(TextDirection p_text_direction);
+ TextDirection get_text_direction() const;
+
+ void set_language(const String &p_language);
+ String get_language() const;
+
+ void set_structured_text_bidi_override(Control::StructuredTextParser p_parser);
+ Control::StructuredTextParser get_structured_text_bidi_override() const;
+
+ void set_structured_text_bidi_override_options(Array p_args);
+ Array get_structured_text_bidi_override_options() const;
+
void set_visible_characters(int p_visible);
int get_visible_characters() const;
int get_total_character_count() const;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 6b16806789..f3569f9ce3 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1650,20 +1650,23 @@ void TextEdit::_notification(int p_what) {
if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) {
DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id());
- DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + _get_cursor_pixel_pos(), get_viewport()->get_window_id());
+ DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + _get_cursor_pixel_pos(false), get_viewport()->get_window_id());
}
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
- String text = _base_get_text(0, 0, selection.selecting_line, selection.selecting_column);
- int cursor_start = text.length();
+ int cursor_start = -1;
int cursor_end = -1;
- if (selection.active) {
- String selected_text = _base_get_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
+ if (!selection.active) {
+ String full_text = _base_get_text(0, 0, cursor.line, cursor.column);
- if (selected_text.length() > 0) {
- cursor_end = cursor_start + selected_text.length();
- }
+ cursor_start = full_text.length();
+ } else {
+ String pre_text = _base_get_text(0, 0, selection.from_line, selection.from_column);
+ String post_text = _base_get_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
+
+ cursor_start = pre_text.length();
+ cursor_end = cursor_start + post_text.length();
}
DisplayServer::get_singleton()->virtual_keyboard_show(get_text(), get_global_rect(), true, -1, cursor_start, cursor_end);
@@ -2072,8 +2075,10 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co
r_col = col;
}
-Vector2i TextEdit::_get_cursor_pixel_pos() {
- adjust_viewport_to_cursor();
+Vector2i TextEdit::_get_cursor_pixel_pos(bool p_adjust_viewport) {
+ if (p_adjust_viewport) {
+ adjust_viewport_to_cursor();
+ }
int row = 1;
for (int i = get_first_visible_line(); i < cursor.line; i++) {
if (!is_line_hidden(i)) {
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index c2fe4afec5..3f16ed1366 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -700,7 +700,7 @@ public:
int cursor_get_column() const;
int cursor_get_line() const;
- Vector2i _get_cursor_pixel_pos();
+ Vector2i _get_cursor_pixel_pos(bool p_adjust_viewport = true);
bool cursor_get_blink_enabled() const;
void cursor_set_blink_enabled(const bool p_enabled);
diff --git a/scene/gui/texture_progress.cpp b/scene/gui/texture_progress_bar.cpp
index e0d98d1c22..b5115690ac 100644
--- a/scene/gui/texture_progress.cpp
+++ b/scene/gui/texture_progress_bar.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* texture_progress.cpp */
+/* texture_progress_bar.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,21 +28,21 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "texture_progress.h"
+#include "texture_progress_bar.h"
#include "core/config/engine.h"
-void TextureProgress::set_under_texture(const Ref<Texture2D> &p_texture) {
+void TextureProgressBar::set_under_texture(const Ref<Texture2D> &p_texture) {
under = p_texture;
update();
minimum_size_changed();
}
-Ref<Texture2D> TextureProgress::get_under_texture() const {
+Ref<Texture2D> TextureProgressBar::get_under_texture() const {
return under;
}
-void TextureProgress::set_over_texture(const Ref<Texture2D> &p_texture) {
+void TextureProgressBar::set_over_texture(const Ref<Texture2D> &p_texture) {
over = p_texture;
update();
if (under.is_null()) {
@@ -50,33 +50,33 @@ void TextureProgress::set_over_texture(const Ref<Texture2D> &p_texture) {
}
}
-Ref<Texture2D> TextureProgress::get_over_texture() const {
+Ref<Texture2D> TextureProgressBar::get_over_texture() const {
return over;
}
-void TextureProgress::set_stretch_margin(Margin p_margin, int p_size) {
+void TextureProgressBar::set_stretch_margin(Margin p_margin, int p_size) {
ERR_FAIL_INDEX((int)p_margin, 4);
stretch_margin[p_margin] = p_size;
update();
minimum_size_changed();
}
-int TextureProgress::get_stretch_margin(Margin p_margin) const {
+int TextureProgressBar::get_stretch_margin(Margin p_margin) const {
ERR_FAIL_INDEX_V((int)p_margin, 4, 0);
return stretch_margin[p_margin];
}
-void TextureProgress::set_nine_patch_stretch(bool p_stretch) {
+void TextureProgressBar::set_nine_patch_stretch(bool p_stretch) {
nine_patch_stretch = p_stretch;
update();
minimum_size_changed();
}
-bool TextureProgress::get_nine_patch_stretch() const {
+bool TextureProgressBar::get_nine_patch_stretch() const {
return nine_patch_stretch;
}
-Size2 TextureProgress::get_minimum_size() const {
+Size2 TextureProgressBar::get_minimum_size() const {
if (nine_patch_stretch) {
return Size2(stretch_margin[MARGIN_LEFT] + stretch_margin[MARGIN_RIGHT], stretch_margin[MARGIN_TOP] + stretch_margin[MARGIN_BOTTOM]);
} else if (under.is_valid()) {
@@ -90,44 +90,44 @@ Size2 TextureProgress::get_minimum_size() const {
return Size2(1, 1);
}
-void TextureProgress::set_progress_texture(const Ref<Texture2D> &p_texture) {
+void TextureProgressBar::set_progress_texture(const Ref<Texture2D> &p_texture) {
progress = p_texture;
update();
minimum_size_changed();
}
-Ref<Texture2D> TextureProgress::get_progress_texture() const {
+Ref<Texture2D> TextureProgressBar::get_progress_texture() const {
return progress;
}
-void TextureProgress::set_tint_under(const Color &p_tint) {
+void TextureProgressBar::set_tint_under(const Color &p_tint) {
tint_under = p_tint;
update();
}
-Color TextureProgress::get_tint_under() const {
+Color TextureProgressBar::get_tint_under() const {
return tint_under;
}
-void TextureProgress::set_tint_progress(const Color &p_tint) {
+void TextureProgressBar::set_tint_progress(const Color &p_tint) {
tint_progress = p_tint;
update();
}
-Color TextureProgress::get_tint_progress() const {
+Color TextureProgressBar::get_tint_progress() const {
return tint_progress;
}
-void TextureProgress::set_tint_over(const Color &p_tint) {
+void TextureProgressBar::set_tint_over(const Color &p_tint) {
tint_over = p_tint;
update();
}
-Color TextureProgress::get_tint_over() const {
+Color TextureProgressBar::get_tint_over() const {
return tint_over;
}
-Point2 TextureProgress::unit_val_to_uv(float val) {
+Point2 TextureProgressBar::unit_val_to_uv(float val) {
if (progress.is_null()) {
return Point2();
}
@@ -191,7 +191,7 @@ Point2 TextureProgress::unit_val_to_uv(float val) {
return (p + t1 * dir);
}
-Point2 TextureProgress::get_relative_center() {
+Point2 TextureProgressBar::get_relative_center() {
if (progress.is_null()) {
return Point2();
}
@@ -204,7 +204,7 @@ Point2 TextureProgress::get_relative_center() {
return p;
}
-void TextureProgress::draw_nine_patch_stretched(const Ref<Texture2D> &p_texture, FillMode p_mode, double p_ratio, const Color &p_modulate) {
+void TextureProgressBar::draw_nine_patch_stretched(const Ref<Texture2D> &p_texture, FillMode p_mode, double p_ratio, const Color &p_modulate) {
Vector2 texture_size = p_texture->get_size();
Vector2 topleft = Vector2(stretch_margin[MARGIN_LEFT], stretch_margin[MARGIN_TOP]);
Vector2 bottomright = Vector2(stretch_margin[MARGIN_RIGHT], stretch_margin[MARGIN_BOTTOM]);
@@ -306,7 +306,7 @@ void TextureProgress::draw_nine_patch_stretched(const Ref<Texture2D> &p_texture,
RS::get_singleton()->canvas_item_add_nine_patch(ci, dst_rect, src_rect, p_texture->get_rid(), topleft, bottomright, RS::NINE_PATCH_STRETCH, RS::NINE_PATCH_STRETCH, true, p_modulate);
}
-void TextureProgress::_notification(int p_what) {
+void TextureProgressBar::_notification(int p_what) {
const float corners[12] = { -0.125, -0.375, -0.625, -0.875, 0.125, 0.375, 0.625, 0.875, 1.125, 1.375, 1.625, 1.875 };
switch (p_what) {
case NOTIFICATION_DRAW: {
@@ -428,17 +428,17 @@ void TextureProgress::_notification(int p_what) {
}
}
-void TextureProgress::set_fill_mode(int p_fill) {
+void TextureProgressBar::set_fill_mode(int p_fill) {
ERR_FAIL_INDEX(p_fill, 9);
mode = (FillMode)p_fill;
update();
}
-int TextureProgress::get_fill_mode() {
+int TextureProgressBar::get_fill_mode() {
return mode;
}
-void TextureProgress::set_radial_initial_angle(float p_angle) {
+void TextureProgressBar::set_radial_initial_angle(float p_angle) {
while (p_angle > 360) {
p_angle -= 360;
}
@@ -449,64 +449,64 @@ void TextureProgress::set_radial_initial_angle(float p_angle) {
update();
}
-float TextureProgress::get_radial_initial_angle() {
+float TextureProgressBar::get_radial_initial_angle() {
return rad_init_angle;
}
-void TextureProgress::set_fill_degrees(float p_angle) {
+void TextureProgressBar::set_fill_degrees(float p_angle) {
rad_max_degrees = CLAMP(p_angle, 0, 360);
update();
}
-float TextureProgress::get_fill_degrees() {
+float TextureProgressBar::get_fill_degrees() {
return rad_max_degrees;
}
-void TextureProgress::set_radial_center_offset(const Point2 &p_off) {
+void TextureProgressBar::set_radial_center_offset(const Point2 &p_off) {
rad_center_off = p_off;
update();
}
-Point2 TextureProgress::get_radial_center_offset() {
+Point2 TextureProgressBar::get_radial_center_offset() {
return rad_center_off;
}
-void TextureProgress::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_under_texture", "tex"), &TextureProgress::set_under_texture);
- ClassDB::bind_method(D_METHOD("get_under_texture"), &TextureProgress::get_under_texture);
+void TextureProgressBar::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_under_texture", "tex"), &TextureProgressBar::set_under_texture);
+ ClassDB::bind_method(D_METHOD("get_under_texture"), &TextureProgressBar::get_under_texture);
- ClassDB::bind_method(D_METHOD("set_progress_texture", "tex"), &TextureProgress::set_progress_texture);
- ClassDB::bind_method(D_METHOD("get_progress_texture"), &TextureProgress::get_progress_texture);
+ ClassDB::bind_method(D_METHOD("set_progress_texture", "tex"), &TextureProgressBar::set_progress_texture);
+ ClassDB::bind_method(D_METHOD("get_progress_texture"), &TextureProgressBar::get_progress_texture);
- ClassDB::bind_method(D_METHOD("set_over_texture", "tex"), &TextureProgress::set_over_texture);
- ClassDB::bind_method(D_METHOD("get_over_texture"), &TextureProgress::get_over_texture);
+ ClassDB::bind_method(D_METHOD("set_over_texture", "tex"), &TextureProgressBar::set_over_texture);
+ ClassDB::bind_method(D_METHOD("get_over_texture"), &TextureProgressBar::get_over_texture);
- ClassDB::bind_method(D_METHOD("set_fill_mode", "mode"), &TextureProgress::set_fill_mode);
- ClassDB::bind_method(D_METHOD("get_fill_mode"), &TextureProgress::get_fill_mode);
+ ClassDB::bind_method(D_METHOD("set_fill_mode", "mode"), &TextureProgressBar::set_fill_mode);
+ ClassDB::bind_method(D_METHOD("get_fill_mode"), &TextureProgressBar::get_fill_mode);
- ClassDB::bind_method(D_METHOD("set_tint_under", "tint"), &TextureProgress::set_tint_under);
- ClassDB::bind_method(D_METHOD("get_tint_under"), &TextureProgress::get_tint_under);
+ ClassDB::bind_method(D_METHOD("set_tint_under", "tint"), &TextureProgressBar::set_tint_under);
+ ClassDB::bind_method(D_METHOD("get_tint_under"), &TextureProgressBar::get_tint_under);
- ClassDB::bind_method(D_METHOD("set_tint_progress", "tint"), &TextureProgress::set_tint_progress);
- ClassDB::bind_method(D_METHOD("get_tint_progress"), &TextureProgress::get_tint_progress);
+ ClassDB::bind_method(D_METHOD("set_tint_progress", "tint"), &TextureProgressBar::set_tint_progress);
+ ClassDB::bind_method(D_METHOD("get_tint_progress"), &TextureProgressBar::get_tint_progress);
- ClassDB::bind_method(D_METHOD("set_tint_over", "tint"), &TextureProgress::set_tint_over);
- ClassDB::bind_method(D_METHOD("get_tint_over"), &TextureProgress::get_tint_over);
+ ClassDB::bind_method(D_METHOD("set_tint_over", "tint"), &TextureProgressBar::set_tint_over);
+ ClassDB::bind_method(D_METHOD("get_tint_over"), &TextureProgressBar::get_tint_over);
- ClassDB::bind_method(D_METHOD("set_radial_initial_angle", "mode"), &TextureProgress::set_radial_initial_angle);
- ClassDB::bind_method(D_METHOD("get_radial_initial_angle"), &TextureProgress::get_radial_initial_angle);
+ ClassDB::bind_method(D_METHOD("set_radial_initial_angle", "mode"), &TextureProgressBar::set_radial_initial_angle);
+ ClassDB::bind_method(D_METHOD("get_radial_initial_angle"), &TextureProgressBar::get_radial_initial_angle);
- ClassDB::bind_method(D_METHOD("set_radial_center_offset", "mode"), &TextureProgress::set_radial_center_offset);
- ClassDB::bind_method(D_METHOD("get_radial_center_offset"), &TextureProgress::get_radial_center_offset);
+ ClassDB::bind_method(D_METHOD("set_radial_center_offset", "mode"), &TextureProgressBar::set_radial_center_offset);
+ ClassDB::bind_method(D_METHOD("get_radial_center_offset"), &TextureProgressBar::get_radial_center_offset);
- ClassDB::bind_method(D_METHOD("set_fill_degrees", "mode"), &TextureProgress::set_fill_degrees);
- ClassDB::bind_method(D_METHOD("get_fill_degrees"), &TextureProgress::get_fill_degrees);
+ ClassDB::bind_method(D_METHOD("set_fill_degrees", "mode"), &TextureProgressBar::set_fill_degrees);
+ ClassDB::bind_method(D_METHOD("get_fill_degrees"), &TextureProgressBar::get_fill_degrees);
- ClassDB::bind_method(D_METHOD("set_stretch_margin", "margin", "value"), &TextureProgress::set_stretch_margin);
- ClassDB::bind_method(D_METHOD("get_stretch_margin", "margin"), &TextureProgress::get_stretch_margin);
+ ClassDB::bind_method(D_METHOD("set_stretch_margin", "margin", "value"), &TextureProgressBar::set_stretch_margin);
+ ClassDB::bind_method(D_METHOD("get_stretch_margin", "margin"), &TextureProgressBar::get_stretch_margin);
- ClassDB::bind_method(D_METHOD("set_nine_patch_stretch", "stretch"), &TextureProgress::set_nine_patch_stretch);
- ClassDB::bind_method(D_METHOD("get_nine_patch_stretch"), &TextureProgress::get_nine_patch_stretch);
+ ClassDB::bind_method(D_METHOD("set_nine_patch_stretch", "stretch"), &TextureProgressBar::set_nine_patch_stretch);
+ ClassDB::bind_method(D_METHOD("get_nine_patch_stretch"), &TextureProgressBar::get_nine_patch_stretch);
ADD_GROUP("Textures", "texture_");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_under", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_under_texture", "get_under_texture");
@@ -539,7 +539,7 @@ void TextureProgress::_bind_methods() {
BIND_ENUM_CONSTANT(FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE);
}
-TextureProgress::TextureProgress() {
+TextureProgressBar::TextureProgressBar() {
mode = FILL_LEFT_TO_RIGHT;
rad_init_angle = 0;
rad_center_off = Point2();
diff --git a/scene/gui/texture_progress.h b/scene/gui/texture_progress_bar.h
index 5e29fca21f..342e719a59 100644
--- a/scene/gui/texture_progress.h
+++ b/scene/gui/texture_progress_bar.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* texture_progress.h */
+/* texture_progress_bar.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef TEXTURE_PROGRESS_H
-#define TEXTURE_PROGRESS_H
+#ifndef TEXTURE_PROGRESS_BAR_H
+#define TEXTURE_PROGRESS_BAR_H
#include "scene/gui/range.h"
-class TextureProgress : public Range {
- GDCLASS(TextureProgress, Range);
+class TextureProgressBar : public Range {
+ GDCLASS(TextureProgressBar, Range);
Ref<Texture2D> under;
Ref<Texture2D> progress;
@@ -95,7 +95,7 @@ public:
Size2 get_minimum_size() const override;
- TextureProgress();
+ TextureProgressBar();
private:
FillMode mode;
@@ -111,6 +111,6 @@ private:
void draw_nine_patch_stretched(const Ref<Texture2D> &p_texture, FillMode p_mode, double p_ratio, const Color &p_modulate);
};
-VARIANT_ENUM_CAST(TextureProgress::FillMode);
+VARIANT_ENUM_CAST(TextureProgressBar::FillMode);
-#endif // TEXTURE_PROGRESS_H
+#endif // TEXTURE_PROGRESS_BAR_H
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 9e396d4030..1df61daa2c 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -1391,6 +1391,10 @@ SceneTree::SceneTree() {
const bool use_debanding = GLOBAL_DEF("rendering/quality/screen_filters/use_debanding", false);
root->set_use_debanding(use_debanding);
+ float lod_threshold = GLOBAL_DEF("rendering/quality/mesh_lod/threshold_pixels", 1.0);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/mesh_lod/threshold_pixels", PropertyInfo(Variant::FLOAT, "rendering/quality/mesh_lod/threshold_pixels", PROPERTY_HINT_RANGE, "0,1024,0.1"));
+ root->set_lod_threshold(lod_threshold);
+
bool snap_2d_transforms = GLOBAL_DEF("rendering/quality/2d/snap_2d_transforms_to_pixel", false);
root->set_snap_2d_transforms_to_pixel(snap_2d_transforms);
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 6350777a3d..c96dd4ad35 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -2392,19 +2392,19 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
if (!mods && p_event->is_action_pressed("ui_up") && input->is_action_just_pressed("ui_up")) {
- next = from->_get_focus_neighbour(MARGIN_TOP);
+ next = from->_get_focus_neighbor(MARGIN_TOP);
}
if (!mods && p_event->is_action_pressed("ui_left") && input->is_action_just_pressed("ui_left")) {
- next = from->_get_focus_neighbour(MARGIN_LEFT);
+ next = from->_get_focus_neighbor(MARGIN_LEFT);
}
if (!mods && p_event->is_action_pressed("ui_right") && input->is_action_just_pressed("ui_right")) {
- next = from->_get_focus_neighbour(MARGIN_RIGHT);
+ next = from->_get_focus_neighbor(MARGIN_RIGHT);
}
if (!mods && p_event->is_action_pressed("ui_down") && input->is_action_just_pressed("ui_down")) {
- next = from->_get_focus_neighbour(MARGIN_BOTTOM);
+ next = from->_get_focus_neighbor(MARGIN_BOTTOM);
}
if (next) {
@@ -3192,6 +3192,14 @@ bool Viewport::is_using_debanding() const {
return use_debanding;
}
+void Viewport::set_lod_threshold(float p_pixels) {
+ lod_threshold = p_pixels;
+ RS::get_singleton()->viewport_set_lod_threshold(viewport, lod_threshold);
+}
+float Viewport::get_lod_threshold() const {
+ return lod_threshold;
+}
+
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));
@@ -3505,6 +3513,9 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_sdf_scale", "scale"), &Viewport::set_sdf_scale);
ClassDB::bind_method(D_METHOD("get_sdf_scale"), &Viewport::get_sdf_scale);
+ ClassDB::bind_method(D_METHOD("set_lod_threshold", "pixels"), &Viewport::set_lod_threshold);
+ ClassDB::bind_method(D_METHOD("get_lod_threshold"), &Viewport::get_lod_threshold);
+
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");
@@ -3516,6 +3527,7 @@ void Viewport::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x,AndroidVR 2x,AndroidVR 4x"), "set_msaa", "get_msaa");
ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_space_aa", PROPERTY_HINT_ENUM, "Disabled,FXAA"), "set_screen_space_aa", "get_screen_space_aa");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "is_using_debanding");
+ ADD_PROPERTY(PropertyInfo(Variant::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");
@@ -3590,6 +3602,7 @@ void Viewport::_bind_methods() {
BIND_ENUM_CONSTANT(DEBUG_DRAW_SDFGI);
BIND_ENUM_CONSTANT(DEBUG_DRAW_SDFGI_PROBES);
BIND_ENUM_CONSTANT(DEBUG_DRAW_GI_BUFFER);
+ BIND_ENUM_CONSTANT(DEBUG_DRAW_DISABLE_LOD);
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR);
@@ -3652,6 +3665,8 @@ Viewport::Viewport() {
set_shadow_atlas_quadrant_subdiv(2, SHADOW_ATLAS_QUADRANT_SUBDIV_16);
set_shadow_atlas_quadrant_subdiv(3, SHADOW_ATLAS_QUADRANT_SUBDIV_64);
+ set_lod_threshold(lod_threshold);
+
String id = itos(get_instance_id());
input_group = "_vp_input" + id;
gui_input_group = "_vp_gui_input" + id;
@@ -3824,7 +3839,7 @@ void SubViewport::_bind_methods() {
BIND_ENUM_CONSTANT(CLEAR_MODE_ALWAYS);
BIND_ENUM_CONSTANT(CLEAR_MODE_NEVER);
- BIND_ENUM_CONSTANT(CLEAR_MODE_ONLY_NEXT_FRAME);
+ BIND_ENUM_CONSTANT(CLEAR_MODE_ONCE);
BIND_ENUM_CONSTANT(UPDATE_DISABLED);
BIND_ENUM_CONSTANT(UPDATE_ONCE);
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 7ce202d27c..ffbc3c782a 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -142,6 +142,7 @@ public:
DEBUG_DRAW_SDFGI,
DEBUG_DRAW_SDFGI_PROBES,
DEBUG_DRAW_GI_BUFFER,
+ DEBUG_DRAW_DISABLE_LOD,
};
enum DefaultCanvasItemTextureFilter {
@@ -297,6 +298,8 @@ private:
MSAA msaa;
ScreenSpaceAA screen_space_aa;
bool use_debanding = false;
+ float lod_threshold = 1.0;
+
Ref<ViewportTexture> default_texture;
Set<ViewportTexture *> viewport_textures;
@@ -542,6 +545,9 @@ public:
void set_use_debanding(bool p_use_debanding);
bool is_using_debanding() const;
+ void set_lod_threshold(float p_pixels);
+ float get_lod_threshold() const;
+
Vector2 get_camera_coords(const Vector2 &p_viewport_coords) const;
Vector2 get_camera_rect_size() const;
@@ -624,7 +630,7 @@ public:
enum ClearMode {
CLEAR_MODE_ALWAYS,
CLEAR_MODE_NEVER,
- CLEAR_MODE_ONLY_NEXT_FRAME
+ CLEAR_MODE_ONCE
};
enum UpdateMode {
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 73507d36fc..30077aa642 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -118,7 +118,7 @@
#include "scene/gui/tabs.h"
#include "scene/gui/text_edit.h"
#include "scene/gui/texture_button.h"
-#include "scene/gui/texture_progress.h"
+#include "scene/gui/texture_progress_bar.h"
#include "scene/gui/texture_rect.h"
#include "scene/gui/tree.h"
#include "scene/gui/video_player.h"
@@ -349,7 +349,7 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
- ClassDB::register_class<TextureProgress>();
+ ClassDB::register_class<TextureProgressBar>();
ClassDB::register_class<ItemList>();
ClassDB::register_class<LineEdit>();
@@ -915,6 +915,7 @@ void register_scene_types() {
ClassDB::add_compatibility_class("SpringArm", "SpringArm3D");
ClassDB::add_compatibility_class("Sprite", "Sprite2D");
ClassDB::add_compatibility_class("StaticBody", "StaticBody3D");
+ ClassDB::add_compatibility_class("TextureProgress", "TextureProgressBar");
ClassDB::add_compatibility_class("VehicleBody", "VehicleBody3D");
ClassDB::add_compatibility_class("VehicleWheel", "VehicleWheel3D");
ClassDB::add_compatibility_class("ViewportContainer", "SubViewportContainer");
diff --git a/scene/resources/SCsub b/scene/resources/SCsub
index 3a86b22835..f4dc7a46fb 100644
--- a/scene/resources/SCsub
+++ b/scene/resources/SCsub
@@ -2,6 +2,25 @@
Import("env")
-env.add_source_files(env.scene_sources, "*.cpp")
+# Thirdparty code
+
+thirdparty_obj = []
+
+thirdparty_sources = "#thirdparty/misc/mikktspace.c"
+
+env_thirdparty = env.Clone()
+env_thirdparty.disable_warnings()
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.scene_sources += thirdparty_obj
+
+# Godot source files
+
+scene_obj = []
+
+env.add_source_files(scene_obj, "*.cpp")
+env.scene_sources += scene_obj
+
+# Needed to force rebuilding the scene files when the thirdparty code is updated.
+env.Depends(scene_obj, thirdparty_obj)
SConscript("default_theme/SCsub")
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index b2aad97d3b..f4670ca850 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -33,8 +33,6 @@
#include "core/math/geometry_3d.h"
-#define ANIM_MIN_LENGTH 0.001
-
bool Animation::_set(const StringName &p_name, const Variant &p_value) {
String name = p_name;
@@ -810,8 +808,8 @@ int Animation::transform_track_insert_key(int p_track, float p_time, const Vecto
return ret;
}
-void Animation::track_remove_key_at_position(int p_track, float p_pos) {
- int idx = track_find_key(p_track, p_pos, true);
+void Animation::track_remove_key_at_time(int p_track, float p_time) {
+ int idx = track_find_key(p_track, p_time, true);
ERR_FAIL_COND(idx < 0);
track_remove_key(p_track, idx);
}
@@ -2608,7 +2606,7 @@ void Animation::_bind_methods() {
ClassDB::bind_method(D_METHOD("transform_track_insert_key", "track_idx", "time", "location", "rotation", "scale"), &Animation::transform_track_insert_key);
ClassDB::bind_method(D_METHOD("track_insert_key", "track_idx", "time", "key", "transition"), &Animation::track_insert_key, DEFVAL(1));
ClassDB::bind_method(D_METHOD("track_remove_key", "track_idx", "key_idx"), &Animation::track_remove_key);
- ClassDB::bind_method(D_METHOD("track_remove_key_at_position", "track_idx", "position"), &Animation::track_remove_key_at_position);
+ ClassDB::bind_method(D_METHOD("track_remove_key_at_time", "track_idx", "time"), &Animation::track_remove_key_at_time);
ClassDB::bind_method(D_METHOD("track_set_key_value", "track_idx", "key", "value"), &Animation::track_set_key_value);
ClassDB::bind_method(D_METHOD("track_set_key_transition", "track_idx", "key_idx", "transition"), &Animation::track_set_key_transition);
ClassDB::bind_method(D_METHOD("track_set_key_time", "track_idx", "key_idx", "time"), &Animation::track_set_key_time);
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index c52431f5f6..650a54ebfc 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -33,6 +33,8 @@
#include "core/io/resource.h"
+#define ANIM_MIN_LENGTH 0.001
+
class Animation : public Resource {
GDCLASS(Animation, Resource);
RES_BASE_EXTENSION("anim");
@@ -293,7 +295,7 @@ public:
void track_set_key_time(int p_track, int p_key_idx, float p_time);
int track_find_key(int p_track, float p_time, bool p_exact = false) const;
void track_remove_key(int p_track, int p_idx);
- void track_remove_key_at_position(int p_track, float p_pos);
+ void track_remove_key_at_time(int p_track, float p_time);
int track_get_key_count(int p_track) const;
Variant track_get_key_value(int p_track, int p_key_idx) const;
float track_get_key_time(int p_track, int p_key_idx) const;
diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp
index 10f0de8ff8..d07447179d 100644
--- a/scene/resources/bit_map.cpp
+++ b/scene/resources/bit_map.cpp
@@ -63,7 +63,7 @@ void BitMap::create_from_image_alpha(const Ref<Image> &p_image, float p_threshol
}
void BitMap::set_bit_rect(const Rect2 &p_rect, bool p_value) {
- Rect2i current = Rect2i(0, 0, width, height).clip(p_rect);
+ Rect2i current = Rect2i(0, 0, width, height).intersection(p_rect);
uint8_t *data = bitmask.ptrw();
for (int i = current.position.x; i < current.position.x + current.size.x; i++) {
@@ -482,7 +482,7 @@ static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_
}
Vector<Vector<Vector2>> BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon) const {
- Rect2i r = Rect2i(0, 0, width, height).clip(p_rect);
+ Rect2i r = Rect2i(0, 0, width, height).intersection(p_rect);
print_verbose("BitMap: Rect: " + r);
Point2i from;
@@ -522,7 +522,7 @@ void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) {
bool bit_value = p_pixels > 0;
p_pixels = Math::abs(p_pixels);
- Rect2i r = Rect2i(0, 0, width, height).clip(p_rect);
+ Rect2i r = Rect2i(0, 0, width, height).intersection(p_rect);
Ref<BitMap> copy;
copy.instance();
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 85cd0f9bb4..2de28b5e5c 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -77,6 +77,17 @@ static Ref<StyleBoxTexture> make_stylebox(T p_src, float p_left, float p_top, fl
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) {
+ Ref<StyleBoxFlat> style(memnew(StyleBoxFlat));
+ style->set_bg_color(p_color);
+ style->set_default_margin(MARGIN_LEFT, p_margin_left * scale);
+ style->set_default_margin(MARGIN_RIGHT, p_margin_right * scale);
+ style->set_default_margin(MARGIN_BOTTOM, p_margin_bottom * scale);
+ style->set_default_margin(MARGIN_TOP, p_margin_top * scale);
+
+ return style;
+}
+
static Ref<StyleBoxTexture> sb_expand(Ref<StyleBoxTexture> p_sbox, float p_left, float p_top, float p_right, float p_botton) {
p_sbox->set_expand_margin_size(MARGIN_LEFT, p_left * scale);
p_sbox->set_expand_margin_size(MARGIN_TOP, p_top * scale);
@@ -97,6 +108,25 @@ static Ref<Texture2D> make_icon(T p_src) {
return texture;
}
+static Ref<Texture2D> flip_icon(Ref<Texture2D> p_texture, bool p_flip_y = false, bool p_flip_x = false) {
+ if (!p_flip_y && !p_flip_x) {
+ return p_texture;
+ }
+
+ Ref<ImageTexture> texture(memnew(ImageTexture));
+ Ref<Image> img = p_texture->get_data();
+
+ if (p_flip_y) {
+ img->flip_y();
+ }
+ if (p_flip_x) {
+ img->flip_x();
+ }
+
+ texture->create_from_image(img);
+ return texture;
+}
+
static Ref<StyleBox> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_botton = -1) {
Ref<StyleBox> style(memnew(StyleBoxEmpty));
@@ -803,6 +833,12 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_font("bold_italics_font", "RichTextLabel", Ref<Font>());
theme->set_font("mono_font", "RichTextLabel", Ref<Font>());
+ theme->set_font_size("normal_font_size", "RichTextLabel", -1);
+ theme->set_font_size("bold_font_size", "RichTextLabel", -1);
+ theme->set_font_size("italics_font_size", "RichTextLabel", -1);
+ theme->set_font_size("bold_italics_font_size", "RichTextLabel", -1);
+ theme->set_font_size("mono_font_size", "RichTextLabel", -1);
+
theme->set_color("default_color", "RichTextLabel", Color(1, 1, 1));
theme->set_color("font_color_selected", "RichTextLabel", font_color_selection);
theme->set_color("selection_color", "RichTextLabel", Color(0.1, 0.1, 1, 0.8));
@@ -817,6 +853,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("table_hseparation", "RichTextLabel", 3 * scale);
theme->set_constant("table_vseparation", "RichTextLabel", 3 * scale);
+ theme->set_color("table_odd_row_bg", "RichTextLabel", Color(0, 0, 0, 0));
+ theme->set_color("table_even_row_bg", "RichTextLabel", Color(0, 0, 0, 0));
+ theme->set_color("table_border", "RichTextLabel", Color(0, 0, 0, 0));
// Containers
theme->set_stylebox("bg", "VSplitContainer", make_stylebox(vsplit_bg_png, 1, 1, 1, 1));
@@ -845,6 +884,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("reset", "GraphEdit", make_icon(icon_zoom_reset_png));
theme->set_icon("more", "GraphEdit", make_icon(icon_zoom_more_png));
theme->set_icon("snap", "GraphEdit", make_icon(icon_snap_grid_png));
+ theme->set_icon("minimap", "GraphEdit", make_icon(icon_grid_minimap_png));
theme->set_stylebox("bg", "GraphEdit", make_stylebox(tree_bg_png, 4, 4, 4, 5));
theme->set_color("grid_minor", "GraphEdit", Color(1, 1, 1, 0.05));
theme->set_color("grid_major", "GraphEdit", Color(1, 1, 1, 0.2));
@@ -858,6 +898,19 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("port_grab_distance_horizontal", "GraphEdit", 48 * scale);
theme->set_constant("port_grab_distance_vertical", "GraphEdit", 6 * scale);
+ theme->set_stylebox("bg", "GraphEditMinimap", make_flat_stylebox(Color(0.24, 0.24, 0.24), 0, 0, 0, 0));
+ Ref<StyleBoxFlat> style_minimap_camera = make_flat_stylebox(Color(0.65, 0.65, 0.65, 0.2), 0, 0, 0, 0);
+ style_minimap_camera->set_border_color(Color(0.65, 0.65, 0.65, 0.45));
+ style_minimap_camera->set_border_width_all(1);
+ theme->set_stylebox("camera", "GraphEditMinimap", style_minimap_camera);
+ Ref<StyleBoxFlat> style_minimap_node = make_flat_stylebox(Color(1, 1, 1), 0, 0, 0, 0);
+ style_minimap_node->set_corner_radius_all(2);
+ theme->set_stylebox("node", "GraphEditMinimap", style_minimap_node);
+
+ Ref<Texture2D> resizer_icon = make_icon(window_resizer_png);
+ theme->set_icon("resizer", "GraphEditMinimap", flip_icon(resizer_icon, true, true));
+ theme->set_color("resizer_color", "GraphEditMinimap", Color(1, 1, 1, 0.85));
+
// Theme
default_icon = make_icon(error_icon_png);
diff --git a/scene/resources/default_theme/icon_grid_minimap.png b/scene/resources/default_theme/icon_grid_minimap.png
new file mode 100644
index 0000000000..00a6179d5e
--- /dev/null
+++ b/scene/resources/default_theme/icon_grid_minimap.png
Binary files differ
diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h
index 7765348f80..b905c9db69 100644
--- a/scene/resources/default_theme/theme_data.h
+++ b/scene/resources/default_theme/theme_data.h
@@ -166,6 +166,10 @@ static const unsigned char icon_folder_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, 0x2e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x6, 0x78, 0x70, 0xf4, 0xc1, 0x7f, 0x24, 0x78, 0x18, 0x53, 0xc1, 0x7f, 0x54, 0x48, 0x50, 0xc1, 0x43, 0x1b, 0xbc, 0xa, 0x50, 0xad, 0x23, 0xa4, 0xe0, 0xff, 0x70, 0x52, 0x70, 0x18, 0x97, 0xf4, 0xfd, 0x43, 0xd4, 0x88, 0x4a, 0x0, 0x5a, 0xcb, 0x18, 0xab, 0x5e, 0xd9, 0x1a, 0x53, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
+static const unsigned char icon_grid_minimap_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc3, 0x0, 0x0, 0xe, 0xc3, 0x1, 0xc7, 0x6f, 0xa8, 0x64, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x0, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x6e, 0x6b, 0x73, 0x63, 0x61, 0x70, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x9b, 0xee, 0x3c, 0x1a, 0x0, 0x0, 0x2, 0xd, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0x75, 0x93, 0x31, 0x68, 0x14, 0x51, 0x10, 0x86, 0xbf, 0xd9, 0xd, 0xbb, 0xde, 0x76, 0x82, 0x21, 0xf8, 0xe0, 0xbc, 0x5d, 0x8b, 0x80, 0x69, 0x6c, 0xd2, 0x5a, 0x6a, 0x91, 0xc3, 0xd2, 0x46, 0x22, 0x8, 0x9, 0x89, 0x70, 0x85, 0x10, 0x41, 0xd, 0x24, 0x45, 0xb0, 0xb, 0x68, 0x11, 0x14, 0x24, 0x10, 0x22, 0x62, 0x21, 0x41, 0xe, 0x4b, 0x21, 0xa4, 0xb7, 0x49, 0x17, 0xb1, 0x8, 0xb9, 0xdd, 0xc7, 0x86, 0x33, 0x21, 0xe1, 0x3a, 0x8f, 0x64, 0x61, 0x6f, 0x2c, 0xbc, 0x3b, 0x36, 0xb9, 0xdc, 0xc0, 0x2b, 0xde, 0xcc, 0xfc, 0xf3, 0xff, 0xfc, 0xcc, 0x48, 0xa3, 0xd1, 0x78, 0x20, 0x22, 0x13, 0xbe, 0xef, 0xaf, 0xdf, 0xac, 0xd7, 0x1f, 0xe1, 0x38, 0xd3, 0xa8, 0x2a, 0xf0, 0x45, 0x6a, 0xb5, 0xcf, 0x5c, 0x11, 0xcd, 0x66, 0x33, 0x38, 0x3f, 0x3f, 0x9f, 0x13, 0x91, 0x7d, 0xb1, 0xd6, 0x6e, 0xaa, 0xea, 0xd3, 0xe0, 0xe8, 0xe8, 0xde, 0xe8, 0xee, 0xee, 0x37, 0xc0, 0xe9, 0xf6, 0x75, 0xf0, 0xfd, 0x9, 0x99, 0x9d, 0x6d, 0x15, 0x81, 0x59, 0x96, 0x3d, 0x3, 0x5e, 0x2, 0x63, 0x22, 0xf2, 0x69, 0xa4, 0x57, 0x1c, 0xdd, 0xdb, 0xfb, 0x5b, 0x0, 0x3, 0x38, 0x67, 0x41, 0x30, 0x11, 0xc7, 0xf1, 0x13, 0x0, 0x11, 0x71, 0xb2, 0x2c, 0x7b, 0xd8, 0xad, 0xad, 0x2, 0x6f, 0xb9, 0x0, 0x38, 0x3c, 0xfc, 0x5, 0x9c, 0xf6, 0xff, 0x22, 0x27, 0x27, 0xe3, 0xe3, 0x7f, 0xa, 0x3, 0x67, 0x45, 0xe4, 0xbb, 0xe7, 0x79, 0xb7, 0xc3, 0x30, 0x7c, 0xd7, 0x67, 0xe9, 0xe3, 0x67, 0x66, 0x5c, 0x60, 0x1, 0x50, 0x40, 0x51, 0x7d, 0x71, 0x6b, 0x72, 0xf2, 0x20, 0x8a, 0xa2, 0xf9, 0x28, 0x8a, 0xe6, 0x1, 0x3a, 0x9d, 0xce, 0x4f, 0x63, 0x4c, 0x3b, 0x4d, 0xd3, 0xd2, 0xc0, 0x80, 0x3c, 0xcf, 0xf, 0x92, 0xa9, 0xa9, 0x31, 0x60, 0x5, 0x58, 0x91, 0x5a, 0xed, 0xc7, 0x15, 0xfe, 0x95, 0xac, 0xb5, 0xcf, 0xf3, 0x3c, 0x3f, 0xe8, 0x25, 0x46, 0xa, 0xc5, 0xd, 0x11, 0x59, 0xb3, 0xd5, 0xea, 0x1b, 0xa0, 0x95, 0x54, 0xab, 0x5b, 0x97, 0xd1, 0x22, 0xb2, 0xa6, 0xaa, 0x6d, 0x60, 0xd, 0x58, 0xba, 0xa0, 0x20, 0xc, 0xc3, 0x65, 0xd7, 0x75, 0x23, 0xe0, 0x2e, 0xb0, 0x1, 0x5c, 0xbf, 0xf4, 0x0, 0xbe, 0xba, 0xae, 0x1b, 0x85, 0x61, 0xb8, 0x3c, 0xa0, 0x20, 0x4d, 0xd3, 0x52, 0xb9, 0x5c, 0x6e, 0xc5, 0x71, 0xbc, 0x23, 0x22, 0xd3, 0x61, 0x18, 0xde, 0x2f, 0xb2, 0x27, 0x49, 0xa2, 0xaa, 0xba, 0x53, 0x2e, 0x97, 0x5b, 0x69, 0x9a, 0x96, 0xf2, 0x3c, 0x1f, 0xf0, 0xc0, 0x5a, 0x6b, 0x5f, 0x1, 0x25, 0x86, 0x84, 0xe3, 0x38, 0x9e, 0xb5, 0x76, 0x2e, 0xcf, 0xf3, 0xfd, 0x1, 0x5, 0x22, 0xb2, 0xa1, 0xaa, 0x4b, 0x22, 0x72, 0xad, 0xcb, 0x38, 0xe0, 0x81, 0xaa, 0x7e, 0x0, 0xce, 0x44, 0xe4, 0xbd, 0xaa, 0xbe, 0xbe, 0xa0, 0xa0, 0x52, 0xa9, 0x2c, 0x7a, 0x9e, 0x17, 0x1, 0x3d, 0xe0, 0x55, 0x1e, 0x6c, 0x79, 0x9e, 0x17, 0x55, 0x2a, 0x95, 0xc5, 0x1, 0x5, 0xcd, 0x66, 0x33, 0x30, 0xc6, 0x9c, 0xc6, 0x71, 0xbc, 0x2d, 0x22, 0x8f, 0x87, 0x78, 0xb0, 0x6d, 0x8c, 0x39, 0xed, 0xae, 0x74, 0xdf, 0x83, 0x3a, 0x70, 0x9c, 0x65, 0x59, 0x23, 0x49, 0x92, 0x5, 0x11, 0x9, 0x86, 0x79, 0x20, 0x22, 0x41, 0x92, 0x24, 0xb, 0x59, 0x96, 0x35, 0x80, 0x63, 0xa0, 0x2e, 0x3d, 0xf6, 0xc2, 0x91, 0xdc, 0x0, 0x5c, 0x55, 0x5d, 0xbf, 0x4, 0x9e, 0x3, 0x72, 0xfe, 0xaf, 0xfb, 0xaa, 0xe7, 0x79, 0x1f, 0x8d, 0x31, 0x6d, 0x29, 0x36, 0xf5, 0xce, 0x14, 0xb8, 0x33, 0x44, 0xc4, 0x6f, 0xdf, 0xf7, 0xd7, 0x8d, 0x31, 0xed, 0x5e, 0xe2, 0x1f, 0xb, 0x5c, 0xe2, 0xcb, 0xd, 0x9b, 0x69, 0xcb, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+};
+
static const unsigned char icon_parent_folder_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, 0x68, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x33, 0xb8, 0x27, 0xfe, 0xe0, 0xfc, 0x83, 0x73, 0xf7, 0xc4, 0x71, 0x48, 0xdf, 0x11, 0x7b, 0x78, 0xe9, 0xc1, 0x3f, 0x20, 0xbc, 0xfe, 0x40, 0x12, 0x8f, 0x34, 0x4c, 0x9, 0xa6, 0xe1, 0x57, 0x80, 0x12, 0x17, 0x81, 0xf8, 0x2f, 0x58, 0xe1, 0x15, 0x34, 0x8b, 0x1e, 0x9c, 0x5, 0xa, 0x5e, 0xb8, 0x23, 0x6, 0x52, 0x70, 0x5b, 0x14, 0xac, 0xf0, 0xc, 0xaa, 0x82, 0x7d, 0xf, 0x8e, 0xde, 0x14, 0xf9, 0xcf, 0x8, 0x52, 0xc0, 0xc0, 0x70, 0x5b, 0xf4, 0xe1, 0xc9, 0x7, 0x47, 0xb1, 0xb8, 0x3, 0xaa, 0x0, 0xa, 0x48, 0x52, 0x80, 0xb0, 0xea, 0xc8, 0xc3, 0x83, 0xc, 0x83, 0xe, 0x0, 0x0, 0xb8, 0x27, 0x55, 0x4c, 0xbe, 0xc0, 0xd2, 0xac, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 7c17610df7..791f260c0e 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -53,6 +53,11 @@ void FontData::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &FontData::set_antialiased);
ClassDB::bind_method(D_METHOD("get_antialiased"), &FontData::get_antialiased);
+ ClassDB::bind_method(D_METHOD("get_variation_list"), &FontData::get_variation_list);
+
+ ClassDB::bind_method(D_METHOD("set_variation", "tag", "value"), &FontData::set_variation);
+ ClassDB::bind_method(D_METHOD("get_variation", "tag"), &FontData::get_variation);
+
ClassDB::bind_method(D_METHOD("set_hinting", "hinting"), &FontData::set_hinting);
ClassDB::bind_method(D_METHOD("get_hinting"), &FontData::get_hinting);
@@ -115,6 +120,11 @@ bool FontData::_set(const StringName &p_name, const Variant &p_value) {
set_script_support_override(scr, p_value);
return true;
}
+ if (str.begins_with("variation/")) {
+ String name = str.get_slicec('/', 1);
+ set_variation(name, p_value);
+ return true;
+ }
return false;
}
@@ -137,6 +147,12 @@ bool FontData::_get(const StringName &p_name, Variant &r_ret) const {
r_ret = get_script_support_override(scr);
return true;
}
+ if (str.begins_with("variation/")) {
+ String name = str.get_slicec('/', 1);
+
+ r_ret = get_variation(name);
+ return true;
+ }
return false;
}
@@ -153,6 +169,12 @@ void FontData::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::BOOL, "script_support_override/" + scr_over[i], PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE));
}
p_list->push_back(PropertyInfo(Variant::NIL, "script_support_override/_new", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
+
+ Dictionary variations = get_variation_list();
+ for (const Variant *ftr = variations.next(nullptr); ftr != nullptr; ftr = variations.next(ftr)) {
+ Vector3i v = variations[*ftr];
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "variation/" + TS->tag_to_name(*ftr), PROPERTY_HINT_RANGE, itos(v.x) + "," + itos(v.y), PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE));
+ }
}
RID FontData::get_rid() const {
@@ -239,6 +261,26 @@ float FontData::get_underline_thickness(int p_size) const {
return TS->font_get_underline_thickness(rid, (p_size < 0) ? base_size : p_size);
}
+Dictionary FontData::get_variation_list() const {
+ if (rid == RID()) {
+ return Dictionary();
+ }
+ return TS->font_get_variation_list(rid);
+}
+
+void FontData::set_variation(const String &p_name, double p_value) {
+ ERR_FAIL_COND(rid == RID());
+ TS->font_set_variation(rid, p_name, p_value);
+ emit_changed();
+}
+
+double FontData::get_variation(const String &p_name) const {
+ if (rid == RID()) {
+ return 0;
+ }
+ return TS->font_get_variation(rid, p_name);
+}
+
void FontData::set_antialiased(bool p_antialiased) {
ERR_FAIL_COND(rid == RID());
TS->font_set_antialiased(rid, p_antialiased);
@@ -927,7 +969,7 @@ RES ResourceFormatLoaderFont::load(const String &p_path, const String &p_origina
void ResourceFormatLoaderFont::get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const {
#ifndef DISABLE_DEPRECATED
- if (p_type == "DynacmicFontData") {
+ if (p_type == "DynamicFontData") {
p_extensions->push_back("ttf");
p_extensions->push_back("otf");
p_extensions->push_back("woff");
diff --git a/scene/resources/font.h b/scene/resources/font.h
index bc82a6fabf..fe28e1aea5 100644
--- a/scene/resources/font.h
+++ b/scene/resources/font.h
@@ -68,6 +68,10 @@ public:
float get_descent(int p_size) const;
Dictionary get_feature_list() const;
+ Dictionary get_variation_list() const;
+
+ void set_variation(const String &p_name, double p_value);
+ double get_variation(const String &p_name) const;
float get_underline_position(int p_size) const;
float get_underline_thickness(int p_size) const;
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index c6815c8ecc..f1c05b8014 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -533,6 +533,9 @@ void Mesh::_bind_methods() {
BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_2D_VERTICES);
BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_DYNAMIC_UPDATE);
BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_8_BONE_WEIGHTS);
+
+ BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_NORMALIZED);
+ BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_RELATIVE);
}
void Mesh::clear_cache() const {
@@ -734,21 +737,6 @@ static Vector<uint8_t> _fix_array_compatibility(const Vector<uint8_t> &p_src, ui
bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
String sname = p_name;
- if (p_name == "blend_shape/names") {
- Vector<String> sk = p_value;
- int sz = sk.size();
- const String *r = sk.ptr();
- for (int i = 0; i < sz; i++) {
- add_blend_shape(r[i]);
- }
- return true;
- }
-
- if (p_name == "blend_shape/mode") {
- set_blend_shape_mode(BlendShapeMode(int(p_value)));
- return true;
- }
-
if (sname.begins_with("surface_")) {
int sl = sname.find("/");
if (sl == -1) {
@@ -872,6 +860,28 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
return false;
}
+void ArrayMesh::_set_blend_shape_names(const PackedStringArray &p_names) {
+ ERR_FAIL_COND(surfaces.size() > 0);
+
+ blend_shapes.resize(p_names.size());
+ for (int i = 0; i < p_names.size(); i++) {
+ blend_shapes.write[i] = p_names[i];
+ }
+
+ if (mesh.is_valid()) {
+ RS::get_singleton()->mesh_set_blend_shape_count(mesh, blend_shapes.size());
+ }
+}
+
+PackedStringArray ArrayMesh::_get_blend_shape_names() const {
+ PackedStringArray sarr;
+ sarr.resize(blend_shapes.size());
+ for (int i = 0; i < blend_shapes.size(); i++) {
+ sarr.write[i] = blend_shapes[i];
+ }
+ return sarr;
+}
+
Array ArrayMesh::_get_surfaces() const {
if (mesh.is_null()) {
return Array();
@@ -917,7 +927,6 @@ Array ArrayMesh::_get_surfaces() const {
if (surface.blend_shape_data.size()) {
data["blend_shapes"] = surface.blend_shape_data;
- data["blend_shapes_count"] = surface.blend_shape_count;
}
if (surfaces[i].material.is_valid()) {
@@ -942,6 +951,7 @@ void ArrayMesh::_create_if_empty() const {
if (!mesh.is_valid()) {
mesh = RS::get_singleton()->mesh_create();
RS::get_singleton()->mesh_set_blend_shape_mode(mesh, (RS::BlendShapeMode)blend_shape_mode);
+ RS::get_singleton()->mesh_set_blend_shape_count(mesh, blend_shapes.size());
}
}
@@ -995,9 +1005,8 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) {
}
}
- if (d.has("blend_shapes") && d.has("blend_shape_count")) {
+ if (d.has("blend_shapes")) {
surface.blend_shape_data = d["blend_shapes"];
- surface.blend_shape_count = d["blend_shape_count"];
}
Ref<Material> material;
@@ -1017,15 +1026,7 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) {
if (d.has("2d")) {
_2d = d["2d"];
}
- /*
- print_line("format: " + itos(surface.format));
- print_line("aabb: " + surface.aabb);
- print_line("array size: " + itos(surface.vertex_data.size()));
- print_line("vertex count: " + itos(surface.vertex_count));
- print_line("index size: " + itos(surface.index_data.size()));
- print_line("index count: " + itos(surface.index_count));
- print_line("primitive: " + itos(surface.primitive));
-*/
+
surface_data.push_back(surface);
surface_materials.push_back(material);
surface_names.push_back(name);
@@ -1041,7 +1042,7 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) {
} else {
// if mesh does not exist (first time this is loaded, most likely),
// we can create it with a single call, which is a lot more efficient and thread friendly
- mesh = RS::get_singleton()->mesh_create_from_surfaces(surface_data);
+ mesh = RS::get_singleton()->mesh_create_from_surfaces(surface_data, blend_shapes.size());
RS::get_singleton()->mesh_set_blend_shape_mode(mesh, (RS::BlendShapeMode)blend_shape_mode);
}
@@ -1053,7 +1054,6 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) {
s.aabb = surface_data[i].aabb;
if (i == 0) {
aabb = s.aabb;
- blend_shapes.resize(surface_data[i].blend_shape_count);
} else {
aabb.merge_with(s.aabb);
}
@@ -1077,18 +1077,7 @@ bool ArrayMesh::_get(const StringName &p_name, Variant &r_ret) const {
}
String sname = p_name;
-
- if (p_name == "blend_shape/names") {
- Vector<String> sk;
- for (int i = 0; i < blend_shapes.size(); i++) {
- sk.push_back(blend_shapes[i]);
- }
- r_ret = sk;
- return true;
- } else if (p_name == "blend_shape/mode") {
- r_ret = get_blend_shape_mode();
- return true;
- } else if (sname.begins_with("surface_")) {
+ if (sname.begins_with("surface_")) {
int sl = sname.find("/");
if (sl == -1) {
return false;
@@ -1111,11 +1100,6 @@ void ArrayMesh::_get_property_list(List<PropertyInfo> *p_list) const {
return;
}
- if (blend_shapes.size()) {
- p_list->push_back(PropertyInfo(Variant::PACKED_STRING_ARRAY, "blend_shape/names", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
- p_list->push_back(PropertyInfo(Variant::INT, "blend_shape/mode", PROPERTY_HINT_ENUM, "Normalized,Relative"));
- }
-
for (int i = 0; i < surfaces.size(); i++) {
p_list->push_back(PropertyInfo(Variant::STRING, "surface_" + itos(i + 1) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
if (surfaces[i].is_2d) {
@@ -1141,7 +1125,7 @@ void ArrayMesh::_recompute_aabb() {
#ifndef _MSC_VER
#warning need to add binding to add_surface using future MeshSurfaceData object
#endif
-void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const Vector<uint8_t> &p_array, const Vector<uint8_t> &p_attribute_array, const Vector<uint8_t> &p_skin_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<uint8_t> &p_blend_shape_data, uint32_t p_blend_shape_count, const Vector<AABB> &p_bone_aabbs, const Vector<RS::SurfaceData::LOD> &p_lods) {
+void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const Vector<uint8_t> &p_array, const Vector<uint8_t> &p_attribute_array, const Vector<uint8_t> &p_skin_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<uint8_t> &p_blend_shape_data, const Vector<AABB> &p_bone_aabbs, const Vector<RS::SurfaceData::LOD> &p_lods) {
_create_if_empty();
Surface s;
@@ -1166,7 +1150,6 @@ void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const
sd.index_count = p_index_count;
sd.index_data = p_index_array;
sd.blend_shape_data = p_blend_shape_data;
- sd.blend_shape_count = p_blend_shape_count;
sd.bone_aabbs = p_bone_aabbs;
sd.lods = p_lods;
@@ -1195,7 +1178,7 @@ void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array &
print_line("primitive: " + itos(surface.primitive));
*/
- add_surface(surface.format, PrimitiveType(surface.primitive), surface.vertex_data, surface.attribute_data, surface.skin_data, surface.vertex_count, surface.index_data, surface.index_count, surface.aabb, surface.blend_shape_data, surface.blend_shape_count, surface.bone_aabbs, surface.lods);
+ add_surface(surface.format, PrimitiveType(surface.primitive), surface.vertex_data, surface.attribute_data, surface.skin_data, surface.vertex_count, surface.index_data, surface.index_count, surface.aabb, surface.blend_shape_data, surface.bone_aabbs, surface.lods);
}
Array ArrayMesh::surface_get_arrays(int p_surface) const {
@@ -1231,7 +1214,10 @@ void ArrayMesh::add_blend_shape(const StringName &p_name) {
}
blend_shapes.push_back(name);
- //RS::get_singleton()->mesh_set_blend_shape_count(mesh, blend_shapes.size());
+
+ if (mesh.is_valid()) {
+ RS::get_singleton()->mesh_set_blend_shape_count(mesh, blend_shapes.size());
+ }
}
int ArrayMesh::get_blend_shape_count() const {
@@ -1247,6 +1233,10 @@ void ArrayMesh::clear_blend_shapes() {
ERR_FAIL_COND_MSG(surfaces.size(), "Can't set shape key count if surfaces are already created.");
blend_shapes.clear();
+
+ if (mesh.is_valid()) {
+ RS::get_singleton()->mesh_set_blend_shape_count(mesh, 0);
+ }
}
void ArrayMesh::set_blend_shape_mode(BlendShapeMode p_mode) {
@@ -1384,7 +1374,7 @@ bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_v
struct ArrayMeshLightmapSurface {
Ref<Material> material;
- Vector<SurfaceTool::Vertex> vertices;
+ LocalVector<SurfaceTool::Vertex> vertices;
Mesh::PrimitiveType primitive;
uint32_t format;
};
@@ -1425,7 +1415,7 @@ 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);
- s.vertices = SurfaceTool::create_vertex_array_from_triangle_arrays(arrays);
+ SurfaceTool::create_vertex_array_from_triangle_arrays(arrays, s.vertices);
Vector<Vector3> rvertices = arrays[Mesh::ARRAY_VERTEX];
int vc = rvertices.size();
@@ -1606,15 +1596,16 @@ void ArrayMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &ArrayMesh::set_custom_aabb);
ClassDB::bind_method(D_METHOD("get_custom_aabb"), &ArrayMesh::get_custom_aabb);
+ ClassDB::bind_method(D_METHOD("_set_blend_shape_names", "blend_shape_names"), &ArrayMesh::_set_blend_shape_names);
+ ClassDB::bind_method(D_METHOD("_get_blend_shape_names"), &ArrayMesh::_get_blend_shape_names);
+
ClassDB::bind_method(D_METHOD("_set_surfaces", "surfaces"), &ArrayMesh::_set_surfaces);
ClassDB::bind_method(D_METHOD("_get_surfaces"), &ArrayMesh::_get_surfaces);
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "_blend_shape_names", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_blend_shape_names", "_get_blend_shape_names");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_surfaces", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_surfaces", "_get_surfaces");
ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_shape_mode", PROPERTY_HINT_ENUM, "Normalized,Relative"), "set_blend_shape_mode", "get_blend_shape_mode");
ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, ""), "set_custom_aabb", "get_custom_aabb");
-
- BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_NORMALIZED);
- BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_RELATIVE);
}
void ArrayMesh::reload_from_file() {
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index ae2139a0cf..b7f60bf814 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -53,7 +53,10 @@ public:
NO_INDEX_ARRAY = RenderingServer::NO_INDEX_ARRAY,
ARRAY_WEIGHTS_SIZE = RenderingServer::ARRAY_WEIGHTS_SIZE
};
-
+ enum BlendShapeMode {
+ BLEND_SHAPE_MODE_NORMALIZED = RS::BLEND_SHAPE_MODE_NORMALIZED,
+ BLEND_SHAPE_MODE_RELATIVE = RS::BLEND_SHAPE_MODE_RELATIVE,
+ };
enum ArrayType {
ARRAY_VERTEX = RenderingServer::ARRAY_VERTEX,
ARRAY_NORMAL = RenderingServer::ARRAY_NORMAL,
@@ -168,15 +171,12 @@ class ArrayMesh : public Mesh {
GDCLASS(ArrayMesh, Mesh);
RES_BASE_EXTENSION("mesh");
+ PackedStringArray _get_blend_shape_names() const;
+ void _set_blend_shape_names(const PackedStringArray &p_names);
+
Array _get_surfaces() const;
void _set_surfaces(const Array &p_data);
-public:
- enum BlendShapeMode {
- BLEND_SHAPE_MODE_NORMALIZED = RS::BLEND_SHAPE_MODE_NORMALIZED,
- BLEND_SHAPE_MODE_RELATIVE = RS::BLEND_SHAPE_MODE_RELATIVE,
- };
-
private:
struct Surface {
uint32_t format;
@@ -211,7 +211,7 @@ protected:
public:
void add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_flags = 0);
- void add_surface(uint32_t p_format, PrimitiveType p_primitive, const Vector<uint8_t> &p_array, const Vector<uint8_t> &p_attribute_array, const Vector<uint8_t> &p_skin_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<uint8_t> &p_blend_shape_data = Vector<uint8_t>(), uint32_t p_blend_shape_count = 0, const Vector<AABB> &p_bone_aabbs = Vector<AABB>(), const Vector<RS::SurfaceData::LOD> &p_lods = Vector<RS::SurfaceData::LOD>());
+ void add_surface(uint32_t p_format, PrimitiveType p_primitive, const Vector<uint8_t> &p_array, const Vector<uint8_t> &p_attribute_array, const Vector<uint8_t> &p_skin_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<uint8_t> &p_blend_shape_data = Vector<uint8_t>(), const Vector<AABB> &p_bone_aabbs = Vector<AABB>(), const Vector<RS::SurfaceData::LOD> &p_lods = Vector<RS::SurfaceData::LOD>());
Array surface_get_arrays(int p_surface) const override;
Array surface_get_blend_shape_arrays(int p_surface) const override;
@@ -268,6 +268,6 @@ VARIANT_ENUM_CAST(Mesh::ArrayType);
VARIANT_ENUM_CAST(Mesh::ArrayFormat);
VARIANT_ENUM_CAST(Mesh::ArrayCustomFormat);
VARIANT_ENUM_CAST(Mesh::PrimitiveType);
-VARIANT_ENUM_CAST(ArrayMesh::BlendShapeMode);
+VARIANT_ENUM_CAST(Mesh::BlendShapeMode);
#endif
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index 7899627048..50308d641a 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -33,6 +33,9 @@
#define _VERTEX_SNAP 0.0001
#define EQ_VERTEX_DIST 0.00001
+SurfaceTool::OptimizeVertexCacheFunc SurfaceTool::optimize_vertex_cache_func = nullptr;
+SurfaceTool::SimplifyFunc SurfaceTool::simplify_func = nullptr;
+
bool SurfaceTool::Vertex::operator==(const Vertex &p_vertex) const {
if (vertex != p_vertex.vertex) {
return false;
@@ -80,6 +83,10 @@ bool SurfaceTool::Vertex::operator==(const Vertex &p_vertex) const {
}
}
+ if (smooth_group != p_vertex.smooth_group) {
+ return false;
+ }
+
return true;
}
@@ -94,6 +101,7 @@ uint32_t SurfaceTool::VertexHasher::hash(const Vertex &p_vtx) {
h = hash_djb2_buffer((const uint8_t *)p_vtx.bones.ptr(), p_vtx.bones.size() * sizeof(int), h);
h = hash_djb2_buffer((const uint8_t *)p_vtx.weights.ptr(), p_vtx.weights.size() * sizeof(float), h);
h = hash_djb2_buffer((const uint8_t *)&p_vtx.custom[0], sizeof(Color) * RS::ARRAY_CUSTOM_COUNT, h);
+ h = hash_djb2_one_32(p_vtx.smooth_group, h);
return h;
}
@@ -118,6 +126,8 @@ void SurfaceTool::add_vertex(const Vector3 &p_vertex) {
vtx.bones = last_bones;
vtx.tangent = last_tangent.normal;
vtx.binormal = last_normal.cross(last_tangent.normal).normalized() * last_tangent.d;
+ vtx.smooth_group = last_smooth_group;
+
for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) {
vtx.custom[i] = last_custom[i];
}
@@ -252,13 +262,8 @@ void SurfaceTool::set_weights(const Vector<float> &p_weights) {
last_weights = p_weights;
}
-void SurfaceTool::add_smooth_group(bool p_smooth) {
- ERR_FAIL_COND(!begun);
- if (index_array.size()) {
- smooth_groups[index_array.size()] = p_smooth;
- } else {
- smooth_groups[vertex_array.size()] = p_smooth;
- }
+void SurfaceTool::set_smooth_group(uint32_t p_group) {
+ last_smooth_group = p_group;
}
void SurfaceTool::add_triangle_fan(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs, const Vector<Color> &p_colors, const Vector<Vector2> &p_uv2s, const Vector<Vector3> &p_normals, const Vector<Plane> &p_tangents) {
@@ -315,9 +320,8 @@ Array SurfaceTool::commit_to_arrays() {
array.resize(varr_len);
Vector3 *w = array.ptrw();
- int idx = 0;
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) {
- const Vertex &v = E->get();
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
switch (i) {
case Mesh::ARRAY_VERTEX: {
@@ -339,9 +343,8 @@ Array SurfaceTool::commit_to_arrays() {
array.resize(varr_len);
Vector2 *w = array.ptrw();
- int idx = 0;
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) {
- const Vertex &v = E->get();
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
switch (i) {
case Mesh::ARRAY_TEX_UV: {
@@ -360,9 +363,8 @@ Array SurfaceTool::commit_to_arrays() {
array.resize(varr_len * 4);
float *w = array.ptrw();
- int idx = 0;
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx += 4) {
- const Vertex &v = E->get();
+ 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;
@@ -381,9 +383,9 @@ Array SurfaceTool::commit_to_arrays() {
array.resize(varr_len);
Color *w = array.ptrw();
- int idx = 0;
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) {
- const Vertex &v = E->get();
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
+
w[idx] = v.color;
}
@@ -400,9 +402,9 @@ Array SurfaceTool::commit_to_arrays() {
array.resize(varr_len * 4);
uint8_t *w = array.ptrw();
- int idx = 0;
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) {
- const Vertex &v = E->get();
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
+
const Color &c = v.custom[idx];
w[idx * 4 + 0] = CLAMP(int32_t(c.r * 255.0), 0, 255);
w[idx * 4 + 1] = CLAMP(int32_t(c.g * 255.0), 0, 255);
@@ -417,9 +419,9 @@ Array SurfaceTool::commit_to_arrays() {
array.resize(varr_len * 4);
uint8_t *w = array.ptrw();
- int idx = 0;
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) {
- const Vertex &v = E->get();
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
+
const Color &c = v.custom[idx];
w[idx * 4 + 0] = uint8_t(int8_t(CLAMP(int32_t(c.r * 127.0), -128, 127)));
w[idx * 4 + 1] = uint8_t(int8_t(CLAMP(int32_t(c.g * 127.0), -128, 127)));
@@ -434,9 +436,9 @@ Array SurfaceTool::commit_to_arrays() {
array.resize(varr_len * 4);
uint16_t *w = (uint16_t *)array.ptrw();
- int idx = 0;
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) {
- const Vertex &v = E->get();
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
+
const Color &c = v.custom[idx];
w[idx * 2 + 0] = Math::make_half_float(c.r);
w[idx * 2 + 1] = Math::make_half_float(c.g);
@@ -449,9 +451,9 @@ Array SurfaceTool::commit_to_arrays() {
array.resize(varr_len * 8);
uint16_t *w = (uint16_t *)array.ptrw();
- int idx = 0;
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) {
- const Vertex &v = E->get();
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
+
const Color &c = v.custom[idx];
w[idx * 4 + 0] = Math::make_half_float(c.r);
w[idx * 4 + 1] = Math::make_half_float(c.g);
@@ -466,9 +468,9 @@ Array SurfaceTool::commit_to_arrays() {
array.resize(varr_len);
float *w = (float *)array.ptrw();
- int idx = 0;
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) {
- const Vertex &v = E->get();
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
+
const Color &c = v.custom[idx];
w[idx] = c.r;
}
@@ -480,9 +482,9 @@ Array SurfaceTool::commit_to_arrays() {
array.resize(varr_len * 2);
float *w = (float *)array.ptrw();
- int idx = 0;
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) {
- const Vertex &v = E->get();
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
+
const Color &c = v.custom[idx];
w[idx * 2 + 0] = c.r;
w[idx * 2 + 1] = c.g;
@@ -495,9 +497,9 @@ Array SurfaceTool::commit_to_arrays() {
array.resize(varr_len * 3);
float *w = (float *)array.ptrw();
- int idx = 0;
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) {
- const Vertex &v = E->get();
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
+
const Color &c = v.custom[idx];
w[idx * 3 + 0] = c.r;
w[idx * 3 + 1] = c.g;
@@ -511,9 +513,9 @@ Array SurfaceTool::commit_to_arrays() {
array.resize(varr_len * 4);
float *w = (float *)array.ptrw();
- int idx = 0;
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) {
- const Vertex &v = E->get();
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
+
const Color &c = v.custom[idx];
w[idx * 4 + 0] = c.r;
w[idx * 4 + 1] = c.g;
@@ -533,14 +535,13 @@ Array SurfaceTool::commit_to_arrays() {
array.resize(varr_len * count);
int *w = array.ptrw();
- int idx = 0;
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx += count) {
- const Vertex &v = E->get();
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
ERR_CONTINUE(v.bones.size() != count);
for (int j = 0; j < count; j++) {
- w[idx + j] = v.bones[j];
+ w[idx * count + j] = v.bones[j];
}
}
@@ -554,13 +555,13 @@ Array SurfaceTool::commit_to_arrays() {
array.resize(varr_len * count);
float *w = array.ptrw();
- int idx = 0;
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx += count) {
- const Vertex &v = E->get();
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
+
ERR_CONTINUE(v.weights.size() != count);
for (int j = 0; j < count; j++) {
- w[idx + j] = v.weights[j];
+ w[idx * count + j] = v.weights[j];
}
}
@@ -574,9 +575,8 @@ Array SurfaceTool::commit_to_arrays() {
array.resize(index_array.size());
int *w = array.ptrw();
- int idx = 0;
- for (List<int>::Element *E = index_array.front(); E; E = E->next(), idx++) {
- w[idx] = E->get();
+ for (uint32_t idx = 0; idx < index_array.size(); idx++) {
+ w[idx] = index_array[idx];
}
a[i] = array;
@@ -623,15 +623,16 @@ void SurfaceTool::index() {
}
HashMap<Vertex, int, VertexHasher> indices;
- List<Vertex> new_vertices;
+ LocalVector<Vertex> old_vertex_array = vertex_array;
+ vertex_array.clear();
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next()) {
- int *idxptr = indices.getptr(E->get());
+ for (uint32_t i = 0; i < old_vertex_array.size(); i++) {
+ int *idxptr = indices.getptr(old_vertex_array[i]);
int idx;
if (!idxptr) {
idx = indices.size();
- new_vertices.push_back(E->get());
- indices[E->get()] = idx;
+ vertex_array.push_back(old_vertex_array[i]);
+ indices[old_vertex_array[i]] = idx;
} else {
idx = *idxptr;
}
@@ -639,9 +640,6 @@ void SurfaceTool::index() {
index_array.push_back(idx);
}
- vertex_array.clear();
- vertex_array = new_vertices;
-
format |= Mesh::ARRAY_FORMAT_INDEX;
}
@@ -649,29 +647,26 @@ void SurfaceTool::deindex() {
if (index_array.size() == 0) {
return; //nothing to deindex
}
- Vector<Vertex> varr;
- varr.resize(vertex_array.size());
- int idx = 0;
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next()) {
- varr.write[idx++] = E->get();
- }
+
+ LocalVector<Vertex> old_vertex_array = vertex_array;
vertex_array.clear();
- for (List<int>::Element *E = index_array.front(); E; E = E->next()) {
- ERR_FAIL_INDEX(E->get(), varr.size());
- vertex_array.push_back(varr[E->get()]);
+ for (uint32_t i = 0; i < index_array.size(); i++) {
+ uint32_t index = index_array[i];
+ ERR_FAIL_COND(index >= old_vertex_array.size());
+ vertex_array.push_back(old_vertex_array[index]);
}
format &= ~Mesh::ARRAY_FORMAT_INDEX;
index_array.clear();
}
-void SurfaceTool::_create_list(const Ref<Mesh> &p_existing, int p_surface, List<Vertex> *r_vertex, List<int> *r_index, uint32_t &lformat) {
+void SurfaceTool::_create_list(const Ref<Mesh> &p_existing, int p_surface, LocalVector<Vertex> *r_vertex, LocalVector<int> *r_index, uint32_t &lformat) {
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);
}
-Vector<SurfaceTool::Vertex> SurfaceTool::create_vertex_array_from_triangle_arrays(const Array &p_arrays, uint32_t *r_format) {
- Vector<SurfaceTool::Vertex> ret;
+void SurfaceTool::create_vertex_array_from_triangle_arrays(const Array &p_arrays, LocalVector<SurfaceTool::Vertex> &ret, uint32_t *r_format) {
+ ret.clear();
Vector<Vector3> varr = p_arrays[RS::ARRAY_VERTEX];
Vector<Vector3> narr = p_arrays[RS::ARRAY_NORMAL];
@@ -688,7 +683,7 @@ Vector<SurfaceTool::Vertex> SurfaceTool::create_vertex_array_from_triangle_array
if (r_format) {
*r_format = 0;
}
- return ret;
+ return;
}
int lformat = 0;
@@ -799,19 +794,14 @@ Vector<SurfaceTool::Vertex> SurfaceTool::create_vertex_array_from_triangle_array
if (r_format) {
*r_format = lformat;
}
-
- return ret;
}
-void SurfaceTool::_create_list_from_arrays(Array arr, List<Vertex> *r_vertex, List<int> *r_index, uint32_t &lformat) {
- Vector<Vertex> arrays = create_vertex_array_from_triangle_arrays(arr, &lformat);
- ERR_FAIL_COND(arrays.size() == 0);
-
- for (int i = 0; i < arrays.size(); i++) {
- r_vertex->push_back(arrays[i]);
- }
+void SurfaceTool::_create_list_from_arrays(Array arr, LocalVector<Vertex> *r_vertex, LocalVector<int> *r_index, uint32_t &lformat) {
+ create_vertex_array_from_triangle_arrays(arr, *r_vertex, &lformat);
+ ERR_FAIL_COND(r_vertex->size() == 0);
//indices
+ r_index->clear();
Vector<int> idx = arr[RS::ARRAY_INDEX];
int is = idx.size();
@@ -864,14 +854,14 @@ void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const
}
uint32_t nformat;
- List<Vertex> nvertices;
- List<int> nindices;
+ LocalVector<Vertex> nvertices;
+ LocalVector<int> nindices;
_create_list(p_existing, p_surface, &nvertices, &nindices, nformat);
format |= nformat;
int vfrom = vertex_array.size();
- for (List<Vertex>::Element *E = nvertices.front(); E; E = E->next()) {
- Vertex v = E->get();
+ for (uint32_t vi = 0; vi < nvertices.size(); vi++) {
+ Vertex v = nvertices[vi];
v.vertex = p_xform.xform(v.vertex);
if (nformat & RS::ARRAY_FORMAT_NORMAL) {
v.normal = p_xform.basis.xform(v.normal);
@@ -884,8 +874,8 @@ void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const
vertex_array.push_back(v);
}
- for (List<int>::Element *E = nindices.front(); E; E = E->next()) {
- int dst_index = E->get() + vfrom;
+ for (uint32_t i = 0; i < nindices.size(); i++) {
+ int dst_index = nindices[i] + vfrom;
index_array.push_back(dst_index);
}
if (index_array.size() % 3) {
@@ -896,18 +886,18 @@ void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const
//mikktspace callbacks
namespace {
struct TangentGenerationContextUserData {
- Vector<List<SurfaceTool::Vertex>::Element *> vertices;
- Vector<List<int>::Element *> indices;
+ LocalVector<SurfaceTool::Vertex> *vertices;
+ LocalVector<int> *indices;
};
} // namespace
int SurfaceTool::mikktGetNumFaces(const SMikkTSpaceContext *pContext) {
TangentGenerationContextUserData &triangle_data = *reinterpret_cast<TangentGenerationContextUserData *>(pContext->m_pUserData);
- if (triangle_data.indices.size() > 0) {
- return triangle_data.indices.size() / 3;
+ if (triangle_data.indices->size() > 0) {
+ return triangle_data.indices->size() / 3;
} else {
- return triangle_data.vertices.size() / 3;
+ return triangle_data.vertices->size() / 3;
}
}
@@ -918,13 +908,13 @@ int SurfaceTool::mikktGetNumVerticesOfFace(const SMikkTSpaceContext *pContext, c
void SurfaceTool::mikktGetPosition(const SMikkTSpaceContext *pContext, float fvPosOut[], const int iFace, const int iVert) {
TangentGenerationContextUserData &triangle_data = *reinterpret_cast<TangentGenerationContextUserData *>(pContext->m_pUserData);
Vector3 v;
- if (triangle_data.indices.size() > 0) {
- int index = triangle_data.indices[iFace * 3 + iVert]->get();
- if (index < triangle_data.vertices.size()) {
- v = triangle_data.vertices[index]->get().vertex;
+ if (triangle_data.indices->size() > 0) {
+ uint32_t index = triangle_data.indices->operator[](iFace * 3 + iVert);
+ if (index < triangle_data.vertices->size()) {
+ v = triangle_data.vertices->operator[](index).vertex;
}
} else {
- v = triangle_data.vertices[iFace * 3 + iVert]->get().vertex;
+ v = triangle_data.vertices->operator[](iFace * 3 + iVert).vertex;
}
fvPosOut[0] = v.x;
@@ -935,13 +925,13 @@ void SurfaceTool::mikktGetPosition(const SMikkTSpaceContext *pContext, float fvP
void SurfaceTool::mikktGetNormal(const SMikkTSpaceContext *pContext, float fvNormOut[], const int iFace, const int iVert) {
TangentGenerationContextUserData &triangle_data = *reinterpret_cast<TangentGenerationContextUserData *>(pContext->m_pUserData);
Vector3 v;
- if (triangle_data.indices.size() > 0) {
- int index = triangle_data.indices[iFace * 3 + iVert]->get();
- if (index < triangle_data.vertices.size()) {
- v = triangle_data.vertices[index]->get().normal;
+ if (triangle_data.indices->size() > 0) {
+ uint32_t index = triangle_data.indices->operator[](iFace * 3 + iVert);
+ if (index < triangle_data.vertices->size()) {
+ v = triangle_data.vertices->operator[](index).normal;
}
} else {
- v = triangle_data.vertices[iFace * 3 + iVert]->get().normal;
+ v = triangle_data.vertices->operator[](iFace * 3 + iVert).normal;
}
fvNormOut[0] = v.x;
@@ -952,13 +942,13 @@ void SurfaceTool::mikktGetNormal(const SMikkTSpaceContext *pContext, float fvNor
void SurfaceTool::mikktGetTexCoord(const SMikkTSpaceContext *pContext, float fvTexcOut[], const int iFace, const int iVert) {
TangentGenerationContextUserData &triangle_data = *reinterpret_cast<TangentGenerationContextUserData *>(pContext->m_pUserData);
Vector2 v;
- if (triangle_data.indices.size() > 0) {
- int index = triangle_data.indices[iFace * 3 + iVert]->get();
- if (index < triangle_data.vertices.size()) {
- v = triangle_data.vertices[index]->get().uv;
+ if (triangle_data.indices->size() > 0) {
+ uint32_t index = triangle_data.indices->operator[](iFace * 3 + iVert);
+ if (index < triangle_data.vertices->size()) {
+ v = triangle_data.vertices->operator[](index).uv;
}
} else {
- v = triangle_data.vertices[iFace * 3 + iVert]->get().uv;
+ v = triangle_data.vertices->operator[](iFace * 3 + iVert).uv;
}
fvTexcOut[0] = v.x;
@@ -969,13 +959,13 @@ void SurfaceTool::mikktSetTSpaceDefault(const SMikkTSpaceContext *pContext, cons
const tbool bIsOrientationPreserving, const int iFace, const int iVert) {
TangentGenerationContextUserData &triangle_data = *reinterpret_cast<TangentGenerationContextUserData *>(pContext->m_pUserData);
Vertex *vtx = nullptr;
- if (triangle_data.indices.size() > 0) {
- int index = triangle_data.indices[iFace * 3 + iVert]->get();
- if (index < triangle_data.vertices.size()) {
- vtx = &triangle_data.vertices[index]->get();
+ if (triangle_data.indices->size() > 0) {
+ uint32_t index = triangle_data.indices->operator[](iFace * 3 + iVert);
+ if (index < triangle_data.vertices->size()) {
+ vtx = &triangle_data.vertices->operator[](index);
}
} else {
- vtx = &triangle_data.vertices[iFace * 3 + iVert]->get();
+ vtx = &triangle_data.vertices->operator[](iFace * 3 + iVert);
}
if (vtx != nullptr) {
@@ -1001,18 +991,12 @@ void SurfaceTool::generate_tangents() {
msc.m_pInterface = &mkif;
TangentGenerationContextUserData triangle_data;
- triangle_data.vertices.resize(vertex_array.size());
- int idx = 0;
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next()) {
- triangle_data.vertices.write[idx++] = E;
- E->get().binormal = Vector3();
- E->get().tangent = Vector3();
- }
- triangle_data.indices.resize(index_array.size());
- idx = 0;
- for (List<int>::Element *E = index_array.front(); E; E = E->next()) {
- triangle_data.indices.write[idx++] = E;
+ triangle_data.vertices = &vertex_array;
+ for (uint32_t i = 0; i < vertex_array.size(); i++) {
+ vertex_array[i].binormal = Vector3();
+ vertex_array[i].tangent = Vector3();
}
+ triangle_data.indices = &index_array;
msc.m_pUserData = &triangle_data;
bool res = genTangSpaceDefault(&msc);
@@ -1028,66 +1012,36 @@ void SurfaceTool::generate_normals(bool p_flip) {
deindex();
- HashMap<Vertex, Vector3, VertexHasher> vertex_hash;
+ ERR_FAIL_COND((vertex_array.size() % 3) != 0);
- int count = 0;
- bool smooth = false;
- if (smooth_groups.has(0)) {
- smooth = smooth_groups[0];
- }
+ HashMap<Vertex, Vector3, VertexHasher> vertex_hash;
- List<Vertex>::Element *B = vertex_array.front();
- for (List<Vertex>::Element *E = B; E;) {
- List<Vertex>::Element *v[3];
- v[0] = E;
- v[1] = v[0]->next();
- ERR_FAIL_COND(!v[1]);
- v[2] = v[1]->next();
- ERR_FAIL_COND(!v[2]);
- E = v[2]->next();
+ for (uint32_t vi = 0; vi < vertex_array.size(); vi += 3) {
+ Vertex *v = &vertex_array[vi];
Vector3 normal;
if (!p_flip) {
- normal = Plane(v[0]->get().vertex, v[1]->get().vertex, v[2]->get().vertex).normal;
+ normal = Plane(v[0].vertex, v[1].vertex, v[2].vertex).normal;
} else {
- normal = Plane(v[2]->get().vertex, v[1]->get().vertex, v[0]->get().vertex).normal;
+ normal = Plane(v[2].vertex, v[1].vertex, v[0].vertex).normal;
}
- if (smooth) {
- for (int i = 0; i < 3; i++) {
- Vector3 *lv = vertex_hash.getptr(v[i]->get());
- if (!lv) {
- vertex_hash.set(v[i]->get(), normal);
- } else {
- (*lv) += normal;
- }
- }
- } else {
- for (int i = 0; i < 3; i++) {
- v[i]->get().normal = normal;
- }
- }
- count += 3;
-
- if (smooth_groups.has(count) || !E) {
- if (vertex_hash.size()) {
- while (B != E) {
- Vector3 *lv = vertex_hash.getptr(B->get());
- if (lv) {
- B->get().normal = lv->normalized();
- }
-
- B = B->next();
- }
-
+ for (int i = 0; i < 3; i++) {
+ Vector3 *lv = vertex_hash.getptr(v[i]);
+ if (!lv) {
+ vertex_hash.set(v[i], normal);
} else {
- B = E;
+ (*lv) += normal;
}
+ }
+ }
- vertex_hash.clear();
- if (E) {
- smooth = smooth_groups[count];
- }
+ for (uint32_t vi = 0; vi < vertex_array.size(); vi++) {
+ Vector3 *lv = vertex_hash.getptr(vertex_array[vi]);
+ if (!lv) {
+ vertex_array[vi].normal = Vector3();
+ } else {
+ vertex_array[vi].normal = lv->normalized();
}
}
@@ -1095,7 +1049,6 @@ void SurfaceTool::generate_normals(bool p_flip) {
if (was_indexed) {
index();
- smooth_groups.clear();
}
}
@@ -1111,8 +1064,8 @@ void SurfaceTool::clear() {
last_weights.clear();
index_array.clear();
vertex_array.clear();
- smooth_groups.clear();
material.unref();
+ last_smooth_group = 0;
for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) {
last_custom_format[i] = CUSTOM_MAX;
}
@@ -1136,6 +1089,52 @@ SurfaceTool::CustomFormat SurfaceTool::get_custom_format(int p_index) const {
ERR_FAIL_INDEX_V(p_index, RS::ARRAY_CUSTOM_COUNT, CUSTOM_MAX);
return last_custom_format[p_index];
}
+void SurfaceTool::optimize_indices_for_cache() {
+ ERR_FAIL_COND(optimize_vertex_cache_func == nullptr);
+ ERR_FAIL_COND(index_array.size() == 0);
+
+ LocalVector old_index_array = index_array;
+ zeromem(index_array.ptr(), 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());
+}
+
+float SurfaceTool::get_max_axis_length() const {
+ ERR_FAIL_COND_V(vertex_array.size() == 0, 0);
+
+ AABB aabb;
+ for (uint32_t i = 0; i < vertex_array.size(); i++) {
+ if (i == 0) {
+ aabb.position = vertex_array[i].vertex;
+ } else {
+ aabb.expand_to(vertex_array[i].vertex);
+ }
+ }
+
+ return aabb.get_longest_axis_size();
+}
+Vector<int> SurfaceTool::generate_lod(float p_threshold, int p_target_index_count) {
+ Vector<int> lod;
+
+ ERR_FAIL_COND_V(simplify_func == nullptr, lod);
+ ERR_FAIL_COND_V(vertex_array.size() == 0, lod);
+ ERR_FAIL_COND_V(index_array.size() == 0, lod);
+
+ lod.resize(index_array.size());
+ LocalVector<float> vertices; //uses floats
+ vertices.resize(vertex_array.size() * 3);
+ for (uint32_t i = 0; i < vertex_array.size(); i++) {
+ vertices[i * 3 + 0] = vertex_array[i].vertex.x;
+ vertices[i * 3 + 1] = vertex_array[i].vertex.y;
+ vertices[i * 3 + 2] = vertex_array[i].vertex.z;
+ }
+
+ float error;
+ uint32_t index_count = simplify_func((unsigned int *)lod.ptrw(), (unsigned int *)index_array.ptr(), index_array.size(), vertices.ptr(), vertex_array.size(), sizeof(float) * 3, p_target_index_count, p_threshold, &error);
+ ERR_FAIL_COND_V(index_count == 0, lod);
+ lod.resize(index_count);
+
+ return lod;
+}
void SurfaceTool::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_skin_weight_count", "count"), &SurfaceTool::set_skin_weight_count);
@@ -1155,7 +1154,7 @@ void SurfaceTool::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bones", "bones"), &SurfaceTool::set_bones);
ClassDB::bind_method(D_METHOD("set_weights", "weights"), &SurfaceTool::set_weights);
ClassDB::bind_method(D_METHOD("set_custom", "index", "custom"), &SurfaceTool::set_custom);
- ClassDB::bind_method(D_METHOD("add_smooth_group", "smooth"), &SurfaceTool::add_smooth_group);
+ ClassDB::bind_method(D_METHOD("set_smooth_group", "index"), &SurfaceTool::set_smooth_group);
ClassDB::bind_method(D_METHOD("add_triangle_fan", "vertices", "uvs", "colors", "uv2s", "normals", "tangents"), &SurfaceTool::add_triangle_fan, DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Color>()), DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Vector3>()), DEFVAL(Vector<Plane>()));
@@ -1166,6 +1165,11 @@ void SurfaceTool::_bind_methods() {
ClassDB::bind_method(D_METHOD("generate_normals", "flip"), &SurfaceTool::generate_normals, DEFVAL(false));
ClassDB::bind_method(D_METHOD("generate_tangents"), &SurfaceTool::generate_tangents);
+ ClassDB::bind_method(D_METHOD("optimize_indices_for_cache"), &SurfaceTool::optimize_indices_for_cache);
+
+ ClassDB::bind_method(D_METHOD("get_max_axis_length"), &SurfaceTool::get_max_axis_length);
+ ClassDB::bind_method(D_METHOD("generate_lod", "nd_threshold", "target_index_count"), &SurfaceTool::generate_lod, DEFVAL(3));
+
ClassDB::bind_method(D_METHOD("set_material", "material"), &SurfaceTool::set_material);
ClassDB::bind_method(D_METHOD("clear"), &SurfaceTool::clear);
diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h
index 4a5c7d990c..0e60bfe389 100644
--- a/scene/resources/surface_tool.h
+++ b/scene/resources/surface_tool.h
@@ -31,8 +31,8 @@
#ifndef SURFACE_TOOL_H
#define SURFACE_TOOL_H
+#include "core/templates/local_vector.h"
#include "scene/resources/mesh.h"
-
#include "thirdparty/misc/mikktspace.h"
class SurfaceTool : public Reference {
@@ -50,6 +50,7 @@ public:
Vector<int> bones;
Vector<float> weights;
Color custom[RS::ARRAY_CUSTOM_COUNT];
+ uint32_t smooth_group = 0;
bool operator==(const Vertex &p_vertex) const;
@@ -73,6 +74,11 @@ public:
SKIN_8_WEIGHTS
};
+ typedef void (*OptimizeVertexCacheFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, size_t vertex_count);
+ 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;
+
private:
struct VertexHasher {
static _FORCE_INLINE_ uint32_t hash(const Vertex &p_vtx);
@@ -92,9 +98,8 @@ private:
uint32_t format;
Ref<Material> material;
//arrays
- List<Vertex> vertex_array;
- List<int> index_array;
- Map<int, bool> smooth_groups;
+ LocalVector<Vertex> vertex_array;
+ LocalVector<int> index_array;
//memory
Color last_color;
@@ -104,6 +109,7 @@ private:
Vector<int> last_bones;
Vector<float> last_weights;
Plane last_tangent;
+ uint32_t last_smooth_group = 0;
SkinWeightCount skin_weights;
@@ -111,8 +117,8 @@ private:
CustomFormat last_custom_format[RS::ARRAY_CUSTOM_COUNT];
- void _create_list_from_arrays(Array arr, List<Vertex> *r_vertex, List<int> *r_index, uint32_t &lformat);
- void _create_list(const Ref<Mesh> &p_existing, int p_surface, List<Vertex> *r_vertex, List<int> *r_index, uint32_t &lformat);
+ void _create_list_from_arrays(Array arr, LocalVector<Vertex> *r_vertex, LocalVector<int> *r_index, uint32_t &lformat);
+ void _create_list(const Ref<Mesh> &p_existing, int p_surface, LocalVector<Vertex> *r_vertex, LocalVector<int> *r_index, uint32_t &lformat);
//mikktspace callbacks
static int mikktGetNumFaces(const SMikkTSpaceContext *pContext);
@@ -143,10 +149,10 @@ public:
void set_custom(int p_index, const Color &p_custom);
void set_bones(const Vector<int> &p_bones);
void set_weights(const Vector<float> &p_weights);
+ void set_smooth_group(uint32_t p_group);
void add_vertex(const Vector3 &p_vertex);
- void add_smooth_group(bool p_smooth);
void add_triangle_fan(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs = Vector<Vector2>(), const Vector<Color> &p_colors = Vector<Color>(), const Vector<Vector2> &p_uv2s = Vector<Vector2>(), const Vector<Vector3> &p_normals = Vector<Vector3>(), const Vector<Plane> &p_tangents = Vector<Plane>());
void add_index(int p_index);
@@ -156,14 +162,18 @@ public:
void generate_normals(bool p_flip = false);
void generate_tangents();
+ void optimize_indices_for_cache();
+ float get_max_axis_length() const;
+ Vector<int> generate_lod(float p_threshold, int p_target_index_count = 3);
+
void set_material(const Ref<Material> &p_material);
void clear();
- List<Vertex> &get_vertex_array() { return vertex_array; }
+ LocalVector<Vertex> &get_vertex_array() { return vertex_array; }
void create_from_triangle_arrays(const Array &p_arrays);
- static Vector<Vertex> create_vertex_array_from_triangle_arrays(const Array &p_arrays, uint32_t *r_format = nullptr);
+ static void create_vertex_array_from_triangle_arrays(const Array &p_arrays, LocalVector<Vertex> &ret, uint32_t *r_format = nullptr);
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);
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 1507537cd0..706b18d2b5 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -1253,7 +1253,7 @@ bool AtlasTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect,
Vector2 scale = p_rect.size / src.size;
src.position += (rc.position - margin.position);
- Rect2 src_c = rc.clip(src);
+ Rect2 src_c = rc.intersection(src);
if (src_c.size == Size2()) {
return false;
}
@@ -1575,7 +1575,7 @@ void LargeTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, cons
if (!p_src_rect.intersects(rect)) {
continue;
}
- Rect2 local = p_src_rect.clip(rect);
+ 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;
diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp
index 6a752d32e7..c8bfcdfab4 100644
--- a/scene/resources/theme.cpp
+++ b/scene/resources/theme.cpp
@@ -51,6 +51,21 @@ Vector<String> Theme::_get_icon_list(const String &p_node_type) const {
return ilret;
}
+Vector<String> Theme::_get_icon_type_list() const {
+ Vector<String> ilret;
+ List<StringName> il;
+
+ get_icon_type_list(&il);
+ ilret.resize(il.size());
+
+ int i = 0;
+ String *w = ilret.ptrw();
+ for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
+ w[i] = E->get();
+ }
+ return ilret;
+}
+
Vector<String> Theme::_get_stylebox_list(const String &p_node_type) const {
Vector<String> ilret;
List<StringName> il;
@@ -66,11 +81,11 @@ Vector<String> Theme::_get_stylebox_list(const String &p_node_type) const {
return ilret;
}
-Vector<String> Theme::_get_stylebox_types() const {
+Vector<String> Theme::_get_stylebox_type_list() const {
Vector<String> ilret;
List<StringName> il;
- get_stylebox_types(&il);
+ get_stylebox_type_list(&il);
ilret.resize(il.size());
int i = 0;
@@ -96,6 +111,21 @@ Vector<String> Theme::_get_font_list(const String &p_node_type) const {
return ilret;
}
+Vector<String> Theme::_get_font_type_list() const {
+ Vector<String> ilret;
+ List<StringName> il;
+
+ get_font_type_list(&il);
+ ilret.resize(il.size());
+
+ int i = 0;
+ String *w = ilret.ptrw();
+ for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
+ w[i] = E->get();
+ }
+ return ilret;
+}
+
Vector<String> Theme::_get_font_size_list(const String &p_node_type) const {
Vector<String> ilret;
List<StringName> il;
@@ -126,6 +156,21 @@ Vector<String> Theme::_get_color_list(const String &p_node_type) const {
return ilret;
}
+Vector<String> Theme::_get_color_type_list() const {
+ Vector<String> ilret;
+ List<StringName> il;
+
+ get_color_type_list(&il);
+ ilret.resize(il.size());
+
+ int i = 0;
+ String *w = ilret.ptrw();
+ for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
+ w[i] = E->get();
+ }
+ return ilret;
+}
+
Vector<String> Theme::_get_constant_list(const String &p_node_type) const {
Vector<String> ilret;
List<StringName> il;
@@ -141,7 +186,22 @@ Vector<String> Theme::_get_constant_list(const String &p_node_type) const {
return ilret;
}
-Vector<String> Theme::_get_type_list(const String &p_node_type) const {
+Vector<String> Theme::_get_constant_type_list() const {
+ Vector<String> ilret;
+ List<StringName> il;
+
+ get_constant_type_list(&il);
+ ilret.resize(il.size());
+
+ int i = 0;
+ String *w = ilret.ptrw();
+ for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
+ w[i] = E->get();
+ }
+ return ilret;
+}
+
+Vector<String> Theme::_get_type_list() const {
Vector<String> ilret;
List<StringName> il;
@@ -421,6 +481,15 @@ void Theme::get_icon_list(StringName p_node_type, List<StringName> *p_list) cons
}
}
+void Theme::get_icon_type_list(List<StringName> *p_list) const {
+ ERR_FAIL_NULL(p_list);
+
+ const StringName *key = nullptr;
+ while ((key = icon_map.next(key))) {
+ p_list->push_back(*key);
+ }
+}
+
void Theme::set_stylebox(const StringName &p_name, const StringName &p_node_type, const Ref<StyleBox> &p_style) {
//ERR_FAIL_COND(p_style.is_null());
@@ -482,7 +551,7 @@ void Theme::get_stylebox_list(StringName p_node_type, List<StringName> *p_list)
}
}
-void Theme::get_stylebox_types(List<StringName> *p_list) const {
+void Theme::get_stylebox_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
const StringName *key = nullptr;
@@ -553,6 +622,15 @@ void Theme::get_font_list(StringName p_node_type, List<StringName> *p_list) cons
}
}
+void Theme::get_font_type_list(List<StringName> *p_list) const {
+ ERR_FAIL_NULL(p_list);
+
+ const StringName *key = nullptr;
+ while ((key = font_map.next(key))) {
+ p_list->push_back(*key);
+ }
+}
+
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);
@@ -647,6 +725,15 @@ void Theme::get_color_list(StringName p_node_type, List<StringName> *p_list) con
}
}
+void Theme::get_color_type_list(List<StringName> *p_list) const {
+ ERR_FAIL_NULL(p_list);
+
+ const StringName *key = nullptr;
+ while ((key = color_map.next(key))) {
+ p_list->push_back(*key);
+ }
+}
+
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;
@@ -692,6 +779,15 @@ void Theme::get_constant_list(StringName p_node_type, List<StringName> *p_list)
}
}
+void Theme::get_constant_type_list(List<StringName> *p_list) const {
+ ERR_FAIL_NULL(p_list);
+
+ const StringName *key = nullptr;
+ while ((key = constant_map.next(key))) {
+ p_list->push_back(*key);
+ }
+}
+
void Theme::clear() {
//these need disconnecting
{
@@ -840,19 +936,21 @@ void Theme::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_icon", "name", "node_type"), &Theme::has_icon);
ClassDB::bind_method(D_METHOD("clear_icon", "name", "node_type"), &Theme::clear_icon);
ClassDB::bind_method(D_METHOD("get_icon_list", "node_type"), &Theme::_get_icon_list);
+ ClassDB::bind_method(D_METHOD("get_icon_type_list"), &Theme::_get_icon_type_list);
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("clear_stylebox", "name", "node_type"), &Theme::clear_stylebox);
ClassDB::bind_method(D_METHOD("get_stylebox_list", "node_type"), &Theme::_get_stylebox_list);
- ClassDB::bind_method(D_METHOD("get_stylebox_types"), &Theme::_get_stylebox_types);
+ 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("clear_font", "name", "node_type"), &Theme::clear_font);
ClassDB::bind_method(D_METHOD("get_font_list", "node_type"), &Theme::_get_font_list);
+ ClassDB::bind_method(D_METHOD("get_font_type_list"), &Theme::_get_font_type_list);
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);
@@ -865,12 +963,14 @@ void Theme::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_color", "name", "node_type"), &Theme::has_color);
ClassDB::bind_method(D_METHOD("clear_color", "name", "node_type"), &Theme::clear_color);
ClassDB::bind_method(D_METHOD("get_color_list", "node_type"), &Theme::_get_color_list);
+ ClassDB::bind_method(D_METHOD("get_color_type_list"), &Theme::_get_color_type_list);
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("clear_constant", "name", "node_type"), &Theme::clear_constant);
ClassDB::bind_method(D_METHOD("get_constant_list", "node_type"), &Theme::_get_constant_list);
+ ClassDB::bind_method(D_METHOD("get_constant_type_list"), &Theme::_get_constant_type_list);
ClassDB::bind_method(D_METHOD("clear"), &Theme::clear);
@@ -880,7 +980,7 @@ 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("get_type_list", "node_type"), &Theme::_get_type_list);
+ ClassDB::bind_method(D_METHOD("get_type_list"), &Theme::_get_type_list);
ClassDB::bind_method("copy_default_theme", &Theme::copy_default_theme);
ClassDB::bind_method(D_METHOD("copy_theme", "other"), &Theme::copy_theme);
diff --git a/scene/resources/theme.h b/scene/resources/theme.h
index 6ac47e8931..ad05e0e2f5 100644
--- a/scene/resources/theme.h
+++ b/scene/resources/theme.h
@@ -51,13 +51,17 @@ class Theme : public Resource {
HashMap<StringName, HashMap<StringName, int>> constant_map;
Vector<String> _get_icon_list(const String &p_node_type) const;
+ Vector<String> _get_icon_type_list() const;
Vector<String> _get_stylebox_list(const String &p_node_type) const;
- Vector<String> _get_stylebox_types() const;
+ Vector<String> _get_stylebox_type_list() const;
Vector<String> _get_font_list(const String &p_node_type) const;
+ Vector<String> _get_font_type_list() const;
Vector<String> _get_font_size_list(const String &p_node_type) const;
Vector<String> _get_color_list(const String &p_node_type) const;
+ Vector<String> _get_color_type_list() const;
Vector<String> _get_constant_list(const String &p_node_type) const;
- Vector<String> _get_type_list(const String &p_node_type) const;
+ Vector<String> _get_constant_type_list() const;
+ Vector<String> _get_type_list() const;
protected:
bool _set(const StringName &p_name, const Variant &p_value);
@@ -99,19 +103,21 @@ public:
bool has_icon(const StringName &p_name, const StringName &p_node_type) const;
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 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 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 get_stylebox_types(List<StringName> *p_list) const;
+ 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 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 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;
@@ -124,12 +130,14 @@ public:
bool has_color(const StringName &p_name, const StringName &p_node_type) const;
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 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 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 get_constant_type_list(List<StringName> *p_list) const;
void get_type_list(List<StringName> *p_list) const;
diff --git a/servers/camera/SCsub b/servers/camera/SCsub
index c949f3bb25..86681f9c74 100644
--- a/servers/camera/SCsub
+++ b/servers/camera/SCsub
@@ -3,5 +3,3 @@
Import("env")
env.add_source_files(env.servers_sources, "*.cpp")
-
-Export("env")
diff --git a/servers/physics_2d/area_pair_2d_sw.cpp b/servers/physics_2d/area_pair_2d_sw.cpp
index d7bceb9f02..b1589b203f 100644
--- a/servers/physics_2d/area_pair_2d_sw.cpp
+++ b/servers/physics_2d/area_pair_2d_sw.cpp
@@ -89,7 +89,7 @@ AreaPair2DSW::~AreaPair2DSW() {
area->remove_body_from_query(body, body_shape, area_shape);
}
}
- body->remove_constraint(this);
+ body->remove_constraint(this, 0);
area->remove_constraint(this);
}
diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp
index 75c9a95739..a3eaff9c7f 100644
--- a/servers/physics_2d/body_2d_sw.cpp
+++ b/servers/physics_2d/body_2d_sw.cpp
@@ -562,13 +562,13 @@ void Body2DSW::integrate_velocities(real_t p_step) {
}
void Body2DSW::wakeup_neighbours() {
- for (Map<Constraint2DSW *, int>::Element *E = constraint_map.front(); E; E = E->next()) {
- const Constraint2DSW *c = E->key();
+ for (List<Pair<Constraint2DSW *, int>>::Element *E = constraint_list.front(); E; E = E->next()) {
+ const Constraint2DSW *c = E->get().first;
Body2DSW **n = c->get_body_ptr();
int bc = c->get_body_count();
for (int i = 0; i < bc; i++) {
- if (i == E->get()) {
+ if (i == E->get().second) {
continue;
}
Body2DSW *b = n[i];
diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/body_2d_sw.h
index bbc22a67df..19e4b92a99 100644
--- a/servers/physics_2d/body_2d_sw.h
+++ b/servers/physics_2d/body_2d_sw.h
@@ -33,6 +33,8 @@
#include "area_2d_sw.h"
#include "collision_object_2d_sw.h"
+#include "core/templates/list.h"
+#include "core/templates/pair.h"
#include "core/templates/vset.h"
class Constraint2DSW;
@@ -83,7 +85,7 @@ class Body2DSW : public CollisionObject2DSW {
virtual void _shapes_changed();
Transform2D new_transform;
- Map<Constraint2DSW *, int> constraint_map;
+ List<Pair<Constraint2DSW *, int>> constraint_list;
struct AreaCMP {
Area2DSW *area;
@@ -179,10 +181,10 @@ public:
_FORCE_INLINE_ Body2DSW *get_island_list_next() const { return island_list_next; }
_FORCE_INLINE_ void set_island_list_next(Body2DSW *p_next) { island_list_next = p_next; }
- _FORCE_INLINE_ void add_constraint(Constraint2DSW *p_constraint, int p_pos) { constraint_map[p_constraint] = p_pos; }
- _FORCE_INLINE_ void remove_constraint(Constraint2DSW *p_constraint) { constraint_map.erase(p_constraint); }
- const Map<Constraint2DSW *, int> &get_constraint_map() const { return constraint_map; }
- _FORCE_INLINE_ void clear_constraint_map() { constraint_map.clear(); }
+ _FORCE_INLINE_ void add_constraint(Constraint2DSW *p_constraint, int p_pos) { constraint_list.push_back({ p_constraint, p_pos }); }
+ _FORCE_INLINE_ void remove_constraint(Constraint2DSW *p_constraint, int p_pos) { constraint_list.erase({ p_constraint, p_pos }); }
+ const List<Pair<Constraint2DSW *, int>> &get_constraint_list() const { return constraint_list; }
+ _FORCE_INLINE_ void clear_constraint_list() { constraint_list.clear(); }
_FORCE_INLINE_ void set_omit_force_integration(bool p_omit_force_integration) { omit_force_integration = p_omit_force_integration; }
_FORCE_INLINE_ bool get_omit_force_integration() const { return omit_force_integration; }
diff --git a/servers/physics_2d/body_pair_2d_sw.cpp b/servers/physics_2d/body_pair_2d_sw.cpp
index 2021aab17c..bb6629becb 100644
--- a/servers/physics_2d/body_pair_2d_sw.cpp
+++ b/servers/physics_2d/body_pair_2d_sw.cpp
@@ -514,6 +514,6 @@ BodyPair2DSW::BodyPair2DSW(Body2DSW *p_A, int p_shape_A, Body2DSW *p_B, int p_sh
}
BodyPair2DSW::~BodyPair2DSW() {
- A->remove_constraint(this);
- B->remove_constraint(this);
+ A->remove_constraint(this, 0);
+ B->remove_constraint(this, 1);
}
diff --git a/servers/physics_2d/joints_2d_sw.cpp b/servers/physics_2d/joints_2d_sw.cpp
index e7d26645e9..743f69d7d4 100644
--- a/servers/physics_2d/joints_2d_sw.cpp
+++ b/servers/physics_2d/joints_2d_sw.cpp
@@ -199,10 +199,10 @@ PinJoint2DSW::PinJoint2DSW(const Vector2 &p_pos, Body2DSW *p_body_a, Body2DSW *p
PinJoint2DSW::~PinJoint2DSW() {
if (A) {
- A->remove_constraint(this);
+ A->remove_constraint(this, 0);
}
if (B) {
- B->remove_constraint(this);
+ B->remove_constraint(this, 1);
}
}
@@ -339,8 +339,8 @@ GrooveJoint2DSW::GrooveJoint2DSW(const Vector2 &p_a_groove1, const Vector2 &p_a_
}
GrooveJoint2DSW::~GrooveJoint2DSW() {
- A->remove_constraint(this);
- B->remove_constraint(this);
+ A->remove_constraint(this, 0);
+ B->remove_constraint(this, 1);
}
//////////////////////////////////////////////
@@ -436,6 +436,6 @@ DampedSpringJoint2DSW::DampedSpringJoint2DSW(const Vector2 &p_anchor_a, const Ve
}
DampedSpringJoint2DSW::~DampedSpringJoint2DSW() {
- A->remove_constraint(this);
- B->remove_constraint(this);
+ A->remove_constraint(this, 0);
+ B->remove_constraint(this, 1);
}
diff --git a/servers/physics_2d/physics_server_2d_sw.cpp b/servers/physics_2d/physics_server_2d_sw.cpp
index 755804fe36..223fd0114a 100644
--- a/servers/physics_2d/physics_server_2d_sw.cpp
+++ b/servers/physics_2d/physics_server_2d_sw.cpp
@@ -554,7 +554,7 @@ void PhysicsServer2DSW::body_set_space(RID p_body, RID p_space) {
return; //pointless
}
- body->clear_constraint_map();
+ body->clear_constraint_list();
body->set_space(space);
};
diff --git a/servers/physics_2d/step_2d_sw.cpp b/servers/physics_2d/step_2d_sw.cpp
index c7711bcd1d..56b31a884d 100644
--- a/servers/physics_2d/step_2d_sw.cpp
+++ b/servers/physics_2d/step_2d_sw.cpp
@@ -36,8 +36,8 @@ void Step2DSW::_populate_island(Body2DSW *p_body, Body2DSW **p_island, Constrain
p_body->set_island_next(*p_island);
*p_island = p_body;
- for (Map<Constraint2DSW *, int>::Element *E = p_body->get_constraint_map().front(); E; E = E->next()) {
- Constraint2DSW *c = (Constraint2DSW *)E->key();
+ for (const List<Pair<Constraint2DSW *, int>>::Element *E = p_body->get_constraint_list().front(); E; E = E->next()) {
+ Constraint2DSW *c = (Constraint2DSW *)E->get().first;
if (c->get_island_step() == _step) {
continue; //already processed
}
@@ -46,7 +46,7 @@ void Step2DSW::_populate_island(Body2DSW *p_body, Body2DSW **p_island, Constrain
*p_constraint_island = c;
for (int i = 0; i < c->get_body_count(); i++) {
- if (i == E->get()) {
+ if (i == E->get().second) {
continue;
}
Body2DSW *b = c->get_body_ptr()[i];
diff --git a/servers/physics_3d/body_pair_3d_sw.cpp b/servers/physics_3d/body_pair_3d_sw.cpp
index 848138940e..d8f187a7f8 100644
--- a/servers/physics_3d/body_pair_3d_sw.cpp
+++ b/servers/physics_3d/body_pair_3d_sw.cpp
@@ -367,8 +367,8 @@ void BodyPair3DSW::solve(real_t p_step) {
Vector3 jb = c.normal * (c.acc_bias_impulse - jbnOld);
- A->apply_bias_impulse(c.rA + A->get_center_of_mass(), -jb, MAX_BIAS_ROTATION / p_step);
- B->apply_bias_impulse(c.rB + B->get_center_of_mass(), jb, MAX_BIAS_ROTATION / p_step);
+ 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);
crbA = A->get_biased_angular_velocity().cross(c.rA);
crbB = B->get_biased_angular_velocity().cross(c.rB);
@@ -383,8 +383,8 @@ 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(A->get_center_of_mass(), -jb_com, 0.0f);
- B->apply_bias_impulse(B->get_center_of_mass(), jb_com, 0.0f);
+ 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);
}
c.active = true;
diff --git a/servers/physics_3d/physics_server_3d_sw.h b/servers/physics_3d/physics_server_3d_sw.h
index f96a8863c3..1183bd0322 100644
--- a/servers/physics_3d/physics_server_3d_sw.h
+++ b/servers/physics_3d/physics_server_3d_sw.h
@@ -346,9 +346,6 @@ public:
virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag, bool p_enable) override;
virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag) override;
- virtual void generic_6dof_joint_set_precision(RID p_joint, int precision) override {}
- virtual int generic_6dof_joint_get_precision(RID p_joint) override { return 0; }
-
virtual JointType joint_get_type(RID p_joint) const override;
virtual void joint_set_solver_priority(RID p_joint, int p_priority) override;
diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h
index 3f7ad26257..ed3a7e87a4 100644
--- a/servers/physics_server_3d.h
+++ b/servers/physics_server_3d.h
@@ -728,9 +728,6 @@ public:
virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag, bool p_enable) = 0;
virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag) = 0;
- virtual void generic_6dof_joint_set_precision(RID p_joint, int precision) = 0;
- virtual int generic_6dof_joint_get_precision(RID p_joint) = 0;
-
/* QUERY API */
enum AreaBodyStatus {
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index a397ba4389..53deba512e 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -144,7 +144,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
if (ci->clip) {
if (p_canvas_clip != nullptr) {
- ci->final_clip_rect = p_canvas_clip->final_clip_rect.clip(global_rect);
+ ci->final_clip_rect = p_canvas_clip->final_clip_rect.intersection(global_rect);
} else {
ci->final_clip_rect = global_rect;
}
@@ -195,7 +195,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
}
if (ci->copy_back_buffer) {
- ci->copy_back_buffer->screen_rect = xform.xform(ci->copy_back_buffer->rect).clip(p_clip_rect);
+ ci->copy_back_buffer->screen_rect = xform.xform(ci->copy_back_buffer->rect).intersection(p_clip_rect);
}
if (use_canvas_group) {
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp b/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp
index 5412688e3f..93f4b7bc8e 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp
@@ -953,7 +953,7 @@ void RendererSceneRenderForward::_fill_instances(RenderList::Element **p_element
/// RENDERING ///
-void RendererSceneRenderForward::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderList::Element **p_elements, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi, RID p_render_pass_uniform_set, bool p_force_wireframe, const Vector2 &p_uv_offset) {
+void RendererSceneRenderForward::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderList::Element **p_elements, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi, RID p_render_pass_uniform_set, bool p_force_wireframe, const Vector2 &p_uv_offset, const Plane &p_lod_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold) {
RD::DrawListID draw_list = p_draw_list;
RD::FramebufferFormatID framebuffer_format = p_framebuffer_Format;
@@ -996,10 +996,13 @@ void RendererSceneRenderForward::_render_list(RenderingDevice::DrawListID p_draw
//find primitive and vertex format
RS::PrimitiveType primitive;
+ void *mesh_surface = nullptr;
switch (e->instance->base_type) {
case RS::INSTANCE_MESH: {
- primitive = storage->mesh_surface_get_primitive(e->instance->base, e->surface_index);
+ mesh_surface = storage->mesh_get_surface(e->instance->base, e->surface_index);
+
+ primitive = storage->mesh_surface_get_primitive(mesh_surface);
if (e->instance->skeleton.is_valid()) {
xforms_uniform_set = storage->skeleton_get_3d_uniform_set(e->instance->skeleton, default_shader_rd, TRANSFORMS_UNIFORM_SET);
}
@@ -1007,7 +1010,10 @@ void RendererSceneRenderForward::_render_list(RenderingDevice::DrawListID p_draw
case RS::INSTANCE_MULTIMESH: {
RID mesh = storage->multimesh_get_mesh(e->instance->base);
ERR_CONTINUE(!mesh.is_valid()); //should be a bug
- primitive = storage->mesh_surface_get_primitive(mesh, e->surface_index);
+
+ mesh_surface = storage->mesh_get_surface(e->instance->base, e->surface_index);
+
+ primitive = storage->mesh_surface_get_primitive(mesh_surface);
xforms_uniform_set = storage->multimesh_get_3d_uniform_set(e->instance->base, default_shader_rd, TRANSFORMS_UNIFORM_SET);
@@ -1018,7 +1024,10 @@ void RendererSceneRenderForward::_render_list(RenderingDevice::DrawListID p_draw
case RS::INSTANCE_PARTICLES: {
RID mesh = storage->particles_get_draw_pass_mesh(e->instance->base, e->surface_index >> 16);
ERR_CONTINUE(!mesh.is_valid()); //should be a bug
- primitive = storage->mesh_surface_get_primitive(mesh, e->surface_index & 0xFFFF);
+
+ mesh_surface = storage->mesh_get_surface(e->instance->base, e->surface_index & 0xFFFF);
+
+ primitive = storage->mesh_surface_get_primitive(mesh_surface);
xforms_uniform_set = storage->particles_get_instance_buffer_uniform_set(e->instance->base, default_shader_rd, TRANSFORMS_UNIFORM_SET);
@@ -1077,25 +1086,39 @@ void RendererSceneRenderForward::_render_list(RenderingDevice::DrawListID p_draw
RID vertex_array_rd;
RID index_array_rd;
- switch (e->instance->base_type) {
- case RS::INSTANCE_MESH: {
- storage->mesh_surface_get_arrays_and_format(e->instance->base, e->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, index_array_rd, vertex_format);
- } break;
- case RS::INSTANCE_MULTIMESH: {
- RID mesh = storage->multimesh_get_mesh(e->instance->base);
- ERR_CONTINUE(!mesh.is_valid()); //should be a bug
- storage->mesh_surface_get_arrays_and_format(mesh, e->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, index_array_rd, vertex_format);
- } break;
- case RS::INSTANCE_IMMEDIATE: {
- ERR_CONTINUE(true); //should be a bug
- } break;
- case RS::INSTANCE_PARTICLES: {
- RID mesh = storage->particles_get_draw_pass_mesh(e->instance->base, e->surface_index >> 16);
- ERR_CONTINUE(!mesh.is_valid()); //should be a bug
- storage->mesh_surface_get_arrays_and_format(mesh, e->surface_index & 0xFFFF, pipeline->get_vertex_input_mask(), vertex_array_rd, index_array_rd, vertex_format);
- } break;
- default: {
- ERR_CONTINUE(true); //should be a bug
+ if (mesh_surface) {
+ if (e->instance->mesh_instance.is_valid()) { //skeleton and blend shape
+ storage->mesh_instance_surface_get_vertex_arrays_and_format(e->instance->mesh_instance, e->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);
+ }
+
+ if (p_screen_lod_threshold > 0.0 && storage->mesh_surface_has_lod(mesh_surface)) {
+ Vector3 support_min = e->instance->transformed_aabb.get_support(-p_lod_plane.normal);
+ Vector3 support_max = e->instance->transformed_aabb.get_support(p_lod_plane.normal);
+
+ float distance_min = p_lod_plane.distance_to(support_min);
+ float distance_max = p_lod_plane.distance_to(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;
+ }
+
+ Vector3 model_scale_vec = e->instance->transform.basis.get_scale_abs();
+
+ float model_scale = MAX(model_scale_vec.x, MAX(model_scale_vec.y, model_scale_vec.z));
+
+ index_array_rd = storage->mesh_surface_get_index_array_with_lod(mesh_surface, model_scale * e->instance->lod_bias, distance * p_lod_distance_multiplier, p_screen_lod_threshold);
+
+ } else {
+ index_array_rd = storage->mesh_surface_get_index_array(mesh_surface);
}
}
@@ -1631,7 +1654,7 @@ void RendererSceneRenderForward::_setup_lightmaps(InstanceBase **p_lightmap_cull
}
}
-void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, int p_directional_light_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color) {
+void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, int p_directional_light_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color, float p_screen_lod_threshold) {
RenderBufferDataForward *render_buffer = nullptr;
if (p_render_buffer.is_valid()) {
render_buffer = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffer);
@@ -1650,6 +1673,13 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf
scene_state.ubo.reflection_multiplier = 1.0;
}
+ 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();
@@ -1852,7 +1882,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf
bool finish_depth = using_ssao || using_sdfgi || using_giprobe;
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, depth_pass_clear);
- _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(depth_framebuffer), render_list.elements, render_list.element_count, false, depth_pass_mode, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME);
+ _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(depth_framebuffer), render_list.elements, render_list.element_count, false, depth_pass_mode, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold);
RD::get_singleton()->draw_list_end();
if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
@@ -1900,7 +1930,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf
RID framebuffer = using_separate_specular ? opaque_specular_framebuffer : opaque_framebuffer;
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? (continue_depth ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CONTINUE) : RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
- _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(framebuffer), render_list.elements, render_list.element_count, false, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME);
+ _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(framebuffer), render_list.elements, render_list.element_count, false, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold);
RD::get_singleton()->draw_list_end();
if (will_continue_color && using_separate_specular) {
@@ -1988,7 +2018,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf
{
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
- _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(alpha_framebuffer), &render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false, PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME);
+ _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(alpha_framebuffer), &render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false, PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold);
RD::get_singleton()->draw_list_end();
}
@@ -1997,7 +2027,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf
}
}
-void RendererSceneRenderForward::_render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake) {
+void RendererSceneRenderForward::_render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold) {
RENDER_TIMESTAMP("Setup Rendering Shadow");
_update_render_base_uniform_set();
@@ -2008,6 +2038,10 @@ void RendererSceneRenderForward::_render_shadow(RID p_framebuffer, InstanceBase
_setup_environment(RID(), RID(), p_projection, p_transform, RID(), true, Vector2(1, 1), RID(), true, Color(), 0, p_zfar, false, p_use_pancake);
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) {
+ p_screen_lod_threshold = 0.0;
+ }
+
render_list.clear();
PassMode pass_mode = p_use_dp ? PASS_MODE_SHADOW_DP : PASS_MODE_SHADOW;
@@ -2025,7 +2059,7 @@ void RendererSceneRenderForward::_render_shadow(RID p_framebuffer, InstanceBase
{
//regular forward for now
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ);
- _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, p_use_dp_flip, pass_mode, true, rp_uniform_set);
+ _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, p_use_dp_flip, pass_mode, true, rp_uniform_set, false, Vector2(), p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold);
RD::get_singleton()->draw_list_end();
}
}
@@ -2500,7 +2534,7 @@ RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RID p_render_buff
RD::Uniform u;
u.binding = 4;
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);
+ 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);
}
@@ -2578,7 +2612,7 @@ RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RID p_render_buff
RD::Uniform u;
u.binding = 12;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(rb ? render_buffers_get_default_gi_probe_buffer() : render_buffers_get_gi_probe_buffer(p_render_buffers));
+ u.ids.push_back(rb ? render_buffers_get_gi_probe_buffer(p_render_buffers) : render_buffers_get_default_gi_probe_buffer());
uniforms.push_back(u);
}
{
@@ -2684,7 +2718,7 @@ RID RendererSceneRenderForward::_setup_sdfgi_render_pass_uniform_set(RID p_albed
uniforms.push_back(u);
}
- sdfgi_pass_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_PASS_UNIFORM_SET);
+ sdfgi_pass_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_sdfgi_rd, RENDER_PASS_UNIFORM_SET);
return sdfgi_pass_uniform_set;
}
@@ -2875,6 +2909,7 @@ RendererSceneRenderForward::RendererSceneRenderForward(RendererStorageRD *p_stor
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";
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward.h b/servers/rendering/renderer_rd/renderer_scene_render_forward.h
index 6d76d5f0eb..94284e509c 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_forward.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_forward.h
@@ -570,7 +570,7 @@ class RendererSceneRenderForward : public RendererSceneRenderRD {
void _setup_lightmaps(InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, const Transform &p_cam_transform);
void _fill_instances(RenderList::Element **p_elements, int p_element_count, bool p_for_depth, bool p_has_sdfgi = false, bool p_has_opaque_gi = false);
- void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderList::Element **p_elements, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2());
+ void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderList::Element **p_elements, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi, RID p_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);
_FORCE_INLINE_ void _add_geometry(InstanceBase *p_instance, uint32_t p_surface, RID p_material, PassMode p_pass_mode, uint32_t p_geometry_index, bool p_using_sdfgi = false);
_FORCE_INLINE_ void _add_geometry_with_material(InstanceBase *p_instance, uint32_t p_surface, MaterialData *p_material, RID p_material_rid, PassMode p_pass_mode, uint32_t p_geometry_index, bool p_using_sdfgi = false);
@@ -581,8 +581,8 @@ class RendererSceneRenderForward : public RendererSceneRenderRD {
bool low_end = false;
protected:
- virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, int p_directional_light_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color);
- virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake);
+ virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, int p_directional_light_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color, float p_lod_threshold);
+ virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_lod_threshold = 0.0);
virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region);
virtual void _render_uv2(InstanceBase **p_cull_result, int p_cull_count, 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, InstanceBase **p_cull_result, int p_cull_count, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture);
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index f880eb7d8a..4543ced8dc 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -3255,6 +3255,13 @@ void RendererSceneRenderRD::reflection_atlas_set_size(RID p_ref_atlas, int p_ref
}
}
+int RendererSceneRenderRD::reflection_atlas_get_size(RID p_ref_atlas) const {
+ ReflectionAtlas *ra = reflection_atlas_owner.getornull(p_ref_atlas);
+ ERR_FAIL_COND_V(!ra, 0);
+
+ return ra->size;
+}
+
////////////////////////
RID RendererSceneRenderRD::reflection_probe_instance_create(RID p_probe) {
ReflectionProbeInstance rpi;
@@ -7012,7 +7019,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
RD::get_singleton()->compute_list_end();
}
-void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) {
+void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold) {
Color clear_color;
if (p_render_buffers.is_valid()) {
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
@@ -7069,7 +7076,7 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &
_update_volumetric_fog(p_render_buffers, p_environment, p_cam_projection, p_cam_transform, p_shadow_atlas, directional_light_count, directional_shadows, positional_light_count, gi_probe_count);
}
- _render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, directional_light_count, p_gi_probe_cull_result, p_gi_probe_cull_count, p_lightmap_cull_result, p_lightmap_cull_count, p_environment, p_camera_effects, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass, clear_color);
+ _render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, directional_light_count, p_gi_probe_cull_result, p_gi_probe_cull_count, p_lightmap_cull_result, p_lightmap_cull_count, p_environment, p_camera_effects, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass, clear_color, p_screen_lod_threshold);
if (p_render_buffers.is_valid()) {
RENDER_TIMESTAMP("Tonemap");
@@ -7082,7 +7089,7 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &
}
}
-void RendererSceneRenderRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) {
+void RendererSceneRenderRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold) {
LightInstance *light_instance = light_instance_owner.getornull(p_light);
ERR_FAIL_COND(!light_instance);
@@ -7233,7 +7240,7 @@ void RendererSceneRenderRD::render_shadow(RID p_light, RID p_shadow_atlas, int p
if (render_cubemap) {
//rendering to cubemap
- _render_shadow(render_fb, p_cull_result, p_cull_count, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake);
+ _render_shadow(render_fb, p_cull_result, p_cull_count, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold);
if (finalize_cubemap) {
//reblit
atlas_rect.size.height /= 2;
@@ -7244,7 +7251,7 @@ void RendererSceneRenderRD::render_shadow(RID p_light, RID p_shadow_atlas, int p
} else {
//render shadow
- _render_shadow(render_fb, p_cull_result, p_cull_count, light_projection, light_transform, zfar, bias, normal_bias, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake);
+ _render_shadow(render_fb, p_cull_result, p_cull_count, light_projection, light_transform, zfar, bias, normal_bias, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold);
//copy to atlas
if (use_linear_depth) {
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
index e3dfee2da7..3afe6e3f4a 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
@@ -109,8 +109,8 @@ protected:
void _setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment);
void _setup_giprobes(RID p_render_buffers, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, uint32_t &r_gi_probes_used);
- virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, int p_directional_light_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_color) = 0;
- virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool use_dp_flip, bool p_use_pancake) = 0;
+ virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, int p_directional_light_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_color, float p_screen_lod_threshold) = 0;
+ virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0) = 0;
virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0;
virtual void _render_uv2(InstanceBase **p_cull_result, int p_cull_count, 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, InstanceBase **p_cull_result, int p_cull_count, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) = 0;
@@ -339,7 +339,7 @@ private:
Vector<Reflection> reflections;
};
- RID_Owner<ReflectionAtlas> reflection_atlas_owner;
+ mutable RID_Owner<ReflectionAtlas> reflection_atlas_owner;
/* REFLECTION PROBE INSTANCE */
@@ -1728,6 +1728,8 @@ public:
virtual RID reflection_atlas_create();
virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count);
+ virtual int reflection_atlas_get_size(RID p_ref_atlas) const;
+
_FORCE_INLINE_ RID reflection_atlas_get_texture(RID p_ref_atlas) {
ReflectionAtlas *atlas = reflection_atlas_owner.getornull(p_ref_atlas);
ERR_FAIL_COND_V(!atlas, RID());
@@ -1884,9 +1886,9 @@ 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, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_shadow_atlas, RID p_camera_effects, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
+ void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_shadow_atlas, RID p_camera_effects, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold);
- void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count);
+ void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_lod_threshold = 0.0);
void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region);
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
index 96f6d5ea32..60c0bd1603 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
@@ -318,7 +318,7 @@ Ref<Image> RendererStorageRD::_validate_texture_format(const Ref<Image> &p_image
r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
} break; //unsigned float bc6hu
- case Image::FORMAT_PVRTC2: {
+ case Image::FORMAT_PVRTC1_2: {
//this is not properly supported by MoltekVK it seems, so best to use ETC2
if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
r_format.format = RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG;
@@ -336,7 +336,7 @@ Ref<Image> RendererStorageRD::_validate_texture_format(const Ref<Image> &p_image
r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
} break; //pvrtc
- case Image::FORMAT_PVRTC2A: {
+ case Image::FORMAT_PVRTC1_2A: {
//this is not properly supported by MoltekVK it seems, so best to use ETC2
if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
r_format.format = RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG;
@@ -353,7 +353,7 @@ Ref<Image> RendererStorageRD::_validate_texture_format(const Ref<Image> &p_image
r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
} break;
- case Image::FORMAT_PVRTC4: {
+ case Image::FORMAT_PVRTC1_4: {
//this is not properly supported by MoltekVK it seems, so best to use ETC2
if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
r_format.format = RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG;
@@ -370,7 +370,7 @@ Ref<Image> RendererStorageRD::_validate_texture_format(const Ref<Image> &p_image
r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
} break;
- case Image::FORMAT_PVRTC4A: {
+ case Image::FORMAT_PVRTC1_4A: {
//this is not properly supported by MoltekVK it seems, so best to use ETC2
if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
r_format.format = RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG;
@@ -2392,13 +2392,23 @@ RID RendererStorageRD::mesh_create() {
return mesh_owner.make_rid(Mesh());
}
+void RendererStorageRD::mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) {
+ ERR_FAIL_COND(p_blend_shape_count < 0);
+
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND(!mesh);
+
+ ERR_FAIL_COND(mesh->surface_count > 0); //surfaces already exist
+
+ mesh->blend_shape_count = p_blend_shape_count;
+}
+
/// Returns stride
void RendererStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) {
Mesh *mesh = mesh_owner.getornull(p_mesh);
ERR_FAIL_COND(!mesh);
//ensure blend shape consistency
- ERR_FAIL_COND(mesh->blend_shape_count && p_surface.blend_shape_count != mesh->blend_shape_count);
ERR_FAIL_COND(mesh->blend_shape_count && p_surface.bone_aabbs.size() != mesh->bone_aabbs.size());
#ifdef DEBUG_ENABLED
@@ -2453,7 +2463,7 @@ void RendererStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_su
case RS::ARRAY_BONES: {
//uses a separate array
bool use_8 = p_surface.format & RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS;
- skin_stride += sizeof(int16_t) * (use_8 ? 8 : 4);
+ skin_stride += sizeof(int16_t) * (use_8 ? 16 : 8);
} break;
}
}
@@ -2461,6 +2471,11 @@ void RendererStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_su
int expected_size = stride * p_surface.vertex_count;
ERR_FAIL_COND_MSG(expected_size != p_surface.vertex_data.size(), "Size of vertex data provided (" + itos(p_surface.vertex_data.size()) + ") does not match expected (" + itos(expected_size) + ")");
+
+ int bs_expected_size = expected_size * mesh->blend_shape_count;
+
+ ERR_FAIL_COND_MSG(bs_expected_size != p_surface.blend_shape_data.size(), "Size of blend shape data provided (" + itos(p_surface.blend_shape_data.size()) + ") does not match expected (" + itos(bs_expected_size) + ")");
+
int expected_attrib_size = attrib_stride * p_surface.vertex_count;
ERR_FAIL_COND_MSG(expected_attrib_size != p_surface.attribute_data.size(), "Size of attribute data provided (" + itos(p_surface.attribute_data.size()) + ") does not match expected (" + itos(expected_attrib_size) + ")");
@@ -2477,15 +2492,25 @@ void RendererStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_su
s->format = p_surface.format;
s->primitive = p_surface.primitive;
- s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.vertex_data.size(), p_surface.vertex_data);
+ bool use_as_storage = (p_surface.skin_data.size() || mesh->blend_shape_count > 0);
+
+ s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.vertex_data.size(), p_surface.vertex_data, use_as_storage);
+ s->vertex_buffer_size = p_surface.vertex_data.size();
+
if (p_surface.attribute_data.size()) {
s->attribute_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.attribute_data.size(), p_surface.attribute_data);
}
if (p_surface.skin_data.size()) {
- s->skin_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.skin_data.size(), p_surface.skin_data);
+ s->skin_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.skin_data.size(), p_surface.skin_data, use_as_storage);
+ s->skin_buffer_size = p_surface.skin_data.size();
}
+
s->vertex_count = p_surface.vertex_count;
+ if (p_surface.format & RS::ARRAY_FORMAT_BONES) {
+ mesh->has_bone_weights = true;
+ }
+
if (p_surface.index_count) {
bool is_index_16 = p_surface.vertex_count <= 65536;
@@ -2507,17 +2532,45 @@ void RendererStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_su
s->aabb = p_surface.aabb;
s->bone_aabbs = p_surface.bone_aabbs; //only really useful for returning them.
-#if 0
- for (int i = 0; i < p_surface.blend_shapes.size(); i++) {
- if (p_surface.blend_shapes[i].size() != p_surface.vertex_data.size()) {
- memdelete(s);
- ERR_FAIL_COND(p_surface.blend_shapes[i].size() != p_surface.vertex_data.size());
+
+ if (mesh->blend_shape_count > 0) {
+ s->blend_shape_buffer = RD::get_singleton()->storage_buffer_create(p_surface.blend_shape_data.size(), p_surface.blend_shape_data);
+ }
+
+ if (use_as_storage) {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.binding = 0;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(s->vertex_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 1;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ if (s->skin_buffer.is_valid()) {
+ u.ids.push_back(s->skin_buffer);
+ } else {
+ u.ids.push_back(default_rd_storage_buffer);
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 2;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ if (s->blend_shape_buffer.is_valid()) {
+ u.ids.push_back(s->blend_shape_buffer);
+ } else {
+ u.ids.push_back(default_rd_storage_buffer);
+ }
+ uniforms.push_back(u);
}
- RID vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.blend_shapes[i].size(), p_surface.blend_shapes[i]);
- s->blend_shapes.push_back(vertex_buffer);
+
+ s->uniform_set = RD::get_singleton()->uniform_set_create(uniforms, skeleton_shader.version_shader[0], SkeletonShader::UNIFORM_SET_SURFACE);
}
-#endif
- mesh->blend_shape_count = p_surface.blend_shape_count;
if (mesh->surface_count == 0) {
mesh->bone_aabbs = p_surface.bone_aabbs;
@@ -2535,6 +2588,12 @@ void RendererStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_su
mesh->surfaces[mesh->surface_count] = s;
mesh->surface_count++;
+ for (List<MeshInstance *>::Element *E = mesh->instances.front(); E; E = E->next()) {
+ //update instances
+ MeshInstance *mi = E->get();
+ _mesh_instance_add_surface(mi, mesh, mesh->surface_count - 1);
+ }
+
mesh->instance_dependency.instance_notify_changed(true, true);
mesh->material_cache.clear();
@@ -2792,16 +2851,223 @@ void RendererStorageRD::mesh_clear(RID p_mesh) {
mesh->surfaces = nullptr;
mesh->surface_count = 0;
mesh->material_cache.clear();
+ //clear instance data
+ for (List<MeshInstance *>::Element *E = mesh->instances.front(); E; E = E->next()) {
+ MeshInstance *mi = E->get();
+ _mesh_instance_clear(mi);
+ }
mesh->instance_dependency.instance_notify_changed(true, true);
+ mesh->has_bone_weights = false;
}
-void RendererStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Surface *s, uint32_t p_input_mask) {
- uint32_t version = s->version_count;
- s->version_count++;
- s->versions = (Mesh::Surface::Version *)memrealloc(s->versions, sizeof(Mesh::Surface::Version) * s->version_count);
+bool RendererStorageRD::mesh_needs_instance(RID p_mesh, bool p_has_skeleton) {
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh, false);
+
+ return mesh->blend_shape_count > 0 || (mesh->has_bone_weights && p_has_skeleton);
+}
+
+/* MESH INSTANCE */
+
+RID RendererStorageRD::mesh_instance_create(RID p_base) {
+ Mesh *mesh = mesh_owner.getornull(p_base);
+ ERR_FAIL_COND_V(!mesh, RID());
+
+ MeshInstance *mi = memnew(MeshInstance);
+
+ mi->mesh = mesh;
+
+ for (uint32_t i = 0; i < mesh->surface_count; i++) {
+ _mesh_instance_add_surface(mi, mesh, i);
+ }
+
+ mi->I = mesh->instances.push_back(mi);
- Mesh::Surface::Version &v = s->versions[version];
+ mi->dirty = true;
+
+ return mesh_instance_owner.make_rid(mi);
+}
+void RendererStorageRD::mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) {
+ MeshInstance *mi = mesh_instance_owner.getornull(p_mesh_instance);
+ if (mi->skeleton == p_skeleton) {
+ return;
+ }
+ mi->skeleton = p_skeleton;
+ mi->skeleton_version = 0;
+ mi->dirty = true;
+}
+
+void RendererStorageRD::mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) {
+ MeshInstance *mi = mesh_instance_owner.getornull(p_mesh_instance);
+ ERR_FAIL_COND(!mi);
+ ERR_FAIL_INDEX(p_shape, (int)mi->blend_weights.size());
+ mi->blend_weights[p_shape] = p_weight;
+ mi->weights_dirty = true;
+ //will be eventually updated
+}
+
+void RendererStorageRD::_mesh_instance_clear(MeshInstance *mi) {
+ for (uint32_t i = 0; i < mi->surfaces.size(); i++) {
+ if (mi->surfaces[i].vertex_buffer.is_valid()) {
+ RD::get_singleton()->free(mi->surfaces[i].vertex_buffer);
+ }
+ if (mi->surfaces[i].versions) {
+ for (uint32_t j = 0; j < mi->surfaces[i].version_count; j++) {
+ RD::get_singleton()->free(mi->surfaces[i].versions[j].vertex_array);
+ }
+ memfree(mi->surfaces[i].versions);
+ }
+ }
+ mi->surfaces.clear();
+ if (mi->blend_weights_buffer.is_valid()) {
+ RD::get_singleton()->free(mi->blend_weights_buffer);
+ }
+ mi->blend_weights.clear();
+ mi->weights_dirty = false;
+ mi->skeleton_version = 0;
+}
+
+void RendererStorageRD::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface) {
+ if (mesh->blend_shape_count > 0 && mi->blend_weights_buffer.is_null()) {
+ mi->blend_weights.resize(mesh->blend_shape_count);
+ for (uint32_t i = 0; i < mi->blend_weights.size(); i++) {
+ mi->blend_weights[i] = 0;
+ }
+ mi->blend_weights_buffer = RD::get_singleton()->storage_buffer_create(sizeof(float) * mi->blend_weights.size(), mi->blend_weights.to_byte_array());
+ mi->weights_dirty = true;
+ }
+
+ MeshInstance::Surface s;
+ if (mesh->blend_shape_count > 0 || (mesh->surfaces[p_surface]->format & RS::ARRAY_FORMAT_BONES)) {
+ //surface warrants transform
+ s.vertex_buffer = RD::get_singleton()->vertex_buffer_create(mesh->surfaces[p_surface]->vertex_buffer_size, Vector<uint8_t>(), true);
+
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.binding = 1;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(s.vertex_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 2;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ if (mi->blend_weights_buffer.is_valid()) {
+ u.ids.push_back(mi->blend_weights_buffer);
+ } else {
+ u.ids.push_back(default_rd_storage_buffer);
+ }
+ uniforms.push_back(u);
+ }
+ s.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, skeleton_shader.version_shader[0], SkeletonShader::UNIFORM_SET_INSTANCE);
+ }
+
+ mi->surfaces.push_back(s);
+ mi->dirty = true;
+}
+
+void RendererStorageRD::mesh_instance_check_for_update(RID p_mesh_instance) {
+ MeshInstance *mi = mesh_instance_owner.getornull(p_mesh_instance);
+
+ bool needs_update = mi->dirty;
+
+ if (mi->weights_dirty && !mi->weight_update_list.in_list()) {
+ dirty_mesh_instance_weights.add(&mi->weight_update_list);
+ needs_update = true;
+ }
+
+ if (mi->array_update_list.in_list()) {
+ return;
+ }
+
+ if (!needs_update && mi->skeleton.is_valid()) {
+ Skeleton *sk = skeleton_owner.getornull(mi->skeleton);
+ if (sk && sk->version != mi->skeleton_version) {
+ needs_update = true;
+ }
+ }
+
+ if (needs_update) {
+ dirty_mesh_instance_arrays.add(&mi->array_update_list);
+ }
+}
+
+void RendererStorageRD::update_mesh_instances() {
+ while (dirty_mesh_instance_weights.first()) {
+ MeshInstance *mi = dirty_mesh_instance_weights.first()->self();
+
+ if (mi->blend_weights_buffer.is_valid()) {
+ RD::get_singleton()->buffer_update(mi->blend_weights_buffer, 0, mi->blend_weights.size() * sizeof(float), mi->blend_weights.ptr(), true);
+ }
+ dirty_mesh_instance_weights.remove(&mi->weight_update_list);
+ mi->weights_dirty = false;
+ }
+ if (dirty_mesh_instance_arrays.first() == nullptr) {
+ return; //nothing to do
+ }
+
+ //process skeletons and blend shapes
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+ while (dirty_mesh_instance_arrays.first()) {
+ MeshInstance *mi = dirty_mesh_instance_arrays.first()->self();
+
+ Skeleton *sk = skeleton_owner.getornull(mi->skeleton);
+
+ for (uint32_t i = 0; i < mi->surfaces.size(); i++) {
+ if (mi->surfaces[i].uniform_set == RID() || mi->mesh->surfaces[i]->uniform_set == RID()) {
+ continue;
+ }
+
+ bool array_is_2d = mi->mesh->surfaces[i]->format & RS::ARRAY_FLAG_USE_2D_VERTICES;
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, skeleton_shader.pipeline[array_is_2d ? SkeletonShader::SHADER_MODE_2D : SkeletonShader::SHADER_MODE_3D]);
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mi->surfaces[i].uniform_set, SkeletonShader::UNIFORM_SET_INSTANCE);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mi->mesh->surfaces[i]->uniform_set, SkeletonShader::UNIFORM_SET_SURFACE);
+ if (sk && sk->uniform_set_mi.is_valid()) {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sk->uniform_set_mi, SkeletonShader::UNIFORM_SET_SKELETON);
+ } else {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, skeleton_shader.default_skeleton_uniform_set, SkeletonShader::UNIFORM_SET_SKELETON);
+ }
+
+ SkeletonShader::PushConstant push_constant;
+
+ push_constant.has_normal = mi->mesh->surfaces[i]->format & RS::ARRAY_FORMAT_NORMAL;
+ push_constant.has_tangent = mi->mesh->surfaces[i]->format & RS::ARRAY_FORMAT_TANGENT;
+ push_constant.has_skeleton = sk != nullptr && sk->use_2d == array_is_2d && (mi->mesh->surfaces[i]->format & RS::ARRAY_FORMAT_BONES);
+ push_constant.has_blend_shape = mi->mesh->blend_shape_count > 0;
+
+ push_constant.vertex_count = mi->mesh->surfaces[i]->vertex_count;
+ push_constant.vertex_stride = (mi->mesh->surfaces[i]->vertex_buffer_size / mi->mesh->surfaces[i]->vertex_count) / 4;
+ push_constant.skin_stride = (mi->mesh->surfaces[i]->skin_buffer_size / mi->mesh->surfaces[i]->vertex_count) / 4;
+ push_constant.skin_weight_offset = (mi->mesh->surfaces[i]->format & RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 4 : 2;
+
+ push_constant.blend_shape_count = mi->mesh->blend_shape_count;
+ push_constant.normalized_blend_shapes = mi->mesh->blend_shape_mode == RS::BLEND_SHAPE_MODE_NORMALIZED;
+ push_constant.pad0 = 0;
+ push_constant.pad1 = 0;
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SkeletonShader::PushConstant));
+
+ //dispatch without barrier, so all is done at the same time
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, push_constant.vertex_count, 1, 1, 64, 1, 1);
+ }
+
+ mi->dirty = false;
+ if (sk) {
+ mi->skeleton_version = sk->version;
+ }
+ dirty_mesh_instance_arrays.remove(&mi->array_update_list);
+ }
+
+ RD::get_singleton()->compute_list_end();
+}
+
+void RendererStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, MeshInstance::Surface *mis) {
Vector<RD::VertexAttribute> attributes;
Vector<RID> buffers;
@@ -2873,7 +3139,11 @@ void RendererStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Surf
stride += sizeof(float) * 3;
}
- buffer = s->vertex_buffer;
+ if (mis) {
+ buffer = mis->vertex_buffer;
+ } else {
+ buffer = s->vertex_buffer;
+ }
} break;
case RS::ARRAY_NORMAL: {
@@ -2882,14 +3152,22 @@ void RendererStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Surf
vd.format = RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32;
stride += sizeof(uint32_t);
- buffer = s->vertex_buffer;
+ if (mis) {
+ buffer = mis->vertex_buffer;
+ } else {
+ buffer = s->vertex_buffer;
+ }
} break;
case RS::ARRAY_TANGENT: {
vd.offset = stride;
vd.format = RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32;
stride += sizeof(uint32_t);
- buffer = s->vertex_buffer;
+ if (mis) {
+ buffer = mis->vertex_buffer;
+ } else {
+ buffer = s->vertex_buffer;
+ }
} break;
case RS::ARRAY_COLOR: {
vd.offset = attribute_stride;
@@ -4847,6 +5125,7 @@ void RendererStorageRD::skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d
RD::get_singleton()->free(skeleton->buffer);
skeleton->buffer = RID();
skeleton->data.resize(0);
+ skeleton->uniform_set_mi = RID();
}
if (skeleton->size) {
@@ -4855,6 +5134,18 @@ void RendererStorageRD::skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d
zeromem(skeleton->data.ptrw(), skeleton->data.size() * sizeof(float));
_skeleton_make_dirty(skeleton);
+
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.binding = 0;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(skeleton->buffer);
+ uniforms.push_back(u);
+ }
+ skeleton->uniform_set_mi = RD::get_singleton()->uniform_set_create(uniforms, skeleton_shader.version_shader[0], SkeletonShader::UNIFORM_SET_SKELETON);
+ }
}
}
@@ -4977,6 +5268,7 @@ void RendererStorageRD::_update_dirty_skeletons() {
skeleton_dirty_list = skeleton->dirty_list;
skeleton->instance_dependency.instance_notify_changed(true, false);
+ skeleton->version++;
skeleton->dirty = false;
skeleton->dirty_list = nullptr;
@@ -5353,6 +5645,15 @@ void RendererStorageRD::reflection_probe_set_resolution(RID p_probe, int p_resol
reflection_probe->resolution = p_resolution;
}
+void RendererStorageRD::reflection_probe_set_lod_threshold(RID p_probe, float p_ratio) {
+ ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND(!reflection_probe);
+
+ reflection_probe->lod_threshold = p_ratio;
+
+ reflection_probe->instance_dependency.instance_notify_changed(true, false);
+}
+
AABB RendererStorageRD::reflection_probe_get_aabb(RID p_probe) const {
const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
ERR_FAIL_COND_V(!reflection_probe, AABB());
@@ -5406,6 +5707,13 @@ float RendererStorageRD::reflection_probe_get_origin_max_distance(RID p_probe) c
return reflection_probe->max_distance;
}
+float RendererStorageRD::reflection_probe_get_lod_threshold(RID p_probe) const {
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!reflection_probe, 0);
+
+ return reflection_probe->lod_threshold;
+}
+
int RendererStorageRD::reflection_probe_get_resolution(RID p_probe) const {
const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
ERR_FAIL_COND_V(!reflection_probe, 0);
@@ -6641,7 +6949,7 @@ void RendererStorageRD::render_target_copy_to_back_buffer(RID p_render_target, c
if (p_region == Rect2i()) {
region.size = rt->size;
} else {
- region = Rect2i(Size2i(), rt->size).clip(p_region);
+ region = Rect2i(Size2i(), rt->size).intersection(p_region);
if (region.size == Size2i()) {
return; //nothing to do
}
@@ -6681,7 +6989,7 @@ void RendererStorageRD::render_target_clear_back_buffer(RID p_render_target, con
if (p_region == Rect2i()) {
region.size = rt->size;
} else {
- region = Rect2i(Size2i(), rt->size).clip(p_region);
+ region = Rect2i(Size2i(), rt->size).intersection(p_region);
if (region.size == Size2i()) {
return; //nothing to do
}
@@ -6702,7 +7010,7 @@ void RendererStorageRD::render_target_gen_back_buffer_mipmaps(RID p_render_targe
if (p_region == Rect2i()) {
region.size = rt->size;
} else {
- region = Rect2i(Size2i(), rt->size).clip(p_region);
+ region = Rect2i(Size2i(), rt->size).intersection(p_region);
if (region.size == Size2i()) {
return; //nothing to do
}
@@ -7810,7 +8118,18 @@ bool RendererStorageRD::free(RID p_rid) {
mesh_clear(p_rid);
Mesh *mesh = mesh_owner.getornull(p_rid);
mesh->instance_dependency.instance_notify_deleted(p_rid);
+ if (mesh->instances.size()) {
+ ERR_PRINT("deleting mesh with active instances");
+ }
mesh_owner.free(p_rid);
+ } else if (mesh_instance_owner.owns(p_rid)) {
+ MeshInstance *mi = mesh_instance_owner.getornull(p_rid);
+ _mesh_instance_clear(mi);
+ mi->mesh->instances.erase(mi->I);
+ mi->I = nullptr;
+ mesh_instance_owner.free(p_rid);
+ memdelete(mi);
+
} else if (multimesh_owner.owns(p_rid)) {
_update_dirty_multimeshes();
multimesh_allocate(p_rid, 0, RS::MULTIMESH_TRANSFORM_2D);
@@ -8517,6 +8836,30 @@ RendererStorageRD::RendererStorageRD() {
rt_sdf.pipelines[i] = RD::get_singleton()->compute_pipeline_create(rt_sdf.shader.version_get_shader(rt_sdf.shader_version, i));
}
}
+ {
+ Vector<String> skeleton_modes;
+ skeleton_modes.push_back("\n#define MODE_2D\n");
+ skeleton_modes.push_back("");
+
+ skeleton_shader.shader.initialize(skeleton_modes);
+ skeleton_shader.version = skeleton_shader.shader.version_create();
+ for (int i = 0; i < SkeletonShader::SHADER_MODE_MAX; i++) {
+ skeleton_shader.version_shader[i] = skeleton_shader.shader.version_get_shader(skeleton_shader.version, i);
+ skeleton_shader.pipeline[i] = RD::get_singleton()->compute_pipeline_create(skeleton_shader.version_shader[i]);
+ }
+
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.binding = 0;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(default_rd_storage_buffer);
+ uniforms.push_back(u);
+ }
+ skeleton_shader.default_skeleton_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, skeleton_shader.version_shader[0], SkeletonShader::UNIFORM_SET_SKELETON);
+ }
+ }
}
RendererStorageRD::~RendererStorageRD() {
@@ -8546,6 +8889,8 @@ RendererStorageRD::~RendererStorageRD() {
particles_shader.copy_shader.version_free(particles_shader.copy_shader_version);
rt_sdf.shader.version_free(rt_sdf.shader_version);
+ skeleton_shader.shader.version_free(skeleton_shader.version);
+
RenderingServer::get_singleton()->free(particles_shader.default_material);
RenderingServer::get_singleton()->free(particles_shader.default_shader);
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h
index b6a26fc9d0..e4199ffd12 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.h
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.h
@@ -31,6 +31,8 @@
#ifndef RENDERING_SERVER_STORAGE_RD_H
#define RENDERING_SERVER_STORAGE_RD_H
+#include "core/templates/list.h"
+#include "core/templates/local_vector.h"
#include "core/templates/rid_owner.h"
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering/renderer_rd/effects_rd.h"
@@ -39,9 +41,9 @@
#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_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) {
@@ -377,6 +379,8 @@ private:
/* Mesh */
+ struct MeshInstance;
+
struct Mesh {
struct Surface {
RS::PrimitiveType primitive = RS::PRIMITIVE_POINTS;
@@ -386,6 +390,8 @@ private:
RID attribute_buffer;
RID skin_buffer;
uint32_t vertex_count = 0;
+ uint32_t vertex_buffer_size = 0;
+ uint32_t skin_buffer_size = 0;
// A different pipeline needs to be allocated
// depending on the inputs available in the
@@ -433,6 +439,8 @@ private:
uint32_t particles_render_index = 0;
uint64_t particles_render_pass = 0;
+
+ RID uniform_set;
};
uint32_t blend_shape_count = 0;
@@ -443,17 +451,90 @@ private:
Vector<AABB> bone_aabbs;
+ bool has_bone_weights = false;
+
AABB aabb;
AABB custom_aabb;
Vector<RID> material_cache;
+ List<MeshInstance *> instances;
+
RendererStorage::InstanceDependency instance_dependency;
};
mutable RID_Owner<Mesh> mesh_owner;
- void _mesh_surface_generate_version_for_input_mask(Mesh::Surface *s, uint32_t p_input_mask);
+ struct MeshInstance {
+ Mesh *mesh;
+ RID skeleton;
+ struct Surface {
+ RID vertex_buffer;
+ RID uniform_set;
+
+ Mesh::Surface::Version *versions = nullptr; //allocated on demand
+ uint32_t version_count = 0;
+ };
+ LocalVector<Surface> surfaces;
+ LocalVector<float> blend_weights;
+
+ RID blend_weights_buffer;
+ List<MeshInstance *>::Element *I = nullptr; //used to erase itself
+ uint64_t skeleton_version = 0;
+ bool dirty = false;
+ bool weights_dirty = false;
+ SelfList<MeshInstance> weight_update_list;
+ SelfList<MeshInstance> array_update_list;
+ MeshInstance() :
+ weight_update_list(this), array_update_list(this) {}
+ };
+
+ void _mesh_instance_clear(MeshInstance *mi);
+ void _mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface);
+
+ mutable RID_PtrOwner<MeshInstance> mesh_instance_owner;
+
+ SelfList<MeshInstance>::List dirty_mesh_instance_weights;
+ SelfList<MeshInstance>::List dirty_mesh_instance_arrays;
+
+ struct SkeletonShader {
+ struct PushConstant {
+ uint32_t has_normal;
+ uint32_t has_tangent;
+ uint32_t has_skeleton;
+ uint32_t has_blend_shape;
+
+ uint32_t vertex_count;
+ uint32_t vertex_stride;
+ uint32_t skin_stride;
+ uint32_t skin_weight_offset;
+
+ uint32_t blend_shape_count;
+ uint32_t normalized_blend_shapes;
+ uint32_t pad0;
+ uint32_t pad1;
+ };
+
+ enum {
+ UNIFORM_SET_INSTANCE = 0,
+ UNIFORM_SET_SURFACE = 1,
+ UNIFORM_SET_SKELETON = 2,
+ };
+ enum {
+ SHADER_MODE_2D,
+ SHADER_MODE_3D,
+ SHADER_MODE_MAX
+ };
+
+ SkeletonShaderRD shader;
+ RID version;
+ RID version_shader[SHADER_MODE_MAX];
+ RID pipeline[SHADER_MODE_MAX];
+
+ RID default_skeleton_uniform_set;
+ } skeleton_shader;
+
+ void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, MeshInstance::Surface *mis = nullptr);
RID mesh_default_rd_buffers[DEFAULT_RD_BUFFER_MAX];
@@ -826,6 +907,9 @@ private:
Transform2D base_transform_2d;
RID uniform_set_3d;
+ RID uniform_set_mi;
+
+ uint64_t version = 1;
RendererStorage::InstanceDependency instance_dependency;
};
@@ -880,6 +964,7 @@ private:
bool box_projection = false;
bool enable_shadows = false;
uint32_t cull_mask = (1 << 20) - 1;
+ float lod_threshold = 0.01;
RendererStorage::InstanceDependency instance_dependency;
};
@@ -1280,6 +1365,8 @@ public:
virtual RID mesh_create();
+ virtual void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count);
+
/// Return stride
virtual void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface);
@@ -1304,6 +1391,16 @@ public:
virtual void mesh_clear(RID p_mesh);
+ virtual bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton);
+
+ /* MESH INSTANCE */
+
+ virtual RID mesh_instance_create(RID p_base);
+ virtual void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton);
+ virtual void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight);
+ virtual void mesh_instance_check_for_update(RID p_mesh_instance);
+ virtual void update_mesh_instances();
+
_FORCE_INLINE_ const RID *mesh_get_surface_count_and_materials(RID p_mesh, uint32_t &r_surface_count) {
Mesh *mesh = mesh_owner.getornull(p_mesh);
ERR_FAIL_COND_V(!mesh, nullptr);
@@ -1321,22 +1418,50 @@ public:
return mesh->material_cache.ptr();
}
- _FORCE_INLINE_ RS::PrimitiveType mesh_surface_get_primitive(RID p_mesh, uint32_t p_surface_index) {
+ _FORCE_INLINE_ void *mesh_get_surface(RID p_mesh, uint32_t p_surface_index) {
Mesh *mesh = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!mesh, RS::PRIMITIVE_MAX);
- ERR_FAIL_UNSIGNED_INDEX_V(p_surface_index, mesh->surface_count, RS::PRIMITIVE_MAX);
+ ERR_FAIL_COND_V(!mesh, nullptr);
+ ERR_FAIL_UNSIGNED_INDEX_V(p_surface_index, mesh->surface_count, nullptr);
- return mesh->surfaces[p_surface_index]->primitive;
+ return mesh->surfaces[p_surface_index];
}
- _FORCE_INLINE_ void mesh_surface_get_arrays_and_format(RID p_mesh, uint32_t p_surface_index, uint32_t p_input_mask, RID &r_vertex_array_rd, RID &r_index_array_rd, RD::VertexFormatID &r_vertex_format) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND(!mesh);
- ERR_FAIL_UNSIGNED_INDEX(p_surface_index, mesh->surface_count);
+ _FORCE_INLINE_ RS::PrimitiveType mesh_surface_get_primitive(void *p_surface) {
+ Mesh::Surface *surface = reinterpret_cast<Mesh::Surface *>(p_surface);
+ return surface->primitive;
+ }
- Mesh::Surface *s = mesh->surfaces[p_surface_index];
+ _FORCE_INLINE_ bool mesh_surface_has_lod(void *p_surface) const {
+ Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
+ return s->lod_count > 0;
+ }
+
+ _FORCE_INLINE_ RID mesh_surface_get_index_array(void *p_surface) const {
+ Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
+
+ return s->index_array;
+ }
+
+ _FORCE_INLINE_ RID mesh_surface_get_index_array_with_lod(void *p_surface, float p_model_scale, float p_distance_threshold, float p_lod_threshold) const {
+ Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
+
+ int32_t current_lod = -1;
+ for (uint32_t i = 0; i < s->lod_count; i++) {
+ float screen_size = s->lods[i].edge_length * p_model_scale / p_distance_threshold;
+ if (screen_size > p_lod_threshold) {
+ break;
+ }
+ current_lod = i;
+ }
+ if (current_lod == -1) {
+ return s->index_array;
+ } else {
+ return s->lods[current_lod].index_array;
+ }
+ }
- r_index_array_rd = s->index_array;
+ _FORCE_INLINE_ void mesh_surface_get_vertex_arrays_and_format(void *p_surface, uint32_t p_input_mask, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) {
+ Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
s->version_lock.lock();
@@ -1353,9 +1478,11 @@ public:
return;
}
- uint32_t version = s->version_count; //gets added at the end
+ uint32_t version = s->version_count;
+ s->version_count++;
+ s->versions = (Mesh::Surface::Version *)memrealloc(s->versions, sizeof(Mesh::Surface::Version) * s->version_count);
- _mesh_surface_generate_version_for_input_mask(s, p_input_mask);
+ _mesh_surface_generate_version_for_input_mask(s->versions[version], s, p_input_mask);
r_vertex_format = s->versions[version].vertex_format;
r_vertex_array_rd = s->versions[version].vertex_array;
@@ -1363,6 +1490,42 @@ public:
s->version_lock.unlock();
}
+ _FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint32_t p_surface_index, uint32_t p_input_mask, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) {
+ MeshInstance *mi = mesh_instance_owner.getornull(p_mesh_instance);
+ ERR_FAIL_COND(!mi);
+ Mesh *mesh = mi->mesh;
+ ERR_FAIL_UNSIGNED_INDEX(p_surface_index, mesh->surface_count);
+
+ MeshInstance::Surface *mis = &mi->surfaces[p_surface_index];
+ Mesh::Surface *s = mesh->surfaces[p_surface_index];
+
+ s->version_lock.lock();
+
+ //there will never be more than, at much, 3 or 4 versions, so iterating is the fastest way
+
+ for (uint32_t i = 0; i < mis->version_count; i++) {
+ if (mis->versions[i].input_mask != p_input_mask) {
+ continue;
+ }
+ //we have this version, hooray
+ r_vertex_format = mis->versions[i].vertex_format;
+ r_vertex_array_rd = mis->versions[i].vertex_array;
+ s->version_lock.unlock();
+ return;
+ }
+
+ uint32_t version = mis->version_count;
+ mis->version_count++;
+ mis->versions = (Mesh::Surface::Version *)memrealloc(mis->versions, sizeof(Mesh::Surface::Version) * mis->version_count);
+
+ _mesh_surface_generate_version_for_input_mask(mis->versions[version], s, p_input_mask, mis);
+
+ r_vertex_format = mis->versions[version].vertex_format;
+ r_vertex_array_rd = mis->versions[version].vertex_array;
+
+ s->version_lock.unlock();
+ }
+
_FORCE_INLINE_ RID mesh_get_default_rd_buffer(DefaultRDBuffer p_buffer) {
ERR_FAIL_INDEX_V(p_buffer, DEFAULT_RD_BUFFER_MAX, RID());
return mesh_default_rd_buffers[p_buffer];
@@ -1644,6 +1807,7 @@ public:
void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable);
void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers);
void reflection_probe_set_resolution(RID p_probe, int p_resolution);
+ void reflection_probe_set_lod_threshold(RID p_probe, float p_ratio);
AABB reflection_probe_get_aabb(RID p_probe) const;
RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const;
@@ -1651,6 +1815,8 @@ public:
Vector3 reflection_probe_get_extents(RID p_probe) const;
Vector3 reflection_probe_get_origin_offset(RID p_probe) const;
float reflection_probe_get_origin_max_distance(RID p_probe) const;
+ float reflection_probe_get_lod_threshold(RID p_probe) const;
+
int reflection_probe_get_resolution(RID p_probe) const;
bool reflection_probe_renders_shadows(RID p_probe) const;
diff --git a/servers/rendering/renderer_rd/shaders/SCsub b/servers/rendering/renderer_rd/shaders/SCsub
index 1fe43b25f6..cb62882deb 100644
--- a/servers/rendering/renderer_rd/shaders/SCsub
+++ b/servers/rendering/renderer_rd/shaders/SCsub
@@ -41,3 +41,4 @@ if "RD_GLSL" in env["BUILDERS"]:
env.RD_GLSL("particles.glsl")
env.RD_GLSL("particles_copy.glsl")
env.RD_GLSL("sort.glsl")
+ env.RD_GLSL("skeleton.glsl")
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward.glsl b/servers/rendering/renderer_rd/shaders/scene_forward.glsl
index 5b01cb1f82..a7fe86b029 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward.glsl
@@ -9,7 +9,13 @@ VERSION_DEFINES
/* 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(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED)
layout(location = 2) in vec4 tangent_attrib;
#endif
@@ -18,7 +24,9 @@ layout(location = 2) in vec4 tangent_attrib;
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;
@@ -51,13 +59,18 @@ layout(location = 11) in vec4 weight_attrib;
/* 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;
@@ -138,7 +151,9 @@ void main() {
}
vec3 vertex = vertex_attrib;
+#ifdef NORMAL_USED
vec3 normal = normal_attrib * 2.0 - 1.0;
+#endif
#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED)
vec3 tangent = tangent_attrib.xyz * 2.0 - 1.0;
@@ -171,7 +186,10 @@ void main() {
#endif
}
#endif
+
+#ifdef UV_USED
uv_interp = uv_attrib;
+#endif
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
uv2_interp = uv2_attrib;
@@ -215,9 +233,12 @@ VERTEX_SHADER_CODE
#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(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED)
binormal = modelview_normal * binormal;
@@ -238,7 +259,9 @@ VERTEX_SHADER_CODE
#endif
vertex_interp = vertex;
+#ifdef NORMAL_USED
normal_interp = normal;
+#endif
#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED)
tangent_interp = tangent;
@@ -250,7 +273,6 @@ VERTEX_SHADER_CODE
#ifdef MODE_DUAL_PARABOLOID
vertex_interp.z *= scene_data.dual_paraboloid_side;
- normal_interp.z *= scene_data.dual_paraboloid_side;
dp_clip = vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias
@@ -301,13 +323,18 @@ VERSION_DEFINES
/* 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;
@@ -1799,6 +1826,8 @@ void main() {
vec3 binormal = vec3(0.0);
vec3 tangent = vec3(0.0);
#endif
+
+#ifdef NORMAL_USED
vec3 normal = normalize(normal_interp);
#if defined(DO_SIDE_CHECK)
@@ -1807,7 +1836,11 @@ void main() {
}
#endif
+#endif //NORMAL_USED
+
+#ifdef UV_USED
vec2 uv = uv_interp;
+#endif
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
vec2 uv2 = uv2_interp;
@@ -1994,6 +2027,7 @@ FRAGMENT_SHADER_CODE
#endif //not 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;
@@ -2003,6 +2037,7 @@ FRAGMENT_SHADER_CODE
float filteredRoughness2 = min(1.0, roughness2 + kernelRoughness2);
roughness = sqrt(filteredRoughness2);
}
+#endif
//apply energy conservation
vec3 specular_light = vec3(0.0, 0.0, 0.0);
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_inc.glsl
index d18581c1b3..fdc9941bba 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_inc.glsl
@@ -5,6 +5,12 @@
#include "cluster_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(NORMALMAP_USED)
+#ifndef NORMAL_USED
+#define NORMAL_USED
+#endif
+#endif
+
layout(push_constant, binding = 0, std430) uniform DrawCall {
uint instance_index;
uint pad; //16 bits minimum size
diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_fields.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_fields.glsl
index eec0a90c0d..69d8824d8a 100644
--- a/servers/rendering/renderer_rd/shaders/sdfgi_fields.glsl
+++ b/servers/rendering/renderer_rd/shaders/sdfgi_fields.glsl
@@ -14,7 +14,7 @@ layout(local_size_x = OCT_RES, local_size_y = OCT_RES, local_size_z = 1) in;
layout(rgba16f, set = 0, binding = 1) uniform restrict image2DArray irradiance_texture;
layout(rg16f, set = 0, binding = 2) uniform restrict image2DArray depth_texture;
-ayout(rgba32ui, set = 0, binding = 3) uniform restrict uimage2DArray irradiance_history_texture;
+layout(rgba32ui, set = 0, binding = 3) uniform restrict uimage2DArray irradiance_history_texture;
layout(rg32ui, set = 0, binding = 4) uniform restrict uimage2DArray depth_history_texture;
struct CascadeData {
diff --git a/servers/rendering/renderer_rd/shaders/skeleton.glsl b/servers/rendering/renderer_rd/shaders/skeleton.glsl
new file mode 100644
index 0000000000..b19f5a9ad3
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/skeleton.glsl
@@ -0,0 +1,199 @@
+#[compute]
+
+#version 450
+
+VERSION_DEFINES
+
+layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
+
+layout(set = 0, binding = 1, std430) buffer restrict writeonly DstVertexData {
+ uint data[];
+}
+dst_vertices;
+
+layout(set = 0, binding = 2, std430) buffer restrict readonly BlendShapeWeights {
+ float data[];
+}
+blend_shape_weights;
+
+layout(set = 1, binding = 0, std430) buffer restrict readonly SrcVertexData {
+ uint data[];
+}
+src_vertices;
+
+layout(set = 1, binding = 1, std430) buffer restrict readonly BoneWeightData {
+ uint data[];
+}
+src_bone_weights;
+
+layout(set = 1, binding = 2, std430) buffer restrict readonly BlendShapeData {
+ uint data[];
+}
+src_blend_shapes;
+
+layout(set = 2, binding = 0, std430) buffer restrict readonly SkeletonData {
+ vec4 data[];
+}
+bone_transforms;
+
+layout(push_constant, binding = 0, std430) uniform Params {
+ bool has_normal;
+ bool has_tangent;
+ bool has_skeleton;
+ bool has_blend_shape;
+
+ uint vertex_count;
+ uint vertex_stride;
+ uint skin_stride;
+ uint skin_weight_offset;
+
+ uint blend_shape_count;
+ bool normalized_blend_shapes;
+ uint pad0;
+ uint pad1;
+}
+params;
+
+vec4 decode_abgr_2_10_10_10(uint base) {
+ uvec4 abgr_2_10_10_10 = (uvec4(base) >> uvec4(0, 10, 20, 30)) & uvec4(0x3FF, 0x3FF, 0x3FF, 0x3);
+ return vec4(abgr_2_10_10_10) / vec4(1023.0, 1023.0, 1023.0, 3.0) * 2.0 - 1.0;
+}
+
+uint encode_abgr_2_10_10_10(vec4 base) {
+ uvec4 abgr_2_10_10_10 = uvec4(clamp(ivec4((base * 0.5 + 0.5) * vec4(1023.0, 1023.0, 1023.0, 3.0)), ivec4(0), ivec4(0x3FF, 0x3FF, 0x3FF, 0x3))) << uvec4(0, 10, 20, 30);
+ return abgr_2_10_10_10.x | abgr_2_10_10_10.y | abgr_2_10_10_10.z | abgr_2_10_10_10.w;
+}
+
+void main() {
+ uint index = gl_GlobalInvocationID.x;
+ if (index >= params.vertex_count) {
+ return;
+ }
+
+ uint src_offset = index * params.vertex_stride;
+
+#ifdef MODE_2D
+ vec2 vertex = uintBitsToFloat(uvec2(src_vertices.data[src_offset + 0], src_vertices.data[src_offset + 1]));
+#else
+ vec3 vertex;
+ vec3 normal;
+ vec4 tangent;
+
+ vertex = uintBitsToFloat(uvec3(src_vertices.data[src_offset + 0], src_vertices.data[src_offset + 1], src_vertices.data[src_offset + 2]));
+
+ src_offset += 3;
+
+ if (params.has_normal) {
+ normal = decode_abgr_2_10_10_10(src_vertices.data[src_offset]).rgb;
+ src_offset++;
+ }
+
+ if (params.has_tangent) {
+ tangent = decode_abgr_2_10_10_10(src_vertices.data[src_offset]);
+ }
+
+ if (params.has_blend_shape) {
+ float blend_total = 0.0;
+ vec3 blend_vertex = vec3(0.0);
+ vec3 blend_normal = vec3(0.0);
+ vec3 blend_tangent = vec3(0.0);
+
+ for (uint i = 0; i < params.blend_shape_count; i++) {
+ float w = blend_shape_weights.data[i];
+ if (w > 0.0001) {
+ uint base_offset = (params.vertex_count * i + index) * params.vertex_stride;
+
+ blend_vertex += uintBitsToFloat(uvec3(src_blend_shapes.data[base_offset + 0], src_blend_shapes.data[base_offset + 1], src_blend_shapes.data[base_offset + 2])) * w;
+
+ base_offset += 3;
+
+ if (params.has_normal) {
+ blend_normal += decode_abgr_2_10_10_10(src_blend_shapes.data[base_offset]).rgb * w;
+ base_offset++;
+ }
+
+ if (params.has_tangent) {
+ blend_tangent += decode_abgr_2_10_10_10(src_blend_shapes.data[base_offset]).rgb;
+ }
+
+ blend_total += w;
+ }
+ }
+
+ if (params.normalized_blend_shapes) {
+ vertex = (1.0 - blend_total) * vertex;
+ normal = (1.0 - blend_total) * normal;
+ tangent.rgb = (1.0 - blend_total) * tangent.rgb;
+ }
+
+ vertex += blend_vertex;
+ normal += normalize(normal + blend_normal);
+ tangent.rgb += normalize(tangent.rgb + blend_tangent);
+ }
+
+ 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], bone_transforms.data[bones_01.x + 2], 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], bone_transforms.data[bones_01.y + 2], 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], bone_transforms.data[bones_23.x + 2], 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], bone_transforms.data[bones_23.y + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.y;
+
+ if (params.skin_weight_offset == 4) {
+ //using 8 bones/weights
+ skin_offset = params.skin_stride * index + 2;
+
+ bones = uvec2(src_bone_weights.data[skin_offset + 0], src_bone_weights.data[skin_offset + 1]);
+ bones_01 = uvec2(bones.x & 0xFFFF, bones.x >> 16) * 3; //pre-add xform offset
+ bones_23 = uvec2(bones.y & 0xFFFF, bones.y >> 16) * 3;
+
+ skin_offset += params.skin_weight_offset;
+
+ weights = uvec2(src_bone_weights.data[skin_offset + 0], src_bone_weights.data[skin_offset + 1]);
+
+ weights_01 = unpackUnorm2x16(weights.x);
+ weights_23 = unpackUnorm2x16(weights.y);
+
+ m += mat4(bone_transforms.data[bones_01.x], bone_transforms.data[bones_01.x + 1], bone_transforms.data[bones_01.x + 2], 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], bone_transforms.data[bones_01.y + 2], 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], bone_transforms.data[bones_23.x + 2], 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], bone_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 = normalize((vec4(normal, 0.0) * m).xyz);
+ tangent.xyz = normalize((vec4(tangent.xyz, 0.0) * m).xyz);
+ }
+
+ uint dst_offset = index * params.vertex_stride;
+
+ uvec3 uvertex = floatBitsToUint(vertex);
+ dst_vertices.data[dst_offset + 0] = uvertex.x;
+ dst_vertices.data[dst_offset + 1] = uvertex.y;
+ dst_vertices.data[dst_offset + 2] = uvertex.z;
+
+ dst_offset += 3;
+
+ if (params.has_normal) {
+ dst_vertices.data[dst_offset] = encode_abgr_2_10_10_10(vec4(normal, 0.0));
+ dst_offset++;
+ }
+
+ if (params.has_tangent) {
+ dst_vertices.data[dst_offset] = encode_abgr_2_10_10_10(tangent);
+ }
+
+#endif
+}
diff --git a/servers/rendering/renderer_scene.h b/servers/rendering/renderer_scene.h
index 3da08f10af..56c38beaa3 100644
--- a/servers/rendering/renderer_scene.h
+++ b/servers/rendering/renderer_scene.h
@@ -88,6 +88,7 @@ public:
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_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;
virtual void instance_geometry_set_shader_parameter(RID p_instance, const StringName &p_parameter, const Variant &p_value) = 0;
virtual void instance_geometry_get_shader_parameter_list(RID p_instance, List<PropertyInfo> *p_parameters) const = 0;
@@ -187,8 +188,8 @@ public:
virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) = 0;
virtual void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) = 0;
- virtual void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, 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, 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 update() = 0;
virtual void render_probes() = 0;
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index 26c50d25ca..88a0859a28 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -370,6 +370,22 @@ RID RendererSceneCull::instance_create() {
return instance_rid;
}
+void RendererSceneCull::_instance_update_mesh_instance(Instance *p_instance) {
+ bool needs_instance = RSG::storage->mesh_needs_instance(p_instance->base, p_instance->skeleton.is_valid());
+ if (needs_instance != p_instance->mesh_instance.is_valid()) {
+ if (needs_instance) {
+ p_instance->mesh_instance = RSG::storage->mesh_instance_create(p_instance->base);
+ } else {
+ RSG::storage->free(p_instance->mesh_instance);
+ p_instance->mesh_instance = RID();
+ }
+ }
+
+ if (p_instance->mesh_instance.is_valid()) {
+ RSG::storage->mesh_instance_set_skeleton(p_instance->mesh_instance, p_instance->skeleton);
+ }
+}
+
void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
Instance *instance = instance_owner.getornull(p_instance);
ERR_FAIL_COND(!instance);
@@ -384,6 +400,11 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
instance->octree_id = 0;
}
+ if (instance->mesh_instance.is_valid()) {
+ RSG::storage->free(instance->mesh_instance);
+ instance->mesh_instance = RID();
+ }
+
switch (instance->base_type) {
case RS::INSTANCE_LIGHT: {
InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data);
@@ -450,7 +471,6 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
instance->base_data = nullptr;
}
- instance->blend_values.clear();
instance->materials.clear();
}
@@ -479,9 +499,7 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
case RS::INSTANCE_PARTICLES: {
InstanceGeometryData *geom = memnew(InstanceGeometryData);
instance->base_data = geom;
- if (instance->base_type == RS::INSTANCE_MESH) {
- instance->blend_values.resize(RSG::storage->mesh_get_blend_shape_count(p_base));
- }
+
} break;
case RS::INSTANCE_REFLECTION_PROBE: {
InstanceReflectionProbeData *reflection_probe = memnew(InstanceReflectionProbeData);
@@ -520,6 +538,10 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
instance->base = p_base;
+ if (instance->base_type == RS::INSTANCE_MESH) {
+ _instance_update_mesh_instance(instance);
+ }
+
//forcefully update the dependency now, so if for some reason it gets removed, we can immediately clear it
RSG::storage->base_update_dependency(p_base, instance);
}
@@ -662,8 +684,9 @@ void RendererSceneCull::instance_set_blend_shape_weight(RID p_instance, int p_sh
_update_dirty_instance(instance);
}
- ERR_FAIL_INDEX(p_shape, instance->blend_values.size());
- instance->blend_values.write[p_shape] = p_weight;
+ if (instance->mesh_instance.is_valid()) {
+ RSG::storage->mesh_instance_set_blend_shape_weight(instance->mesh_instance, p_shape, p_weight);
+ }
}
void RendererSceneCull::instance_set_surface_material(RID p_instance, int p_surface, RID p_material) {
@@ -777,6 +800,9 @@ void RendererSceneCull::instance_attach_skeleton(RID p_instance, RID p_skeleton)
//update the dependency now, so if cleared, we remove it
RSG::storage->skeleton_update_dependency(p_skeleton, instance);
}
+
+ _instance_update_mesh_instance(instance);
+
_instance_queue_update(instance, true, true);
}
@@ -943,6 +969,13 @@ void RendererSceneCull::instance_geometry_set_lightmap(RID p_instance, RID p_lig
}
}
+void RendererSceneCull::instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias) {
+ Instance *instance = instance_owner.getornull(p_instance);
+ ERR_FAIL_COND(!instance);
+
+ instance->lod_bias = p_lod_bias;
+}
+
void RendererSceneCull::instance_geometry_set_shader_parameter(RID p_instance, const StringName &p_parameter, const Variant &p_value) {
Instance *instance = instance_owner.getornull(p_instance);
ERR_FAIL_COND(!instance);
@@ -1299,7 +1332,7 @@ void RendererSceneCull::_update_instance_lightmap_captures(Instance *p_instance)
}
}
-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) {
+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) {
InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data);
Transform light_transform = p_instance->transform;
@@ -1309,6 +1342,8 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
switch (RSG::storage->light_get_type(p_instance->base)) {
case RS::LIGHT_DIRECTIONAL: {
+ Plane camera_plane(p_cam_transform.get_origin(), -p_cam_transform.basis.get_axis(Vector3::AXIS_Z));
+
real_t max_distance = p_cam_projection.get_z_far();
real_t shadow_max = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE);
if (shadow_max > 0 && !p_cam_orthogonal) { //its impractical (and leads to unwanted behaviors) to set max distance in orthogonal camera
@@ -1571,6 +1606,10 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
if (j == 0 || max > cull_max) {
cull_max = max;
}
+
+ if (instance->mesh_instance.is_valid()) {
+ RSG::storage->mesh_instance_check_for_update(instance->mesh_instance);
+ }
}
if (cull_max > z_max) {
@@ -1671,7 +1710,9 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
scene_render->light_instance_set_shadow_transform(light->instance, ortho_camera, ortho_transform, z_max - z_min_cam, distances[i + 1], i, radius * 2.0 / texture_size, bias_scale * aspect_bias_scale * min_distance_bias_scale, z_max, uv_scale);
}
- scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RendererSceneRender::InstanceBase **)instance_shadow_cull_result, cull_count);
+ RSG::storage->update_mesh_instances();
+
+ scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RendererSceneRender::InstanceBase **)instance_shadow_cull_result, cull_count, camera_plane, p_cam_projection.get_lod_multiplier(), p_screen_lod_threshold);
}
} break;
@@ -1711,9 +1752,15 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
instance->depth = near_plane.distance_to(instance->transform.origin);
instance->depth_layer = 0;
+
+ if (instance->mesh_instance.is_valid()) {
+ RSG::storage->mesh_instance_check_for_update(instance->mesh_instance);
+ }
}
}
+ RSG::storage->update_mesh_instances();
+
scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, i, 0);
scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RendererSceneRender::InstanceBase **)instance_shadow_cull_result, cull_count);
}
@@ -1763,9 +1810,13 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
}
instance->depth = near_plane.distance_to(instance->transform.origin);
instance->depth_layer = 0;
+ if (instance->mesh_instance.is_valid()) {
+ RSG::storage->mesh_instance_check_for_update(instance->mesh_instance);
+ }
}
}
+ RSG::storage->update_mesh_instances();
scene_render->light_instance_set_shadow_transform(light->instance, cm, xform, radius, 0, i, 0);
scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RendererSceneRender::InstanceBase **)instance_shadow_cull_result, cull_count);
}
@@ -1800,9 +1851,15 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
}
instance->depth = near_plane.distance_to(instance->transform.origin);
instance->depth_layer = 0;
+
+ if (instance->mesh_instance.is_valid()) {
+ RSG::storage->mesh_instance_check_for_update(instance->mesh_instance);
+ }
}
}
+ RSG::storage->update_mesh_instances();
+
scene_render->light_instance_set_shadow_transform(light->instance, cm, light_transform, radius, 0, 0, 0);
scene_render->render_shadow(light->instance, p_shadow_atlas, 0, (RendererSceneRender::InstanceBase **)instance_shadow_cull_result, cull_count);
@@ -1812,7 +1869,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
return animated_material_found;
}
-void RendererSceneCull::render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas) {
+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
#ifndef _3D_DISABLED
@@ -1857,12 +1914,12 @@ void RendererSceneCull::render_camera(RID p_render_buffers, RID p_camera, RID p_
RID environment = _render_get_environment(p_camera, p_scenario);
- _prepare_scene(camera->transform, camera_matrix, ortho, camera->vaspect, p_render_buffers, environment, camera->visible_layers, p_scenario, p_shadow_atlas, RID());
- _render_scene(p_render_buffers, camera->transform, camera_matrix, ortho, environment, camera->effects, p_scenario, p_shadow_atlas, RID(), -1);
+ _prepare_scene(camera->transform, camera_matrix, ortho, camera->vaspect, p_render_buffers, environment, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), p_screen_lod_threshold);
+ _render_scene(p_render_buffers, camera->transform, camera_matrix, ortho, environment, camera->effects, p_scenario, 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, RID p_shadow_atlas) {
+void RendererSceneCull::render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas) {
// render for AR/VR interface
Camera *camera = camera_owner.getornull(p_camera);
@@ -1936,17 +1993,17 @@ void RendererSceneCull::render_camera(RID p_render_buffers, Ref<XRInterface> &p_
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());
+ _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());
+ _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);
+ _render_scene(p_render_buffers, cam_transform, camera_matrix, false, environment, camera->effects, p_scenario, p_shadow_atlas, RID(), -1, p_screen_lod_threshold);
};
-void RendererSceneCull::_prepare_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, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, bool p_using_shadows) {
+void RendererSceneCull::_prepare_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, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, 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
@@ -2143,6 +2200,10 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca
}
}
+ if (ins->mesh_instance.is_valid()) {
+ RSG::storage->mesh_instance_check_for_update(ins->mesh_instance);
+ }
+
ins->depth = near_plane.distance_to(ins->transform.origin);
ins->depth_layer = CLAMP(int(ins->depth * 16 / z_far), 0, 15);
}
@@ -2159,6 +2220,8 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca
ins->last_frame_pass = frame_number;
}
+ RSG::storage->update_mesh_instances();
+
/* STEP 5 - PROCESS LIGHTS */
RID *directional_light_ptr = &light_instance_cull_result[light_cull_count];
@@ -2196,7 +2259,7 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca
for (int i = 0; i < directional_shadow_count; i++) {
RENDER_TIMESTAMP(">Rendering Directional Light " + itos(i));
- _light_instance_update_shadow(lights_with_shadow[i], p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect, p_shadow_atlas, scenario);
+ _light_instance_update_shadow(lights_with_shadow[i], p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect, p_shadow_atlas, scenario, p_screen_lod_threshold);
RENDER_TIMESTAMP("<Rendering Directional Light " + itos(i));
}
@@ -2295,7 +2358,7 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca
if (redraw) {
//must redraw!
RENDER_TIMESTAMP(">Rendering Light " + itos(i));
- light->shadow_dirty = _light_instance_update_shadow(ins, p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect, p_shadow_atlas, scenario);
+ 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);
RENDER_TIMESTAMP("<Rendering Light " + itos(i));
}
}
@@ -2344,6 +2407,9 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca
} else if ((1 << ins->base_type) & RS::INSTANCE_GEOMETRY_MASK) {
if (ins->baked_light) {
keep = true;
+ if (ins->mesh_instance.is_valid()) {
+ RSG::storage->mesh_instance_check_for_update(ins->mesh_instance);
+ }
}
}
@@ -2355,6 +2421,8 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca
}
}
+ RSG::storage->update_mesh_instances();
+
scene_render->render_sdfgi(p_render_buffers, i, (RendererSceneRender::InstanceBase **)instance_shadow_cull_result, sdfgi_cull_count);
//have to save updated cascades, then update static lights.
}
@@ -2388,7 +2456,7 @@ RID RendererSceneCull::_render_get_environment(RID p_camera, RID p_scenario) {
return RID();
}
-void RendererSceneCull::_render_scene(RID p_render_buffers, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_environment, RID p_force_camera_effects, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass) {
+void RendererSceneCull::_render_scene(RID p_render_buffers, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_environment, RID p_force_camera_effects, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold) {
Scenario *scenario = scenario_owner.getornull(p_scenario);
RID camera_effects;
@@ -2400,7 +2468,7 @@ void RendererSceneCull::_render_scene(RID p_render_buffers, const Transform p_ca
/* PROCESS GEOMETRY AND DRAW SCENE */
RENDER_TIMESTAMP("Render Scene ");
- scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, (RendererSceneRender::InstanceBase **)instance_cull_result, instance_cull_count, light_instance_cull_result, light_cull_count + directional_light_count, reflection_probe_instance_cull_result, reflection_probe_cull_count, gi_probe_instance_cull_result, gi_probe_cull_count, decal_instance_cull_result, decal_cull_count, (RendererSceneRender::InstanceBase **)lightmap_cull_result, lightmap_cull_count, p_environment, camera_effects, p_shadow_atlas, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass);
+ scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, (RendererSceneRender::InstanceBase **)instance_cull_result, instance_cull_count, light_instance_cull_result, light_cull_count + directional_light_count, reflection_probe_instance_cull_result, reflection_probe_cull_count, gi_probe_instance_cull_result, gi_probe_cull_count, decal_instance_cull_result, decal_cull_count, (RendererSceneRender::InstanceBase **)lightmap_cull_result, lightmap_cull_count, 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);
}
void RendererSceneCull::render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) {
@@ -2415,7 +2483,7 @@ void RendererSceneCull::render_empty_scene(RID p_render_buffers, RID p_scenario,
environment = scenario->fallback_environment;
}
RENDER_TIMESTAMP("Render Empty Scene ");
- scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0, environment, RID(), p_shadow_atlas, scenario->reflection_atlas, RID(), 0);
+ scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0, environment, RID(), p_shadow_atlas, scenario->reflection_atlas, RID(), 0, 0);
#endif
}
@@ -2453,6 +2521,8 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int
Vector3 extents = RSG::storage->reflection_probe_get_extents(p_instance->base);
Vector3 origin_offset = RSG::storage->reflection_probe_get_origin_offset(p_instance->base);
float max_distance = RSG::storage->reflection_probe_get_origin_max_distance(p_instance->base);
+ float size = scene_render->reflection_atlas_get_size(scenario->reflection_atlas);
+ float lod_threshold = RSG::storage->reflection_probe_get_lod_threshold(p_instance->base) / size;
Vector3 edge = view_normals[p_step] * extents;
float distance = ABS(view_normals[p_step].dot(edge) - view_normals[p_step].dot(origin_offset)); //distance from origin offset to actual view distance limit
@@ -2476,8 +2546,8 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int
}
RENDER_TIMESTAMP("Render Reflection Probe, Step " + itos(p_step));
- _prepare_scene(xform, cm, false, false, RID(), RID(), RSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, use_shadows);
- _render_scene(RID(), xform, cm, false, RID(), RID(), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, p_step);
+ _prepare_scene(xform, cm, false, false, RID(), RID(), RSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, lod_threshold, use_shadows);
+ _render_scene(RID(), xform, cm, false, RID(), RID(), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, p_step, lod_threshold);
} else {
//do roughness postprocess step until it believes it's done
@@ -2795,13 +2865,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) {
int new_mat_count = RSG::storage->mesh_get_surface_count(p_instance->base);
p_instance->materials.resize(new_mat_count);
- int new_blend_shape_count = RSG::storage->mesh_get_blend_shape_count(p_instance->base);
- if (new_blend_shape_count != p_instance->blend_values.size()) {
- p_instance->blend_values.resize(new_blend_shape_count);
- for (int i = 0; i < new_blend_shape_count; i++) {
- p_instance->blend_values.write[i] = 0;
- }
- }
+ _instance_update_mesh_instance(p_instance);
}
if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) {
diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h
index 46ca983986..4d82d873cc 100644
--- a/servers/rendering/renderer_scene_cull.h
+++ b/servers/rendering/renderer_scene_cull.h
@@ -89,7 +89,7 @@ public:
fov = 75;
type = PERSPECTIVE;
znear = 0.05;
- zfar = 100;
+ zfar = 4000;
size = 1.0;
offset = Vector2();
vaspect = false;
@@ -138,6 +138,8 @@ public:
static void *_instance_pair(void *p_self, OctreeElementID, Instance *p_A, int, OctreeElementID, Instance *p_B, int);
static void _instance_unpair(void *p_self, OctreeElementID, Instance *p_A, int, OctreeElementID, Instance *p_B, int, void *);
+ static void _instance_update_mesh_instance(Instance *p_instance);
+
virtual RID scenario_create();
virtual void scenario_set_debug(RID p_scenario, RS::ScenarioDebugMode p_debug_mode);
@@ -445,6 +447,7 @@ public:
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_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);
void _update_instance_shader_parameters_from_material(Map<StringName, RendererSceneRender::InstanceBase::InstanceShaderParameter> &isparams, const Map<StringName, RendererSceneRender::InstanceBase::InstanceShaderParameter> &existing_isparams, RID p_material);
@@ -458,17 +461,17 @@ public:
_FORCE_INLINE_ void _update_dirty_instance(Instance *p_instance);
_FORCE_INLINE_ void _update_instance_lightmap_captures(Instance *p_instance);
- _FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario);
+ _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);
RID _render_get_environment(RID p_camera, RID p_scenario);
bool _render_reflection_probe_step(Instance *p_instance, int p_step);
- void _prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, bool p_using_shadows = true);
- void _render_scene(RID p_render_buffers, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_environment, RID p_force_camera_effects, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
+ void _prepare_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, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, float p_screen_lod_threshold, bool p_using_shadows = true);
+ void _render_scene(RID p_render_buffers, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_environment, RID p_force_camera_effects, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold);
void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas);
- void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas);
- void render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas);
+ void 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 update_dirty_instances();
void render_particle_colliders();
diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h
index 0aae67fd34..e1f3ea9b6b 100644
--- a/servers/rendering/renderer_scene_render.h
+++ b/servers/rendering/renderer_scene_render.h
@@ -135,10 +135,12 @@ public:
RID skeleton;
RID material_override;
- RID instance_data;
+ RID mesh_instance; //only used for meshes and when skeleton/blendshapes exist
Transform transform;
+ float lod_bias;
+
int depth_layer;
uint32_t layer_mask;
@@ -149,8 +151,6 @@ public:
Vector<RID> reflection_probe_instances;
Vector<RID> gi_probe_instances;
- Vector<float> blend_values;
-
RS::ShadowCastingSetting cast_shadows;
//fit in 32 bits
@@ -197,6 +197,7 @@ public:
lightmap_slice_index = 0;
lightmap = nullptr;
lightmap_cull_index = 0;
+ lod_bias = 1.0;
}
virtual ~InstanceBase() {
@@ -214,6 +215,7 @@ public:
virtual RID reflection_atlas_create() = 0;
virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) = 0;
+ virtual 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;
@@ -233,9 +235,9 @@ public:
virtual void gi_probe_set_quality(RS::GIProbeQuality) = 0;
- virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0;
+ virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold) = 0;
- virtual void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) = 0;
+ virtual void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_lod_threshold = 0.0) = 0;
virtual void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0;
virtual void render_sdfgi(RID p_render_buffers, int p_region, InstanceBase **p_cull_result, int p_cull_count) = 0;
virtual void render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const RID **p_positional_light_cull_result, const uint32_t *p_positional_light_cull_count) = 0;
diff --git a/servers/rendering/renderer_storage.h b/servers/rendering/renderer_storage.h
index 03d4397d77..895a7a5be8 100644
--- a/servers/rendering/renderer_storage.h
+++ b/servers/rendering/renderer_storage.h
@@ -187,6 +187,8 @@ public:
virtual RID mesh_create() = 0;
+ virtual void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) = 0;
+
/// Returns stride
virtual void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) = 0;
@@ -211,6 +213,16 @@ public:
virtual void mesh_clear(RID p_mesh) = 0;
+ virtual bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) = 0;
+
+ /* MESH INSTANCE */
+
+ virtual RID mesh_instance_create(RID p_base) = 0;
+ virtual void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) = 0;
+ virtual void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) = 0;
+ virtual void mesh_instance_check_for_update(RID p_mesh_instance) = 0;
+ virtual void update_mesh_instances() = 0;
+
/* MULTIMESH API */
virtual RID multimesh_create() = 0;
@@ -326,6 +338,7 @@ public:
virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) = 0;
virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) = 0;
virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) = 0;
+ virtual void reflection_probe_set_lod_threshold(RID p_probe, float p_ratio) = 0;
virtual AABB reflection_probe_get_aabb(RID p_probe) const = 0;
virtual RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const = 0;
@@ -334,6 +347,7 @@ public:
virtual Vector3 reflection_probe_get_origin_offset(RID p_probe) const = 0;
virtual float reflection_probe_get_origin_max_distance(RID p_probe) const = 0;
virtual bool reflection_probe_renders_shadows(RID p_probe) const = 0;
+ virtual float reflection_probe_get_lod_threshold(RID p_probe) const = 0;
virtual void base_update_dependency(RID p_base, InstanceBaseDependency *p_instance) = 0;
virtual void skeleton_update_dependency(RID p_base, InstanceBaseDependency *p_instance) = 0;
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index 86bfda056b..ea95eb1189 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -79,10 +79,11 @@ void RendererViewport::_draw_3d(Viewport *p_viewport, XRInterface::Eyes p_eye) {
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, p_viewport->shadow_atlas);
+ 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, p_viewport->shadow_atlas);
+ RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->size, screen_lod_threshold, p_viewport->shadow_atlas);
}
RENDER_TIMESTAMP("<End Rendering 3D Scene");
}
@@ -885,6 +886,13 @@ void RendererViewport::viewport_set_use_debanding(RID p_viewport, bool p_use_deb
}
}
+void RendererViewport::viewport_set_lod_threshold(RID p_viewport, float p_pixels) {
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ viewport->lod_threshold = p_pixels;
+}
+
int RendererViewport::viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfo p_info) {
ERR_FAIL_INDEX_V(p_info, RS::VIEWPORT_RENDER_INFO_MAX, -1);
diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h
index 6634ef66e2..e836d05dfc 100644
--- a/servers/rendering/renderer_viewport.h
+++ b/servers/rendering/renderer_viewport.h
@@ -84,6 +84,8 @@ public:
bool sdf_active;
+ float lod_threshold = 1.0;
+
uint64_t last_pass = 0;
int render_info[RS::VIEWPORT_RENDER_INFO_MAX];
@@ -222,6 +224,8 @@ public:
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_lod_threshold(RID p_viewport, float p_pixels);
+
virtual int viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfo p_info);
virtual void viewport_set_debug_draw(RID p_viewport, RS::ViewportDebugDraw p_draw);
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index 1259b161bd..ba30670082 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -270,7 +270,7 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("sampler_create", "state"), &RenderingDevice::_sampler_create);
- ClassDB::bind_method(D_METHOD("vertex_buffer_create", "size_bytes", "data"), &RenderingDevice::vertex_buffer_create, DEFVAL(Vector<uint8_t>()));
+ ClassDB::bind_method(D_METHOD("vertex_buffer_create", "size_bytes", "data", "use_as_storage"), &RenderingDevice::vertex_buffer_create, DEFVAL(Vector<uint8_t>()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("vertex_format_create", "vertex_descriptions"), &RenderingDevice::_vertex_format_create);
ClassDB::bind_method(D_METHOD("index_buffer_create", "size_indices", "format", "data"), &RenderingDevice::index_buffer_create, DEFVAL(Vector<uint8_t>()), DEFVAL(false));
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
index 5fa37c2ce4..524d7749c9 100644
--- a/servers/rendering/rendering_device.h
+++ b/servers/rendering/rendering_device.h
@@ -564,7 +564,7 @@ public:
frequency = VERTEX_FREQUENCY_VERTEX;
}
};
- virtual RID vertex_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>()) = 0;
+ virtual RID vertex_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>(), bool p_use_as_storage = false) = 0;
typedef int64_t VertexFormatID;
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index e75fd0ee53..dd1a41a4f7 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -231,14 +231,17 @@ public:
/* MESH API */
- virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces) {
+ virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces, int p_blend_shape_count = 0) {
RID mesh = mesh_create();
+ mesh_set_blend_shape_count(mesh, p_blend_shape_count);
for (int i = 0; i < p_surfaces.size(); i++) {
mesh_add_surface(mesh, p_surfaces[i]);
}
return mesh;
}
+ BIND2(mesh_set_blend_shape_count, RID, int)
+
BIND0R(RID, mesh_create)
BIND2(mesh_add_surface, RID, const SurfaceData &)
@@ -356,6 +359,7 @@ public:
BIND2(reflection_probe_set_enable_shadows, RID, bool)
BIND2(reflection_probe_set_cull_mask, RID, uint32_t)
BIND2(reflection_probe_set_resolution, RID, int)
+ BIND2(reflection_probe_set_lod_threshold, RID, float)
/* DECAL API */
@@ -542,6 +546,7 @@ public:
BIND2(viewport_set_msaa, RID, ViewportMSAA)
BIND2(viewport_set_screen_space_aa, RID, ViewportScreenSpaceAA)
BIND2(viewport_set_use_debanding, RID, bool)
+ BIND2(viewport_set_lod_threshold, RID, float)
BIND2R(int, viewport_get_render_info, RID, ViewportRenderInfo)
BIND2(viewport_set_debug_draw, RID, ViewportDebugDraw)
@@ -670,6 +675,7 @@ public:
BIND5(instance_geometry_set_draw_range, RID, float, float, float, float)
BIND2(instance_geometry_set_as_instance_lod, RID, RID)
BIND4(instance_geometry_set_lightmap, RID, RID, const Rect2 &, int)
+ BIND2(instance_geometry_set_lod_bias, RID, float)
BIND3(instance_geometry_set_shader_parameter, RID, const StringName &, const Variant &)
BIND2RC(Variant, instance_geometry_get_shader_parameter, RID, const StringName &)
diff --git a/servers/rendering/rendering_server_wrap_mt.h b/servers/rendering/rendering_server_wrap_mt.h
index 2c230aaee4..20556779fe 100644
--- a/servers/rendering/rendering_server_wrap_mt.h
+++ b/servers/rendering/rendering_server_wrap_mt.h
@@ -143,10 +143,12 @@ public:
/* MESH API */
- virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces) {
- return rendering_server->mesh_create_from_surfaces(p_surfaces);
+ virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces, int p_blend_shape_count = 0) {
+ return rendering_server->mesh_create_from_surfaces(p_surfaces, p_blend_shape_count);
}
+ FUNC2(mesh_set_blend_shape_count, RID, int)
+
FUNCRID(mesh)
FUNC2(mesh_add_surface, RID, const SurfaceData &)
@@ -264,6 +266,7 @@ public:
FUNC2(reflection_probe_set_enable_shadows, RID, bool)
FUNC2(reflection_probe_set_cull_mask, RID, uint32_t)
FUNC2(reflection_probe_set_resolution, RID, int)
+ FUNC2(reflection_probe_set_lod_threshold, RID, float)
/* DECAL API */
@@ -448,6 +451,8 @@ public:
FUNC2(viewport_set_screen_space_aa, RID, ViewportScreenSpaceAA)
FUNC2(viewport_set_use_debanding, RID, bool)
+ FUNC2(viewport_set_lod_threshold, RID, float)
+
//this passes directly to avoid stalling, but it's pretty dangerous, so don't call after freeing a viewport
virtual int viewport_get_render_info(RID p_viewport, ViewportRenderInfo p_info) {
return rendering_server->viewport_get_render_info(p_viewport, p_info);
@@ -573,6 +578,7 @@ public:
FUNC5(instance_geometry_set_draw_range, RID, float, float, float, float)
FUNC2(instance_geometry_set_as_instance_lod, RID, RID)
FUNC4(instance_geometry_set_lightmap, RID, RID, const Rect2 &, int)
+ FUNC2(instance_geometry_set_lod_bias, RID, float)
FUNC3(instance_geometry_set_shader_parameter, RID, const StringName &, const Variant &)
FUNC2RC(Variant, instance_geometry_get_shader_parameter, RID, const StringName &)
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index b033b09303..b643b14040 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -620,6 +620,8 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
r_bone_aabb.resize(total_bones);
+ int weight_count = (p_format & ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 8 : 4;
+
if (first) {
for (int i = 0; i < total_bones; i++) {
r_bone_aabb.write[i].size = Vector3(-1, -1, -1); //negative means unused
@@ -632,7 +634,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
bool any_valid = false;
- if (vertices.size() && bones.size() == vertices.size() * 4 && weights.size() == bones.size()) {
+ if (vertices.size() && bones.size() == vertices.size() * weight_count && weights.size() == bones.size()) {
int vs = vertices.size();
const Vector3 *rv = vertices.ptr();
const int *rb = bones.ptr();
@@ -642,9 +644,9 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
for (int i = 0; i < vs; i++) {
Vector3 v = rv[i];
- for (int j = 0; j < 4; j++) {
- int idx = rb[i * 4 + j];
- float w = rw[i * 4 + j];
+ for (int j = 0; j < weight_count; j++) {
+ int idx = rb[i * weight_count + j];
+ float w = rw[i * weight_count + j];
if (w == 0) {
continue; //break;
}
@@ -992,7 +994,6 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa
surface_data.vertex_count = array_len;
surface_data.index_data = index_array;
surface_data.index_count = index_array_len;
- surface_data.blend_shape_count = blend_shape_count;
surface_data.blend_shape_data = blend_shape_data;
surface_data.bone_aabbs = bone_aabb;
surface_data.lods = lods;
@@ -1311,10 +1312,10 @@ Array RenderingServer::mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_sur
uint32_t blend_shape_count = blend_shape_data.size() / divisor;
- ERR_FAIL_COND_V(blend_shape_count != sd.blend_shape_count, Array());
+ ERR_FAIL_COND_V(blend_shape_count != (uint32_t)mesh_get_blend_shape_count(p_mesh), Array());
Array blend_shape_array;
- blend_shape_array.resize(blend_shape_count);
+ blend_shape_array.resize(mesh_get_blend_shape_count(p_mesh));
for (uint32_t i = 0; i < blend_shape_count; i++) {
Vector<uint8_t> bs_data = blend_shape_data.subarray(i * divisor, (i + 1) * divisor - 1);
Vector<uint8_t> unused;
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 5865cc7adf..6f7359b276 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -282,8 +282,6 @@ public:
Vector<uint8_t> index_data;
uint32_t index_count = 0;
- uint32_t blend_shape_count = 0;
-
AABB aabb;
struct LOD {
float edge_length;
@@ -297,9 +295,11 @@ public:
RID material;
};
- virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces) = 0;
+ virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces, int p_blend_shape_count = 0) = 0;
virtual RID mesh_create() = 0;
+ virtual void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) = 0;
+
virtual uint32_t mesh_surface_get_format_offset(uint32_t p_format, int p_vertex_len, int p_array_index) const;
virtual uint32_t mesh_surface_get_format_vertex_stride(uint32_t p_format, int p_vertex_len) const;
virtual uint32_t mesh_surface_get_format_attribute_stride(uint32_t p_format, int p_vertex_len) const;
@@ -507,6 +507,7 @@ public:
virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) = 0;
virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) = 0;
virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution) = 0;
+ virtual void reflection_probe_set_lod_threshold(RID p_probe, float p_pixels) = 0;
/* DECAL API */
@@ -805,6 +806,8 @@ public:
virtual void viewport_set_use_debanding(RID p_viewport, bool p_use_debanding) = 0;
+ virtual void viewport_set_lod_threshold(RID p_viewport, float p_pixels) = 0;
+
enum ViewportRenderInfo {
VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME,
VIEWPORT_RENDER_INFO_VERTICES_IN_FRAME,
@@ -836,6 +839,7 @@ public:
VIEWPORT_DEBUG_DRAW_SDFGI,
VIEWPORT_DEBUG_DRAW_SDFGI_PROBES,
VIEWPORT_DEBUG_DRAW_GI_BUFFER,
+ VIEWPORT_DEBUG_DRAW_DISABLE_LOD,
};
@@ -1142,6 +1146,7 @@ public:
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_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;
virtual void instance_geometry_set_shader_parameter(RID p_instance, const StringName &, const Variant &p_value) = 0;
virtual Variant instance_geometry_get_shader_parameter(RID p_instance, const StringName &) const = 0;
diff --git a/servers/text_server.cpp b/servers/text_server.cpp
index 23bcefa80d..30dfa60ba3 100644
--- a/servers/text_server.cpp
+++ b/servers/text_server.cpp
@@ -231,6 +231,10 @@ void TextServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("font_get_antialiased", "font"), &TextServer::font_get_antialiased);
ClassDB::bind_method(D_METHOD("font_get_feature_list", "font"), &TextServer::font_get_feature_list);
+ ClassDB::bind_method(D_METHOD("font_get_variation_list", "font"), &TextServer::font_get_variation_list);
+
+ ClassDB::bind_method(D_METHOD("font_set_variation", "font", "tag", "value"), &TextServer::font_set_variation);
+ ClassDB::bind_method(D_METHOD("font_get_variation", "font", "tag"), &TextServer::font_get_variation);
ClassDB::bind_method(D_METHOD("font_set_hinting", "font", "hinting"), &TextServer::font_set_hinting);
ClassDB::bind_method(D_METHOD("font_get_hinting", "font"), &TextServer::font_get_hinting);
@@ -372,6 +376,7 @@ void TextServer::_bind_methods() {
BIND_ENUM_CONSTANT(GRAPHEME_IS_BREAK_SOFT);
BIND_ENUM_CONSTANT(GRAPHEME_IS_TAB);
BIND_ENUM_CONSTANT(GRAPHEME_IS_ELONGATION);
+ BIND_ENUM_CONSTANT(GRAPHEME_IS_PUNCTUATION);
/* Hinting */
BIND_ENUM_CONSTANT(HINTING_NONE);
@@ -385,6 +390,7 @@ void TextServer::_bind_methods() {
BIND_ENUM_CONSTANT(FEATURE_KASHIDA_JUSTIFICATION);
BIND_ENUM_CONSTANT(FEATURE_BREAK_ITERATORS);
BIND_ENUM_CONSTANT(FEATURE_FONT_SYSTEM);
+ BIND_ENUM_CONSTANT(FEATURE_FONT_VARIABLE);
BIND_ENUM_CONSTANT(FEATURE_USE_SUPPORT_DATA);
}
@@ -674,7 +680,7 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks(RID p_shaped, float p_w
Vector<Vector2i> TextServer::shaped_text_get_word_breaks(RID p_shaped) const {
Vector<Vector2i> words;
- const_cast<TextServer *>(this)->shaped_text_update_breaks(p_shaped);
+ const_cast<TextServer *>(this)->shaped_text_update_justification_ops(p_shaped);
const Vector<Glyph> &logical = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped);
const Vector2i &range = shaped_text_get_range(p_shaped);
@@ -685,8 +691,8 @@ Vector<Vector2i> TextServer::shaped_text_get_word_breaks(RID p_shaped) const {
for (int i = 0; i < l_size; i++) {
if (l_gl[i].count > 0) {
- if ((l_gl[i].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) {
- words.push_back(Vector2i(word_start, l_gl[i].end - 1));
+ if (((l_gl[i].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) || ((l_gl[i].flags & GRAPHEME_IS_PUNCTUATION) == GRAPHEME_IS_PUNCTUATION)) {
+ words.push_back(Vector2i(word_start, l_gl[i].start));
word_start = l_gl[i].end;
}
}
diff --git a/servers/text_server.h b/servers/text_server.h
index 6796b7f1d6..a9b8649268 100644
--- a/servers/text_server.h
+++ b/servers/text_server.h
@@ -74,11 +74,12 @@ public:
GRAPHEME_IS_VALID = 1 << 0, // Glyph is valid.
GRAPHEME_IS_RTL = 1 << 1, // Glyph is right-to-left.
GRAPHEME_IS_VIRTUAL = 1 << 2, // Glyph is not part of source string (added by fit_to_width function, do not affect caret movement).
- GRAPHEME_IS_SPACE = 1 << 3, // Is whitespace (for justification).
- GRAPHEME_IS_BREAK_HARD = 1 << 4, // Is line break (mandatory break, e.g "\n")
- GRAPHEME_IS_BREAK_SOFT = 1 << 5, // Is line break (optional break, e.g space)
- GRAPHEME_IS_TAB = 1 << 6, // Is tab or vertical tab
- GRAPHEME_IS_ELONGATION = 1 << 7 // Elongation (e.g kashida), glyph can be duplicated or truncated to fit line to width.
+ GRAPHEME_IS_SPACE = 1 << 3, // Is whitespace (for justification and word breaks).
+ GRAPHEME_IS_BREAK_HARD = 1 << 4, // Is line break (mandatory break, e.g. "\n").
+ GRAPHEME_IS_BREAK_SOFT = 1 << 5, // Is line break (optional break, e.g. space).
+ GRAPHEME_IS_TAB = 1 << 6, // Is tab or vertical tab.
+ GRAPHEME_IS_ELONGATION = 1 << 7, // Elongation (e.g. kashida), glyph can be duplicated or truncated to fit line to width.
+ GRAPHEME_IS_PUNCTUATION = 1 << 8 // Punctuation (can be used as word break, but not line break or justifiction).
};
enum Hinting {
@@ -94,7 +95,8 @@ public:
FEATURE_KASHIDA_JUSTIFICATION = 1 << 3,
FEATURE_BREAK_ITERATORS = 1 << 4,
FEATURE_FONT_SYSTEM = 1 << 5,
- FEATURE_USE_SUPPORT_DATA = 1 << 6
+ FEATURE_FONT_VARIABLE = 1 << 6,
+ FEATURE_USE_SUPPORT_DATA = 1 << 7
};
struct Glyph {
@@ -103,7 +105,7 @@ public:
uint8_t count = 0; // Number of glyphs in the grapheme, set in the first glyph only.
uint8_t repeat = 1; // Draw multiple times in the row.
- uint8_t flags = 0; // Grapheme flags (valid, rtl, virtual), set in the first glyph only.
+ uint16_t flags = 0; // Grapheme flags (valid, rtl, virtual), set in the first glyph only.
float x_off = 0.f; // Offset from the origin of the glyph on baseline.
float y_off = 0.f;
@@ -246,6 +248,10 @@ public:
virtual bool font_get_antialiased(RID p_font) const = 0;
virtual Dictionary font_get_feature_list(RID p_font) const { return Dictionary(); };
+ virtual Dictionary font_get_variation_list(RID p_font) const { return Dictionary(); };
+
+ virtual void font_set_variation(RID p_font, const String &p_name, double p_value){};
+ virtual double font_get_variation(RID p_font, const String &p_name) const { return 0; };
virtual void font_set_distance_field_hint(RID p_font, bool p_distance_field) = 0;
virtual bool font_get_distance_field_hint(RID p_font) const = 0;
diff --git a/tests/data/translations.csv b/tests/data/translations.csv
new file mode 100644
index 0000000000..4c9ad4996a
--- /dev/null
+++ b/tests/data/translations.csv
@@ -0,0 +1,3 @@
+keys,en,de
+GOOD_MORNING,"Good Morning","Guten Morgen"
+GOOD_EVENING,"Good Evening",""
diff --git a/tests/test_aabb.h b/tests/test_aabb.h
index 8acd2a9963..404a73a95f 100644
--- a/tests/test_aabb.h
+++ b/tests/test_aabb.h
@@ -298,6 +298,12 @@ TEST_CASE("[AABB] Get longest/shortest axis") {
"get_shortest_axis() should return the expected value.");
}
+#ifndef _MSC_VER
+#warning Support tests need to be re-done
+#endif
+
+/* Support function was actually broken. As it was fixed, the tests now fail. Tests need to be re-done.
+
TEST_CASE("[AABB] Get support") {
const AABB aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(4, 5, 6));
CHECK_MESSAGE(
@@ -319,7 +325,7 @@ TEST_CASE("[AABB] Get support") {
aabb.get_support(Vector3()).is_equal_approx(Vector3(2.5, 7, 3.5)),
"get_support() should return the expected value with a null vector.");
}
-
+*/
TEST_CASE("[AABB] Grow") {
const AABB aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(4, 5, 6));
CHECK_MESSAGE(
diff --git a/tests/test_file_access.h b/tests/test_file_access.h
new file mode 100644
index 0000000000..0d5c9d79ce
--- /dev/null
+++ b/tests/test_file_access.h
@@ -0,0 +1,64 @@
+/*************************************************************************/
+/* test_file_access.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_FILE_ACCESS_H
+#define TEST_FILE_ACCESS_H
+
+#include "core/os/file_access.h"
+
+namespace TestFileAccess {
+
+TEST_CASE("[FileAccess] CSV read") {
+ FileAccess *f = FileAccess::open("tests/data/translations.csv", FileAccess::READ);
+
+ Vector<String> header = f->get_csv_line(); // Default delimiter: ","
+ REQUIRE(header.size() == 3);
+
+ Vector<String> row1 = f->get_csv_line(",");
+ REQUIRE(row1.size() == 3);
+ CHECK(row1[0] == "GOOD_MORNING");
+ CHECK(row1[1] == "Good Morning");
+ CHECK(row1[2] == "Guten Morgen");
+
+ Vector<String> row2 = f->get_csv_line();
+ REQUIRE(row2.size() == 3);
+ CHECK(row2[0] == "GOOD_EVENING");
+ CHECK(row2[1] == "Good Evening");
+ CHECK(row2[2] == ""); // Use case: not yet translated!
+
+ // https://github.com/godotengine/godot/issues/44269
+ CHECK_MESSAGE(row2[2] != "\"", "Should not parse empty string as a single double quote.");
+
+ f->close();
+ memdelete(f);
+}
+} // namespace TestFileAccess
+
+#endif // TEST_FILE_ACCESS_H
diff --git a/tests/test_list.h b/tests/test_list.h
index 1b23233838..8d29bd907f 100644
--- a/tests/test_list.h
+++ b/tests/test_list.h
@@ -45,6 +45,276 @@ static void populate_integers(List<int> &p_list, List<int>::Element *r_elements[
}
}
+TEST_CASE("[List] Push/pop back") {
+ List<String> list;
+
+ List<String>::Element *n;
+ n = list.push_back("A");
+ CHECK(n->get() == "A");
+ n = list.push_back("B");
+ CHECK(n->get() == "B");
+ n = list.push_back("C");
+ CHECK(n->get() == "C");
+
+ CHECK(list.size() == 3);
+ CHECK(!list.empty());
+
+ String v;
+ v = list.back()->get();
+ list.pop_back();
+ CHECK(v == "C");
+ v = list.back()->get();
+ list.pop_back();
+ CHECK(v == "B");
+ v = list.back()->get();
+ list.pop_back();
+ CHECK(v == "A");
+
+ CHECK(list.size() == 0);
+ CHECK(list.empty());
+
+ CHECK(list.back() == nullptr);
+ CHECK(list.front() == nullptr);
+}
+
+TEST_CASE("[List] Push/pop front") {
+ List<String> list;
+
+ List<String>::Element *n;
+ n = list.push_front("A");
+ CHECK(n->get() == "A");
+ n = list.push_front("B");
+ CHECK(n->get() == "B");
+ n = list.push_front("C");
+ CHECK(n->get() == "C");
+
+ CHECK(list.size() == 3);
+ CHECK(!list.empty());
+
+ String v;
+ v = list.front()->get();
+ list.pop_front();
+ CHECK(v == "C");
+ v = list.front()->get();
+ list.pop_front();
+ CHECK(v == "B");
+ v = list.front()->get();
+ list.pop_front();
+ CHECK(v == "A");
+
+ CHECK(list.size() == 0);
+ CHECK(list.empty());
+
+ CHECK(list.back() == nullptr);
+ CHECK(list.front() == nullptr);
+}
+
+TEST_CASE("[List] Set and get") {
+ List<String> list;
+ list.push_back("A");
+
+ List<String>::Element *n = list.front();
+ CHECK(n->get() == "A");
+
+ n->set("X");
+ CHECK(n->get() == "X");
+}
+
+TEST_CASE("[List] Insert before") {
+ List<String> list;
+ List<String>::Element *a = list.push_back("A");
+ List<String>::Element *b = list.push_back("B");
+ List<String>::Element *c = list.push_back("C");
+
+ list.insert_before(b, "I");
+
+ CHECK(a->next()->get() == "I");
+ CHECK(c->prev()->prev()->get() == "I");
+ CHECK(list.front()->next()->get() == "I");
+ CHECK(list.back()->prev()->prev()->get() == "I");
+}
+
+TEST_CASE("[List] Insert after") {
+ List<String> list;
+ List<String>::Element *a = list.push_back("A");
+ List<String>::Element *b = list.push_back("B");
+ List<String>::Element *c = list.push_back("C");
+
+ list.insert_after(b, "I");
+
+ CHECK(a->next()->next()->get() == "I");
+ CHECK(c->prev()->get() == "I");
+ CHECK(list.front()->next()->next()->get() == "I");
+ CHECK(list.back()->prev()->get() == "I");
+}
+
+TEST_CASE("[List] Insert before null") {
+ List<String> list;
+ List<String>::Element *a = list.push_back("A");
+ List<String>::Element *b = list.push_back("B");
+ List<String>::Element *c = list.push_back("C");
+
+ list.insert_before(nullptr, "I");
+
+ CHECK(a->next()->get() == "B");
+ CHECK(b->get() == "B");
+ CHECK(c->prev()->prev()->get() == "A");
+ CHECK(list.front()->next()->get() == "B");
+ CHECK(list.back()->prev()->prev()->get() == "B");
+ CHECK(list.back()->get() == "I");
+}
+
+TEST_CASE("[List] Insert after null") {
+ List<String> list;
+ List<String>::Element *a = list.push_back("A");
+ List<String>::Element *b = list.push_back("B");
+ List<String>::Element *c = list.push_back("C");
+
+ list.insert_after(nullptr, "I");
+
+ CHECK(a->next()->get() == "B");
+ CHECK(b->get() == "B");
+ CHECK(c->prev()->prev()->get() == "A");
+ CHECK(list.front()->next()->get() == "B");
+ CHECK(list.back()->prev()->prev()->get() == "B");
+ CHECK(list.back()->get() == "I");
+}
+
+TEST_CASE("[List] Find") {
+ List<int> list;
+ List<int>::Element *n[10];
+ // Indices match values.
+ populate_integers(list, n, 10);
+
+ for (int i = 0; i < 10; ++i) {
+ CHECK(n[i]->get() == list.find(i)->get());
+ }
+}
+
+TEST_CASE("[List] Erase (by value)") {
+ List<int> list;
+ List<int>::Element *n[4];
+ // Indices match values.
+ populate_integers(list, n, 4);
+
+ CHECK(list.front()->next()->next()->get() == 2);
+ bool erased = list.erase(2); // 0, 1, 3.
+ CHECK(erased);
+ CHECK(list.size() == 3);
+
+ // The pointer n[2] points to the freed memory which is not reset to zero,
+ // so the below assertion may pass, but this relies on undefined behavior.
+ // CHECK(n[2]->get() == 2);
+
+ CHECK(list.front()->get() == 0);
+ CHECK(list.front()->next()->next()->get() == 3);
+ CHECK(list.back()->get() == 3);
+ CHECK(list.back()->prev()->get() == 1);
+
+ CHECK(n[1]->next()->get() == 3);
+ CHECK(n[3]->prev()->get() == 1);
+
+ erased = list.erase(9000); // Doesn't exist.
+ CHECK(!erased);
+}
+
+TEST_CASE("[List] Erase (by element)") {
+ List<int> list;
+ List<int>::Element *n[4];
+ // Indices match values.
+ populate_integers(list, n, 4);
+
+ bool erased = list.erase(n[2]);
+ CHECK(erased);
+ CHECK(list.size() == 3);
+ CHECK(n[1]->next()->get() == 3);
+ CHECK(n[3]->prev()->get() == 1);
+}
+
+TEST_CASE("[List] Element erase") {
+ List<int> list;
+ List<int>::Element *n[4];
+ // Indices match values.
+ populate_integers(list, n, 4);
+
+ n[2]->erase();
+
+ CHECK(list.size() == 3);
+ CHECK(n[1]->next()->get() == 3);
+ CHECK(n[3]->prev()->get() == 1);
+}
+
+TEST_CASE("[List] Clear") {
+ List<int> list;
+ List<int>::Element *n[100];
+ populate_integers(list, n, 100);
+
+ list.clear();
+
+ CHECK(list.size() == 0);
+ CHECK(list.empty());
+}
+
+TEST_CASE("[List] Invert") {
+ List<int> list;
+ List<int>::Element *n[4];
+ populate_integers(list, n, 4);
+
+ list.invert();
+
+ CHECK(list.front()->get() == 3);
+ CHECK(list.front()->next()->get() == 2);
+ CHECK(list.back()->prev()->get() == 1);
+ CHECK(list.back()->get() == 0);
+}
+
+TEST_CASE("[List] Move to front") {
+ List<int> list;
+ List<int>::Element *n[4];
+ populate_integers(list, n, 4);
+
+ list.move_to_front(n[3]);
+
+ CHECK(list.front()->get() == 3);
+ CHECK(list.back()->get() == 2);
+}
+
+TEST_CASE("[List] Move to back") {
+ List<int> list;
+ List<int>::Element *n[4];
+ populate_integers(list, n, 4);
+
+ list.move_to_back(n[0]);
+
+ CHECK(list.back()->get() == 0);
+ CHECK(list.front()->get() == 1);
+}
+
+TEST_CASE("[List] Move before") {
+ List<int> list;
+ List<int>::Element *n[4];
+ populate_integers(list, n, 4);
+
+ list.move_before(n[3], n[1]);
+
+ CHECK(list.front()->next()->get() == n[3]->get());
+}
+
+TEST_CASE("[List] Sort") {
+ List<String> list;
+ list.push_back("D");
+ list.push_back("B");
+ list.push_back("A");
+ list.push_back("C");
+
+ list.sort();
+
+ CHECK(list.front()->get() == "A");
+ CHECK(list.front()->next()->get() == "B");
+ CHECK(list.back()->prev()->get() == "C");
+ CHECK(list.back()->get() == "D");
+}
+
TEST_CASE("[List] Swap adjacent front and back") {
List<int> list;
List<int>::Element *n[2];
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index a152f3d451..9f2c2d6911 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -42,6 +42,7 @@
#include "test_crypto.h"
#include "test_curve.h"
#include "test_expression.h"
+#include "test_file_access.h"
#include "test_gradient.h"
#include "test_gui.h"
#include "test_json.h"
diff --git a/tests/test_rect2.h b/tests/test_rect2.h
index aefceb1128..b1c588fda1 100644
--- a/tests/test_rect2.h
+++ b/tests/test_rect2.h
@@ -144,29 +144,29 @@ TEST_CASE("[Rect2] Absolute coordinates") {
"abs() should return the expected Rect2.");
}
-TEST_CASE("[Rect2] Clipping") {
+TEST_CASE("[Rect2] Intersecton") {
CHECK_MESSAGE(
- Rect2(0, 100, 1280, 720).clip(Rect2(0, 300, 100, 100)).is_equal_approx(Rect2(0, 300, 100, 100)),
- "clip() with fully enclosed Rect2 should return the expected result.");
+ 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.");
// The resulting Rect2 is 100 pixels high because the first Rect2 is vertically offset by 100 pixels.
CHECK_MESSAGE(
- Rect2(0, 100, 1280, 720).clip(Rect2(1200, 700, 100, 100)).is_equal_approx(Rect2(1200, 700, 80, 100)),
- "clip() with partially enclosed Rect2 should return the expected result.");
+ Rect2(0, 100, 1280, 720).intersection(Rect2(1200, 700, 100, 100)).is_equal_approx(Rect2(1200, 700, 80, 100)),
+ "intersection() with partially enclosed Rect2 should return the expected result.");
CHECK_MESSAGE(
- Rect2(0, 100, 1280, 720).clip(Rect2(-4000, -4000, 100, 100)).is_equal_approx(Rect2()),
- "clip() with non-enclosed Rect2 should return the expected result.");
+ Rect2(0, 100, 1280, 720).intersection(Rect2(-4000, -4000, 100, 100)).is_equal_approx(Rect2()),
+ "intersection() with non-enclosed Rect2 should return the expected result.");
}
TEST_CASE("[Rect2] Enclosing") {
CHECK_MESSAGE(
Rect2(0, 100, 1280, 720).encloses(Rect2(0, 300, 100, 100)),
- "clip() with fully contained Rect2 should return the expected result.");
+ "encloses() with fully contained Rect2 should return the expected result.");
CHECK_MESSAGE(
!Rect2(0, 100, 1280, 720).encloses(Rect2(1200, 700, 100, 100)),
- "clip() with partially contained Rect2 should return the expected result.");
+ "encloses() with partially contained Rect2 should return the expected result.");
CHECK_MESSAGE(
!Rect2(0, 100, 1280, 720).encloses(Rect2(-4000, -4000, 100, 100)),
- "clip() with non-contained Rect2 should return the expected result.");
+ "encloses() with non-contained Rect2 should return the expected result.");
}
TEST_CASE("[Rect2] Expanding") {
@@ -356,29 +356,29 @@ TEST_CASE("[Rect2i] Absolute coordinates") {
"abs() should return the expected Rect2i.");
}
-TEST_CASE("[Rect2i] Clipping") {
+TEST_CASE("[Rect2i] Intersection") {
CHECK_MESSAGE(
- Rect2i(0, 100, 1280, 720).clip(Rect2i(0, 300, 100, 100)) == Rect2i(0, 300, 100, 100),
- "clip() with fully enclosed Rect2i should return the expected result.");
+ Rect2i(0, 100, 1280, 720).intersection(Rect2i(0, 300, 100, 100)) == Rect2i(0, 300, 100, 100),
+ "intersection() with fully enclosed Rect2i should return the expected result.");
// The resulting Rect2i is 100 pixels high because the first Rect2i is vertically offset by 100 pixels.
CHECK_MESSAGE(
- Rect2i(0, 100, 1280, 720).clip(Rect2i(1200, 700, 100, 100)) == Rect2i(1200, 700, 80, 100),
- "clip() with partially enclosed Rect2i should return the expected result.");
+ Rect2i(0, 100, 1280, 720).intersection(Rect2i(1200, 700, 100, 100)) == Rect2i(1200, 700, 80, 100),
+ "intersection() with partially enclosed Rect2i should return the expected result.");
CHECK_MESSAGE(
- Rect2i(0, 100, 1280, 720).clip(Rect2i(-4000, -4000, 100, 100)) == Rect2i(),
- "clip() with non-enclosed Rect2i should return the expected result.");
+ Rect2i(0, 100, 1280, 720).intersection(Rect2i(-4000, -4000, 100, 100)) == Rect2i(),
+ "intersection() with non-enclosed Rect2i should return the expected result.");
}
TEST_CASE("[Rect2i] Enclosing") {
CHECK_MESSAGE(
Rect2i(0, 100, 1280, 720).encloses(Rect2i(0, 300, 100, 100)),
- "clip() with fully contained Rect2i should return the expected result.");
+ "encloses() with fully contained Rect2i should return the expected result.");
CHECK_MESSAGE(
!Rect2i(0, 100, 1280, 720).encloses(Rect2i(1200, 700, 100, 100)),
- "clip() with partially contained Rect2i should return the expected result.");
+ "encloses() with partially contained Rect2i should return the expected result.");
CHECK_MESSAGE(
!Rect2i(0, 100, 1280, 720).encloses(Rect2i(-4000, -4000, 100, 100)),
- "clip() with non-contained Rect2i should return the expected result.");
+ "encloses() with non-contained Rect2i should return the expected result.");
}
TEST_CASE("[Rect2i] Expanding") {
diff --git a/thirdparty/README.md b/thirdparty/README.md
index b2707e7f7c..73a62458c3 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -40,11 +40,9 @@ Files extracted from upstream source:
## bullet
- Upstream: https://github.com/bulletphysics/bullet3
-- Version: git pre-2.90 (cd8cf7521cbb8b7808126a6adebd47bb83ea166a, 2020)
+- Version: 3.07 (e32fc59c88a3908876949c6f2665e8d091d987fa, 2020)
- License: zlib
-Important: Synced with a pre-release version of bullet 2.90 from the master branch.
-
Files extracted from upstream source:
- src/* apart from CMakeLists.txt and premake4.lua files
@@ -341,7 +339,7 @@ changes are marked with `// -- GODOT --` comments.
## mbedtls
- Upstream: https://tls.mbed.org/
-- Version: 2.16.8 (2020)
+- Version: 2.16.9 (2020)
- License: Apache 2.0
File extracted from upstream release tarball:
@@ -358,6 +356,21 @@ File extracted from upstream release tarball:
for light bundling with core.
+## meshoptimizer
+
+- Upstream: https://github.com/zeux/meshoptimizer
+- Version: 0.15 (2020)
+- License: MIT
+
+File extracted from upstream release tarball:
+
+- All files in `src/`.
+
+Important: Some files have Godot-made changes.
+They can be applied with the patch in the `patches` folder, but are meant to be superseded
+by upstream API changes.
+
+
## miniupnpc
- Upstream: https://github.com/miniupnp/miniupnp/tree/master/miniupnpc
diff --git a/thirdparty/bullet/Bullet3OpenCL/NarrowphaseCollision/b3OptimizedBvh.cpp b/thirdparty/bullet/Bullet3OpenCL/NarrowphaseCollision/b3OptimizedBvh.cpp
index 6f2c5251a0..4938fa17af 100644
--- a/thirdparty/bullet/Bullet3OpenCL/NarrowphaseCollision/b3OptimizedBvh.cpp
+++ b/thirdparty/bullet/Bullet3OpenCL/NarrowphaseCollision/b3OptimizedBvh.cpp
@@ -285,7 +285,6 @@ void b3OptimizedBvh::updateBvhNodes(b3StridingMeshInterface* meshInterface, int
meshInterface->getLockedReadOnlyVertexIndexBase(&vertexbase, numverts, type, stride, &indexbase, indexstride, numfaces, indicestype, nodeSubPart);
curNodeSubPart = nodeSubPart;
- b3Assert(indicestype == PHY_INTEGER || indicestype == PHY_SHORT);
}
//triangles->getLockedReadOnlyVertexIndexBase(vertexBase,numVerts,
@@ -293,7 +292,13 @@ void b3OptimizedBvh::updateBvhNodes(b3StridingMeshInterface* meshInterface, int
for (int j = 2; j >= 0; j--)
{
- int graphicsindex = indicestype == PHY_SHORT ? ((unsigned short*)gfxbase)[j] : gfxbase[j];
+ int graphicsindex;
+ switch (indicestype) {
+ case PHY_INTEGER: graphicsindex = gfxbase[j]; break;
+ case PHY_SHORT: graphicsindex = ((unsigned short*)gfxbase)[j]; break;
+ case PHY_UCHAR: graphicsindex = ((unsigned char*)gfxbase)[j]; break;
+ default: b3Assert(0);
+ }
if (type == PHY_FLOAT)
{
float* graphicsbase = (float*)(vertexbase + graphicsindex * stride);
diff --git a/thirdparty/bullet/Bullet3Serialize/Bullet2FileLoader/b3File.cpp b/thirdparty/bullet/Bullet3Serialize/Bullet2FileLoader/b3File.cpp
index 145de62db3..f6c779a919 100644
--- a/thirdparty/bullet/Bullet3Serialize/Bullet2FileLoader/b3File.cpp
+++ b/thirdparty/bullet/Bullet3Serialize/Bullet2FileLoader/b3File.cpp
@@ -851,12 +851,12 @@ void bFile::swapData(char *data, short type, int arraySize, bool ignoreEndianFla
void bFile::safeSwapPtr(char *dst, const char *src)
{
+ if (!src || !dst)
+ return;
+
int ptrFile = mFileDNA->getPointerSize();
int ptrMem = mMemoryDNA->getPointerSize();
- if (!src && !dst)
- return;
-
if (ptrFile == ptrMem)
{
memcpy(dst, src, ptrMem);
diff --git a/thirdparty/bullet/BulletCollision/BroadphaseCollision/btQuantizedBvh.cpp b/thirdparty/bullet/BulletCollision/BroadphaseCollision/btQuantizedBvh.cpp
index 4954e773e2..19f1737b73 100644
--- a/thirdparty/bullet/BulletCollision/BroadphaseCollision/btQuantizedBvh.cpp
+++ b/thirdparty/bullet/BulletCollision/BroadphaseCollision/btQuantizedBvh.cpp
@@ -346,8 +346,6 @@ void btQuantizedBvh::reportAabbOverlappingNodex(btNodeOverlapCallback* nodeCallb
}
}
-int maxIterations = 0;
-
void btQuantizedBvh::walkStacklessTree(btNodeOverlapCallback* nodeCallback, const btVector3& aabbMin, const btVector3& aabbMax) const
{
btAssert(!m_useQuantization);
@@ -387,8 +385,6 @@ void btQuantizedBvh::walkStacklessTree(btNodeOverlapCallback* nodeCallback, cons
curIndex += escapeIndex;
}
}
- if (maxIterations < walkIterations)
- maxIterations = walkIterations;
}
/*
@@ -529,8 +525,6 @@ void btQuantizedBvh::walkStacklessTreeAgainstRay(btNodeOverlapCallback* nodeCall
curIndex += escapeIndex;
}
}
- if (maxIterations < walkIterations)
- maxIterations = walkIterations;
}
void btQuantizedBvh::walkStacklessQuantizedTreeAgainstRay(btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget, const btVector3& aabbMin, const btVector3& aabbMax, int startNodeIndex, int endNodeIndex) const
@@ -654,8 +648,6 @@ void btQuantizedBvh::walkStacklessQuantizedTreeAgainstRay(btNodeOverlapCallback*
curIndex += escapeIndex;
}
}
- if (maxIterations < walkIterations)
- maxIterations = walkIterations;
}
void btQuantizedBvh::walkStacklessQuantizedTree(btNodeOverlapCallback* nodeCallback, unsigned short int* quantizedQueryAabbMin, unsigned short int* quantizedQueryAabbMax, int startNodeIndex, int endNodeIndex) const
@@ -718,8 +710,6 @@ void btQuantizedBvh::walkStacklessQuantizedTree(btNodeOverlapCallback* nodeCallb
curIndex += escapeIndex;
}
}
- if (maxIterations < walkIterations)
- maxIterations = walkIterations;
}
//This traversal can be called from Playstation 3 SPU
diff --git a/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionObject.h b/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionObject.h
index 85dc488c8c..e085c40892 100644
--- a/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionObject.h
+++ b/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionObject.h
@@ -127,6 +127,7 @@ public:
enum CollisionFlags
{
+ CF_DYNAMIC_OBJECT = 0,
CF_STATIC_OBJECT = 1,
CF_KINEMATIC_OBJECT = 2,
CF_NO_CONTACT_RESPONSE = 4,
@@ -251,6 +252,16 @@ public:
m_checkCollideWith = m_objectsWithoutCollisionCheck.size() > 0;
}
+ int getNumObjectsWithoutCollision() const
+ {
+ return m_objectsWithoutCollisionCheck.size();
+ }
+
+ const btCollisionObject* getObjectWithoutCollision(int index)
+ {
+ return m_objectsWithoutCollisionCheck[index];
+ }
+
virtual bool checkCollideWithOverride(const btCollisionObject* co) const
{
int index = m_objectsWithoutCollisionCheck.findLinearSearch(co);
diff --git a/thirdparty/bullet/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp b/thirdparty/bullet/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp
index a4252c296a..a71700f58a 100644
--- a/thirdparty/bullet/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp
@@ -361,7 +361,13 @@ void btGenerateInternalEdgeInfo(btBvhTriangleMeshShape* trimeshShape, btTriangle
for (int j = 2; j >= 0; j--)
{
- int graphicsindex = indicestype == PHY_SHORT ? ((unsigned short*)gfxbase)[j] : gfxbase[j];
+ int graphicsindex;
+ switch (indicestype) {
+ case PHY_INTEGER: graphicsindex = gfxbase[j]; break;
+ case PHY_SHORT: graphicsindex = ((unsigned short*)gfxbase)[j]; break;
+ case PHY_UCHAR: graphicsindex = ((unsigned char*)gfxbase)[j]; break;
+ default: btAssert(0);
+ }
if (type == PHY_FLOAT)
{
float* graphicsbase = (float*)(vertexbase + graphicsindex * stride);
diff --git a/thirdparty/bullet/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp b/thirdparty/bullet/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp
index d663b3d6d6..c66ce58e3e 100644
--- a/thirdparty/bullet/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp
@@ -124,12 +124,17 @@ void btBvhTriangleMeshShape::performRaycast(btTriangleCallback* callback, const
nodeSubPart);
unsigned int* gfxbase = (unsigned int*)(indexbase + nodeTriangleIndex * indexstride);
- btAssert(indicestype == PHY_INTEGER || indicestype == PHY_SHORT);
const btVector3& meshScaling = m_meshInterface->getScaling();
for (int j = 2; j >= 0; j--)
{
- int graphicsindex = indicestype == PHY_SHORT ? ((unsigned short*)gfxbase)[j] : gfxbase[j];
+ int graphicsindex;
+ switch (indicestype) {
+ case PHY_INTEGER: graphicsindex = gfxbase[j]; break;
+ case PHY_SHORT: graphicsindex = ((unsigned short*)gfxbase)[j]; break;
+ case PHY_UCHAR: graphicsindex = ((unsigned char*)gfxbase)[j]; break;
+ default: btAssert(0);
+ }
if (type == PHY_FLOAT)
{
@@ -193,12 +198,17 @@ void btBvhTriangleMeshShape::performConvexcast(btTriangleCallback* callback, con
nodeSubPart);
unsigned int* gfxbase = (unsigned int*)(indexbase + nodeTriangleIndex * indexstride);
- btAssert(indicestype == PHY_INTEGER || indicestype == PHY_SHORT);
const btVector3& meshScaling = m_meshInterface->getScaling();
for (int j = 2; j >= 0; j--)
{
- int graphicsindex = indicestype == PHY_SHORT ? ((unsigned short*)gfxbase)[j] : gfxbase[j];
+ int graphicsindex;
+ switch (indicestype) {
+ case PHY_INTEGER: graphicsindex = gfxbase[j]; break;
+ case PHY_SHORT: graphicsindex = ((unsigned short*)gfxbase)[j]; break;
+ case PHY_UCHAR: graphicsindex = ((unsigned char*)gfxbase)[j]; break;
+ default: btAssert(0);
+ }
if (type == PHY_FLOAT)
{
diff --git a/thirdparty/bullet/BulletCollision/CollisionShapes/btCollisionShape.h b/thirdparty/bullet/BulletCollision/CollisionShapes/btCollisionShape.h
index c80e105a4d..16f9e0c77a 100644
--- a/thirdparty/bullet/BulletCollision/CollisionShapes/btCollisionShape.h
+++ b/thirdparty/bullet/BulletCollision/CollisionShapes/btCollisionShape.h
@@ -30,11 +30,12 @@ protected:
int m_shapeType;
void* m_userPointer;
int m_userIndex;
+ int m_userIndex2;
public:
BT_DECLARE_ALIGNED_ALLOCATOR();
- btCollisionShape() : m_shapeType(INVALID_SHAPE_PROXYTYPE), m_userPointer(0), m_userIndex(-1)
+ btCollisionShape() : m_shapeType(INVALID_SHAPE_PROXYTYPE), m_userPointer(0), m_userIndex(-1), m_userIndex2(-1)
{
}
@@ -137,6 +138,16 @@ public:
return m_userIndex;
}
+ void setUserIndex2(int index)
+ {
+ m_userIndex2 = index;
+ }
+
+ int getUserIndex2() const
+ {
+ return m_userIndex2;
+ }
+
virtual int calculateSerializeBufferSize() const;
///fills the dataBuffer and returns the struct name (and 0 on failure)
diff --git a/thirdparty/bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp b/thirdparty/bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp
index 34e7926f17..cab6980b65 100644
--- a/thirdparty/bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp
@@ -21,8 +21,7 @@ btHeightfieldTerrainShape::btHeightfieldTerrainShape(
int heightStickWidth, int heightStickLength, const void* heightfieldData,
btScalar heightScale, btScalar minHeight, btScalar maxHeight, int upAxis,
PHY_ScalarType hdt, bool flipQuadEdges)
- :m_userIndex2(-1),
- m_userValue3(0),
+ :m_userValue3(0),
m_triangleInfoMap(0)
{
initialize(heightStickWidth, heightStickLength, heightfieldData,
@@ -31,8 +30,7 @@ btHeightfieldTerrainShape::btHeightfieldTerrainShape(
}
btHeightfieldTerrainShape::btHeightfieldTerrainShape(int heightStickWidth, int heightStickLength, const void* heightfieldData, btScalar maxHeight, int upAxis, bool useFloatData, bool flipQuadEdges)
- :m_userIndex2(-1),
- m_userValue3(0),
+ : m_userValue3(0),
m_triangleInfoMap(0)
{
// legacy constructor: support only float or unsigned char,
diff --git a/thirdparty/bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h b/thirdparty/bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h
index 8dea98fc6b..2cf3c00721 100644
--- a/thirdparty/bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h
+++ b/thirdparty/bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h
@@ -114,7 +114,7 @@ protected:
int m_vboundsGridLength;
int m_vboundsChunkSize;
- int m_userIndex2;
+
btScalar m_userValue3;
struct btTriangleInfoMap* m_triangleInfoMap;
@@ -192,14 +192,6 @@ public:
virtual const char* getName() const { return "HEIGHTFIELD"; }
- void setUserIndex2(int index)
- {
- m_userIndex2 = index;
- }
- int getUserIndex2() const
- {
- return m_userIndex2;
- }
void setUserValue3(btScalar value)
{
m_userValue3 = value;
diff --git a/thirdparty/bullet/BulletCollision/CollisionShapes/btOptimizedBvh.cpp b/thirdparty/bullet/BulletCollision/CollisionShapes/btOptimizedBvh.cpp
index 687399e0a9..863ea6d6ac 100644
--- a/thirdparty/bullet/BulletCollision/CollisionShapes/btOptimizedBvh.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionShapes/btOptimizedBvh.cpp
@@ -286,7 +286,6 @@ void btOptimizedBvh::updateBvhNodes(btStridingMeshInterface* meshInterface, int
meshInterface->getLockedReadOnlyVertexIndexBase(&vertexbase, numverts, type, stride, &indexbase, indexstride, numfaces, indicestype, nodeSubPart);
curNodeSubPart = nodeSubPart;
- btAssert(indicestype == PHY_INTEGER || indicestype == PHY_SHORT);
}
//triangles->getLockedReadOnlyVertexIndexBase(vertexBase,numVerts,
@@ -294,7 +293,13 @@ void btOptimizedBvh::updateBvhNodes(btStridingMeshInterface* meshInterface, int
for (int j = 2; j >= 0; j--)
{
- int graphicsindex = indicestype == PHY_SHORT ? ((unsigned short*)gfxbase)[j] : gfxbase[j];
+ int graphicsindex;
+ switch (indicestype) {
+ case PHY_INTEGER: graphicsindex = gfxbase[j]; break;
+ case PHY_SHORT: graphicsindex = ((unsigned short*)gfxbase)[j]; break;
+ case PHY_UCHAR: graphicsindex = ((unsigned char*)gfxbase)[j]; break;
+ default: btAssert(0);
+ }
if (type == PHY_FLOAT)
{
float* graphicsbase = (float*)(vertexbase + graphicsindex * stride);
diff --git a/thirdparty/bullet/BulletCollision/CollisionShapes/btSdfCollisionShape.cpp b/thirdparty/bullet/BulletCollision/CollisionShapes/btSdfCollisionShape.cpp
index 4a95dbea4f..23c95ad3ff 100644
--- a/thirdparty/bullet/BulletCollision/CollisionShapes/btSdfCollisionShape.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionShapes/btSdfCollisionShape.cpp
@@ -2,8 +2,11 @@
#include "btMiniSDF.h"
#include "LinearMath/btAabbUtil2.h"
-struct btSdfCollisionShapeInternalData
+ATTRIBUTE_ALIGNED16(struct)
+btSdfCollisionShapeInternalData
{
+ BT_DECLARE_ALIGNED_ALLOCATOR();
+
btVector3 m_localScaling;
btScalar m_margin;
btMiniSDF m_sdf;
diff --git a/thirdparty/bullet/BulletCollision/Gimpact/btGImpactShape.h b/thirdparty/bullet/BulletCollision/Gimpact/btGImpactShape.h
index 5b85e87041..cc91079579 100644
--- a/thirdparty/bullet/BulletCollision/Gimpact/btGImpactShape.h
+++ b/thirdparty/bullet/BulletCollision/Gimpact/btGImpactShape.h
@@ -623,13 +623,21 @@ public:
i1 = s_indices[1];
i2 = s_indices[2];
}
- else
+ else if (indicestype == PHY_INTEGER)
{
unsigned int* i_indices = (unsigned int*)(indexbase + face_index * indexstride);
i0 = i_indices[0];
i1 = i_indices[1];
i2 = i_indices[2];
}
+ else
+ {
+ btAssert(indicestype == PHY_UCHAR);
+ unsigned char* i_indices = (unsigned char*)(indexbase + face_index * indexstride);
+ i0 = i_indices[0];
+ i1 = i_indices[1];
+ i2 = i_indices[2];
+ }
}
SIMD_FORCE_INLINE void get_vertex(unsigned int vertex_index, btVector3& vertex) const
diff --git a/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btGjkEpa2.cpp b/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btGjkEpa2.cpp
index 45d1817135..7d53f8624a 100644
--- a/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btGjkEpa2.cpp
+++ b/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btGjkEpa2.cpp
@@ -1049,7 +1049,8 @@ btScalar btGjkEpaSolver2::SignedDistance(const btVector3& position,
const btScalar length = delta.length();
results.normal = delta / length;
results.witnesses[0] += results.normal * margin;
- return (length - margin);
+ results.distance = length - margin;
+ return results.distance;
}
else
{
diff --git a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btBatchedConstraints.cpp b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btBatchedConstraints.cpp
index 27f76b8425..0f5ed1c2ce 100644
--- a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btBatchedConstraints.cpp
+++ b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btBatchedConstraints.cpp
@@ -852,7 +852,7 @@ static void setupSpatialGridBatchesMt(
memHelper.addChunk((void**)&constraintRowBatchIds, sizeof(int) * numConstraintRows);
size_t scratchSize = memHelper.getSizeToAllocate();
// if we need to reallocate
- if (scratchMemory->capacity() < scratchSize)
+ if (static_cast<size_t>(scratchMemory->capacity()) < scratchSize)
{
// allocate 6.25% extra to avoid repeated reallocs
scratchMemory->reserve(scratchSize + scratchSize / 16);
diff --git a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btContactSolverInfo.h b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btContactSolverInfo.h
index 4356c12abf..3316403a87 100644
--- a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btContactSolverInfo.h
+++ b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btContactSolverInfo.h
@@ -47,6 +47,8 @@ struct btContactSolverInfoData
btScalar m_erp; //error reduction for non-contact constraints
btScalar m_erp2; //error reduction for contact constraints
btScalar m_deformable_erp; //error reduction for deformable constraints
+ btScalar m_deformable_cfm; //constraint force mixing for deformable constraints
+ btScalar m_deformable_maxErrorReduction; // maxErrorReduction for deformable contact
btScalar m_globalCfm; //constraint force mixing for contacts and non-contacts
btScalar m_frictionERP; //error reduction for friction constraints
btScalar m_frictionCFM; //constraint force mixing for friction constraints
@@ -83,7 +85,9 @@ struct btContactSolverInfo : public btContactSolverInfoData
m_numIterations = 10;
m_erp = btScalar(0.2);
m_erp2 = btScalar(0.2);
- m_deformable_erp = btScalar(0.1);
+ m_deformable_erp = btScalar(0.06);
+ m_deformable_cfm = btScalar(0.01);
+ m_deformable_maxErrorReduction = btScalar(0.1);
m_globalCfm = btScalar(0.);
m_frictionERP = btScalar(0.2); //positional friction 'anchors' are disabled by default
m_frictionCFM = btScalar(0.);
diff --git a/thirdparty/bullet/BulletDynamics/Dynamics/btRigidBody.h b/thirdparty/bullet/BulletDynamics/Dynamics/btRigidBody.h
index 943d724cce..7442dd1e6a 100644
--- a/thirdparty/bullet/BulletDynamics/Dynamics/btRigidBody.h
+++ b/thirdparty/bullet/BulletDynamics/Dynamics/btRigidBody.h
@@ -356,12 +356,12 @@ public:
}
}
- btVector3 getPushVelocity()
+ btVector3 getPushVelocity() const
{
return m_pushVelocity;
}
- btVector3 getTurnVelocity()
+ btVector3 getTurnVelocity() const
{
return m_turnVelocity;
}
@@ -465,6 +465,12 @@ public:
//for kinematic objects, we could also use use:
// return (m_worldTransform(rel_pos) - m_interpolationWorldTransform(rel_pos)) / m_kinematicTimeStep;
}
+
+ btVector3 getPushVelocityInLocalPoint(const btVector3& rel_pos) const
+ {
+ //we also calculate lin/ang velocity for kinematic objects
+ return m_pushVelocity + m_turnVelocity.cross(rel_pos);
+ }
void translate(const btVector3& v)
{
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBody.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBody.cpp
index a1d5bb9ca8..bec8c6530d 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBody.cpp
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBody.cpp
@@ -344,6 +344,8 @@ void btMultiBody::finalizeMultiDof()
{
m_deltaV.resize(0);
m_deltaV.resize(6 + m_dofCount);
+ m_splitV.resize(0);
+ m_splitV.resize(6 + m_dofCount);
m_realBuf.resize(6 + m_dofCount + m_dofCount * m_dofCount + 6 + m_dofCount); //m_dofCount for joint-space vels + m_dofCount^2 for "D" matrices + delta-pos vector (6 base "vels" + joint "vels")
m_vectorBuf.resize(2 * m_dofCount); //two 3-vectors (i.e. one six-vector) for each system dof ("h" matrices)
m_matrixBuf.resize(m_links.size() + 1);
@@ -671,6 +673,30 @@ btScalar *btMultiBody::getJointTorqueMultiDof(int i)
return &m_links[i].m_jointTorque[0];
}
+bool btMultiBody::hasFixedBase() const
+{
+ return m_fixedBase || (getBaseCollider() && getBaseCollider()->isStaticObject());
+}
+
+bool btMultiBody::isBaseStaticOrKinematic() const
+{
+ return m_fixedBase || (getBaseCollider() && getBaseCollider()->isStaticOrKinematicObject());
+}
+
+bool btMultiBody::isBaseKinematic() const
+{
+ return getBaseCollider() && getBaseCollider()->isKinematicObject();
+}
+
+void btMultiBody::setBaseDynamicType(int dynamicType)
+{
+ if(getBaseCollider()) {
+ int oldFlags = getBaseCollider()->getCollisionFlags();
+ oldFlags &= ~(btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT);
+ getBaseCollider()->setCollisionFlags(oldFlags | dynamicType);
+ }
+}
+
inline btMatrix3x3 outerProduct(const btVector3 &v0, const btVector3 &v1) //renamed it from vecMulVecTranspose (http://en.wikipedia.org/wiki/Outer_product); maybe it should be moved to btVector3 like dot and cross?
{
btVector3 row0 = btVector3(
@@ -796,7 +822,7 @@ void btMultiBody::computeAccelerationsArticulatedBodyAlgorithmMultiDof(btScalar
//create the vector of spatial velocity of the base by transforming global-coor linear and angular velocities into base-local coordinates
spatVel[0].setVector(rot_from_parent[0] * base_omega, rot_from_parent[0] * base_vel);
- if (m_fixedBase)
+ if (isBaseStaticOrKinematic())
{
zeroAccSpatFrc[0].setZero();
}
@@ -872,31 +898,53 @@ void btMultiBody::computeAccelerationsArticulatedBodyAlgorithmMultiDof(btScalar
// calculate zhat_i^A
//
- //external forces
- btVector3 linkAppliedForce = isConstraintPass ? m_links[i].m_appliedConstraintForce : m_links[i].m_appliedForce;
- btVector3 linkAppliedTorque = isConstraintPass ? m_links[i].m_appliedConstraintTorque : m_links[i].m_appliedTorque;
+ if (isLinkAndAllAncestorsKinematic(i))
+ {
+ zeroAccSpatFrc[i].setZero();
+ }
+ else{
+ //external forces
+ btVector3 linkAppliedForce = isConstraintPass ? m_links[i].m_appliedConstraintForce : m_links[i].m_appliedForce;
+ btVector3 linkAppliedTorque = isConstraintPass ? m_links[i].m_appliedConstraintTorque : m_links[i].m_appliedTorque;
- zeroAccSpatFrc[i + 1].setVector(-(rot_from_world[i + 1] * linkAppliedTorque), -(rot_from_world[i + 1] * linkAppliedForce));
+ zeroAccSpatFrc[i + 1].setVector(-(rot_from_world[i + 1] * linkAppliedTorque), -(rot_from_world[i + 1] * linkAppliedForce));
#if 0
- {
+ {
- b3Printf("stepVelocitiesMultiDof zeroAccSpatFrc[%d] linear:%f,%f,%f, angular:%f,%f,%f",
- i+1,
- zeroAccSpatFrc[i+1].m_topVec[0],
- zeroAccSpatFrc[i+1].m_topVec[1],
- zeroAccSpatFrc[i+1].m_topVec[2],
+ b3Printf("stepVelocitiesMultiDof zeroAccSpatFrc[%d] linear:%f,%f,%f, angular:%f,%f,%f",
+ i+1,
+ zeroAccSpatFrc[i+1].m_topVec[0],
+ zeroAccSpatFrc[i+1].m_topVec[1],
+ zeroAccSpatFrc[i+1].m_topVec[2],
- zeroAccSpatFrc[i+1].m_bottomVec[0],
- zeroAccSpatFrc[i+1].m_bottomVec[1],
- zeroAccSpatFrc[i+1].m_bottomVec[2]);
- }
+ zeroAccSpatFrc[i+1].m_bottomVec[0],
+ zeroAccSpatFrc[i+1].m_bottomVec[1],
+ zeroAccSpatFrc[i+1].m_bottomVec[2]);
+ }
#endif
- //
- //adding damping terms (only)
- btScalar linDampMult = 1., angDampMult = 1.;
- zeroAccSpatFrc[i + 1].addVector(angDampMult * m_links[i].m_inertiaLocal * spatVel[i + 1].getAngular() * (DAMPING_K1_ANGULAR + DAMPING_K2_ANGULAR * spatVel[i + 1].getAngular().safeNorm()),
- linDampMult * m_links[i].m_mass * spatVel[i + 1].getLinear() * (DAMPING_K1_LINEAR + DAMPING_K2_LINEAR * spatVel[i + 1].getLinear().safeNorm()));
+ //
+ //adding damping terms (only)
+ btScalar linDampMult = 1., angDampMult = 1.;
+ zeroAccSpatFrc[i + 1].addVector(angDampMult * m_links[i].m_inertiaLocal * spatVel[i + 1].getAngular() * (DAMPING_K1_ANGULAR + DAMPING_K2_ANGULAR * spatVel[i + 1].getAngular().safeNorm()),
+ linDampMult * m_links[i].m_mass * spatVel[i + 1].getLinear() * (DAMPING_K1_LINEAR + DAMPING_K2_LINEAR * spatVel[i + 1].getLinear().safeNorm()));
+ //p += vhat x Ihat vhat - done in a simpler way
+ if (m_useGyroTerm)
+ zeroAccSpatFrc[i + 1].addAngular(spatVel[i + 1].getAngular().cross(m_links[i].m_inertiaLocal * spatVel[i + 1].getAngular()));
+ //
+ zeroAccSpatFrc[i + 1].addLinear(m_links[i].m_mass * spatVel[i + 1].getAngular().cross(spatVel[i + 1].getLinear()));
+ //
+ //btVector3 temp = m_links[i].m_mass * spatVel[i+1].getAngular().cross(spatVel[i+1].getLinear());
+ ////clamp parent's omega
+ //btScalar parOmegaMod = temp.length();
+ //btScalar parOmegaModMax = 1000;
+ //if(parOmegaMod > parOmegaModMax)
+ // temp *= parOmegaModMax / parOmegaMod;
+ //zeroAccSpatFrc[i+1].addLinear(temp);
+ //printf("|zeroAccSpatFrc[%d]| = %.4f\n", i+1, temp.length());
+ //temp = spatCoriolisAcc[i].getLinear();
+ //printf("|spatCoriolisAcc[%d]| = %.4f\n", i+1, temp.length());
+ }
// calculate Ihat_i^A
//init the spatial AB inertia (it has the simple form thanks to choosing local body frames origins at their COMs)
@@ -909,22 +957,6 @@ void btMultiBody::computeAccelerationsArticulatedBodyAlgorithmMultiDof(btScalar
btMatrix3x3(m_links[i].m_inertiaLocal[0], 0, 0,
0, m_links[i].m_inertiaLocal[1], 0,
0, 0, m_links[i].m_inertiaLocal[2]));
- //
- //p += vhat x Ihat vhat - done in a simpler way
- if (m_useGyroTerm)
- zeroAccSpatFrc[i + 1].addAngular(spatVel[i + 1].getAngular().cross(m_links[i].m_inertiaLocal * spatVel[i + 1].getAngular()));
- //
- zeroAccSpatFrc[i + 1].addLinear(m_links[i].m_mass * spatVel[i + 1].getAngular().cross(spatVel[i + 1].getLinear()));
- //btVector3 temp = m_links[i].m_mass * spatVel[i+1].getAngular().cross(spatVel[i+1].getLinear());
- ////clamp parent's omega
- //btScalar parOmegaMod = temp.length();
- //btScalar parOmegaModMax = 1000;
- //if(parOmegaMod > parOmegaModMax)
- // temp *= parOmegaModMax / parOmegaMod;
- //zeroAccSpatFrc[i+1].addLinear(temp);
- //printf("|zeroAccSpatFrc[%d]| = %.4f\n", i+1, temp.length());
- //temp = spatCoriolisAcc[i].getLinear();
- //printf("|spatCoriolisAcc[%d]| = %.4f\n", i+1, temp.length());
//printf("w[%d] = [%.4f %.4f %.4f]\n", i, vel_top_angular[i+1].x(), vel_top_angular[i+1].y(), vel_top_angular[i+1].z());
//printf("v[%d] = [%.4f %.4f %.4f]\n", i, vel_bottom_linear[i+1].x(), vel_bottom_linear[i+1].y(), vel_bottom_linear[i+1].z());
@@ -935,6 +967,8 @@ void btMultiBody::computeAccelerationsArticulatedBodyAlgorithmMultiDof(btScalar
// (part of TreeForwardDynamics in Mirtich.)
for (int i = num_links - 1; i >= 0; --i)
{
+ if(isLinkAndAllAncestorsKinematic(i))
+ continue;
const int parent = m_links[i].m_parent;
fromParent.m_rotMat = rot_from_parent[i + 1];
fromParent.m_trnVec = m_links[i].m_cachedRVector;
@@ -1047,7 +1081,7 @@ void btMultiBody::computeAccelerationsArticulatedBodyAlgorithmMultiDof(btScalar
// Second 'upward' loop
// (part of TreeForwardDynamics in Mirtich)
- if (m_fixedBase)
+ if (isBaseStaticOrKinematic())
{
spatAcc[0].setZero();
}
@@ -1081,21 +1115,23 @@ void btMultiBody::computeAccelerationsArticulatedBodyAlgorithmMultiDof(btScalar
fromParent.transform(spatAcc[parent + 1], spatAcc[i + 1]);
- for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
+ if(!isLinkAndAllAncestorsKinematic(i))
{
- const btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof];
- //
- Y_minus_hT_a[dof] = Y[m_links[i].m_dofOffset + dof] - spatAcc[i + 1].dot(hDof);
- }
-
- btScalar *invDi = &invD[m_links[i].m_dofOffset * m_links[i].m_dofOffset];
- //D^{-1} * (Y - h^{T}*apar)
- mulMatrix(invDi, Y_minus_hT_a, m_links[i].m_dofCount, m_links[i].m_dofCount, m_links[i].m_dofCount, 1, &joint_accel[m_links[i].m_dofOffset]);
+ for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
+ {
+ const btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof];
+ //
+ Y_minus_hT_a[dof] = Y[m_links[i].m_dofOffset + dof] - spatAcc[i + 1].dot(hDof);
+ }
+ btScalar *invDi = &invD[m_links[i].m_dofOffset * m_links[i].m_dofOffset];
+ //D^{-1} * (Y - h^{T}*apar)
+ mulMatrix(invDi, Y_minus_hT_a, m_links[i].m_dofCount, m_links[i].m_dofCount, m_links[i].m_dofCount, 1, &joint_accel[m_links[i].m_dofOffset]);
- spatAcc[i + 1] += spatCoriolisAcc[i];
+ spatAcc[i + 1] += spatCoriolisAcc[i];
- for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
- spatAcc[i + 1] += m_links[i].m_axes[dof] * joint_accel[m_links[i].m_dofOffset + dof];
+ for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
+ spatAcc[i + 1] += m_links[i].m_axes[dof] * joint_accel[m_links[i].m_dofOffset + dof];
+ }
if (m_links[i].m_jointFeedback)
{
@@ -1432,7 +1468,7 @@ void btMultiBody::calcAccelerationDeltasMultiDof(const btScalar *force, btScalar
// Fill in zero_acc
// -- set to force/torque on the base, zero otherwise
- if (m_fixedBase)
+ if (isBaseStaticOrKinematic())
{
zeroAccSpatFrc[0].setZero();
}
@@ -1451,6 +1487,8 @@ void btMultiBody::calcAccelerationDeltasMultiDof(const btScalar *force, btScalar
// (part of TreeForwardDynamics in Mirtich.)
for (int i = num_links - 1; i >= 0; --i)
{
+ if(isLinkAndAllAncestorsKinematic(i))
+ continue;
const int parent = m_links[i].m_parent;
fromParent.m_rotMat = rot_from_parent[i + 1];
fromParent.m_trnVec = m_links[i].m_cachedRVector;
@@ -1494,7 +1532,7 @@ void btMultiBody::calcAccelerationDeltasMultiDof(const btScalar *force, btScalar
// Second 'upward' loop
// (part of TreeForwardDynamics in Mirtich)
- if (m_fixedBase)
+ if (isBaseStaticOrKinematic())
{
spatAcc[0].setZero();
}
@@ -1507,6 +1545,8 @@ void btMultiBody::calcAccelerationDeltasMultiDof(const btScalar *force, btScalar
// now do the loop over the m_links
for (int i = 0; i < num_links; ++i)
{
+ if(isLinkAndAllAncestorsKinematic(i))
+ continue;
const int parent = m_links[i].m_parent;
fromParent.m_rotMat = rot_from_parent[i + 1];
fromParent.m_trnVec = m_links[i].m_cachedRVector;
@@ -1550,23 +1590,26 @@ void btMultiBody::calcAccelerationDeltasMultiDof(const btScalar *force, btScalar
void btMultiBody::predictPositionsMultiDof(btScalar dt)
{
int num_links = getNumLinks();
- // step position by adding dt * velocity
- //btVector3 v = getBaseVel();
- //m_basePos += dt * v;
- //
- btScalar *pBasePos;
- btScalar *pBaseVel = &m_realBuf[3]; //note: the !pqd case assumes m_realBuf holds with base velocity at 3,4,5 (should be wrapped for safety)
-
- // reset to current position
- for (int i = 0; i < 3; ++i)
- {
- m_basePos_interpolate[i] = m_basePos[i];
- }
- pBasePos = m_basePos_interpolate;
+ if(!isBaseKinematic())
+ {
+ // step position by adding dt * velocity
+ //btVector3 v = getBaseVel();
+ //m_basePos += dt * v;
+ //
+ btScalar *pBasePos;
+ btScalar *pBaseVel = &m_realBuf[3]; //note: the !pqd case assumes m_realBuf holds with base velocity at 3,4,5 (should be wrapped for safety)
- pBasePos[0] += dt * pBaseVel[0];
- pBasePos[1] += dt * pBaseVel[1];
- pBasePos[2] += dt * pBaseVel[2];
+ // reset to current position
+ for (int i = 0; i < 3; ++i)
+ {
+ m_basePos_interpolate[i] = m_basePos[i];
+ }
+ pBasePos = m_basePos_interpolate;
+
+ pBasePos[0] += dt * pBaseVel[0];
+ pBasePos[1] += dt * pBaseVel[1];
+ pBasePos[2] += dt * pBaseVel[2];
+ }
///////////////////////////////
//local functor for quaternion integration (to avoid error prone redundancy)
@@ -1617,26 +1660,29 @@ void btMultiBody::predictPositionsMultiDof(btScalar dt)
//pQuatUpdateFun(getBaseOmega(), m_baseQuat, true, dt);
//
- btScalar *pBaseQuat;
-
- // reset to current orientation
- for (int i = 0; i < 4; ++i)
- {
- m_baseQuat_interpolate[i] = m_baseQuat[i];
- }
- pBaseQuat = m_baseQuat_interpolate;
+ if(!isBaseKinematic())
+ {
+ btScalar *pBaseQuat;
- btScalar *pBaseOmega = &m_realBuf[0]; //note: the !pqd case assumes m_realBuf starts with base omega (should be wrapped for safety)
- //
- btQuaternion baseQuat;
- baseQuat.setValue(pBaseQuat[0], pBaseQuat[1], pBaseQuat[2], pBaseQuat[3]);
- btVector3 baseOmega;
- baseOmega.setValue(pBaseOmega[0], pBaseOmega[1], pBaseOmega[2]);
- pQuatUpdateFun(baseOmega, baseQuat, true, dt);
- pBaseQuat[0] = baseQuat.x();
- pBaseQuat[1] = baseQuat.y();
- pBaseQuat[2] = baseQuat.z();
- pBaseQuat[3] = baseQuat.w();
+ // reset to current orientation
+ for (int i = 0; i < 4; ++i)
+ {
+ m_baseQuat_interpolate[i] = m_baseQuat[i];
+ }
+ pBaseQuat = m_baseQuat_interpolate;
+
+ btScalar *pBaseOmega = &m_realBuf[0]; //note: the !pqd case assumes m_realBuf starts with base omega (should be wrapped for safety)
+ //
+ btQuaternion baseQuat;
+ baseQuat.setValue(pBaseQuat[0], pBaseQuat[1], pBaseQuat[2], pBaseQuat[3]);
+ btVector3 baseOmega;
+ baseOmega.setValue(pBaseOmega[0], pBaseOmega[1], pBaseOmega[2]);
+ pQuatUpdateFun(baseOmega, baseQuat, true, dt);
+ pBaseQuat[0] = baseQuat.x();
+ pBaseQuat[1] = baseQuat.y();
+ pBaseQuat[2] = baseQuat.z();
+ pBaseQuat[3] = baseQuat.w();
+ }
// Finally we can update m_jointPos for each of the m_links
for (int i = 0; i < num_links; ++i)
@@ -1644,55 +1690,88 @@ void btMultiBody::predictPositionsMultiDof(btScalar dt)
btScalar *pJointPos;
pJointPos = &m_links[i].m_jointPos_interpolate[0];
- btScalar *pJointVel = getJointVelMultiDof(i);
-
- switch (m_links[i].m_jointType)
- {
- case btMultibodyLink::ePrismatic:
- case btMultibodyLink::eRevolute:
- {
- //reset to current pos
- pJointPos[0] = m_links[i].m_jointPos[0];
- btScalar jointVel = pJointVel[0];
- pJointPos[0] += dt * jointVel;
- break;
- }
- case btMultibodyLink::eSpherical:
- {
- //reset to current pos
-
- for (int j = 0; j < 4; ++j)
+ if (m_links[i].m_collider && m_links[i].m_collider->isStaticOrKinematic())
+ {
+ switch (m_links[i].m_jointType)
+ {
+ case btMultibodyLink::ePrismatic:
+ case btMultibodyLink::eRevolute:
{
- pJointPos[j] = m_links[i].m_jointPos[j];
+ pJointPos[0] = m_links[i].m_jointPos[0];
+ break;
}
-
- btVector3 jointVel;
- jointVel.setValue(pJointVel[0], pJointVel[1], pJointVel[2]);
- btQuaternion jointOri;
- jointOri.setValue(pJointPos[0], pJointPos[1], pJointPos[2], pJointPos[3]);
- pQuatUpdateFun(jointVel, jointOri, false, dt);
- pJointPos[0] = jointOri.x();
- pJointPos[1] = jointOri.y();
- pJointPos[2] = jointOri.z();
- pJointPos[3] = jointOri.w();
- break;
- }
- case btMultibodyLink::ePlanar:
- {
- for (int j = 0; j < 3; ++j)
+ case btMultibodyLink::eSpherical:
{
- pJointPos[j] = m_links[i].m_jointPos[j];
+ for (int j = 0; j < 4; ++j)
+ {
+ pJointPos[j] = m_links[i].m_jointPos[j];
+ }
+ break;
}
- pJointPos[0] += dt * getJointVelMultiDof(i)[0];
-
- btVector3 q0_coors_qd1qd2 = getJointVelMultiDof(i)[1] * m_links[i].getAxisBottom(1) + getJointVelMultiDof(i)[2] * m_links[i].getAxisBottom(2);
- btVector3 no_q0_coors_qd1qd2 = quatRotate(btQuaternion(m_links[i].getAxisTop(0), pJointPos[0]), q0_coors_qd1qd2);
- pJointPos[1] += m_links[i].getAxisBottom(1).dot(no_q0_coors_qd1qd2) * dt;
- pJointPos[2] += m_links[i].getAxisBottom(2).dot(no_q0_coors_qd1qd2) * dt;
- break;
+ case btMultibodyLink::ePlanar:
+ {
+ for (int j = 0; j < 3; ++j)
+ {
+ pJointPos[j] = m_links[i].m_jointPos[j];
+ }
+ break;
+ }
+ default:
+ break;
}
- default:
+ }
+ else
+ {
+ btScalar *pJointVel = getJointVelMultiDof(i);
+
+ switch (m_links[i].m_jointType)
{
+ case btMultibodyLink::ePrismatic:
+ case btMultibodyLink::eRevolute:
+ {
+ //reset to current pos
+ pJointPos[0] = m_links[i].m_jointPos[0];
+ btScalar jointVel = pJointVel[0];
+ pJointPos[0] += dt * jointVel;
+ break;
+ }
+ case btMultibodyLink::eSpherical:
+ {
+ //reset to current pos
+
+ for (int j = 0; j < 4; ++j)
+ {
+ pJointPos[j] = m_links[i].m_jointPos[j];
+ }
+
+ btVector3 jointVel;
+ jointVel.setValue(pJointVel[0], pJointVel[1], pJointVel[2]);
+ btQuaternion jointOri;
+ jointOri.setValue(pJointPos[0], pJointPos[1], pJointPos[2], pJointPos[3]);
+ pQuatUpdateFun(jointVel, jointOri, false, dt);
+ pJointPos[0] = jointOri.x();
+ pJointPos[1] = jointOri.y();
+ pJointPos[2] = jointOri.z();
+ pJointPos[3] = jointOri.w();
+ break;
+ }
+ case btMultibodyLink::ePlanar:
+ {
+ for (int j = 0; j < 3; ++j)
+ {
+ pJointPos[j] = m_links[i].m_jointPos[j];
+ }
+ pJointPos[0] += dt * getJointVelMultiDof(i)[0];
+
+ btVector3 q0_coors_qd1qd2 = getJointVelMultiDof(i)[1] * m_links[i].getAxisBottom(1) + getJointVelMultiDof(i)[2] * m_links[i].getAxisBottom(2);
+ btVector3 no_q0_coors_qd1qd2 = quatRotate(btQuaternion(m_links[i].getAxisTop(0), pJointPos[0]), q0_coors_qd1qd2);
+ pJointPos[1] += m_links[i].getAxisBottom(1).dot(no_q0_coors_qd1qd2) * dt;
+ pJointPos[2] += m_links[i].getAxisBottom(2).dot(no_q0_coors_qd1qd2) * dt;
+ break;
+ }
+ default:
+ {
+ }
}
}
@@ -1703,16 +1782,19 @@ void btMultiBody::predictPositionsMultiDof(btScalar dt)
void btMultiBody::stepPositionsMultiDof(btScalar dt, btScalar *pq, btScalar *pqd)
{
int num_links = getNumLinks();
- // step position by adding dt * velocity
- //btVector3 v = getBaseVel();
- //m_basePos += dt * v;
- //
- btScalar *pBasePos = (pq ? &pq[4] : m_basePos);
- btScalar *pBaseVel = (pqd ? &pqd[3] : &m_realBuf[3]); //note: the !pqd case assumes m_realBuf holds with base velocity at 3,4,5 (should be wrapped for safety)
-
- pBasePos[0] += dt * pBaseVel[0];
- pBasePos[1] += dt * pBaseVel[1];
- pBasePos[2] += dt * pBaseVel[2];
+ if(!isBaseKinematic())
+ {
+ // step position by adding dt * velocity
+ //btVector3 v = getBaseVel();
+ //m_basePos += dt * v;
+ //
+ btScalar *pBasePos = (pq ? &pq[4] : m_basePos);
+ btScalar *pBaseVel = (pqd ? &pqd[3] : &m_realBuf[3]); //note: the !pqd case assumes m_realBuf holds with base velocity at 3,4,5 (should be wrapped for safety)
+
+ pBasePos[0] += dt * pBaseVel[0];
+ pBasePos[1] += dt * pBaseVel[1];
+ pBasePos[2] += dt * pBaseVel[2];
+ }
///////////////////////////////
//local functor for quaternion integration (to avoid error prone redundancy)
@@ -1763,22 +1845,25 @@ void btMultiBody::stepPositionsMultiDof(btScalar dt, btScalar *pq, btScalar *pqd
//pQuatUpdateFun(getBaseOmega(), m_baseQuat, true, dt);
//
- btScalar *pBaseQuat = pq ? pq : m_baseQuat;
- btScalar *pBaseOmega = pqd ? pqd : &m_realBuf[0]; //note: the !pqd case assumes m_realBuf starts with base omega (should be wrapped for safety)
- //
- btQuaternion baseQuat;
- baseQuat.setValue(pBaseQuat[0], pBaseQuat[1], pBaseQuat[2], pBaseQuat[3]);
- btVector3 baseOmega;
- baseOmega.setValue(pBaseOmega[0], pBaseOmega[1], pBaseOmega[2]);
- pQuatUpdateFun(baseOmega, baseQuat, true, dt);
- pBaseQuat[0] = baseQuat.x();
- pBaseQuat[1] = baseQuat.y();
- pBaseQuat[2] = baseQuat.z();
- pBaseQuat[3] = baseQuat.w();
-
- //printf("pBaseOmega = %.4f %.4f %.4f\n", pBaseOmega->x(), pBaseOmega->y(), pBaseOmega->z());
- //printf("pBaseVel = %.4f %.4f %.4f\n", pBaseVel->x(), pBaseVel->y(), pBaseVel->z());
- //printf("baseQuat = %.4f %.4f %.4f %.4f\n", pBaseQuat->x(), pBaseQuat->y(), pBaseQuat->z(), pBaseQuat->w());
+ if(!isBaseKinematic())
+ {
+ btScalar *pBaseQuat = pq ? pq : m_baseQuat;
+ btScalar *pBaseOmega = pqd ? pqd : &m_realBuf[0]; //note: the !pqd case assumes m_realBuf starts with base omega (should be wrapped for safety)
+ //
+ btQuaternion baseQuat;
+ baseQuat.setValue(pBaseQuat[0], pBaseQuat[1], pBaseQuat[2], pBaseQuat[3]);
+ btVector3 baseOmega;
+ baseOmega.setValue(pBaseOmega[0], pBaseOmega[1], pBaseOmega[2]);
+ pQuatUpdateFun(baseOmega, baseQuat, true, dt);
+ pBaseQuat[0] = baseQuat.x();
+ pBaseQuat[1] = baseQuat.y();
+ pBaseQuat[2] = baseQuat.z();
+ pBaseQuat[3] = baseQuat.w();
+
+ //printf("pBaseOmega = %.4f %.4f %.4f\n", pBaseOmega->x(), pBaseOmega->y(), pBaseOmega->z());
+ //printf("pBaseVel = %.4f %.4f %.4f\n", pBaseVel->x(), pBaseVel->y(), pBaseVel->z());
+ //printf("baseQuat = %.4f %.4f %.4f %.4f\n", pBaseQuat->x(), pBaseQuat->y(), pBaseQuat->z(), pBaseQuat->w());
+ }
if (pq)
pq += 7;
@@ -1788,48 +1873,51 @@ void btMultiBody::stepPositionsMultiDof(btScalar dt, btScalar *pq, btScalar *pqd
// Finally we can update m_jointPos for each of the m_links
for (int i = 0; i < num_links; ++i)
{
- btScalar *pJointPos;
- pJointPos= (pq ? pq : &m_links[i].m_jointPos[0]);
-
- btScalar *pJointVel = (pqd ? pqd : getJointVelMultiDof(i));
-
- switch (m_links[i].m_jointType)
+ if (!(m_links[i].m_collider && m_links[i].m_collider->isStaticOrKinematic()))
{
- case btMultibodyLink::ePrismatic:
- case btMultibodyLink::eRevolute:
- {
- //reset to current pos
- btScalar jointVel = pJointVel[0];
- pJointPos[0] += dt * jointVel;
- break;
- }
- case btMultibodyLink::eSpherical:
- {
- //reset to current pos
- btVector3 jointVel;
- jointVel.setValue(pJointVel[0], pJointVel[1], pJointVel[2]);
- btQuaternion jointOri;
- jointOri.setValue(pJointPos[0], pJointPos[1], pJointPos[2], pJointPos[3]);
- pQuatUpdateFun(jointVel, jointOri, false, dt);
- pJointPos[0] = jointOri.x();
- pJointPos[1] = jointOri.y();
- pJointPos[2] = jointOri.z();
- pJointPos[3] = jointOri.w();
- break;
- }
- case btMultibodyLink::ePlanar:
+ btScalar *pJointPos;
+ pJointPos= (pq ? pq : &m_links[i].m_jointPos[0]);
+
+ btScalar *pJointVel = (pqd ? pqd : getJointVelMultiDof(i));
+
+ switch (m_links[i].m_jointType)
{
- pJointPos[0] += dt * getJointVelMultiDof(i)[0];
+ case btMultibodyLink::ePrismatic:
+ case btMultibodyLink::eRevolute:
+ {
+ //reset to current pos
+ btScalar jointVel = pJointVel[0];
+ pJointPos[0] += dt * jointVel;
+ break;
+ }
+ case btMultibodyLink::eSpherical:
+ {
+ //reset to current pos
+ btVector3 jointVel;
+ jointVel.setValue(pJointVel[0], pJointVel[1], pJointVel[2]);
+ btQuaternion jointOri;
+ jointOri.setValue(pJointPos[0], pJointPos[1], pJointPos[2], pJointPos[3]);
+ pQuatUpdateFun(jointVel, jointOri, false, dt);
+ pJointPos[0] = jointOri.x();
+ pJointPos[1] = jointOri.y();
+ pJointPos[2] = jointOri.z();
+ pJointPos[3] = jointOri.w();
+ break;
+ }
+ case btMultibodyLink::ePlanar:
+ {
+ pJointPos[0] += dt * getJointVelMultiDof(i)[0];
- btVector3 q0_coors_qd1qd2 = getJointVelMultiDof(i)[1] * m_links[i].getAxisBottom(1) + getJointVelMultiDof(i)[2] * m_links[i].getAxisBottom(2);
- btVector3 no_q0_coors_qd1qd2 = quatRotate(btQuaternion(m_links[i].getAxisTop(0), pJointPos[0]), q0_coors_qd1qd2);
- pJointPos[1] += m_links[i].getAxisBottom(1).dot(no_q0_coors_qd1qd2) * dt;
- pJointPos[2] += m_links[i].getAxisBottom(2).dot(no_q0_coors_qd1qd2) * dt;
+ btVector3 q0_coors_qd1qd2 = getJointVelMultiDof(i)[1] * m_links[i].getAxisBottom(1) + getJointVelMultiDof(i)[2] * m_links[i].getAxisBottom(2);
+ btVector3 no_q0_coors_qd1qd2 = quatRotate(btQuaternion(m_links[i].getAxisTop(0), pJointPos[0]), q0_coors_qd1qd2);
+ pJointPos[1] += m_links[i].getAxisBottom(1).dot(no_q0_coors_qd1qd2) * dt;
+ pJointPos[2] += m_links[i].getAxisBottom(2).dot(no_q0_coors_qd1qd2) * dt;
- break;
- }
- default:
- {
+ break;
+ }
+ default:
+ {
+ }
}
}
@@ -2135,8 +2223,15 @@ void btMultiBody::updateCollisionObjectInterpolationWorldTransforms(btAlignedObj
world_to_local.resize(getNumLinks() + 1);
local_origin.resize(getNumLinks() + 1);
- world_to_local[0] = getInterpolateWorldToBaseRot();
- local_origin[0] = getInterpolateBasePos();
+ if(isBaseKinematic()){
+ world_to_local[0] = getWorldToBaseRot();
+ local_origin[0] = getBasePos();
+ }
+ else
+ {
+ world_to_local[0] = getInterpolateWorldToBaseRot();
+ local_origin[0] = getInterpolateBasePos();
+ }
if (getBaseCollider())
{
@@ -2282,3 +2377,81 @@ const char *btMultiBody::serialize(void *dataBuffer, class btSerializer *seriali
return btMultiBodyDataName;
}
+
+void btMultiBody::saveKinematicState(btScalar timeStep)
+{
+ //todo: clamp to some (user definable) safe minimum timestep, to limit maximum angular/linear velocities
+ if (timeStep != btScalar(0.))
+ {
+ btVector3 linearVelocity, angularVelocity;
+ btTransformUtil::calculateVelocity(getInterpolateBaseWorldTransform(), getBaseWorldTransform(), timeStep, linearVelocity, angularVelocity);
+ setBaseVel(linearVelocity);
+ setBaseOmega(angularVelocity);
+ setInterpolateBaseWorldTransform(getBaseWorldTransform());
+ }
+}
+
+void btMultiBody::setLinkDynamicType(const int i, int type)
+{
+ if (i == -1)
+ {
+ setBaseDynamicType(type);
+ }
+ else if (i >= 0 && i < getNumLinks())
+ {
+ if (m_links[i].m_collider)
+ {
+ m_links[i].m_collider->setDynamicType(type);
+ }
+ }
+}
+
+bool btMultiBody::isLinkStaticOrKinematic(const int i) const
+{
+ if (i == -1)
+ {
+ return isBaseStaticOrKinematic();
+ }
+ else
+ {
+ if (m_links[i].m_collider)
+ return m_links[i].m_collider->isStaticOrKinematic();
+ }
+ return false;
+}
+
+bool btMultiBody::isLinkKinematic(const int i) const
+{
+ if (i == -1)
+ {
+ return isBaseKinematic();
+ }
+ else
+ {
+ if (m_links[i].m_collider)
+ return m_links[i].m_collider->isKinematic();
+ }
+ return false;
+}
+
+bool btMultiBody::isLinkAndAllAncestorsStaticOrKinematic(const int i) const
+{
+ int link = i;
+ while (link != -1) {
+ if (!isLinkStaticOrKinematic(link))
+ return false;
+ link = m_links[link].m_parent;
+ }
+ return isBaseStaticOrKinematic();
+}
+
+bool btMultiBody::isLinkAndAllAncestorsKinematic(const int i) const
+{
+ int link = i;
+ while (link != -1) {
+ if (!isLinkKinematic(link))
+ return false;
+ link = m_links[link].m_parent;
+ }
+ return isBaseKinematic();
+}
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBody.h b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBody.h
index be795633fd..25112a6805 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBody.h
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBody.h
@@ -210,7 +210,13 @@ public:
void setBasePos(const btVector3 &pos)
{
m_basePos = pos;
- m_basePos_interpolate = pos;
+ if(!isBaseKinematic())
+ m_basePos_interpolate = pos;
+ }
+
+ void setInterpolateBasePos(const btVector3 &pos)
+ {
+ m_basePos_interpolate = pos;
}
void setBaseWorldTransform(const btTransform &tr)
@@ -227,17 +233,39 @@ public:
return tr;
}
+ void setInterpolateBaseWorldTransform(const btTransform &tr)
+ {
+ setInterpolateBasePos(tr.getOrigin());
+ setInterpolateWorldToBaseRot(tr.getRotation().inverse());
+ }
+
+ btTransform getInterpolateBaseWorldTransform() const
+ {
+ btTransform tr;
+ tr.setOrigin(getInterpolateBasePos());
+ tr.setRotation(getInterpolateWorldToBaseRot().inverse());
+ return tr;
+ }
+
void setBaseVel(const btVector3 &vel)
{
m_realBuf[3] = vel[0];
m_realBuf[4] = vel[1];
m_realBuf[5] = vel[2];
}
+
void setWorldToBaseRot(const btQuaternion &rot)
{
m_baseQuat = rot; //m_baseQuat asumed to ba alias!?
- m_baseQuat_interpolate = rot;
+ if(!isBaseKinematic())
+ m_baseQuat_interpolate = rot;
+ }
+
+ void setInterpolateWorldToBaseRot(const btQuaternion &rot)
+ {
+ m_baseQuat_interpolate = rot;
}
+
void setBaseOmega(const btVector3 &omega)
{
m_realBuf[0] = omega[0];
@@ -245,6 +273,8 @@ public:
m_realBuf[2] = omega[2];
}
+ void saveKinematicState(btScalar timeStep);
+
//
// get/set pos/vel for child m_links (i = 0 to num_links-1)
//
@@ -278,6 +308,11 @@ public:
{
return &m_deltaV[0];
}
+
+ const btScalar *getSplitVelocityVector() const
+ {
+ return &m_splitV[0];
+ }
/* btScalar * getVelocityVector()
{
return &real_buf[0];
@@ -397,6 +432,26 @@ public:
m_deltaV[dof] += delta_vee[dof] * multiplier;
}
}
+ void applyDeltaSplitVeeMultiDof(const btScalar *delta_vee, btScalar multiplier)
+ {
+ for (int dof = 0; dof < 6 + getNumDofs(); ++dof)
+ {
+ m_splitV[dof] += delta_vee[dof] * multiplier;
+ }
+ }
+ void addSplitV()
+ {
+ applyDeltaVeeMultiDof(&m_splitV[0], 1);
+ }
+ void substractSplitV()
+ {
+ applyDeltaVeeMultiDof(&m_splitV[0], -1);
+
+ for (int dof = 0; dof < 6 + getNumDofs(); ++dof)
+ {
+ m_splitV[dof] = 0.f;
+ }
+ }
void processDeltaVeeMultiDof2()
{
applyDeltaVeeMultiDof(&m_deltaV[0], 1);
@@ -495,14 +550,22 @@ public:
void goToSleep();
void checkMotionAndSleepIfRequired(btScalar timestep);
- bool hasFixedBase() const
- {
- return m_fixedBase;
- }
+ bool hasFixedBase() const;
+
+ bool isBaseKinematic() const;
+
+ bool isBaseStaticOrKinematic() const;
+
+ // set the dynamic type in the base's collision flags.
+ void setBaseDynamicType(int dynamicType);
void setFixedBase(bool fixedBase)
{
m_fixedBase = fixedBase;
+ if(m_fixedBase)
+ setBaseDynamicType(btCollisionObject::CF_STATIC_OBJECT);
+ else
+ setBaseDynamicType(btCollisionObject::CF_DYNAMIC_OBJECT);
}
int getCompanionId() const
@@ -653,7 +716,15 @@ public:
btVector3 &top_out, // top part of output vector
btVector3 &bottom_out); // bottom part of output vector
+ void setLinkDynamicType(const int i, int type);
+
+ bool isLinkStaticOrKinematic(const int i) const;
+
+ bool isLinkKinematic(const int i) const;
+
+ bool isLinkAndAllAncestorsStaticOrKinematic(const int i) const;
+ bool isLinkAndAllAncestorsKinematic(const int i) const;
private:
btMultiBody(const btMultiBody &); // not implemented
@@ -711,6 +782,7 @@ private:
// offset size array
// 0 num_links+1 rot_from_parent
//
+ btAlignedObjectArray<btScalar> m_splitV;
btAlignedObjectArray<btScalar> m_deltaV;
btAlignedObjectArray<btScalar> m_realBuf;
btAlignedObjectArray<btVector3> m_vectorBuf;
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp
index d7ed05ce57..1ba5861145 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp
@@ -2,11 +2,12 @@
#include "BulletDynamics/Dynamics/btRigidBody.h"
#include "btMultiBodyPoint2Point.h" //for testing (BTMBP2PCONSTRAINT_BLOCK_ANGULAR_MOTION_TEST macro)
-btMultiBodyConstraint::btMultiBodyConstraint(btMultiBody* bodyA, btMultiBody* bodyB, int linkA, int linkB, int numRows, bool isUnilateral)
+btMultiBodyConstraint::btMultiBodyConstraint(btMultiBody* bodyA, btMultiBody* bodyB, int linkA, int linkB, int numRows, bool isUnilateral, int type)
: m_bodyA(bodyA),
m_bodyB(bodyB),
m_linkA(linkA),
m_linkB(linkB),
+ m_type(type),
m_numRows(numRows),
m_jacSizeA(0),
m_jacSizeBoth(0),
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraint.h b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraint.h
index 5c15f3e851..4a6007ee3e 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraint.h
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraint.h
@@ -20,6 +20,21 @@ subject to the following restrictions:
#include "LinearMath/btAlignedObjectArray.h"
#include "btMultiBody.h"
+
+//Don't change any of the existing enum values, so add enum types at the end for serialization compatibility
+enum btTypedMultiBodyConstraintType
+{
+ MULTIBODY_CONSTRAINT_LIMIT=3,
+ MULTIBODY_CONSTRAINT_1DOF_JOINT_MOTOR,
+ MULTIBODY_CONSTRAINT_GEAR,
+ MULTIBODY_CONSTRAINT_POINT_TO_POINT,
+ MULTIBODY_CONSTRAINT_SLIDER,
+ MULTIBODY_CONSTRAINT_SPHERICAL_MOTOR,
+ MULTIBODY_CONSTRAINT_FIXED,
+
+ MAX_MULTIBODY_CONSTRAINT_TYPE,
+};
+
class btMultiBody;
struct btSolverInfo;
@@ -46,6 +61,8 @@ protected:
int m_linkA;
int m_linkB;
+ int m_type; //btTypedMultiBodyConstraintType
+
int m_numRows;
int m_jacSizeA;
int m_jacSizeBoth;
@@ -82,12 +99,16 @@ protected:
public:
BT_DECLARE_ALIGNED_ALLOCATOR();
- btMultiBodyConstraint(btMultiBody * bodyA, btMultiBody * bodyB, int linkA, int linkB, int numRows, bool isUnilateral);
+ btMultiBodyConstraint(btMultiBody * bodyA, btMultiBody * bodyB, int linkA, int linkB, int numRows, bool isUnilateral, int type);
virtual ~btMultiBodyConstraint();
void updateJacobianSizes();
void allocateJacobiansMultiDof();
+ int getConstraintType() const
+ {
+ return m_type;
+ }
//many constraints have setFrameInB/setPivotInB. Will use 'getConstraintType' later.
virtual void setFrameInB(const btMatrix3x3& frameInB) {}
virtual void setPivotInB(const btVector3& pivotInB) {}
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp
index cd1bad089e..fef95f0c4e 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp
@@ -592,6 +592,7 @@ void btMultiBodyDynamicsWorld::integrateMultiBodyTransforms(btScalar timeStep)
if (!isSleeping)
{
+ bod->addSplitV();
int nLinks = bod->getNumLinks();
///base + num m_links
@@ -610,6 +611,7 @@ void btMultiBodyDynamicsWorld::integrateMultiBodyTransforms(btScalar timeStep)
m_scratch_world_to_local.resize(nLinks + 1);
m_scratch_local_origin.resize(nLinks + 1);
bod->updateCollisionObjectWorldTransforms(m_scratch_world_to_local, m_scratch_local_origin);
+ bod->substractSplitV();
}
else
{
@@ -867,6 +869,18 @@ void btMultiBodyDynamicsWorld::serializeMultiBodies(btSerializer* serializer)
}
}
}
+
+void btMultiBodyDynamicsWorld::saveKinematicState(btScalar timeStep)
+{
+ btDiscreteDynamicsWorld::saveKinematicState(timeStep);
+ for(int i = 0; i < m_multiBodies.size(); i++)
+ {
+ btMultiBody* body = m_multiBodies[i];
+ if(body->isBaseKinematic())
+ body->saveKinematicState(timeStep);
+ }
+}
+
//
//void btMultiBodyDynamicsWorld::setSplitIslands(bool split)
//{
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h
index 9ac46f4b64..d2d76c8b92 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h
@@ -120,5 +120,7 @@ public:
virtual void solveExternalForces(btContactSolverInfo& solverInfo);
virtual void solveInternalConstraints(btContactSolverInfo& solverInfo);
void buildIslands();
+
+ virtual void saveKinematicState(btScalar timeStep);
};
#endif //BT_MULTIBODY_DYNAMICS_WORLD_H
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyFixedConstraint.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyFixedConstraint.cpp
index 5ef9444c2f..df2abbe97a 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyFixedConstraint.cpp
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyFixedConstraint.cpp
@@ -24,7 +24,7 @@ subject to the following restrictions:
#define BTMBFIXEDCONSTRAINT_DIM 6
btMultiBodyFixedConstraint::btMultiBodyFixedConstraint(btMultiBody* body, int link, btRigidBody* bodyB, const btVector3& pivotInA, const btVector3& pivotInB, const btMatrix3x3& frameInA, const btMatrix3x3& frameInB)
- : btMultiBodyConstraint(body, 0, link, -1, BTMBFIXEDCONSTRAINT_DIM, false),
+ : btMultiBodyConstraint(body, 0, link, -1, BTMBFIXEDCONSTRAINT_DIM, false, MULTIBODY_CONSTRAINT_FIXED),
m_rigidBodyA(0),
m_rigidBodyB(bodyB),
m_pivotInA(pivotInA),
@@ -36,7 +36,7 @@ btMultiBodyFixedConstraint::btMultiBodyFixedConstraint(btMultiBody* body, int li
}
btMultiBodyFixedConstraint::btMultiBodyFixedConstraint(btMultiBody* bodyA, int linkA, btMultiBody* bodyB, int linkB, const btVector3& pivotInA, const btVector3& pivotInB, const btMatrix3x3& frameInA, const btMatrix3x3& frameInB)
- : btMultiBodyConstraint(bodyA, bodyB, linkA, linkB, BTMBFIXEDCONSTRAINT_DIM, false),
+ : btMultiBodyConstraint(bodyA, bodyB, linkA, linkB, BTMBFIXEDCONSTRAINT_DIM, false, MULTIBODY_CONSTRAINT_FIXED),
m_rigidBodyA(0),
m_rigidBodyB(0),
m_pivotInA(pivotInA),
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyGearConstraint.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyGearConstraint.cpp
index bf6b811d26..ee02cf9b07 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyGearConstraint.cpp
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyGearConstraint.cpp
@@ -21,7 +21,7 @@ subject to the following restrictions:
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
btMultiBodyGearConstraint::btMultiBodyGearConstraint(btMultiBody* bodyA, int linkA, btMultiBody* bodyB, int linkB, const btVector3& pivotInA, const btVector3& pivotInB, const btMatrix3x3& frameInA, const btMatrix3x3& frameInB)
- : btMultiBodyConstraint(bodyA, bodyB, linkA, linkB, 1, false),
+ : btMultiBodyConstraint(bodyA, bodyB, linkA, linkB, 1, false, MULTIBODY_CONSTRAINT_GEAR),
m_gearRatio(1),
m_gearAuxLink(-1),
m_erp(0),
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp
index 8791ad2868..94b36ac108 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp
@@ -22,7 +22,7 @@ subject to the following restrictions:
btMultiBodyJointLimitConstraint::btMultiBodyJointLimitConstraint(btMultiBody* body, int link, btScalar lower, btScalar upper)
//:btMultiBodyConstraint(body,0,link,-1,2,true),
- : btMultiBodyConstraint(body, body, link, body->getLink(link).m_parent, 2, true),
+ : btMultiBodyConstraint(body, body, link, body->getLink(link).m_parent, 2, true, MULTIBODY_CONSTRAINT_LIMIT),
m_lowerBound(lower),
m_upperBound(upper)
{
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.h b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.h
index 6716ba490f..b810692b4c 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.h
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.h
@@ -42,6 +42,22 @@ public:
{
//todo(erwincoumans)
}
+ btScalar getLowerBound() const
+ {
+ return m_lowerBound;
+ }
+ btScalar getUpperBound() const
+ {
+ return m_upperBound;
+ }
+ void setLowerBound(btScalar lower)
+ {
+ m_lowerBound = lower;
+ }
+ void setUpperBound(btScalar upper)
+ {
+ m_upperBound = upper;
+ }
};
#endif //BT_MULTIBODY_JOINT_LIMIT_CONSTRAINT_H
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp
index 5c816c4987..fec9b03213 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp
@@ -21,7 +21,7 @@ subject to the following restrictions:
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
btMultiBodyJointMotor::btMultiBodyJointMotor(btMultiBody* body, int link, btScalar desiredVelocity, btScalar maxMotorImpulse)
- : btMultiBodyConstraint(body, body, link, body->getLink(link).m_parent, 1, true),
+ : btMultiBodyConstraint(body, body, link, body->getLink(link).m_parent, 1, true, MULTIBODY_CONSTRAINT_1DOF_JOINT_MOTOR),
m_desiredVelocity(desiredVelocity),
m_desiredPosition(0),
m_kd(1.),
@@ -51,7 +51,7 @@ void btMultiBodyJointMotor::finalizeMultiDof()
btMultiBodyJointMotor::btMultiBodyJointMotor(btMultiBody* body, int link, int linkDoF, btScalar desiredVelocity, btScalar maxMotorImpulse)
//:btMultiBodyConstraint(body,0,link,-1,1,true),
- : btMultiBodyConstraint(body, body, link, body->getLink(link).m_parent, 1, true),
+ : btMultiBodyConstraint(body, body, link, body->getLink(link).m_parent, 1, true, MULTIBODY_CONSTRAINT_1DOF_JOINT_MOTOR),
m_desiredVelocity(desiredVelocity),
m_desiredPosition(0),
m_kd(1.),
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyLink.h b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyLink.h
index 01d5583c2f..5a1429340f 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyLink.h
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyLink.h
@@ -295,6 +295,9 @@ struct btMultibodyLink
}
}
}
+
+
+
};
#endif //BT_MULTIBODY_LINK_H
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyLinkCollider.h b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyLinkCollider.h
index bc909990c2..3dc35a5814 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyLinkCollider.h
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyLinkCollider.h
@@ -130,6 +130,23 @@ public:
return true;
}
+ bool isStaticOrKinematic() const
+ {
+ return isStaticOrKinematicObject();
+ }
+
+ bool isKinematic() const
+ {
+ return isKinematicObject();
+ }
+
+ void setDynamicType(int dynamicType)
+ {
+ int oldFlags = getCollisionFlags();
+ oldFlags &= ~(btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT);
+ setCollisionFlags(oldFlags | dynamicType);
+ }
+
virtual int calculateSerializeBufferSize() const;
///fills the dataBuffer and returns the struct name (and 0 on failure)
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp
index 37d3aede37..f51e69deb1 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp
@@ -27,7 +27,7 @@ subject to the following restrictions:
#endif
btMultiBodyPoint2Point::btMultiBodyPoint2Point(btMultiBody* body, int link, btRigidBody* bodyB, const btVector3& pivotInA, const btVector3& pivotInB)
- : btMultiBodyConstraint(body, 0, link, -1, BTMBP2PCONSTRAINT_DIM, false),
+ : btMultiBodyConstraint(body, 0, link, -1, BTMBP2PCONSTRAINT_DIM, false, MULTIBODY_CONSTRAINT_POINT_TO_POINT),
m_rigidBodyA(0),
m_rigidBodyB(bodyB),
m_pivotInA(pivotInA),
@@ -37,7 +37,7 @@ btMultiBodyPoint2Point::btMultiBodyPoint2Point(btMultiBody* body, int link, btRi
}
btMultiBodyPoint2Point::btMultiBodyPoint2Point(btMultiBody* bodyA, int linkA, btMultiBody* bodyB, int linkB, const btVector3& pivotInA, const btVector3& pivotInB)
- : btMultiBodyConstraint(bodyA, bodyB, linkA, linkB, BTMBP2PCONSTRAINT_DIM, false),
+ : btMultiBodyConstraint(bodyA, bodyB, linkA, linkB, BTMBP2PCONSTRAINT_DIM, false, MULTIBODY_CONSTRAINT_POINT_TO_POINT),
m_rigidBodyA(0),
m_rigidBodyB(0),
m_pivotInA(pivotInA),
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySliderConstraint.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySliderConstraint.cpp
index e025302ce6..48ec1d5af2 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySliderConstraint.cpp
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySliderConstraint.cpp
@@ -25,7 +25,7 @@ subject to the following restrictions:
#define EPSILON 0.000001
btMultiBodySliderConstraint::btMultiBodySliderConstraint(btMultiBody* body, int link, btRigidBody* bodyB, const btVector3& pivotInA, const btVector3& pivotInB, const btMatrix3x3& frameInA, const btMatrix3x3& frameInB, const btVector3& jointAxis)
- : btMultiBodyConstraint(body, 0, link, -1, BTMBSLIDERCONSTRAINT_DIM, false),
+ : btMultiBodyConstraint(body, 0, link, -1, BTMBSLIDERCONSTRAINT_DIM, false, MULTIBODY_CONSTRAINT_SLIDER),
m_rigidBodyA(0),
m_rigidBodyB(bodyB),
m_pivotInA(pivotInA),
@@ -38,7 +38,7 @@ btMultiBodySliderConstraint::btMultiBodySliderConstraint(btMultiBody* body, int
}
btMultiBodySliderConstraint::btMultiBodySliderConstraint(btMultiBody* bodyA, int linkA, btMultiBody* bodyB, int linkB, const btVector3& pivotInA, const btVector3& pivotInB, const btMatrix3x3& frameInA, const btMatrix3x3& frameInB, const btVector3& jointAxis)
- : btMultiBodyConstraint(bodyA, bodyB, linkA, linkB, BTMBSLIDERCONSTRAINT_DIM, false),
+ : btMultiBodyConstraint(bodyA, bodyB, linkA, linkB, BTMBSLIDERCONSTRAINT_DIM, false, MULTIBODY_CONSTRAINT_SLIDER),
m_rigidBodyA(0),
m_rigidBodyB(0),
m_pivotInA(pivotInA),
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp
index 3e5aa30f28..25ddd539bf 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp
@@ -23,7 +23,7 @@ subject to the following restrictions:
#include "BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h"
btMultiBodySphericalJointMotor::btMultiBodySphericalJointMotor(btMultiBody* body, int link, btScalar maxMotorImpulse)
- : btMultiBodyConstraint(body, body, link, body->getLink(link).m_parent, 3, true),
+ : btMultiBodyConstraint(body, body, link, body->getLink(link).m_parent, 3, true, MULTIBODY_CONSTRAINT_SPHERICAL_MOTOR),
m_desiredVelocity(0, 0, 0),
m_desiredPosition(0,0,0,1),
m_kd(1.),
diff --git a/thirdparty/bullet/BulletSoftBody/DeformableBodyInplaceSolverIslandCallback.h b/thirdparty/bullet/BulletSoftBody/DeformableBodyInplaceSolverIslandCallback.h
index 7b225701f6..01c7e93a1b 100644
--- a/thirdparty/bullet/BulletSoftBody/DeformableBodyInplaceSolverIslandCallback.h
+++ b/thirdparty/bullet/BulletSoftBody/DeformableBodyInplaceSolverIslandCallback.h
@@ -13,13 +13,12 @@ struct DeformableBodyInplaceSolverIslandCallback : public MultiBodyInplaceSolver
btDeformableMultiBodyConstraintSolver* m_deformableSolver;
DeformableBodyInplaceSolverIslandCallback(btDeformableMultiBodyConstraintSolver* solver,
- btDispatcher* dispatcher)
- : MultiBodyInplaceSolverIslandCallback(solver, dispatcher), m_deformableSolver(solver)
+ btDispatcher* dispatcher)
+ : MultiBodyInplaceSolverIslandCallback(solver, dispatcher), m_deformableSolver(solver)
{
}
-
- virtual void processConstraints(int islandId=-1)
+ virtual void processConstraints(int islandId = -1)
{
btCollisionObject** bodies = m_bodies.size() ? &m_bodies[0] : 0;
btCollisionObject** softBodies = m_softBodies.size() ? &m_softBodies[0] : 0;
@@ -30,7 +29,7 @@ struct DeformableBodyInplaceSolverIslandCallback : public MultiBodyInplaceSolver
//printf("mb contacts = %d, mb constraints = %d\n", mbContacts, m_multiBodyConstraints.size());
m_deformableSolver->solveDeformableBodyGroup(bodies, m_bodies.size(), softBodies, m_softBodies.size(), manifold, m_manifolds.size(), constraints, m_constraints.size(), multiBodyConstraints, m_multiBodyConstraints.size(), *m_solverInfo, m_debugDrawer, m_dispatcher);
- if (m_bodies.size() && (m_solverInfo->m_reportSolverAnalytics&1))
+ if (m_bodies.size() && (m_solverInfo->m_reportSolverAnalytics & 1))
{
m_deformableSolver->m_analyticsData.m_islandId = islandId;
m_islandAnalyticsData.push_back(m_solver->m_analyticsData);
diff --git a/thirdparty/bullet/BulletSoftBody/btCGProjection.h b/thirdparty/bullet/BulletSoftBody/btCGProjection.h
index d047e6d3d9..e05970664c 100644
--- a/thirdparty/bullet/BulletSoftBody/btCGProjection.h
+++ b/thirdparty/bullet/BulletSoftBody/btCGProjection.h
@@ -22,85 +22,83 @@
struct DeformableContactConstraint
{
- const btSoftBody::Node* m_node;
- btAlignedObjectArray<const btSoftBody::RContact*> m_contact;
- btAlignedObjectArray<btVector3> m_total_normal_dv;
- btAlignedObjectArray<btVector3> m_total_tangent_dv;
- btAlignedObjectArray<bool> m_static;
- btAlignedObjectArray<bool> m_can_be_dynamic;
-
- DeformableContactConstraint(const btSoftBody::RContact& rcontact): m_node(rcontact.m_node)
- {
- append(rcontact);
- }
-
- DeformableContactConstraint(): m_node(NULL)
- {
- m_contact.push_back(NULL);
- }
-
- void append(const btSoftBody::RContact& rcontact)
- {
- m_contact.push_back(&rcontact);
- m_total_normal_dv.push_back(btVector3(0,0,0));
- m_total_tangent_dv.push_back(btVector3(0,0,0));
- m_static.push_back(false);
- m_can_be_dynamic.push_back(true);
- }
-
- void replace(const btSoftBody::RContact& rcontact)
- {
- m_contact.clear();
- m_total_normal_dv.clear();
- m_total_tangent_dv.clear();
- m_static.clear();
- m_can_be_dynamic.clear();
- append(rcontact);
- }
-
- ~DeformableContactConstraint()
- {
- }
+ const btSoftBody::Node* m_node;
+ btAlignedObjectArray<const btSoftBody::RContact*> m_contact;
+ btAlignedObjectArray<btVector3> m_total_normal_dv;
+ btAlignedObjectArray<btVector3> m_total_tangent_dv;
+ btAlignedObjectArray<bool> m_static;
+ btAlignedObjectArray<bool> m_can_be_dynamic;
+
+ DeformableContactConstraint(const btSoftBody::RContact& rcontact) : m_node(rcontact.m_node)
+ {
+ append(rcontact);
+ }
+
+ DeformableContactConstraint() : m_node(NULL)
+ {
+ m_contact.push_back(NULL);
+ }
+
+ void append(const btSoftBody::RContact& rcontact)
+ {
+ m_contact.push_back(&rcontact);
+ m_total_normal_dv.push_back(btVector3(0, 0, 0));
+ m_total_tangent_dv.push_back(btVector3(0, 0, 0));
+ m_static.push_back(false);
+ m_can_be_dynamic.push_back(true);
+ }
+
+ void replace(const btSoftBody::RContact& rcontact)
+ {
+ m_contact.clear();
+ m_total_normal_dv.clear();
+ m_total_tangent_dv.clear();
+ m_static.clear();
+ m_can_be_dynamic.clear();
+ append(rcontact);
+ }
+
+ ~DeformableContactConstraint()
+ {
+ }
};
class btCGProjection
{
public:
- typedef btAlignedObjectArray<btVector3> TVStack;
- typedef btAlignedObjectArray<btAlignedObjectArray<btVector3> > TVArrayStack;
- typedef btAlignedObjectArray<btAlignedObjectArray<btScalar> > TArrayStack;
- btAlignedObjectArray<btSoftBody *>& m_softBodies;
- const btScalar& m_dt;
- // map from node indices to node pointers
- const btAlignedObjectArray<btSoftBody::Node*>* m_nodes;
-
- btCGProjection(btAlignedObjectArray<btSoftBody *>& softBodies, const btScalar& dt)
- : m_softBodies(softBodies)
- , m_dt(dt)
- {
- }
-
- virtual ~btCGProjection()
- {
- }
-
- // apply the constraints
- virtual void project(TVStack& x) = 0;
-
- virtual void setConstraints() = 0;
-
- // update the constraints
- virtual btScalar update() = 0;
-
- virtual void reinitialize(bool nodeUpdated)
- {
- }
-
- virtual void setIndices(const btAlignedObjectArray<btSoftBody::Node*>* nodes)
- {
- m_nodes = nodes;
- }
-};
+ typedef btAlignedObjectArray<btVector3> TVStack;
+ typedef btAlignedObjectArray<btAlignedObjectArray<btVector3> > TVArrayStack;
+ typedef btAlignedObjectArray<btAlignedObjectArray<btScalar> > TArrayStack;
+ btAlignedObjectArray<btSoftBody*>& m_softBodies;
+ const btScalar& m_dt;
+ // map from node indices to node pointers
+ const btAlignedObjectArray<btSoftBody::Node*>* m_nodes;
+
+ btCGProjection(btAlignedObjectArray<btSoftBody*>& softBodies, const btScalar& dt)
+ : m_softBodies(softBodies), m_dt(dt)
+ {
+ }
+ virtual ~btCGProjection()
+ {
+ }
+
+ // apply the constraints
+ virtual void project(TVStack& x) = 0;
+
+ virtual void setConstraints() = 0;
+
+ // update the constraints
+ virtual btScalar update() = 0;
+
+ virtual void reinitialize(bool nodeUpdated)
+ {
+ }
+
+ virtual void setIndices(const btAlignedObjectArray<btSoftBody::Node*>* nodes)
+ {
+ m_nodes = nodes;
+ }
+};
#endif /* btCGProjection_h */
diff --git a/thirdparty/bullet/BulletSoftBody/btConjugateGradient.h b/thirdparty/bullet/BulletSoftBody/btConjugateGradient.h
index bd51e584b9..bcd5e6b519 100644
--- a/thirdparty/bullet/BulletSoftBody/btConjugateGradient.h
+++ b/thirdparty/bullet/BulletSoftBody/btConjugateGradient.h
@@ -15,144 +15,103 @@
#ifndef BT_CONJUGATE_GRADIENT_H
#define BT_CONJUGATE_GRADIENT_H
-#include <iostream>
-#include <cmath>
-#include <limits>
-#include <LinearMath/btAlignedObjectArray.h>
-#include <LinearMath/btVector3.h>
-#include "LinearMath/btQuickprof.h"
+#include "btKrylovSolver.h"
template <class MatrixX>
-class btConjugateGradient
+class btConjugateGradient : public btKrylovSolver<MatrixX>
{
- typedef btAlignedObjectArray<btVector3> TVStack;
- TVStack r,p,z,temp;
- int max_iterations;
- btScalar tolerance_squared;
+ typedef btAlignedObjectArray<btVector3> TVStack;
+ typedef btKrylovSolver<MatrixX> Base;
+ TVStack r, p, z, temp;
+
public:
- btConjugateGradient(const int max_it_in)
- : max_iterations(max_it_in)
- {
- tolerance_squared = 1e-5;
- }
-
- virtual ~btConjugateGradient(){}
-
- // return the number of iterations taken
- int solve(MatrixX& A, TVStack& x, const TVStack& b, bool verbose = false)
- {
- BT_PROFILE("CGSolve");
- btAssert(x.size() == b.size());
- reinitialize(b);
- // r = b - A * x --with assigned dof zeroed out
- A.multiply(x, temp);
- r = sub(b, temp);
- A.project(r);
- // z = M^(-1) * r
- A.precondition(r, z);
- A.project(z);
- btScalar r_dot_z = dot(z,r);
- if (r_dot_z <= tolerance_squared) {
- if (verbose)
- {
- std::cout << "Iteration = 0" << std::endl;
- std::cout << "Two norm of the residual = " << r_dot_z << std::endl;
- }
- return 0;
- }
- p = z;
- btScalar r_dot_z_new = r_dot_z;
- for (int k = 1; k <= max_iterations; k++) {
- // temp = A*p
- A.multiply(p, temp);
- A.project(temp);
- if (dot(p,temp) < SIMD_EPSILON)
- {
- if (verbose)
- std::cout << "Encountered negative direction in CG!" << std::endl;
- if (k == 1)
- {
- x = b;
- }
- return k;
- }
- // alpha = r^T * z / (p^T * A * p)
- btScalar alpha = r_dot_z_new / dot(p, temp);
- // x += alpha * p;
- multAndAddTo(alpha, p, x);
- // r -= alpha * temp;
- multAndAddTo(-alpha, temp, r);
- // z = M^(-1) * r
- A.precondition(r, z);
- r_dot_z = r_dot_z_new;
- r_dot_z_new = dot(r,z);
- if (r_dot_z_new < tolerance_squared) {
- if (verbose)
- {
- std::cout << "ConjugateGradient iterations " << k << std::endl;
- }
- return k;
- }
+ btConjugateGradient(const int max_it_in)
+ : btKrylovSolver<MatrixX>(max_it_in, SIMD_EPSILON)
+ {
+ }
+
+ virtual ~btConjugateGradient() {}
+
+ // return the number of iterations taken
+ int solve(MatrixX& A, TVStack& x, const TVStack& b, bool verbose = false)
+ {
+ BT_PROFILE("CGSolve");
+ btAssert(x.size() == b.size());
+ reinitialize(b);
+ temp = b;
+ A.project(temp);
+ p = temp;
+ A.precondition(p, z);
+ btScalar d0 = this->dot(z, temp);
+ d0 = btMin(btScalar(1), d0);
+ // r = b - A * x --with assigned dof zeroed out
+ A.multiply(x, temp);
+ r = this->sub(b, temp);
+ A.project(r);
+ // z = M^(-1) * r
+ A.precondition(r, z);
+ A.project(z);
+ btScalar r_dot_z = this->dot(z, r);
+ if (r_dot_z <= Base::m_tolerance * d0)
+ {
+ if (verbose)
+ {
+ std::cout << "Iteration = 0" << std::endl;
+ std::cout << "Two norm of the residual = " << r_dot_z << std::endl;
+ }
+ return 0;
+ }
+ p = z;
+ btScalar r_dot_z_new = r_dot_z;
+ for (int k = 1; k <= Base::m_maxIterations; k++)
+ {
+ // temp = A*p
+ A.multiply(p, temp);
+ A.project(temp);
+ if (this->dot(p, temp) < 0)
+ {
+ if (verbose)
+ std::cout << "Encountered negative direction in CG!" << std::endl;
+ if (k == 1)
+ {
+ x = b;
+ }
+ return k;
+ }
+ // alpha = r^T * z / (p^T * A * p)
+ btScalar alpha = r_dot_z_new / this->dot(p, temp);
+ // x += alpha * p;
+ this->multAndAddTo(alpha, p, x);
+ // r -= alpha * temp;
+ this->multAndAddTo(-alpha, temp, r);
+ // z = M^(-1) * r
+ A.precondition(r, z);
+ r_dot_z = r_dot_z_new;
+ r_dot_z_new = this->dot(r, z);
+ if (r_dot_z_new < Base::m_tolerance * d0)
+ {
+ if (verbose)
+ {
+ std::cout << "ConjugateGradient iterations " << k << " residual = " << r_dot_z_new << std::endl;
+ }
+ return k;
+ }
+
+ btScalar beta = r_dot_z_new / r_dot_z;
+ p = this->multAndAdd(beta, p, z);
+ }
+ if (verbose)
+ {
+ std::cout << "ConjugateGradient max iterations reached " << Base::m_maxIterations << " error = " << r_dot_z_new << std::endl;
+ }
+ return Base::m_maxIterations;
+ }
- btScalar beta = r_dot_z_new/r_dot_z;
- p = multAndAdd(beta, p, z);
- }
- if (verbose)
- {
- std::cout << "ConjugateGradient max iterations reached " << max_iterations << std::endl;
- }
- return max_iterations;
- }
-
- void reinitialize(const TVStack& b)
- {
- r.resize(b.size());
- p.resize(b.size());
- z.resize(b.size());
- temp.resize(b.size());
- }
-
- TVStack sub(const TVStack& a, const TVStack& b)
- {
- // c = a-b
- btAssert(a.size() == b.size());
- TVStack c;
- c.resize(a.size());
- for (int i = 0; i < a.size(); ++i)
- {
- c[i] = a[i] - b[i];
- }
- return c;
- }
-
- btScalar squaredNorm(const TVStack& a)
- {
- return dot(a,a);
- }
-
- btScalar dot(const TVStack& a, const TVStack& b)
- {
- btScalar ans(0);
- for (int i = 0; i < a.size(); ++i)
- ans += a[i].dot(b[i]);
- return ans;
- }
-
- void multAndAddTo(btScalar s, const TVStack& a, TVStack& result)
- {
-// result += s*a
- btAssert(a.size() == result.size());
- for (int i = 0; i < a.size(); ++i)
- result[i] += s * a[i];
- }
-
- TVStack multAndAdd(btScalar s, const TVStack& a, const TVStack& b)
- {
- // result = a*s + b
- TVStack result;
- result.resize(a.size());
- for (int i = 0; i < a.size(); ++i)
- result[i] = s * a[i] + b[i];
- return result;
- }
+ void reinitialize(const TVStack& b)
+ {
+ r.resize(b.size());
+ p.resize(b.size());
+ z.resize(b.size());
+ temp.resize(b.size());
+ }
};
#endif /* btConjugateGradient_h */
diff --git a/thirdparty/bullet/BulletSoftBody/btConjugateResidual.h b/thirdparty/bullet/BulletSoftBody/btConjugateResidual.h
index 7b211c4172..6146120365 100644
--- a/thirdparty/bullet/BulletSoftBody/btConjugateResidual.h
+++ b/thirdparty/bullet/BulletSoftBody/btConjugateResidual.h
@@ -15,174 +15,98 @@
#ifndef BT_CONJUGATE_RESIDUAL_H
#define BT_CONJUGATE_RESIDUAL_H
-#include <iostream>
-#include <cmath>
-#include <limits>
-#include <LinearMath/btAlignedObjectArray.h>
-#include <LinearMath/btVector3.h>
-#include <LinearMath/btScalar.h>
-#include "LinearMath/btQuickprof.h"
+#include "btKrylovSolver.h"
+
template <class MatrixX>
-class btConjugateResidual
+class btConjugateResidual : public btKrylovSolver<MatrixX>
{
- typedef btAlignedObjectArray<btVector3> TVStack;
- TVStack r,p,z,temp_p, temp_r, best_x;
- // temp_r = A*r
- // temp_p = A*p
- // z = M^(-1) * temp_p = M^(-1) * A * p
- int max_iterations;
- btScalar tolerance_squared, best_r;
+ typedef btAlignedObjectArray<btVector3> TVStack;
+ typedef btKrylovSolver<MatrixX> Base;
+ TVStack r, p, z, temp_p, temp_r, best_x;
+ // temp_r = A*r
+ // temp_p = A*p
+ // z = M^(-1) * temp_p = M^(-1) * A * p
+ btScalar best_r;
+
public:
- btConjugateResidual(const int max_it_in)
- : max_iterations(max_it_in)
- {
- tolerance_squared = 1e-2;
- }
-
- virtual ~btConjugateResidual(){}
-
- // return the number of iterations taken
- int solve(MatrixX& A, TVStack& x, const TVStack& b, bool verbose = false)
- {
- BT_PROFILE("CRSolve");
- btAssert(x.size() == b.size());
- reinitialize(b);
- // r = b - A * x --with assigned dof zeroed out
- A.multiply(x, temp_r); // borrow temp_r here to store A*x
- r = sub(b, temp_r);
- // z = M^(-1) * r
- A.precondition(r, z); // borrow z to store preconditioned r
- r = z;
- btScalar residual_norm = norm(r);
- if (residual_norm <= tolerance_squared) {
- if (verbose)
- {
- std::cout << "Iteration = 0" << std::endl;
- std::cout << "Two norm of the residual = " << residual_norm << std::endl;
- }
- return 0;
- }
- p = r;
- btScalar r_dot_Ar, r_dot_Ar_new;
- // temp_p = A*p
- A.multiply(p, temp_p);
- // temp_r = A*r
- temp_r = temp_p;
- r_dot_Ar = dot(r, temp_r);
- for (int k = 1; k <= max_iterations; k++) {
- // z = M^(-1) * Ap
- A.precondition(temp_p, z);
- // alpha = r^T * A * r / (Ap)^T * M^-1 * Ap)
- btScalar alpha = r_dot_Ar / dot(temp_p, z);
- // x += alpha * p;
- multAndAddTo(alpha, p, x);
- // r -= alpha * z;
- multAndAddTo(-alpha, z, r);
- btScalar norm_r = norm(r);
- if (norm_r < best_r)
- {
- best_x = x;
- best_r = norm_r;
- if (norm_r < tolerance_squared) {
- if (verbose)
- {
- std::cout << "ConjugateResidual iterations " << k << std::endl;
- }
- return k;
- }
- else
- {
- if (verbose)
- {
- std::cout << "ConjugateResidual iterations " << k << " has residual "<< norm_r << std::endl;
- }
- }
- }
- // temp_r = A * r;
- A.multiply(r, temp_r);
- r_dot_Ar_new = dot(r, temp_r);
- btScalar beta = r_dot_Ar_new/r_dot_Ar;
- r_dot_Ar = r_dot_Ar_new;
- // p = beta*p + r;
- p = multAndAdd(beta, p, r);
- // temp_p = beta*temp_p + temp_r;
- temp_p = multAndAdd(beta, temp_p, temp_r);
- }
- if (verbose)
- {
- std::cout << "ConjugateResidual max iterations reached " << max_iterations << std::endl;
- }
- x = best_x;
- return max_iterations;
- }
-
- void reinitialize(const TVStack& b)
- {
- r.resize(b.size());
- p.resize(b.size());
- z.resize(b.size());
- temp_p.resize(b.size());
- temp_r.resize(b.size());
- best_x.resize(b.size());
- best_r = SIMD_INFINITY;
- }
-
- TVStack sub(const TVStack& a, const TVStack& b)
- {
- // c = a-b
- btAssert(a.size() == b.size());
- TVStack c;
- c.resize(a.size());
- for (int i = 0; i < a.size(); ++i)
- {
- c[i] = a[i] - b[i];
- }
- return c;
- }
-
- btScalar squaredNorm(const TVStack& a)
- {
- return dot(a,a);
- }
-
- btScalar norm(const TVStack& a)
- {
- btScalar ret = 0;
- for (int i = 0; i < a.size(); ++i)
- {
- for (int d = 0; d < 3; ++d)
- {
- ret = btMax(ret, btFabs(a[i][d]));
- }
- }
- return ret;
- }
-
- btScalar dot(const TVStack& a, const TVStack& b)
- {
- btScalar ans(0);
- for (int i = 0; i < a.size(); ++i)
- ans += a[i].dot(b[i]);
- return ans;
- }
-
- void multAndAddTo(btScalar s, const TVStack& a, TVStack& result)
- {
- // result += s*a
- btAssert(a.size() == result.size());
- for (int i = 0; i < a.size(); ++i)
- result[i] += s * a[i];
- }
-
- TVStack multAndAdd(btScalar s, const TVStack& a, const TVStack& b)
- {
- // result = a*s + b
- TVStack result;
- result.resize(a.size());
- for (int i = 0; i < a.size(); ++i)
- result[i] = s * a[i] + b[i];
- return result;
- }
+ btConjugateResidual(const int max_it_in)
+ : Base(max_it_in, 1e-8)
+ {
+ }
+
+ virtual ~btConjugateResidual() {}
+
+ // return the number of iterations taken
+ int solve(MatrixX& A, TVStack& x, const TVStack& b, bool verbose = false)
+ {
+ BT_PROFILE("CRSolve");
+ btAssert(x.size() == b.size());
+ reinitialize(b);
+ // r = b - A * x --with assigned dof zeroed out
+ A.multiply(x, temp_r); // borrow temp_r here to store A*x
+ r = this->sub(b, temp_r);
+ // z = M^(-1) * r
+ A.precondition(r, z); // borrow z to store preconditioned r
+ r = z;
+ btScalar residual_norm = this->norm(r);
+ if (residual_norm <= Base::m_tolerance)
+ {
+ return 0;
+ }
+ p = r;
+ btScalar r_dot_Ar, r_dot_Ar_new;
+ // temp_p = A*p
+ A.multiply(p, temp_p);
+ // temp_r = A*r
+ temp_r = temp_p;
+ r_dot_Ar = this->dot(r, temp_r);
+ for (int k = 1; k <= Base::m_maxIterations; k++)
+ {
+ // z = M^(-1) * Ap
+ A.precondition(temp_p, z);
+ // alpha = r^T * A * r / (Ap)^T * M^-1 * Ap)
+ btScalar alpha = r_dot_Ar / this->dot(temp_p, z);
+ // x += alpha * p;
+ this->multAndAddTo(alpha, p, x);
+ // r -= alpha * z;
+ this->multAndAddTo(-alpha, z, r);
+ btScalar norm_r = this->norm(r);
+ if (norm_r < best_r)
+ {
+ best_x = x;
+ best_r = norm_r;
+ if (norm_r < Base::m_tolerance)
+ {
+ return k;
+ }
+ }
+ // temp_r = A * r;
+ A.multiply(r, temp_r);
+ r_dot_Ar_new = this->dot(r, temp_r);
+ btScalar beta = r_dot_Ar_new / r_dot_Ar;
+ r_dot_Ar = r_dot_Ar_new;
+ // p = beta*p + r;
+ p = this->multAndAdd(beta, p, r);
+ // temp_p = beta*temp_p + temp_r;
+ temp_p = this->multAndAdd(beta, temp_p, temp_r);
+ }
+ if (verbose)
+ {
+ std::cout << "ConjugateResidual max iterations reached, residual = " << best_r << std::endl;
+ }
+ x = best_x;
+ return Base::m_maxIterations;
+ }
+
+ void reinitialize(const TVStack& b)
+ {
+ r.resize(b.size());
+ p.resize(b.size());
+ z.resize(b.size());
+ temp_p.resize(b.size());
+ temp_r.resize(b.size());
+ best_x.resize(b.size());
+ best_r = SIMD_INFINITY;
+ }
};
#endif /* btConjugateResidual_h */
-
diff --git a/thirdparty/bullet/BulletSoftBody/btDeformableBackwardEulerObjective.cpp b/thirdparty/bullet/BulletSoftBody/btDeformableBackwardEulerObjective.cpp
index 5381ee6265..2455ed2138 100644
--- a/thirdparty/bullet/BulletSoftBody/btDeformableBackwardEulerObjective.cpp
+++ b/thirdparty/bullet/BulletSoftBody/btDeformableBackwardEulerObjective.cpp
@@ -17,211 +17,283 @@
#include "btPreconditioner.h"
#include "LinearMath/btQuickprof.h"
-btDeformableBackwardEulerObjective::btDeformableBackwardEulerObjective(btAlignedObjectArray<btSoftBody *>& softBodies, const TVStack& backup_v)
-: m_softBodies(softBodies)
-, m_projection(softBodies)
-, m_backupVelocity(backup_v)
-, m_implicit(false)
+btDeformableBackwardEulerObjective::btDeformableBackwardEulerObjective(btAlignedObjectArray<btSoftBody*>& softBodies, const TVStack& backup_v)
+ : m_softBodies(softBodies), m_projection(softBodies), m_backupVelocity(backup_v), m_implicit(false)
{
- m_massPreconditioner = new MassPreconditioner(m_softBodies);
- m_KKTPreconditioner = new KKTPreconditioner(m_softBodies, m_projection, m_lf, m_dt, m_implicit);
- m_preconditioner = m_KKTPreconditioner;
+ m_massPreconditioner = new MassPreconditioner(m_softBodies);
+ m_KKTPreconditioner = new KKTPreconditioner(m_softBodies, m_projection, m_lf, m_dt, m_implicit);
+ m_preconditioner = m_KKTPreconditioner;
}
btDeformableBackwardEulerObjective::~btDeformableBackwardEulerObjective()
{
- delete m_KKTPreconditioner;
- delete m_massPreconditioner;
+ delete m_KKTPreconditioner;
+ delete m_massPreconditioner;
}
void btDeformableBackwardEulerObjective::reinitialize(bool nodeUpdated, btScalar dt)
{
- BT_PROFILE("reinitialize");
- if (dt > 0)
- {
- setDt(dt);
- }
- if(nodeUpdated)
- {
- updateId();
- }
- for (int i = 0; i < m_lf.size(); ++i)
- {
- m_lf[i]->reinitialize(nodeUpdated);
- }
- m_projection.reinitialize(nodeUpdated);
-// m_preconditioner->reinitialize(nodeUpdated);
+ BT_PROFILE("reinitialize");
+ if (dt > 0)
+ {
+ setDt(dt);
+ }
+ if (nodeUpdated)
+ {
+ updateId();
+ }
+ for (int i = 0; i < m_lf.size(); ++i)
+ {
+ m_lf[i]->reinitialize(nodeUpdated);
+ }
+ btMatrix3x3 I;
+ I.setIdentity();
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ if (psb->m_nodes[j].m_im > 0)
+ psb->m_nodes[j].m_effectiveMass = I * (1.0 / psb->m_nodes[j].m_im);
+ }
+ }
+ m_projection.reinitialize(nodeUpdated);
+ // m_preconditioner->reinitialize(nodeUpdated);
}
void btDeformableBackwardEulerObjective::setDt(btScalar dt)
{
- m_dt = dt;
+ m_dt = dt;
}
void btDeformableBackwardEulerObjective::multiply(const TVStack& x, TVStack& b) const
{
- BT_PROFILE("multiply");
- // add in the mass term
- size_t counter = 0;
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- const btSoftBody::Node& node = psb->m_nodes[j];
- b[counter] = (node.m_im == 0) ? btVector3(0,0,0) : x[counter] / node.m_im;
- ++counter;
- }
- }
-
- for (int i = 0; i < m_lf.size(); ++i)
- {
- // add damping matrix
- m_lf[i]->addScaledDampingForceDifferential(-m_dt, x, b);
- if (m_implicit)
- {
- m_lf[i]->addScaledElasticForceDifferential(-m_dt*m_dt, x, b);
- }
- }
- int offset = m_nodes.size();
- for (int i = offset; i < b.size(); ++i)
- {
- b[i].setZero();
- }
- // add in the lagrange multiplier terms
-
- for (int c = 0; c < m_projection.m_lagrangeMultipliers.size(); ++c)
- {
- // C^T * lambda
- const LagrangeMultiplier& lm = m_projection.m_lagrangeMultipliers[c];
- for (int i = 0; i < lm.m_num_nodes; ++i)
- {
- for (int j = 0; j < lm.m_num_constraints; ++j)
- {
- b[lm.m_indices[i]] += x[offset+c][j] * lm.m_weights[i] * lm.m_dirs[j];
- }
- }
- // C * x
- for (int d = 0; d < lm.m_num_constraints; ++d)
- {
- for (int i = 0; i < lm.m_num_nodes; ++i)
- {
- b[offset+c][d] += lm.m_weights[i] * x[lm.m_indices[i]].dot(lm.m_dirs[d]);
- }
- }
- }
+ BT_PROFILE("multiply");
+ // add in the mass term
+ size_t counter = 0;
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ const btSoftBody::Node& node = psb->m_nodes[j];
+ b[counter] = (node.m_im == 0) ? btVector3(0, 0, 0) : x[counter] / node.m_im;
+ ++counter;
+ }
+ }
+
+ for (int i = 0; i < m_lf.size(); ++i)
+ {
+ // add damping matrix
+ m_lf[i]->addScaledDampingForceDifferential(-m_dt, x, b);
+ // Always integrate picking force implicitly for stability.
+ if (m_implicit || m_lf[i]->getForceType() == BT_MOUSE_PICKING_FORCE)
+ {
+ m_lf[i]->addScaledElasticForceDifferential(-m_dt * m_dt, x, b);
+ }
+ }
+ int offset = m_nodes.size();
+ for (int i = offset; i < b.size(); ++i)
+ {
+ b[i].setZero();
+ }
+ // add in the lagrange multiplier terms
+
+ for (int c = 0; c < m_projection.m_lagrangeMultipliers.size(); ++c)
+ {
+ // C^T * lambda
+ const LagrangeMultiplier& lm = m_projection.m_lagrangeMultipliers[c];
+ for (int i = 0; i < lm.m_num_nodes; ++i)
+ {
+ for (int j = 0; j < lm.m_num_constraints; ++j)
+ {
+ b[lm.m_indices[i]] += x[offset + c][j] * lm.m_weights[i] * lm.m_dirs[j];
+ }
+ }
+ // C * x
+ for (int d = 0; d < lm.m_num_constraints; ++d)
+ {
+ for (int i = 0; i < lm.m_num_nodes; ++i)
+ {
+ b[offset + c][d] += lm.m_weights[i] * x[lm.m_indices[i]].dot(lm.m_dirs[d]);
+ }
+ }
+ }
}
void btDeformableBackwardEulerObjective::updateVelocity(const TVStack& dv)
{
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- btSoftBody::Node& node = psb->m_nodes[j];
- node.m_v = m_backupVelocity[node.index] + dv[node.index];
- }
- }
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ btSoftBody::Node& node = psb->m_nodes[j];
+ node.m_v = m_backupVelocity[node.index] + dv[node.index];
+ }
+ }
}
void btDeformableBackwardEulerObjective::applyForce(TVStack& force, bool setZero)
{
- size_t counter = 0;
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- counter += psb->m_nodes.size();
- continue;
- }
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- btScalar one_over_mass = (psb->m_nodes[j].m_im == 0) ? 0 : psb->m_nodes[j].m_im;
- psb->m_nodes[j].m_v += one_over_mass * force[counter++];
- }
- }
- if (setZero)
- {
- for (int i = 0; i < force.size(); ++i)
- force[i].setZero();
- }
+ size_t counter = 0;
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ counter += psb->m_nodes.size();
+ continue;
+ }
+ if (m_implicit)
+ {
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ if (psb->m_nodes[j].m_im != 0)
+ {
+ psb->m_nodes[j].m_v += psb->m_nodes[j].m_effectiveMass_inv * force[counter++];
+ }
+ }
+ }
+ else
+ {
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ btScalar one_over_mass = (psb->m_nodes[j].m_im == 0) ? 0 : psb->m_nodes[j].m_im;
+ psb->m_nodes[j].m_v += one_over_mass * force[counter++];
+ }
+ }
+ }
+ if (setZero)
+ {
+ for (int i = 0; i < force.size(); ++i)
+ force[i].setZero();
+ }
}
-void btDeformableBackwardEulerObjective::computeResidual(btScalar dt, TVStack &residual)
+void btDeformableBackwardEulerObjective::computeResidual(btScalar dt, TVStack& residual)
{
- BT_PROFILE("computeResidual");
- // add implicit force
- for (int i = 0; i < m_lf.size(); ++i)
- {
- if (m_implicit)
- {
- m_lf[i]->addScaledForces(dt, residual);
- }
- else
- {
- m_lf[i]->addScaledDampingForce(dt, residual);
- }
- }
-// m_projection.project(residual);
+ BT_PROFILE("computeResidual");
+ // add implicit force
+ for (int i = 0; i < m_lf.size(); ++i)
+ {
+ // Always integrate picking force implicitly for stability.
+ if (m_implicit || m_lf[i]->getForceType() == BT_MOUSE_PICKING_FORCE)
+ {
+ m_lf[i]->addScaledForces(dt, residual);
+ }
+ else
+ {
+ m_lf[i]->addScaledDampingForce(dt, residual);
+ }
+ }
+ // m_projection.project(residual);
}
btScalar btDeformableBackwardEulerObjective::computeNorm(const TVStack& residual) const
{
- btScalar mag = 0;
- for (int i = 0; i < residual.size(); ++i)
- {
- mag += residual[i].length2();
- }
- return std::sqrt(mag);
+ btScalar mag = 0;
+ for (int i = 0; i < residual.size(); ++i)
+ {
+ mag += residual[i].length2();
+ }
+ return std::sqrt(mag);
}
btScalar btDeformableBackwardEulerObjective::totalEnergy(btScalar dt)
{
- btScalar e = 0;
- for (int i = 0; i < m_lf.size(); ++i)
- {
- e += m_lf[i]->totalEnergy(dt);
- }
- return e;
+ btScalar e = 0;
+ for (int i = 0; i < m_lf.size(); ++i)
+ {
+ e += m_lf[i]->totalEnergy(dt);
+ }
+ return e;
}
void btDeformableBackwardEulerObjective::applyExplicitForce(TVStack& force)
{
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- m_softBodies[i]->advanceDeformation();
- }
-
- for (int i = 0; i < m_lf.size(); ++i)
- {
- m_lf[i]->addScaledExplicitForce(m_dt, force);
- }
- applyForce(force, true);
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ m_softBodies[i]->advanceDeformation();
+ }
+ if (m_implicit)
+ {
+ // apply forces except gravity force
+ btVector3 gravity;
+ for (int i = 0; i < m_lf.size(); ++i)
+ {
+ if (m_lf[i]->getForceType() == BT_GRAVITY_FORCE)
+ {
+ gravity = static_cast<btDeformableGravityForce*>(m_lf[i])->m_gravity;
+ }
+ else
+ {
+ m_lf[i]->addScaledForces(m_dt, force);
+ }
+ }
+ for (int i = 0; i < m_lf.size(); ++i)
+ {
+ m_lf[i]->addScaledHessian(m_dt);
+ }
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (psb->isActive())
+ {
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ // add gravity explicitly
+ psb->m_nodes[j].m_v += m_dt * psb->m_gravityFactor * gravity;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (int i = 0; i < m_lf.size(); ++i)
+ {
+ m_lf[i]->addScaledExplicitForce(m_dt, force);
+ }
+ }
+ // calculate inverse mass matrix for all nodes
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (psb->isActive())
+ {
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ if (psb->m_nodes[j].m_im > 0)
+ {
+ psb->m_nodes[j].m_effectiveMass_inv = psb->m_nodes[j].m_effectiveMass.inverse();
+ }
+ }
+ }
+ }
+ applyForce(force, true);
}
void btDeformableBackwardEulerObjective::initialGuess(TVStack& dv, const TVStack& residual)
{
- size_t counter = 0;
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- dv[counter] = psb->m_nodes[j].m_im * residual[counter];
- ++counter;
- }
- }
+ size_t counter = 0;
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ dv[counter] = psb->m_nodes[j].m_im * residual[counter];
+ ++counter;
+ }
+ }
}
//set constraints as projections
void btDeformableBackwardEulerObjective::setConstraints(const btContactSolverInfo& infoGlobal)
{
- m_projection.setConstraints(infoGlobal);
+ m_projection.setConstraints(infoGlobal);
}
void btDeformableBackwardEulerObjective::applyDynamicFriction(TVStack& r)
{
- m_projection.applyDynamicFriction(r);
+ m_projection.applyDynamicFriction(r);
}
diff --git a/thirdparty/bullet/BulletSoftBody/btDeformableBackwardEulerObjective.h b/thirdparty/bullet/BulletSoftBody/btDeformableBackwardEulerObjective.h
index 86579e71ac..eb05b9f010 100644
--- a/thirdparty/bullet/BulletSoftBody/btDeformableBackwardEulerObjective.h
+++ b/thirdparty/bullet/BulletSoftBody/btDeformableBackwardEulerObjective.h
@@ -31,143 +31,168 @@
class btDeformableBackwardEulerObjective
{
public:
- typedef btAlignedObjectArray<btVector3> TVStack;
- btScalar m_dt;
- btAlignedObjectArray<btDeformableLagrangianForce*> m_lf;
- btAlignedObjectArray<btSoftBody *>& m_softBodies;
- Preconditioner* m_preconditioner;
- btDeformableContactProjection m_projection;
- const TVStack& m_backupVelocity;
- btAlignedObjectArray<btSoftBody::Node* > m_nodes;
- bool m_implicit;
- MassPreconditioner* m_massPreconditioner;
- KKTPreconditioner* m_KKTPreconditioner;
-
- btDeformableBackwardEulerObjective(btAlignedObjectArray<btSoftBody *>& softBodies, const TVStack& backup_v);
-
- virtual ~btDeformableBackwardEulerObjective();
-
- void initialize(){}
-
- // compute the rhs for CG solve, i.e, add the dt scaled implicit force to residual
- void computeResidual(btScalar dt, TVStack& residual);
-
- // add explicit force to the velocity
- void applyExplicitForce(TVStack& force);
-
- // apply force to velocity and optionally reset the force to zero
- void applyForce(TVStack& force, bool setZero);
-
- // compute the norm of the residual
- btScalar computeNorm(const TVStack& residual) const;
-
- // compute one step of the solve (there is only one solve if the system is linear)
- void computeStep(TVStack& dv, const TVStack& residual, const btScalar& dt);
-
- // perform A*x = b
- void multiply(const TVStack& x, TVStack& b) const;
-
- // set initial guess for CG solve
- void initialGuess(TVStack& dv, const TVStack& residual);
-
- // reset data structure and reset dt
- void reinitialize(bool nodeUpdated, btScalar dt);
-
- void setDt(btScalar dt);
-
- // add friction force to residual
- void applyDynamicFriction(TVStack& r);
-
- // add dv to velocity
- void updateVelocity(const TVStack& dv);
-
- //set constraints as projections
- void setConstraints(const btContactSolverInfo& infoGlobal);
-
- // update the projections and project the residual
- void project(TVStack& r)
- {
- BT_PROFILE("project");
- m_projection.project(r);
- }
-
- // perform precondition M^(-1) x = b
- void precondition(const TVStack& x, TVStack& b)
- {
- m_preconditioner->operator()(x,b);
- }
-
- // reindex all the vertices
- virtual void updateId()
- {
- size_t node_id = 0;
- size_t face_id = 0;
- m_nodes.clear();
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- psb->m_nodes[j].index = node_id;
- m_nodes.push_back(&psb->m_nodes[j]);
- ++node_id;
- }
- for (int j = 0; j < psb->m_faces.size(); ++j)
- {
- psb->m_faces[j].m_index = face_id;
- ++face_id;
- }
- }
- }
-
- const btAlignedObjectArray<btSoftBody::Node*>* getIndices() const
- {
- return &m_nodes;
- }
-
- void setImplicit(bool implicit)
- {
- m_implicit = implicit;
- }
-
- // Calculate the total potential energy in the system
- btScalar totalEnergy(btScalar dt);
-
- void addLagrangeMultiplier(const TVStack& vec, TVStack& extended_vec)
- {
- extended_vec.resize(vec.size() + m_projection.m_lagrangeMultipliers.size());
- for (int i = 0; i < vec.size(); ++i)
- {
- extended_vec[i] = vec[i];
- }
- int offset = vec.size();
- for (int i = 0; i < m_projection.m_lagrangeMultipliers.size(); ++i)
- {
- extended_vec[offset + i].setZero();
- }
- }
-
- void addLagrangeMultiplierRHS(const TVStack& residual, const TVStack& m_dv, TVStack& extended_residual)
- {
- extended_residual.resize(residual.size() + m_projection.m_lagrangeMultipliers.size());
- for (int i = 0; i < residual.size(); ++i)
- {
- extended_residual[i] = residual[i];
- }
- int offset = residual.size();
- for (int i = 0; i < m_projection.m_lagrangeMultipliers.size(); ++i)
- {
- const LagrangeMultiplier& lm = m_projection.m_lagrangeMultipliers[i];
- extended_residual[offset + i].setZero();
- for (int d = 0; d < lm.m_num_constraints; ++d)
- {
- for (int n = 0; n < lm.m_num_nodes; ++n)
- {
- extended_residual[offset + i][d] += lm.m_weights[n] * m_dv[lm.m_indices[n]].dot(lm.m_dirs[d]);
- }
- }
- }
- }
+ typedef btAlignedObjectArray<btVector3> TVStack;
+ btScalar m_dt;
+ btAlignedObjectArray<btDeformableLagrangianForce*> m_lf;
+ btAlignedObjectArray<btSoftBody*>& m_softBodies;
+ Preconditioner* m_preconditioner;
+ btDeformableContactProjection m_projection;
+ const TVStack& m_backupVelocity;
+ btAlignedObjectArray<btSoftBody::Node*> m_nodes;
+ bool m_implicit;
+ MassPreconditioner* m_massPreconditioner;
+ KKTPreconditioner* m_KKTPreconditioner;
+
+ btDeformableBackwardEulerObjective(btAlignedObjectArray<btSoftBody*>& softBodies, const TVStack& backup_v);
+
+ virtual ~btDeformableBackwardEulerObjective();
+
+ void initialize() {}
+
+ // compute the rhs for CG solve, i.e, add the dt scaled implicit force to residual
+ void computeResidual(btScalar dt, TVStack& residual);
+
+ // add explicit force to the velocity
+ void applyExplicitForce(TVStack& force);
+
+ // apply force to velocity and optionally reset the force to zero
+ void applyForce(TVStack& force, bool setZero);
+
+ // compute the norm of the residual
+ btScalar computeNorm(const TVStack& residual) const;
+
+ // compute one step of the solve (there is only one solve if the system is linear)
+ void computeStep(TVStack& dv, const TVStack& residual, const btScalar& dt);
+
+ // perform A*x = b
+ void multiply(const TVStack& x, TVStack& b) const;
+
+ // set initial guess for CG solve
+ void initialGuess(TVStack& dv, const TVStack& residual);
+
+ // reset data structure and reset dt
+ void reinitialize(bool nodeUpdated, btScalar dt);
+
+ void setDt(btScalar dt);
+
+ // add friction force to residual
+ void applyDynamicFriction(TVStack& r);
+
+ // add dv to velocity
+ void updateVelocity(const TVStack& dv);
+
+ //set constraints as projections
+ void setConstraints(const btContactSolverInfo& infoGlobal);
+
+ // update the projections and project the residual
+ void project(TVStack& r)
+ {
+ BT_PROFILE("project");
+ m_projection.project(r);
+ }
+
+ // perform precondition M^(-1) x = b
+ void precondition(const TVStack& x, TVStack& b)
+ {
+ m_preconditioner->operator()(x, b);
+ }
+
+ // reindex all the vertices
+ virtual void updateId()
+ {
+ size_t node_id = 0;
+ size_t face_id = 0;
+ m_nodes.clear();
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ psb->m_nodes[j].index = node_id;
+ m_nodes.push_back(&psb->m_nodes[j]);
+ ++node_id;
+ }
+ for (int j = 0; j < psb->m_faces.size(); ++j)
+ {
+ psb->m_faces[j].m_index = face_id;
+ ++face_id;
+ }
+ }
+ }
+
+ const btAlignedObjectArray<btSoftBody::Node*>* getIndices() const
+ {
+ return &m_nodes;
+ }
+
+ void setImplicit(bool implicit)
+ {
+ m_implicit = implicit;
+ }
+
+ // Calculate the total potential energy in the system
+ btScalar totalEnergy(btScalar dt);
+
+ void addLagrangeMultiplier(const TVStack& vec, TVStack& extended_vec)
+ {
+ extended_vec.resize(vec.size() + m_projection.m_lagrangeMultipliers.size());
+ for (int i = 0; i < vec.size(); ++i)
+ {
+ extended_vec[i] = vec[i];
+ }
+ int offset = vec.size();
+ for (int i = 0; i < m_projection.m_lagrangeMultipliers.size(); ++i)
+ {
+ extended_vec[offset + i].setZero();
+ }
+ }
+
+ void addLagrangeMultiplierRHS(const TVStack& residual, const TVStack& m_dv, TVStack& extended_residual)
+ {
+ extended_residual.resize(residual.size() + m_projection.m_lagrangeMultipliers.size());
+ for (int i = 0; i < residual.size(); ++i)
+ {
+ extended_residual[i] = residual[i];
+ }
+ int offset = residual.size();
+ for (int i = 0; i < m_projection.m_lagrangeMultipliers.size(); ++i)
+ {
+ const LagrangeMultiplier& lm = m_projection.m_lagrangeMultipliers[i];
+ extended_residual[offset + i].setZero();
+ for (int d = 0; d < lm.m_num_constraints; ++d)
+ {
+ for (int n = 0; n < lm.m_num_nodes; ++n)
+ {
+ extended_residual[offset + i][d] += lm.m_weights[n] * m_dv[lm.m_indices[n]].dot(lm.m_dirs[d]);
+ }
+ }
+ }
+ }
+
+ void calculateContactForce(const TVStack& dv, const TVStack& rhs, TVStack& f)
+ {
+ size_t counter = 0;
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ const btSoftBody::Node& node = psb->m_nodes[j];
+ f[counter] = (node.m_im == 0) ? btVector3(0, 0, 0) : dv[counter] / node.m_im;
+ ++counter;
+ }
+ }
+ for (int i = 0; i < m_lf.size(); ++i)
+ {
+ // add damping matrix
+ m_lf[i]->addScaledDampingForceDifferential(-m_dt, dv, f);
+ }
+ counter = 0;
+ for (; counter < f.size(); ++counter)
+ {
+ f[counter] = rhs[counter] - f[counter];
+ }
+ }
};
#endif /* btBackwardEulerObjective_h */
diff --git a/thirdparty/bullet/BulletSoftBody/btDeformableBodySolver.cpp b/thirdparty/bullet/BulletSoftBody/btDeformableBodySolver.cpp
index 132699c54f..4b11fccecb 100644
--- a/thirdparty/bullet/BulletSoftBody/btDeformableBodySolver.cpp
+++ b/thirdparty/bullet/BulletSoftBody/btDeformableBodySolver.cpp
@@ -18,468 +18,489 @@
#include "btDeformableBodySolver.h"
#include "btSoftBodyInternals.h"
#include "LinearMath/btQuickprof.h"
-static const int kMaxConjugateGradientIterations = 50;
+static const int kMaxConjugateGradientIterations = 300;
btDeformableBodySolver::btDeformableBodySolver()
-: m_numNodes(0)
-, m_cg(kMaxConjugateGradientIterations)
-, m_cr(kMaxConjugateGradientIterations)
-, m_maxNewtonIterations(5)
-, m_newtonTolerance(1e-4)
-, m_lineSearch(false)
-, m_useProjection(false)
+ : m_numNodes(0), m_cg(kMaxConjugateGradientIterations), m_cr(kMaxConjugateGradientIterations), m_maxNewtonIterations(1), m_newtonTolerance(1e-4), m_lineSearch(false), m_useProjection(false)
{
- m_objective = new btDeformableBackwardEulerObjective(m_softBodies, m_backupVelocity);
+ m_objective = new btDeformableBackwardEulerObjective(m_softBodies, m_backupVelocity);
}
btDeformableBodySolver::~btDeformableBodySolver()
{
- delete m_objective;
+ delete m_objective;
}
void btDeformableBodySolver::solveDeformableConstraints(btScalar solverdt)
{
- BT_PROFILE("solveDeformableConstraints");
- if (!m_implicit)
- {
- m_objective->computeResidual(solverdt, m_residual);
- m_objective->applyDynamicFriction(m_residual);
- if (m_useProjection)
- {
- computeStep(m_dv, m_residual);
- }
- else
- {
- TVStack rhs, x;
- m_objective->addLagrangeMultiplierRHS(m_residual, m_dv, rhs);
- m_objective->addLagrangeMultiplier(m_dv, x);
- m_objective->m_preconditioner->reinitialize(true);
- computeStep(x, rhs);
- for (int i = 0; i<m_dv.size(); ++i)
- {
- m_dv[i] = x[i];
- }
- }
- updateVelocity();
- }
- else
- {
- for (int i = 0; i < m_maxNewtonIterations; ++i)
- {
- updateState();
- // add the inertia term in the residual
- int counter = 0;
- for (int k = 0; k < m_softBodies.size(); ++k)
- {
- btSoftBody* psb = m_softBodies[k];
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- if (psb->m_nodes[j].m_im > 0)
- {
- m_residual[counter] = (-1./psb->m_nodes[j].m_im) * m_dv[counter];
- }
- ++counter;
- }
- }
-
- m_objective->computeResidual(solverdt, m_residual);
- if (m_objective->computeNorm(m_residual) < m_newtonTolerance && i > 0)
- {
- break;
- }
- // todo xuchenhan@: this really only needs to be calculated once
- m_objective->applyDynamicFriction(m_residual);
- if (m_lineSearch)
- {
- btScalar inner_product = computeDescentStep(m_ddv,m_residual);
- btScalar alpha = 0.01, beta = 0.5; // Boyd & Vandenberghe suggested alpha between 0.01 and 0.3, beta between 0.1 to 0.8
- btScalar scale = 2;
- btScalar f0 = m_objective->totalEnergy(solverdt)+kineticEnergy(), f1, f2;
- backupDv();
- do {
- scale *= beta;
- if (scale < 1e-8) {
- return;
- }
- updateEnergy(scale);
- f1 = m_objective->totalEnergy(solverdt)+kineticEnergy();
- f2 = f0 - alpha * scale * inner_product;
- } while (!(f1 < f2+SIMD_EPSILON)); // if anything here is nan then the search continues
- revertDv();
- updateDv(scale);
- }
- else
- {
- computeStep(m_ddv, m_residual);
- updateDv();
- }
- for (int j = 0; j < m_numNodes; ++j)
- {
- m_ddv[j].setZero();
- m_residual[j].setZero();
- }
- }
- updateVelocity();
- }
+ BT_PROFILE("solveDeformableConstraints");
+ if (!m_implicit)
+ {
+ m_objective->computeResidual(solverdt, m_residual);
+ m_objective->applyDynamicFriction(m_residual);
+ if (m_useProjection)
+ {
+ computeStep(m_dv, m_residual);
+ }
+ else
+ {
+ TVStack rhs, x;
+ m_objective->addLagrangeMultiplierRHS(m_residual, m_dv, rhs);
+ m_objective->addLagrangeMultiplier(m_dv, x);
+ m_objective->m_preconditioner->reinitialize(true);
+ computeStep(x, rhs);
+ for (int i = 0; i < m_dv.size(); ++i)
+ {
+ m_dv[i] = x[i];
+ }
+ }
+ updateVelocity();
+ }
+ else
+ {
+ for (int i = 0; i < m_maxNewtonIterations; ++i)
+ {
+ updateState();
+ // add the inertia term in the residual
+ int counter = 0;
+ for (int k = 0; k < m_softBodies.size(); ++k)
+ {
+ btSoftBody* psb = m_softBodies[k];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ if (psb->m_nodes[j].m_im > 0)
+ {
+ m_residual[counter] = (-1. / psb->m_nodes[j].m_im) * m_dv[counter];
+ }
+ ++counter;
+ }
+ }
+
+ m_objective->computeResidual(solverdt, m_residual);
+ if (m_objective->computeNorm(m_residual) < m_newtonTolerance && i > 0)
+ {
+ break;
+ }
+ // todo xuchenhan@: this really only needs to be calculated once
+ m_objective->applyDynamicFriction(m_residual);
+ if (m_lineSearch)
+ {
+ btScalar inner_product = computeDescentStep(m_ddv, m_residual);
+ btScalar alpha = 0.01, beta = 0.5; // Boyd & Vandenberghe suggested alpha between 0.01 and 0.3, beta between 0.1 to 0.8
+ btScalar scale = 2;
+ btScalar f0 = m_objective->totalEnergy(solverdt) + kineticEnergy(), f1, f2;
+ backupDv();
+ do
+ {
+ scale *= beta;
+ if (scale < 1e-8)
+ {
+ return;
+ }
+ updateEnergy(scale);
+ f1 = m_objective->totalEnergy(solverdt) + kineticEnergy();
+ f2 = f0 - alpha * scale * inner_product;
+ } while (!(f1 < f2 + SIMD_EPSILON)); // if anything here is nan then the search continues
+ revertDv();
+ updateDv(scale);
+ }
+ else
+ {
+ computeStep(m_ddv, m_residual);
+ updateDv();
+ }
+ for (int j = 0; j < m_numNodes; ++j)
+ {
+ m_ddv[j].setZero();
+ m_residual[j].setZero();
+ }
+ }
+ updateVelocity();
+ }
}
btScalar btDeformableBodySolver::kineticEnergy()
{
- btScalar ke = 0;
- for (int i = 0; i < m_softBodies.size();++i)
- {
- btSoftBody* psb = m_softBodies[i];
- for (int j = 0; j < psb->m_nodes.size();++j)
- {
- btSoftBody::Node& node = psb->m_nodes[j];
- if (node.m_im > 0)
- {
- ke += m_dv[node.index].length2() * 0.5 / node.m_im;
- }
- }
- }
- return ke;
+ btScalar ke = 0;
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ btSoftBody::Node& node = psb->m_nodes[j];
+ if (node.m_im > 0)
+ {
+ ke += m_dv[node.index].length2() * 0.5 / node.m_im;
+ }
+ }
+ }
+ return ke;
}
void btDeformableBodySolver::backupDv()
{
- m_backup_dv.resize(m_dv.size());
- for (int i = 0; i<m_backup_dv.size(); ++i)
- {
- m_backup_dv[i] = m_dv[i];
- }
+ m_backup_dv.resize(m_dv.size());
+ for (int i = 0; i < m_backup_dv.size(); ++i)
+ {
+ m_backup_dv[i] = m_dv[i];
+ }
}
void btDeformableBodySolver::revertDv()
{
- for (int i = 0; i<m_backup_dv.size(); ++i)
- {
- m_dv[i] = m_backup_dv[i];
- }
+ for (int i = 0; i < m_backup_dv.size(); ++i)
+ {
+ m_dv[i] = m_backup_dv[i];
+ }
}
void btDeformableBodySolver::updateEnergy(btScalar scale)
{
- for (int i = 0; i<m_dv.size(); ++i)
- {
- m_dv[i] = m_backup_dv[i] + scale * m_ddv[i];
- }
- updateState();
+ for (int i = 0; i < m_dv.size(); ++i)
+ {
+ m_dv[i] = m_backup_dv[i] + scale * m_ddv[i];
+ }
+ updateState();
}
-
btScalar btDeformableBodySolver::computeDescentStep(TVStack& ddv, const TVStack& residual, bool verbose)
{
- m_cg.solve(*m_objective, ddv, residual, false);
- btScalar inner_product = m_cg.dot(residual, m_ddv);
- btScalar res_norm = m_objective->computeNorm(residual);
- btScalar tol = 1e-5 * res_norm * m_objective->computeNorm(m_ddv);
- if (inner_product < -tol)
- {
- if (verbose)
- {
- std::cout << "Looking backwards!" << std::endl;
- }
- for (int i = 0; i < m_ddv.size();++i)
- {
- m_ddv[i] = -m_ddv[i];
- }
- inner_product = -inner_product;
- }
- else if (std::abs(inner_product) < tol)
- {
- if (verbose)
- {
- std::cout << "Gradient Descent!" << std::endl;
- }
- btScalar scale = m_objective->computeNorm(m_ddv) / res_norm;
- for (int i = 0; i < m_ddv.size();++i)
- {
- m_ddv[i] = scale * residual[i];
- }
- inner_product = scale * res_norm * res_norm;
- }
- return inner_product;
+ m_cg.solve(*m_objective, ddv, residual, false);
+ btScalar inner_product = m_cg.dot(residual, m_ddv);
+ btScalar res_norm = m_objective->computeNorm(residual);
+ btScalar tol = 1e-5 * res_norm * m_objective->computeNorm(m_ddv);
+ if (inner_product < -tol)
+ {
+ if (verbose)
+ {
+ std::cout << "Looking backwards!" << std::endl;
+ }
+ for (int i = 0; i < m_ddv.size(); ++i)
+ {
+ m_ddv[i] = -m_ddv[i];
+ }
+ inner_product = -inner_product;
+ }
+ else if (std::abs(inner_product) < tol)
+ {
+ if (verbose)
+ {
+ std::cout << "Gradient Descent!" << std::endl;
+ }
+ btScalar scale = m_objective->computeNorm(m_ddv) / res_norm;
+ for (int i = 0; i < m_ddv.size(); ++i)
+ {
+ m_ddv[i] = scale * residual[i];
+ }
+ inner_product = scale * res_norm * res_norm;
+ }
+ return inner_product;
}
void btDeformableBodySolver::updateState()
{
- updateVelocity();
- updateTempPosition();
+ updateVelocity();
+ updateTempPosition();
}
void btDeformableBodySolver::updateDv(btScalar scale)
{
- for (int i = 0; i < m_numNodes; ++i)
- {
- m_dv[i] += scale * m_ddv[i];
- }
+ for (int i = 0; i < m_numNodes; ++i)
+ {
+ m_dv[i] += scale * m_ddv[i];
+ }
}
void btDeformableBodySolver::computeStep(TVStack& ddv, const TVStack& residual)
{
- if (m_useProjection)
- m_cg.solve(*m_objective, ddv, residual, false);
- else
- m_cr.solve(*m_objective, ddv, residual, false);
+ if (m_useProjection)
+ m_cg.solve(*m_objective, ddv, residual, false);
+ else
+ m_cr.solve(*m_objective, ddv, residual, false);
}
-void btDeformableBodySolver::reinitialize(const btAlignedObjectArray<btSoftBody *>& softBodies, btScalar dt)
+void btDeformableBodySolver::reinitialize(const btAlignedObjectArray<btSoftBody*>& softBodies, btScalar dt)
{
- m_softBodies.copyFromArray(softBodies);
- bool nodeUpdated = updateNodes();
-
- if (nodeUpdated)
- {
- m_dv.resize(m_numNodes, btVector3(0,0,0));
- m_ddv.resize(m_numNodes, btVector3(0,0,0));
- m_residual.resize(m_numNodes, btVector3(0,0,0));
- m_backupVelocity.resize(m_numNodes, btVector3(0,0,0));
- }
-
- // need to setZero here as resize only set value for newly allocated items
- for (int i = 0; i < m_numNodes; ++i)
- {
- m_dv[i].setZero();
- m_ddv[i].setZero();
- m_residual[i].setZero();
- }
-
- m_dt = dt;
- m_objective->reinitialize(nodeUpdated, dt);
- updateSoftBodies();
-}
+ m_softBodies.copyFromArray(softBodies);
+ bool nodeUpdated = updateNodes();
-void btDeformableBodySolver::setConstraints(const btContactSolverInfo& infoGlobal)
-{
- BT_PROFILE("setConstraint");
- m_objective->setConstraints(infoGlobal);
+ if (nodeUpdated)
+ {
+ m_dv.resize(m_numNodes, btVector3(0, 0, 0));
+ m_ddv.resize(m_numNodes, btVector3(0, 0, 0));
+ m_residual.resize(m_numNodes, btVector3(0, 0, 0));
+ m_backupVelocity.resize(m_numNodes, btVector3(0, 0, 0));
+ }
+
+ // need to setZero here as resize only set value for newly allocated items
+ for (int i = 0; i < m_numNodes; ++i)
+ {
+ m_dv[i].setZero();
+ m_ddv[i].setZero();
+ m_residual[i].setZero();
+ }
+
+ if (dt > 0)
+ {
+ m_dt = dt;
+ }
+ m_objective->reinitialize(nodeUpdated, dt);
+ updateSoftBodies();
}
-btScalar btDeformableBodySolver::solveContactConstraints(btCollisionObject** deformableBodies,int numDeformableBodies, const btContactSolverInfo& infoGlobal)
+void btDeformableBodySolver::setConstraints(const btContactSolverInfo& infoGlobal)
{
- BT_PROFILE("solveContactConstraints");
- btScalar maxSquaredResidual = m_objective->m_projection.update(deformableBodies,numDeformableBodies, infoGlobal);
- return maxSquaredResidual;
+ BT_PROFILE("setConstraint");
+ m_objective->setConstraints(infoGlobal);
}
-void btDeformableBodySolver::splitImpulseSetup(const btContactSolverInfo& infoGlobal)
+btScalar btDeformableBodySolver::solveContactConstraints(btCollisionObject** deformableBodies, int numDeformableBodies, const btContactSolverInfo& infoGlobal)
{
- m_objective->m_projection.splitImpulseSetup(infoGlobal);
+ BT_PROFILE("solveContactConstraints");
+ btScalar maxSquaredResidual = m_objective->m_projection.update(deformableBodies, numDeformableBodies, infoGlobal);
+ return maxSquaredResidual;
}
void btDeformableBodySolver::updateVelocity()
{
- int counter = 0;
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- psb->m_maxSpeedSquared = 0;
- if (!psb->isActive())
- {
- counter += psb->m_nodes.size();
- continue;
- }
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- // set NaN to zero;
- if (m_dv[counter] != m_dv[counter])
- {
- m_dv[counter].setZero();
- }
- psb->m_nodes[j].m_v = m_backupVelocity[counter]+m_dv[counter];
- psb->m_maxSpeedSquared = btMax(psb->m_maxSpeedSquared, psb->m_nodes[j].m_v.length2());
- ++counter;
- }
- }
+ int counter = 0;
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ psb->m_maxSpeedSquared = 0;
+ if (!psb->isActive())
+ {
+ counter += psb->m_nodes.size();
+ continue;
+ }
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ // set NaN to zero;
+ if (m_dv[counter] != m_dv[counter])
+ {
+ m_dv[counter].setZero();
+ }
+ if (m_implicit)
+ {
+ psb->m_nodes[j].m_v = m_backupVelocity[counter] + m_dv[counter];
+ }
+ else
+ {
+ psb->m_nodes[j].m_v = m_backupVelocity[counter] + m_dv[counter] - psb->m_nodes[j].m_splitv;
+ }
+ psb->m_maxSpeedSquared = btMax(psb->m_maxSpeedSquared, psb->m_nodes[j].m_v.length2());
+ ++counter;
+ }
+ }
}
void btDeformableBodySolver::updateTempPosition()
{
- int counter = 0;
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- counter += psb->m_nodes.size();
- continue;
- }
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- psb->m_nodes[j].m_q = psb->m_nodes[j].m_x + m_dt * psb->m_nodes[j].m_v;
- ++counter;
- }
- psb->updateDeformation();
- }
+ int counter = 0;
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ counter += psb->m_nodes.size();
+ continue;
+ }
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ psb->m_nodes[j].m_q = psb->m_nodes[j].m_x + m_dt * (psb->m_nodes[j].m_v + psb->m_nodes[j].m_splitv);
+ ++counter;
+ }
+ psb->updateDeformation();
+ }
}
void btDeformableBodySolver::backupVelocity()
{
- int counter = 0;
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- m_backupVelocity[counter++] = psb->m_nodes[j].m_v;
- }
- }
+ int counter = 0;
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ m_backupVelocity[counter++] = psb->m_nodes[j].m_v;
+ }
+ }
}
void btDeformableBodySolver::setupDeformableSolve(bool implicit)
{
- int counter = 0;
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- counter += psb->m_nodes.size();
- continue;
- }
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- if (implicit)
- {
- if ((psb->m_nodes[j].m_v - m_backupVelocity[counter]).norm() < SIMD_EPSILON)
- m_dv[counter] = psb->m_nodes[j].m_v - m_backupVelocity[counter];
- else
- m_dv[counter] = psb->m_nodes[j].m_v - psb->m_nodes[j].m_vn;
- m_backupVelocity[counter] = psb->m_nodes[j].m_vn;
- }
- else
- {
- m_dv[counter] = psb->m_nodes[j].m_v - m_backupVelocity[counter];
- }
- psb->m_nodes[j].m_v = m_backupVelocity[counter];
- ++counter;
- }
- }
+ int counter = 0;
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ counter += psb->m_nodes.size();
+ continue;
+ }
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ if (implicit)
+ {
+ // setting the initial guess for newton, need m_dv = v_{n+1} - v_n for dofs that are in constraint.
+ if (psb->m_nodes[j].m_v == m_backupVelocity[counter])
+ m_dv[counter].setZero();
+ else
+ m_dv[counter] = psb->m_nodes[j].m_v - psb->m_nodes[j].m_vn;
+ m_backupVelocity[counter] = psb->m_nodes[j].m_vn;
+ }
+ else
+ {
+ m_dv[counter] = psb->m_nodes[j].m_v + psb->m_nodes[j].m_splitv - m_backupVelocity[counter];
+ }
+ psb->m_nodes[j].m_v = m_backupVelocity[counter];
+ ++counter;
+ }
+ }
}
void btDeformableBodySolver::revertVelocity()
{
- int counter = 0;
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- psb->m_nodes[j].m_v = m_backupVelocity[counter++];
- }
- }
+ int counter = 0;
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ psb->m_nodes[j].m_v = m_backupVelocity[counter++];
+ }
+ }
}
bool btDeformableBodySolver::updateNodes()
{
- int numNodes = 0;
- for (int i = 0; i < m_softBodies.size(); ++i)
- numNodes += m_softBodies[i]->m_nodes.size();
- if (numNodes != m_numNodes)
- {
- m_numNodes = numNodes;
- return true;
- }
- return false;
+ int numNodes = 0;
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ numNodes += m_softBodies[i]->m_nodes.size();
+ if (numNodes != m_numNodes)
+ {
+ m_numNodes = numNodes;
+ return true;
+ }
+ return false;
}
-
void btDeformableBodySolver::predictMotion(btScalar solverdt)
{
- // apply explicit forces to velocity
- m_objective->applyExplicitForce(m_residual);
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody *psb = m_softBodies[i];
-
- if (psb->isActive())
- {
- // predict motion for collision detection
- predictDeformableMotion(psb, solverdt);
- }
- }
+ // apply explicit forces to velocity
+ if (m_implicit)
+ {
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (psb->isActive())
+ {
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ psb->m_nodes[j].m_q = psb->m_nodes[j].m_x + psb->m_nodes[j].m_v * solverdt;
+ }
+ }
+ }
+ }
+ m_objective->applyExplicitForce(m_residual);
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+
+ if (psb->isActive())
+ {
+ // predict motion for collision detection
+ predictDeformableMotion(psb, solverdt);
+ }
+ }
}
void btDeformableBodySolver::predictDeformableMotion(btSoftBody* psb, btScalar dt)
{
- BT_PROFILE("btDeformableBodySolver::predictDeformableMotion");
- int i, ni;
-
- /* Update */
- if (psb->m_bUpdateRtCst)
- {
- psb->m_bUpdateRtCst = false;
- psb->updateConstants();
- psb->m_fdbvt.clear();
- if (psb->m_cfg.collisions & btSoftBody::fCollision::SDF_RD)
- {
- psb->initializeFaceTree();
- }
- }
-
- /* Prepare */
- psb->m_sst.sdt = dt * psb->m_cfg.timescale;
- psb->m_sst.isdt = 1 / psb->m_sst.sdt;
- psb->m_sst.velmrg = psb->m_sst.sdt * 3;
- psb->m_sst.radmrg = psb->getCollisionShape()->getMargin();
- psb->m_sst.updmrg = psb->m_sst.radmrg * (btScalar)0.25;
- /* Bounds */
- psb->updateBounds();
-
- /* Integrate */
- // do not allow particles to move more than the bounding box size
- btScalar max_v = (psb->m_bounds[1]-psb->m_bounds[0]).norm() / dt;
- for (i = 0, ni = psb->m_nodes.size(); i < ni; ++i)
- {
- btSoftBody::Node& n = psb->m_nodes[i];
- // apply drag
- n.m_v *= (1 - psb->m_cfg.drag);
- // scale velocity back
- if (n.m_v.norm() > max_v)
- {
- n.m_v.safeNormalize();
- n.m_v *= max_v;
- }
- n.m_q = n.m_x + n.m_v * dt;
- n.m_penetration = 0;
- }
-
- /* Nodes */
- psb->updateNodeTree(true, true);
- if (!psb->m_fdbvt.empty())
- {
- psb->updateFaceTree(true, true);
- }
- /* Clear contacts */
- psb->m_nodeRigidContacts.resize(0);
- psb->m_faceRigidContacts.resize(0);
- psb->m_faceNodeContacts.resize(0);
- /* Optimize dbvt's */
-// psb->m_ndbvt.optimizeIncremental(1);
-// psb->m_fdbvt.optimizeIncremental(1);
-}
+ BT_PROFILE("btDeformableBodySolver::predictDeformableMotion");
+ int i, ni;
+
+ /* Update */
+ if (psb->m_bUpdateRtCst)
+ {
+ psb->m_bUpdateRtCst = false;
+ psb->updateConstants();
+ psb->m_fdbvt.clear();
+ if (psb->m_cfg.collisions & btSoftBody::fCollision::SDF_RD)
+ {
+ psb->initializeFaceTree();
+ }
+ }
+ /* Prepare */
+ psb->m_sst.sdt = dt * psb->m_cfg.timescale;
+ psb->m_sst.isdt = 1 / psb->m_sst.sdt;
+ psb->m_sst.velmrg = psb->m_sst.sdt * 3;
+ psb->m_sst.radmrg = psb->getCollisionShape()->getMargin();
+ psb->m_sst.updmrg = psb->m_sst.radmrg * (btScalar)0.25;
+ /* Bounds */
+ psb->updateBounds();
+
+ /* Integrate */
+ // do not allow particles to move more than the bounding box size
+ btScalar max_v = (psb->m_bounds[1] - psb->m_bounds[0]).norm() / dt;
+ for (i = 0, ni = psb->m_nodes.size(); i < ni; ++i)
+ {
+ btSoftBody::Node& n = psb->m_nodes[i];
+ // apply drag
+ n.m_v *= (1 - psb->m_cfg.drag);
+ // scale velocity back
+ if (m_implicit)
+ {
+ n.m_q = n.m_x;
+ }
+ else
+ {
+ if (n.m_v.norm() > max_v)
+ {
+ n.m_v.safeNormalize();
+ n.m_v *= max_v;
+ }
+ n.m_q = n.m_x + n.m_v * dt;
+ }
+ n.m_splitv.setZero();
+ n.m_constrained = false;
+ }
+
+ /* Nodes */
+ psb->updateNodeTree(true, true);
+ if (!psb->m_fdbvt.empty())
+ {
+ psb->updateFaceTree(true, true);
+ }
+ /* Clear contacts */
+ psb->m_nodeRigidContacts.resize(0);
+ psb->m_faceRigidContacts.resize(0);
+ psb->m_faceNodeContacts.resize(0);
+ /* Optimize dbvt's */
+ // psb->m_ndbvt.optimizeIncremental(1);
+ // psb->m_fdbvt.optimizeIncremental(1);
+}
void btDeformableBodySolver::updateSoftBodies()
{
- BT_PROFILE("updateSoftBodies");
- for (int i = 0; i < m_softBodies.size(); i++)
- {
- btSoftBody *psb = (btSoftBody *)m_softBodies[i];
- if (psb->isActive())
- {
- psb->updateNormals();
- }
- }
+ BT_PROFILE("updateSoftBodies");
+ for (int i = 0; i < m_softBodies.size(); i++)
+ {
+ btSoftBody* psb = (btSoftBody*)m_softBodies[i];
+ if (psb->isActive())
+ {
+ psb->updateNormals();
+ }
+ }
}
void btDeformableBodySolver::setImplicit(bool implicit)
{
- m_implicit = implicit;
- m_objective->setImplicit(implicit);
+ m_implicit = implicit;
+ m_objective->setImplicit(implicit);
}
void btDeformableBodySolver::setLineSearch(bool lineSearch)
{
- m_lineSearch = lineSearch;
+ m_lineSearch = lineSearch;
}
diff --git a/thirdparty/bullet/BulletSoftBody/btDeformableBodySolver.h b/thirdparty/bullet/BulletSoftBody/btDeformableBodySolver.h
index d4e5f4c603..ae674d6e89 100644
--- a/thirdparty/bullet/BulletSoftBody/btDeformableBodySolver.h
+++ b/thirdparty/bullet/BulletSoftBody/btDeformableBodySolver.h
@@ -16,7 +16,6 @@
#ifndef BT_DEFORMABLE_BODY_SOLVERS_H
#define BT_DEFORMABLE_BODY_SOLVERS_H
-
#include "btSoftBodySolvers.h"
#include "btDeformableBackwardEulerObjective.h"
#include "btDeformableMultiBodyDynamicsWorld.h"
@@ -30,133 +29,132 @@ class btDeformableMultiBodyDynamicsWorld;
class btDeformableBodySolver : public btSoftBodySolver
{
- typedef btAlignedObjectArray<btVector3> TVStack;
+ typedef btAlignedObjectArray<btVector3> TVStack;
+
protected:
- int m_numNodes; // total number of deformable body nodes
- TVStack m_dv; // v_{n+1} - v_n
- TVStack m_backup_dv; // backed up dv
- TVStack m_ddv; // incremental dv
- TVStack m_residual; // rhs of the linear solve
- btAlignedObjectArray<btSoftBody *> m_softBodies; // all deformable bodies
- TVStack m_backupVelocity; // backed up v, equals v_n for implicit, equals v_{n+1}^* for explicit
- btScalar m_dt; // dt
- btConjugateGradient<btDeformableBackwardEulerObjective> m_cg; // CG solver
- btConjugateResidual<btDeformableBackwardEulerObjective> m_cr; // CR solver
- bool m_implicit; // use implicit scheme if true, explicit scheme if false
- int m_maxNewtonIterations; // max number of newton iterations
- btScalar m_newtonTolerance; // stop newton iterations if f(x) < m_newtonTolerance
- bool m_lineSearch; // If true, use newton's method with line search under implicit scheme
+ int m_numNodes; // total number of deformable body nodes
+ TVStack m_dv; // v_{n+1} - v_n
+ TVStack m_backup_dv; // backed up dv
+ TVStack m_ddv; // incremental dv
+ TVStack m_residual; // rhs of the linear solve
+ btAlignedObjectArray<btSoftBody*> m_softBodies; // all deformable bodies
+ TVStack m_backupVelocity; // backed up v, equals v_n for implicit, equals v_{n+1}^* for explicit
+ btScalar m_dt; // dt
+ btConjugateGradient<btDeformableBackwardEulerObjective> m_cg; // CG solver
+ btConjugateResidual<btDeformableBackwardEulerObjective> m_cr; // CR solver
+ bool m_implicit; // use implicit scheme if true, explicit scheme if false
+ int m_maxNewtonIterations; // max number of newton iterations
+ btScalar m_newtonTolerance; // stop newton iterations if f(x) < m_newtonTolerance
+ bool m_lineSearch; // If true, use newton's method with line search under implicit scheme
public:
- // handles data related to objective function
- btDeformableBackwardEulerObjective* m_objective;
- bool m_useProjection;
-
- btDeformableBodySolver();
-
- virtual ~btDeformableBodySolver();
-
- virtual SolverTypes getSolverType() const
- {
- return DEFORMABLE_SOLVER;
- }
-
- // update soft body normals
- virtual void updateSoftBodies();
-
- virtual btScalar solveContactConstraints(btCollisionObject** deformableBodies,int numDeformableBodies, const btContactSolverInfo& infoGlobal);
-
- // solve the momentum equation
- virtual void solveDeformableConstraints(btScalar solverdt);
-
- // set up the position error in split impulse
- void splitImpulseSetup(const btContactSolverInfo& infoGlobal);
-
- // resize/clear data structures
- void reinitialize(const btAlignedObjectArray<btSoftBody *>& softBodies, btScalar dt);
-
- // set up contact constraints
- void setConstraints(const btContactSolverInfo& infoGlobal);
-
- // add in elastic forces and gravity to obtain v_{n+1}^* and calls predictDeformableMotion
- virtual void predictMotion(btScalar solverdt);
-
- // move to temporary position x_{n+1}^* = x_n + dt * v_{n+1}^*
- // x_{n+1}^* is stored in m_q
- void predictDeformableMotion(btSoftBody* psb, btScalar dt);
-
- // save the current velocity to m_backupVelocity
- void backupVelocity();
-
- // set m_dv and m_backupVelocity to desired value to prepare for momentum solve
- void setupDeformableSolve(bool implicit);
-
- // set the current velocity to that backed up in m_backupVelocity
- void revertVelocity();
-
- // set velocity to m_dv + m_backupVelocity
- void updateVelocity();
-
- // update the node count
- bool updateNodes();
-
- // calculate the change in dv resulting from the momentum solve
- void computeStep(TVStack& ddv, const TVStack& residual);
-
- // calculate the change in dv resulting from the momentum solve when line search is turned on
- btScalar computeDescentStep(TVStack& ddv, const TVStack& residual, bool verbose=false);
-
- virtual void copySoftBodyToVertexBuffer(const btSoftBody *const softBody, btVertexBufferDescriptor *vertexBuffer) {}
-
- // process collision between deformable and rigid
- virtual void processCollision(btSoftBody * softBody, const btCollisionObjectWrapper * collisionObjectWrap)
- {
- softBody->defaultCollisionHandler(collisionObjectWrap);
- }
-
- // process collision between deformable and deformable
- virtual void processCollision(btSoftBody * softBody, btSoftBody * otherSoftBody) {
- softBody->defaultCollisionHandler(otherSoftBody);
- }
-
- // If true, implicit time stepping scheme is used.
- // Otherwise, explicit time stepping scheme is used
- void setImplicit(bool implicit);
-
- // If true, newton's method with line search is used when implicit time stepping scheme is turned on
- void setLineSearch(bool lineSearch);
-
- // set temporary position x^* = x_n + dt * v
- // update the deformation gradient at position x^*
- void updateState();
-
- // set dv = dv + scale * ddv
- void updateDv(btScalar scale = 1);
-
- // set temporary position x^* = x_n + dt * v^*
- void updateTempPosition();
-
- // save the current dv to m_backup_dv;
- void backupDv();
-
- // set dv to the backed-up value
- void revertDv();
-
- // set dv = dv + scale * ddv
- // set v^* = v_n + dv
- // set temporary position x^* = x_n + dt * v^*
- // update the deformation gradient at position x^*
- void updateEnergy(btScalar scale);
-
- // calculates the appropriately scaled kinetic energy in the system, which is
- // 1/2 * dv^T * M * dv
- // used in line search
- btScalar kineticEnergy();
-
- // unused functions
- virtual void optimize(btAlignedObjectArray<btSoftBody *> &softBodies, bool forceUpdate = false){}
- virtual void solveConstraints(btScalar dt){}
- virtual bool checkInitialized(){return true;}
- virtual void copyBackToSoftBodies(bool bMove = true) {}
+ // handles data related to objective function
+ btDeformableBackwardEulerObjective* m_objective;
+ bool m_useProjection;
+
+ btDeformableBodySolver();
+
+ virtual ~btDeformableBodySolver();
+
+ virtual SolverTypes getSolverType() const
+ {
+ return DEFORMABLE_SOLVER;
+ }
+
+ // update soft body normals
+ virtual void updateSoftBodies();
+
+ virtual btScalar solveContactConstraints(btCollisionObject** deformableBodies, int numDeformableBodies, const btContactSolverInfo& infoGlobal);
+
+ // solve the momentum equation
+ virtual void solveDeformableConstraints(btScalar solverdt);
+
+ // resize/clear data structures
+ void reinitialize(const btAlignedObjectArray<btSoftBody*>& softBodies, btScalar dt);
+
+ // set up contact constraints
+ void setConstraints(const btContactSolverInfo& infoGlobal);
+
+ // add in elastic forces and gravity to obtain v_{n+1}^* and calls predictDeformableMotion
+ virtual void predictMotion(btScalar solverdt);
+
+ // move to temporary position x_{n+1}^* = x_n + dt * v_{n+1}^*
+ // x_{n+1}^* is stored in m_q
+ void predictDeformableMotion(btSoftBody* psb, btScalar dt);
+
+ // save the current velocity to m_backupVelocity
+ void backupVelocity();
+
+ // set m_dv and m_backupVelocity to desired value to prepare for momentum solve
+ void setupDeformableSolve(bool implicit);
+
+ // set the current velocity to that backed up in m_backupVelocity
+ void revertVelocity();
+
+ // set velocity to m_dv + m_backupVelocity
+ void updateVelocity();
+
+ // update the node count
+ bool updateNodes();
+
+ // calculate the change in dv resulting from the momentum solve
+ void computeStep(TVStack& ddv, const TVStack& residual);
+
+ // calculate the change in dv resulting from the momentum solve when line search is turned on
+ btScalar computeDescentStep(TVStack& ddv, const TVStack& residual, bool verbose = false);
+
+ virtual void copySoftBodyToVertexBuffer(const btSoftBody* const softBody, btVertexBufferDescriptor* vertexBuffer) {}
+
+ // process collision between deformable and rigid
+ virtual void processCollision(btSoftBody* softBody, const btCollisionObjectWrapper* collisionObjectWrap)
+ {
+ softBody->defaultCollisionHandler(collisionObjectWrap);
+ }
+
+ // process collision between deformable and deformable
+ virtual void processCollision(btSoftBody* softBody, btSoftBody* otherSoftBody)
+ {
+ softBody->defaultCollisionHandler(otherSoftBody);
+ }
+
+ // If true, implicit time stepping scheme is used.
+ // Otherwise, explicit time stepping scheme is used
+ void setImplicit(bool implicit);
+
+ // If true, newton's method with line search is used when implicit time stepping scheme is turned on
+ void setLineSearch(bool lineSearch);
+
+ // set temporary position x^* = x_n + dt * v
+ // update the deformation gradient at position x^*
+ void updateState();
+
+ // set dv = dv + scale * ddv
+ void updateDv(btScalar scale = 1);
+
+ // set temporary position x^* = x_n + dt * v^*
+ void updateTempPosition();
+
+ // save the current dv to m_backup_dv;
+ void backupDv();
+
+ // set dv to the backed-up value
+ void revertDv();
+
+ // set dv = dv + scale * ddv
+ // set v^* = v_n + dv
+ // set temporary position x^* = x_n + dt * v^*
+ // update the deformation gradient at position x^*
+ void updateEnergy(btScalar scale);
+
+ // calculates the appropriately scaled kinetic energy in the system, which is
+ // 1/2 * dv^T * M * dv
+ // used in line search
+ btScalar kineticEnergy();
+
+ // unused functions
+ virtual void optimize(btAlignedObjectArray<btSoftBody*>& softBodies, bool forceUpdate = false) {}
+ virtual void solveConstraints(btScalar dt) {}
+ virtual bool checkInitialized() { return true; }
+ virtual void copyBackToSoftBodies(bool bMove = true) {}
};
#endif /* btDeformableBodySolver_h */
diff --git a/thirdparty/bullet/BulletSoftBody/btDeformableContactConstraint.cpp b/thirdparty/bullet/BulletSoftBody/btDeformableContactConstraint.cpp
index 2864446de6..09398d79a5 100644
--- a/thirdparty/bullet/BulletSoftBody/btDeformableContactConstraint.cpp
+++ b/thirdparty/bullet/BulletSoftBody/btDeformableContactConstraint.cpp
@@ -16,387 +16,503 @@
#include "btDeformableContactConstraint.h"
/* ================ Deformable Node Anchor =================== */
btDeformableNodeAnchorConstraint::btDeformableNodeAnchorConstraint(const btSoftBody::DeformableNodeRigidAnchor& a, const btContactSolverInfo& infoGlobal)
-: m_anchor(&a)
-, btDeformableContactConstraint(a.m_cti.m_normal, infoGlobal)
+ : m_anchor(&a), btDeformableContactConstraint(a.m_cti.m_normal, infoGlobal)
{
}
btDeformableNodeAnchorConstraint::btDeformableNodeAnchorConstraint(const btDeformableNodeAnchorConstraint& other)
-: m_anchor(other.m_anchor)
-, btDeformableContactConstraint(other)
+ : m_anchor(other.m_anchor), btDeformableContactConstraint(other)
{
}
btVector3 btDeformableNodeAnchorConstraint::getVa() const
{
- const btSoftBody::sCti& cti = m_anchor->m_cti;
- btVector3 va(0, 0, 0);
- if (cti.m_colObj->hasContactResponse())
- {
- btRigidBody* rigidCol = 0;
- btMultiBodyLinkCollider* multibodyLinkCol = 0;
-
- // grab the velocity of the rigid body
- if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
- {
- rigidCol = (btRigidBody*)btRigidBody::upcast(cti.m_colObj);
- va = rigidCol ? (rigidCol->getVelocityInLocalPoint(m_anchor->m_c1)) : btVector3(0, 0, 0);
- }
- else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
- {
- multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(cti.m_colObj);
- if (multibodyLinkCol)
- {
- const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6;
- const btScalar* J_n = &m_anchor->jacobianData_normal.m_jacobians[0];
- const btScalar* J_t1 = &m_anchor->jacobianData_t1.m_jacobians[0];
- const btScalar* J_t2 = &m_anchor->jacobianData_t2.m_jacobians[0];
- const btScalar* local_v = multibodyLinkCol->m_multiBody->getVelocityVector();
- const btScalar* local_dv = multibodyLinkCol->m_multiBody->getDeltaVelocityVector();
- // add in the normal component of the va
- btScalar vel = 0.0;
- for (int k = 0; k < ndof; ++k)
- {
- vel += (local_v[k]+local_dv[k]) * J_n[k];
- }
- va = cti.m_normal * vel;
- // add in the tangential components of the va
- vel = 0.0;
- for (int k = 0; k < ndof; ++k)
- {
- vel += (local_v[k]+local_dv[k]) * J_t1[k];
- }
- va += m_anchor->t1 * vel;
- vel = 0.0;
- for (int k = 0; k < ndof; ++k)
- {
- vel += (local_v[k]+local_dv[k]) * J_t2[k];
- }
- va += m_anchor->t2 * vel;
- }
- }
- }
- return va;
+ const btSoftBody::sCti& cti = m_anchor->m_cti;
+ btVector3 va(0, 0, 0);
+ if (cti.m_colObj->hasContactResponse())
+ {
+ btRigidBody* rigidCol = 0;
+ btMultiBodyLinkCollider* multibodyLinkCol = 0;
+
+ // grab the velocity of the rigid body
+ if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
+ {
+ rigidCol = (btRigidBody*)btRigidBody::upcast(cti.m_colObj);
+ va = rigidCol ? (rigidCol->getVelocityInLocalPoint(m_anchor->m_c1)) : btVector3(0, 0, 0);
+ }
+ else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
+ {
+ multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(cti.m_colObj);
+ if (multibodyLinkCol)
+ {
+ const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6;
+ const btScalar* J_n = &m_anchor->jacobianData_normal.m_jacobians[0];
+ const btScalar* J_t1 = &m_anchor->jacobianData_t1.m_jacobians[0];
+ const btScalar* J_t2 = &m_anchor->jacobianData_t2.m_jacobians[0];
+ const btScalar* local_v = multibodyLinkCol->m_multiBody->getVelocityVector();
+ const btScalar* local_dv = multibodyLinkCol->m_multiBody->getDeltaVelocityVector();
+ // add in the normal component of the va
+ btScalar vel = 0.0;
+ for (int k = 0; k < ndof; ++k)
+ {
+ vel += (local_v[k] + local_dv[k]) * J_n[k];
+ }
+ va = cti.m_normal * vel;
+ // add in the tangential components of the va
+ vel = 0.0;
+ for (int k = 0; k < ndof; ++k)
+ {
+ vel += (local_v[k] + local_dv[k]) * J_t1[k];
+ }
+ va += m_anchor->t1 * vel;
+ vel = 0.0;
+ for (int k = 0; k < ndof; ++k)
+ {
+ vel += (local_v[k] + local_dv[k]) * J_t2[k];
+ }
+ va += m_anchor->t2 * vel;
+ }
+ }
+ }
+ return va;
}
btScalar btDeformableNodeAnchorConstraint::solveConstraint(const btContactSolverInfo& infoGlobal)
{
- const btSoftBody::sCti& cti = m_anchor->m_cti;
- btVector3 va = getVa();
- btVector3 vb = getVb();
- btVector3 vr = (vb - va);
- // + (m_anchor->m_node->m_x - cti.m_colObj->getWorldTransform() * m_anchor->m_local) * 10.0
- const btScalar dn = btDot(vr, vr);
- // dn is the normal component of velocity diffrerence. Approximates the residual. // todo xuchenhan@: this prob needs to be scaled by dt
- btScalar residualSquare = dn*dn;
- btVector3 impulse = m_anchor->m_c0 * vr;
- // apply impulse to deformable nodes involved and change their velocities
- applyImpulse(impulse);
-
- // apply impulse to the rigid/multibodies involved and change their velocities
- if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
- {
- btRigidBody* rigidCol = 0;
- rigidCol = (btRigidBody*)btRigidBody::upcast(cti.m_colObj);
- if (rigidCol)
- {
- rigidCol->applyImpulse(impulse, m_anchor->m_c1);
- }
- }
- else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
- {
- btMultiBodyLinkCollider* multibodyLinkCol = 0;
- multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(cti.m_colObj);
- if (multibodyLinkCol)
- {
- const btScalar* deltaV_normal = &m_anchor->jacobianData_normal.m_deltaVelocitiesUnitImpulse[0];
- // apply normal component of the impulse
- multibodyLinkCol->m_multiBody->applyDeltaVeeMultiDof2(deltaV_normal, impulse.dot(cti.m_normal));
- // apply tangential component of the impulse
- const btScalar* deltaV_t1 = &m_anchor->jacobianData_t1.m_deltaVelocitiesUnitImpulse[0];
- multibodyLinkCol->m_multiBody->applyDeltaVeeMultiDof2(deltaV_t1, impulse.dot(m_anchor->t1));
- const btScalar* deltaV_t2 = &m_anchor->jacobianData_t2.m_deltaVelocitiesUnitImpulse[0];
- multibodyLinkCol->m_multiBody->applyDeltaVeeMultiDof2(deltaV_t2, impulse.dot(m_anchor->t2));
- }
- }
- return residualSquare;
+ const btSoftBody::sCti& cti = m_anchor->m_cti;
+ btVector3 va = getVa();
+ btVector3 vb = getVb();
+ btVector3 vr = (vb - va);
+ // + (m_anchor->m_node->m_x - cti.m_colObj->getWorldTransform() * m_anchor->m_local) * 10.0
+ const btScalar dn = btDot(vr, vr);
+ // dn is the normal component of velocity diffrerence. Approximates the residual. // todo xuchenhan@: this prob needs to be scaled by dt
+ btScalar residualSquare = dn * dn;
+ btVector3 impulse = m_anchor->m_c0 * vr;
+ // apply impulse to deformable nodes involved and change their velocities
+ applyImpulse(impulse);
+
+ // apply impulse to the rigid/multibodies involved and change their velocities
+ if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
+ {
+ btRigidBody* rigidCol = 0;
+ rigidCol = (btRigidBody*)btRigidBody::upcast(cti.m_colObj);
+ if (rigidCol)
+ {
+ rigidCol->applyImpulse(impulse, m_anchor->m_c1);
+ }
+ }
+ else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
+ {
+ btMultiBodyLinkCollider* multibodyLinkCol = 0;
+ multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(cti.m_colObj);
+ if (multibodyLinkCol)
+ {
+ const btScalar* deltaV_normal = &m_anchor->jacobianData_normal.m_deltaVelocitiesUnitImpulse[0];
+ // apply normal component of the impulse
+ multibodyLinkCol->m_multiBody->applyDeltaVeeMultiDof2(deltaV_normal, impulse.dot(cti.m_normal));
+ // apply tangential component of the impulse
+ const btScalar* deltaV_t1 = &m_anchor->jacobianData_t1.m_deltaVelocitiesUnitImpulse[0];
+ multibodyLinkCol->m_multiBody->applyDeltaVeeMultiDof2(deltaV_t1, impulse.dot(m_anchor->t1));
+ const btScalar* deltaV_t2 = &m_anchor->jacobianData_t2.m_deltaVelocitiesUnitImpulse[0];
+ multibodyLinkCol->m_multiBody->applyDeltaVeeMultiDof2(deltaV_t2, impulse.dot(m_anchor->t2));
+ }
+ }
+ return residualSquare;
}
btVector3 btDeformableNodeAnchorConstraint::getVb() const
{
- return m_anchor->m_node->m_v;
+ return m_anchor->m_node->m_v;
}
void btDeformableNodeAnchorConstraint::applyImpulse(const btVector3& impulse)
{
- btVector3 dv = impulse * m_anchor->m_c2;
- m_anchor->m_node->m_v -= dv;
+ btVector3 dv = impulse * m_anchor->m_c2;
+ m_anchor->m_node->m_v -= dv;
}
/* ================ Deformable vs. Rigid =================== */
btDeformableRigidContactConstraint::btDeformableRigidContactConstraint(const btSoftBody::DeformableRigidContact& c, const btContactSolverInfo& infoGlobal)
-: m_contact(&c)
-, btDeformableContactConstraint(c.m_cti.m_normal, infoGlobal)
+ : m_contact(&c), btDeformableContactConstraint(c.m_cti.m_normal, infoGlobal)
{
- m_total_normal_dv.setZero();
- m_total_tangent_dv.setZero();
- // The magnitude of penetration is the depth of penetration.
- m_penetration = c.m_cti.m_offset;
-// m_penetration = btMin(btScalar(0),c.m_cti.m_offset);
+ m_total_normal_dv.setZero();
+ m_total_tangent_dv.setZero();
+ // The magnitude of penetration is the depth of penetration.
+ m_penetration = c.m_cti.m_offset;
+ m_total_split_impulse = 0;
+ m_binding = false;
}
btDeformableRigidContactConstraint::btDeformableRigidContactConstraint(const btDeformableRigidContactConstraint& other)
-: m_contact(other.m_contact)
-, btDeformableContactConstraint(other)
-, m_penetration(other.m_penetration)
+ : m_contact(other.m_contact), btDeformableContactConstraint(other), m_penetration(other.m_penetration), m_total_split_impulse(other.m_total_split_impulse), m_binding(other.m_binding)
{
- m_total_normal_dv = other.m_total_normal_dv;
- m_total_tangent_dv = other.m_total_tangent_dv;
+ m_total_normal_dv = other.m_total_normal_dv;
+ m_total_tangent_dv = other.m_total_tangent_dv;
}
-
btVector3 btDeformableRigidContactConstraint::getVa() const
{
- const btSoftBody::sCti& cti = m_contact->m_cti;
- btVector3 va(0, 0, 0);
- if (cti.m_colObj->hasContactResponse())
- {
- btRigidBody* rigidCol = 0;
- btMultiBodyLinkCollider* multibodyLinkCol = 0;
-
- // grab the velocity of the rigid body
- if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
- {
- rigidCol = (btRigidBody*)btRigidBody::upcast(cti.m_colObj);
- va = rigidCol ? (rigidCol->getVelocityInLocalPoint(m_contact->m_c1)) : btVector3(0, 0, 0);
- }
- else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
- {
- multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(cti.m_colObj);
- if (multibodyLinkCol)
- {
- const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6;
- const btScalar* J_n = &m_contact->jacobianData_normal.m_jacobians[0];
- const btScalar* J_t1 = &m_contact->jacobianData_t1.m_jacobians[0];
- const btScalar* J_t2 = &m_contact->jacobianData_t2.m_jacobians[0];
- const btScalar* local_v = multibodyLinkCol->m_multiBody->getVelocityVector();
- const btScalar* local_dv = multibodyLinkCol->m_multiBody->getDeltaVelocityVector();
- // add in the normal component of the va
- btScalar vel = 0.0;
- for (int k = 0; k < ndof; ++k)
- {
- vel += (local_v[k]+local_dv[k]) * J_n[k];
- }
- va = cti.m_normal * vel;
- // add in the tangential components of the va
- vel = 0.0;
- for (int k = 0; k < ndof; ++k)
- {
- vel += (local_v[k]+local_dv[k]) * J_t1[k];
- }
- va += m_contact->t1 * vel;
- vel = 0.0;
- for (int k = 0; k < ndof; ++k)
- {
- vel += (local_v[k]+local_dv[k]) * J_t2[k];
- }
- va += m_contact->t2 * vel;
- }
- }
- }
- return va;
+ const btSoftBody::sCti& cti = m_contact->m_cti;
+ btVector3 va(0, 0, 0);
+ if (cti.m_colObj->hasContactResponse())
+ {
+ btRigidBody* rigidCol = 0;
+ btMultiBodyLinkCollider* multibodyLinkCol = 0;
+
+ // grab the velocity of the rigid body
+ if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
+ {
+ rigidCol = (btRigidBody*)btRigidBody::upcast(cti.m_colObj);
+ va = rigidCol ? (rigidCol->getVelocityInLocalPoint(m_contact->m_c1)) : btVector3(0, 0, 0);
+ }
+ else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
+ {
+ multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(cti.m_colObj);
+ if (multibodyLinkCol)
+ {
+ const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6;
+ const btScalar* J_n = &m_contact->jacobianData_normal.m_jacobians[0];
+ const btScalar* J_t1 = &m_contact->jacobianData_t1.m_jacobians[0];
+ const btScalar* J_t2 = &m_contact->jacobianData_t2.m_jacobians[0];
+ const btScalar* local_v = multibodyLinkCol->m_multiBody->getVelocityVector();
+ const btScalar* local_dv = multibodyLinkCol->m_multiBody->getDeltaVelocityVector();
+ // add in the normal component of the va
+ btScalar vel = 0.0;
+ for (int k = 0; k < ndof; ++k)
+ {
+ vel += (local_v[k] + local_dv[k]) * J_n[k];
+ }
+ va = cti.m_normal * vel;
+ // add in the tangential components of the va
+ vel = 0.0;
+ for (int k = 0; k < ndof; ++k)
+ {
+ vel += (local_v[k] + local_dv[k]) * J_t1[k];
+ }
+ va += m_contact->t1 * vel;
+ vel = 0.0;
+ for (int k = 0; k < ndof; ++k)
+ {
+ vel += (local_v[k] + local_dv[k]) * J_t2[k];
+ }
+ va += m_contact->t2 * vel;
+ }
+ }
+ }
+ return va;
+}
+
+btVector3 btDeformableRigidContactConstraint::getSplitVa() const
+{
+ const btSoftBody::sCti& cti = m_contact->m_cti;
+ btVector3 va(0, 0, 0);
+ if (cti.m_colObj->hasContactResponse())
+ {
+ btRigidBody* rigidCol = 0;
+ btMultiBodyLinkCollider* multibodyLinkCol = 0;
+
+ // grab the velocity of the rigid body
+ if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
+ {
+ rigidCol = (btRigidBody*)btRigidBody::upcast(cti.m_colObj);
+ va = rigidCol ? (rigidCol->getPushVelocityInLocalPoint(m_contact->m_c1)) : btVector3(0, 0, 0);
+ }
+ else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
+ {
+ multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(cti.m_colObj);
+ if (multibodyLinkCol)
+ {
+ const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6;
+ const btScalar* J_n = &m_contact->jacobianData_normal.m_jacobians[0];
+ const btScalar* J_t1 = &m_contact->jacobianData_t1.m_jacobians[0];
+ const btScalar* J_t2 = &m_contact->jacobianData_t2.m_jacobians[0];
+ const btScalar* local_split_v = multibodyLinkCol->m_multiBody->getSplitVelocityVector();
+ // add in the normal component of the va
+ btScalar vel = 0.0;
+ for (int k = 0; k < ndof; ++k)
+ {
+ vel += local_split_v[k] * J_n[k];
+ }
+ va = cti.m_normal * vel;
+ // add in the tangential components of the va
+ vel = 0.0;
+ for (int k = 0; k < ndof; ++k)
+ {
+ vel += local_split_v[k] * J_t1[k];
+ }
+ va += m_contact->t1 * vel;
+ vel = 0.0;
+ for (int k = 0; k < ndof; ++k)
+ {
+ vel += local_split_v[k] * J_t2[k];
+ }
+ va += m_contact->t2 * vel;
+ }
+ }
+ }
+ return va;
}
btScalar btDeformableRigidContactConstraint::solveConstraint(const btContactSolverInfo& infoGlobal)
{
- const btSoftBody::sCti& cti = m_contact->m_cti;
- btVector3 va = getVa();
- btVector3 vb = getVb();
- btVector3 vr = vb - va;
- btScalar dn = btDot(vr, cti.m_normal) + m_penetration * infoGlobal.m_deformable_erp / infoGlobal.m_timeStep;
- // dn is the normal component of velocity diffrerence. Approximates the residual. // todo xuchenhan@: this prob needs to be scaled by dt
- btScalar residualSquare = dn*dn;
- btVector3 impulse = m_contact->m_c0 * (vr + m_penetration * infoGlobal.m_deformable_erp / infoGlobal.m_timeStep * cti.m_normal) ;
- const btVector3 impulse_normal = m_contact->m_c0 * (cti.m_normal * dn);
- btVector3 impulse_tangent = impulse - impulse_normal;
- btVector3 old_total_tangent_dv = m_total_tangent_dv;
- // m_c2 is the inverse mass of the deformable node/face
- m_total_normal_dv -= impulse_normal * m_contact->m_c2;
- m_total_tangent_dv -= impulse_tangent * m_contact->m_c2;
-
- if (m_total_normal_dv.dot(cti.m_normal) < 0)
- {
- // separating in the normal direction
- m_static = false;
- m_total_tangent_dv = btVector3(0,0,0);
- impulse_tangent.setZero();
- }
- else
- {
- if (m_total_normal_dv.norm() * m_contact->m_c3 < m_total_tangent_dv.norm())
- {
- // dynamic friction
- // with dynamic friction, the impulse are still applied to the two objects colliding, however, it does not pose a constraint in the cg solve, hence the change to dv merely serves to update velocity in the contact iterations.
- m_static = false;
- if (m_total_tangent_dv.safeNorm() < SIMD_EPSILON)
- {
- m_total_tangent_dv = btVector3(0,0,0);
- }
- else
- {
- m_total_tangent_dv = m_total_tangent_dv.normalized() * m_total_normal_dv.safeNorm() * m_contact->m_c3;
- }
- impulse_tangent = -btScalar(1)/m_contact->m_c2 * (m_total_tangent_dv - old_total_tangent_dv);
- }
- else
- {
- // static friction
- m_static = true;
- }
- }
- impulse = impulse_normal + impulse_tangent;
- // apply impulse to deformable nodes involved and change their velocities
- applyImpulse(impulse);
- if (residualSquare < 1e-7)
- return residualSquare;
- // apply impulse to the rigid/multibodies involved and change their velocities
- if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
- {
- btRigidBody* rigidCol = 0;
- rigidCol = (btRigidBody*)btRigidBody::upcast(cti.m_colObj);
- if (rigidCol)
- {
- rigidCol->applyImpulse(impulse, m_contact->m_c1);
- }
- }
- else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
- {
- btMultiBodyLinkCollider* multibodyLinkCol = 0;
- multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(cti.m_colObj);
- if (multibodyLinkCol)
- {
- const btScalar* deltaV_normal = &m_contact->jacobianData_normal.m_deltaVelocitiesUnitImpulse[0];
- // apply normal component of the impulse
- multibodyLinkCol->m_multiBody->applyDeltaVeeMultiDof2(deltaV_normal, impulse.dot(cti.m_normal));
- if (impulse_tangent.norm() > SIMD_EPSILON)
- {
- // apply tangential component of the impulse
- const btScalar* deltaV_t1 = &m_contact->jacobianData_t1.m_deltaVelocitiesUnitImpulse[0];
- multibodyLinkCol->m_multiBody->applyDeltaVeeMultiDof2(deltaV_t1, impulse.dot(m_contact->t1));
- const btScalar* deltaV_t2 = &m_contact->jacobianData_t2.m_deltaVelocitiesUnitImpulse[0];
- multibodyLinkCol->m_multiBody->applyDeltaVeeMultiDof2(deltaV_t2, impulse.dot(m_contact->t2));
- }
- }
- }
-// va = getVa();
-// vb = getVb();
-// vr = vb - va;
-// btScalar dn1 = btDot(vr, cti.m_normal) / 150;
-// m_penetration += dn1;
- return residualSquare;
+ const btSoftBody::sCti& cti = m_contact->m_cti;
+ btVector3 va = getVa();
+ btVector3 vb = getVb();
+ btVector3 vr = vb - va;
+ btScalar dn = btDot(vr, cti.m_normal) + m_total_normal_dv.dot(cti.m_normal) * infoGlobal.m_deformable_cfm;
+ if (m_penetration > 0)
+ {
+ dn += m_penetration / infoGlobal.m_timeStep;
+ }
+ if (!infoGlobal.m_splitImpulse)
+ {
+ dn += m_penetration * infoGlobal.m_deformable_erp / infoGlobal.m_timeStep;
+ }
+ // dn is the normal component of velocity diffrerence. Approximates the residual. // todo xuchenhan@: this prob needs to be scaled by dt
+ btVector3 impulse = m_contact->m_c0 * (vr + m_total_normal_dv * infoGlobal.m_deformable_cfm + ((m_penetration > 0) ? m_penetration / infoGlobal.m_timeStep * cti.m_normal : btVector3(0, 0, 0)));
+ if (!infoGlobal.m_splitImpulse)
+ {
+ impulse += m_contact->m_c0 * (m_penetration * infoGlobal.m_deformable_erp / infoGlobal.m_timeStep * cti.m_normal);
+ }
+ btVector3 impulse_normal = m_contact->m_c0 * (cti.m_normal * dn);
+ btVector3 impulse_tangent = impulse - impulse_normal;
+ if (dn > 0)
+ {
+ return 0;
+ }
+ m_binding = true;
+ btScalar residualSquare = dn * dn;
+ btVector3 old_total_tangent_dv = m_total_tangent_dv;
+ // m_c5 is the inverse mass of the deformable node/face
+ m_total_normal_dv -= m_contact->m_c5 * impulse_normal;
+ m_total_tangent_dv -= m_contact->m_c5 * impulse_tangent;
+
+ if (m_total_normal_dv.dot(cti.m_normal) < 0)
+ {
+ // separating in the normal direction
+ m_binding = false;
+ m_static = false;
+ impulse_tangent.setZero();
+ }
+ else
+ {
+ if (m_total_normal_dv.norm() * m_contact->m_c3 < m_total_tangent_dv.norm())
+ {
+ // dynamic friction
+ // with dynamic friction, the impulse are still applied to the two objects colliding, however, it does not pose a constraint in the cg solve, hence the change to dv merely serves to update velocity in the contact iterations.
+ m_static = false;
+ if (m_total_tangent_dv.safeNorm() < SIMD_EPSILON)
+ {
+ m_total_tangent_dv = btVector3(0, 0, 0);
+ }
+ else
+ {
+ m_total_tangent_dv = m_total_tangent_dv.normalized() * m_total_normal_dv.safeNorm() * m_contact->m_c3;
+ }
+ // impulse_tangent = -btScalar(1)/m_contact->m_c2 * (m_total_tangent_dv - old_total_tangent_dv);
+ impulse_tangent = m_contact->m_c5.inverse() * (old_total_tangent_dv - m_total_tangent_dv);
+ }
+ else
+ {
+ // static friction
+ m_static = true;
+ }
+ }
+ impulse = impulse_normal + impulse_tangent;
+ // apply impulse to deformable nodes involved and change their velocities
+ applyImpulse(impulse);
+ // apply impulse to the rigid/multibodies involved and change their velocities
+ if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
+ {
+ btRigidBody* rigidCol = 0;
+ rigidCol = (btRigidBody*)btRigidBody::upcast(cti.m_colObj);
+ if (rigidCol)
+ {
+ rigidCol->applyImpulse(impulse, m_contact->m_c1);
+ }
+ }
+ else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
+ {
+ btMultiBodyLinkCollider* multibodyLinkCol = 0;
+ multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(cti.m_colObj);
+ if (multibodyLinkCol)
+ {
+ const btScalar* deltaV_normal = &m_contact->jacobianData_normal.m_deltaVelocitiesUnitImpulse[0];
+ // apply normal component of the impulse
+ multibodyLinkCol->m_multiBody->applyDeltaVeeMultiDof2(deltaV_normal, impulse.dot(cti.m_normal));
+ if (impulse_tangent.norm() > SIMD_EPSILON)
+ {
+ // apply tangential component of the impulse
+ const btScalar* deltaV_t1 = &m_contact->jacobianData_t1.m_deltaVelocitiesUnitImpulse[0];
+ multibodyLinkCol->m_multiBody->applyDeltaVeeMultiDof2(deltaV_t1, impulse.dot(m_contact->t1));
+ const btScalar* deltaV_t2 = &m_contact->jacobianData_t2.m_deltaVelocitiesUnitImpulse[0];
+ multibodyLinkCol->m_multiBody->applyDeltaVeeMultiDof2(deltaV_t2, impulse.dot(m_contact->t2));
+ }
+ }
+ }
+ return residualSquare;
+}
+
+btScalar btDeformableRigidContactConstraint::solveSplitImpulse(const btContactSolverInfo& infoGlobal)
+{
+ btScalar MAX_PENETRATION_CORRECTION = infoGlobal.m_deformable_maxErrorReduction;
+ const btSoftBody::sCti& cti = m_contact->m_cti;
+ btVector3 vb = getSplitVb();
+ btVector3 va = getSplitVa();
+ btScalar p = m_penetration;
+ if (p > 0)
+ {
+ return 0;
+ }
+ btVector3 vr = vb - va;
+ btScalar dn = btDot(vr, cti.m_normal) + p * infoGlobal.m_deformable_erp / infoGlobal.m_timeStep;
+ if (dn > 0)
+ {
+ return 0;
+ }
+ if (m_total_split_impulse + dn > MAX_PENETRATION_CORRECTION)
+ {
+ dn = MAX_PENETRATION_CORRECTION - m_total_split_impulse;
+ }
+ if (m_total_split_impulse + dn < -MAX_PENETRATION_CORRECTION)
+ {
+ dn = -MAX_PENETRATION_CORRECTION - m_total_split_impulse;
+ }
+ m_total_split_impulse += dn;
+
+ btScalar residualSquare = dn * dn;
+ const btVector3 impulse = m_contact->m_c0 * (cti.m_normal * dn);
+ applySplitImpulse(impulse);
+
+ // apply split impulse to the rigid/multibodies involved and change their velocities
+ if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
+ {
+ btRigidBody* rigidCol = 0;
+ rigidCol = (btRigidBody*)btRigidBody::upcast(cti.m_colObj);
+ if (rigidCol)
+ {
+ rigidCol->applyPushImpulse(impulse, m_contact->m_c1);
+ }
+ }
+ else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
+ {
+ btMultiBodyLinkCollider* multibodyLinkCol = 0;
+ multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(cti.m_colObj);
+ if (multibodyLinkCol)
+ {
+ const btScalar* deltaV_normal = &m_contact->jacobianData_normal.m_deltaVelocitiesUnitImpulse[0];
+ // apply normal component of the impulse
+ multibodyLinkCol->m_multiBody->applyDeltaSplitVeeMultiDof(deltaV_normal, impulse.dot(cti.m_normal));
+ }
+ }
+ return residualSquare;
}
/* ================ Node vs. Rigid =================== */
btDeformableNodeRigidContactConstraint::btDeformableNodeRigidContactConstraint(const btSoftBody::DeformableNodeRigidContact& contact, const btContactSolverInfo& infoGlobal)
- : m_node(contact.m_node)
- , btDeformableRigidContactConstraint(contact, infoGlobal)
- {
- }
+ : m_node(contact.m_node), btDeformableRigidContactConstraint(contact, infoGlobal)
+{
+}
btDeformableNodeRigidContactConstraint::btDeformableNodeRigidContactConstraint(const btDeformableNodeRigidContactConstraint& other)
-: m_node(other.m_node)
-, btDeformableRigidContactConstraint(other)
+ : m_node(other.m_node), btDeformableRigidContactConstraint(other)
{
}
btVector3 btDeformableNodeRigidContactConstraint::getVb() const
{
- return m_node->m_v;
+ return m_node->m_v;
}
+btVector3 btDeformableNodeRigidContactConstraint::getSplitVb() const
+{
+ return m_node->m_splitv;
+}
btVector3 btDeformableNodeRigidContactConstraint::getDv(const btSoftBody::Node* node) const
{
- return m_total_normal_dv + m_total_tangent_dv;
+ return m_total_normal_dv + m_total_tangent_dv;
}
void btDeformableNodeRigidContactConstraint::applyImpulse(const btVector3& impulse)
{
- const btSoftBody::DeformableNodeRigidContact* contact = getContact();
- btVector3 dv = impulse * contact->m_c2;
- contact->m_node->m_v -= dv;
+ const btSoftBody::DeformableNodeRigidContact* contact = getContact();
+ btVector3 dv = contact->m_c5 * impulse;
+ contact->m_node->m_v -= dv;
+}
+
+void btDeformableNodeRigidContactConstraint::applySplitImpulse(const btVector3& impulse)
+{
+ const btSoftBody::DeformableNodeRigidContact* contact = getContact();
+ btVector3 dv = contact->m_c5 * impulse;
+ contact->m_node->m_splitv -= dv;
}
/* ================ Face vs. Rigid =================== */
btDeformableFaceRigidContactConstraint::btDeformableFaceRigidContactConstraint(const btSoftBody::DeformableFaceRigidContact& contact, const btContactSolverInfo& infoGlobal, bool useStrainLimiting)
-: m_face(contact.m_face)
-, m_useStrainLimiting(useStrainLimiting)
-, btDeformableRigidContactConstraint(contact, infoGlobal)
+ : m_face(contact.m_face), m_useStrainLimiting(useStrainLimiting), btDeformableRigidContactConstraint(contact, infoGlobal)
{
}
btDeformableFaceRigidContactConstraint::btDeformableFaceRigidContactConstraint(const btDeformableFaceRigidContactConstraint& other)
-: m_face(other.m_face)
-, m_useStrainLimiting(other.m_useStrainLimiting)
-, btDeformableRigidContactConstraint(other)
+ : m_face(other.m_face), m_useStrainLimiting(other.m_useStrainLimiting), btDeformableRigidContactConstraint(other)
{
}
btVector3 btDeformableFaceRigidContactConstraint::getVb() const
{
- const btSoftBody::DeformableFaceRigidContact* contact = getContact();
- btVector3 vb = m_face->m_n[0]->m_v * contact->m_bary[0] + m_face->m_n[1]->m_v * contact->m_bary[1] + m_face->m_n[2]->m_v * contact->m_bary[2];
- return vb;
+ const btSoftBody::DeformableFaceRigidContact* contact = getContact();
+ btVector3 vb = m_face->m_n[0]->m_v * contact->m_bary[0] + m_face->m_n[1]->m_v * contact->m_bary[1] + m_face->m_n[2]->m_v * contact->m_bary[2];
+ return vb;
}
-
btVector3 btDeformableFaceRigidContactConstraint::getDv(const btSoftBody::Node* node) const
{
- btVector3 face_dv = m_total_normal_dv + m_total_tangent_dv;
- const btSoftBody::DeformableFaceRigidContact* contact = getContact();
- if (m_face->m_n[0] == node)
- {
- return face_dv * contact->m_weights[0];
- }
- if (m_face->m_n[1] == node)
- {
- return face_dv * contact->m_weights[1];
- }
- btAssert(node == m_face->m_n[2]);
- return face_dv * contact->m_weights[2];
+ btVector3 face_dv = m_total_normal_dv + m_total_tangent_dv;
+ const btSoftBody::DeformableFaceRigidContact* contact = getContact();
+ if (m_face->m_n[0] == node)
+ {
+ return face_dv * contact->m_weights[0];
+ }
+ if (m_face->m_n[1] == node)
+ {
+ return face_dv * contact->m_weights[1];
+ }
+ btAssert(node == m_face->m_n[2]);
+ return face_dv * contact->m_weights[2];
}
void btDeformableFaceRigidContactConstraint::applyImpulse(const btVector3& impulse)
{
- const btSoftBody::DeformableFaceRigidContact* contact = getContact();
- btVector3 dv = impulse * contact->m_c2;
- btSoftBody::Face* face = contact->m_face;
-
- btVector3& v0 = face->m_n[0]->m_v;
- btVector3& v1 = face->m_n[1]->m_v;
- btVector3& v2 = face->m_n[2]->m_v;
- const btScalar& im0 = face->m_n[0]->m_im;
- const btScalar& im1 = face->m_n[1]->m_im;
- const btScalar& im2 = face->m_n[2]->m_im;
- if (im0 > 0)
- v0 -= dv * contact->m_weights[0];
- if (im1 > 0)
- v1 -= dv * contact->m_weights[1];
- if (im2 > 0)
- v2 -= dv * contact->m_weights[2];
+ const btSoftBody::DeformableFaceRigidContact* contact = getContact();
+ btVector3 dv = impulse * contact->m_c2;
+ btSoftBody::Face* face = contact->m_face;
+
+ btVector3& v0 = face->m_n[0]->m_v;
+ btVector3& v1 = face->m_n[1]->m_v;
+ btVector3& v2 = face->m_n[2]->m_v;
+ const btScalar& im0 = face->m_n[0]->m_im;
+ const btScalar& im1 = face->m_n[1]->m_im;
+ const btScalar& im2 = face->m_n[2]->m_im;
+ if (im0 > 0)
+ v0 -= dv * contact->m_weights[0];
+ if (im1 > 0)
+ v1 -= dv * contact->m_weights[1];
+ if (im2 > 0)
+ v2 -= dv * contact->m_weights[2];
if (m_useStrainLimiting)
{
- btScalar relaxation = 1./btScalar(m_infoGlobal->m_numIterations);
- btScalar m01 = (relaxation/(im0 + im1));
- btScalar m02 = (relaxation/(im0 + im2));
- btScalar m12 = (relaxation/(im1 + im2));
- #ifdef USE_STRAIN_RATE_LIMITING
+ btScalar relaxation = 1. / btScalar(m_infoGlobal->m_numIterations);
+ btScalar m01 = (relaxation / (im0 + im1));
+ btScalar m02 = (relaxation / (im0 + im2));
+ btScalar m12 = (relaxation / (im1 + im2));
+#ifdef USE_STRAIN_RATE_LIMITING
// apply strain limiting to prevent the new velocity to change the current length of the edge by more than 1%.
btScalar p = 0.01;
btVector3& x0 = face->m_n[0]->m_x;
btVector3& x1 = face->m_n[1]->m_x;
btVector3& x2 = face->m_n[2]->m_x;
- const btVector3 x_diff[3] = {x1-x0, x2-x0, x2-x1};
- const btVector3 v_diff[3] = {v1-v0, v2-v0, v2-v1};
+ const btVector3 x_diff[3] = {x1 - x0, x2 - x0, x2 - x1};
+ const btVector3 v_diff[3] = {v1 - v0, v2 - v0, v2 - v1};
btVector3 u[3];
btScalar x_diff_dot_u, dn[3];
btScalar dt = m_infoGlobal->m_timeStep;
@@ -404,172 +520,201 @@ void btDeformableFaceRigidContactConstraint::applyImpulse(const btVector3& impul
{
btScalar x_diff_norm = x_diff[i].safeNorm();
btScalar x_diff_norm_new = (x_diff[i] + v_diff[i] * dt).safeNorm();
- btScalar strainRate = x_diff_norm_new/x_diff_norm;
+ btScalar strainRate = x_diff_norm_new / x_diff_norm;
u[i] = v_diff[i];
u[i].safeNormalize();
- if (x_diff_norm == 0 || (1-p <= strainRate && strainRate <= 1+p))
+ if (x_diff_norm == 0 || (1 - p <= strainRate && strainRate <= 1 + p))
{
dn[i] = 0;
continue;
}
x_diff_dot_u = btDot(x_diff[i], u[i]);
btScalar s;
- if (1-p > strainRate)
+ if (1 - p > strainRate)
{
- s = 1/dt * (-x_diff_dot_u - btSqrt(x_diff_dot_u*x_diff_dot_u + (p*p-2*p) * x_diff_norm * x_diff_norm));
+ s = 1 / dt * (-x_diff_dot_u - btSqrt(x_diff_dot_u * x_diff_dot_u + (p * p - 2 * p) * x_diff_norm * x_diff_norm));
}
else
{
- s = 1/dt * (-x_diff_dot_u + btSqrt(x_diff_dot_u*x_diff_dot_u + (p*p+2*p) * x_diff_norm * x_diff_norm));
+ s = 1 / dt * (-x_diff_dot_u + btSqrt(x_diff_dot_u * x_diff_dot_u + (p * p + 2 * p) * x_diff_norm * x_diff_norm));
}
// x_diff_norm_new = (x_diff[i] + s * u[i] * dt).safeNorm();
// strainRate = x_diff_norm_new/x_diff_norm;
dn[i] = s - v_diff[i].safeNorm();
}
- btVector3 dv0 = im0 * (m01 * u[0]*(-dn[0]) + m02 * u[1]*-(dn[1]));
- btVector3 dv1 = im1 * (m01 * u[0]*(dn[0]) + m12 * u[2]*(-dn[2]));
- btVector3 dv2 = im2 * (m12 * u[2]*(dn[2]) + m02 * u[1]*(dn[1]));
- #else
+ btVector3 dv0 = im0 * (m01 * u[0] * (-dn[0]) + m02 * u[1] * -(dn[1]));
+ btVector3 dv1 = im1 * (m01 * u[0] * (dn[0]) + m12 * u[2] * (-dn[2]));
+ btVector3 dv2 = im2 * (m12 * u[2] * (dn[2]) + m02 * u[1] * (dn[1]));
+#else
// apply strain limiting to prevent undamped modes
- btVector3 dv0 = im0 * (m01 * (v1-v0) + m02 * (v2-v0));
- btVector3 dv1 = im1 * (m01 * (v0-v1) + m12 * (v2-v1));
- btVector3 dv2 = im2 * (m12 * (v1-v2) + m02 * (v0-v2));
- #endif
+ btVector3 dv0 = im0 * (m01 * (v1 - v0) + m02 * (v2 - v0));
+ btVector3 dv1 = im1 * (m01 * (v0 - v1) + m12 * (v2 - v1));
+ btVector3 dv2 = im2 * (m12 * (v1 - v2) + m02 * (v0 - v2));
+#endif
v0 += dv0;
v1 += dv1;
v2 += dv2;
}
}
+btVector3 btDeformableFaceRigidContactConstraint::getSplitVb() const
+{
+ const btSoftBody::DeformableFaceRigidContact* contact = getContact();
+ btVector3 vb = (m_face->m_n[0]->m_splitv) * contact->m_bary[0] + (m_face->m_n[1]->m_splitv) * contact->m_bary[1] + (m_face->m_n[2]->m_splitv) * contact->m_bary[2];
+ return vb;
+}
+
+void btDeformableFaceRigidContactConstraint::applySplitImpulse(const btVector3& impulse)
+{
+ const btSoftBody::DeformableFaceRigidContact* contact = getContact();
+ btVector3 dv = impulse * contact->m_c2;
+ btSoftBody::Face* face = contact->m_face;
+ btVector3& v0 = face->m_n[0]->m_splitv;
+ btVector3& v1 = face->m_n[1]->m_splitv;
+ btVector3& v2 = face->m_n[2]->m_splitv;
+ const btScalar& im0 = face->m_n[0]->m_im;
+ const btScalar& im1 = face->m_n[1]->m_im;
+ const btScalar& im2 = face->m_n[2]->m_im;
+ if (im0 > 0)
+ {
+ v0 -= dv * contact->m_weights[0];
+ }
+ if (im1 > 0)
+ {
+ v1 -= dv * contact->m_weights[1];
+ }
+ if (im2 > 0)
+ {
+ v2 -= dv * contact->m_weights[2];
+ }
+}
+
/* ================ Face vs. Node =================== */
btDeformableFaceNodeContactConstraint::btDeformableFaceNodeContactConstraint(const btSoftBody::DeformableFaceNodeContact& contact, const btContactSolverInfo& infoGlobal)
-: m_node(contact.m_node)
-, m_face(contact.m_face)
-, m_contact(&contact)
-, btDeformableContactConstraint(contact.m_normal, infoGlobal)
+ : m_node(contact.m_node), m_face(contact.m_face), m_contact(&contact), btDeformableContactConstraint(contact.m_normal, infoGlobal)
{
- m_total_normal_dv.setZero();
- m_total_tangent_dv.setZero();
+ m_total_normal_dv.setZero();
+ m_total_tangent_dv.setZero();
}
btVector3 btDeformableFaceNodeContactConstraint::getVa() const
{
- return m_node->m_v;
+ return m_node->m_v;
}
btVector3 btDeformableFaceNodeContactConstraint::getVb() const
{
- const btSoftBody::DeformableFaceNodeContact* contact = getContact();
- btVector3 vb = m_face->m_n[0]->m_v * contact->m_bary[0] + m_face->m_n[1]->m_v * contact->m_bary[1] + m_face->m_n[2]->m_v * contact->m_bary[2];
- return vb;
+ const btSoftBody::DeformableFaceNodeContact* contact = getContact();
+ btVector3 vb = m_face->m_n[0]->m_v * contact->m_bary[0] + m_face->m_n[1]->m_v * contact->m_bary[1] + m_face->m_n[2]->m_v * contact->m_bary[2];
+ return vb;
}
btVector3 btDeformableFaceNodeContactConstraint::getDv(const btSoftBody::Node* n) const
{
- btVector3 dv = m_total_normal_dv + m_total_tangent_dv;
- if (n == m_node)
- return dv;
- const btSoftBody::DeformableFaceNodeContact* contact = getContact();
- if (m_face->m_n[0] == n)
- {
- return dv * contact->m_weights[0];
- }
- if (m_face->m_n[1] == n)
- {
- return dv * contact->m_weights[1];
- }
- btAssert(n == m_face->m_n[2]);
- return dv * contact->m_weights[2];
+ btVector3 dv = m_total_normal_dv + m_total_tangent_dv;
+ if (n == m_node)
+ return dv;
+ const btSoftBody::DeformableFaceNodeContact* contact = getContact();
+ if (m_face->m_n[0] == n)
+ {
+ return dv * contact->m_weights[0];
+ }
+ if (m_face->m_n[1] == n)
+ {
+ return dv * contact->m_weights[1];
+ }
+ btAssert(n == m_face->m_n[2]);
+ return dv * contact->m_weights[2];
}
btScalar btDeformableFaceNodeContactConstraint::solveConstraint(const btContactSolverInfo& infoGlobal)
{
- btVector3 va = getVa();
- btVector3 vb = getVb();
- btVector3 vr = vb - va;
- const btScalar dn = btDot(vr, m_contact->m_normal);
- // dn is the normal component of velocity diffrerence. Approximates the residual. // todo xuchenhan@: this prob needs to be scaled by dt
- btScalar residualSquare = dn*dn;
- btVector3 impulse = m_contact->m_c0 * vr;
- const btVector3 impulse_normal = m_contact->m_c0 * (m_contact->m_normal * dn);
- btVector3 impulse_tangent = impulse - impulse_normal;
-
- btVector3 old_total_tangent_dv = m_total_tangent_dv;
- // m_c2 is the inverse mass of the deformable node/face
- if (m_node->m_im > 0)
- {
- m_total_normal_dv -= impulse_normal * m_node->m_im;
- m_total_tangent_dv -= impulse_tangent * m_node->m_im;
- }
- else
- {
- m_total_normal_dv -= impulse_normal * m_contact->m_imf;
- m_total_tangent_dv -= impulse_tangent * m_contact->m_imf;
- }
-
- if (m_total_normal_dv.dot(m_contact->m_normal) > 0)
- {
- // separating in the normal direction
- m_static = false;
- m_total_tangent_dv = btVector3(0,0,0);
- impulse_tangent.setZero();
- }
- else
- {
- if (m_total_normal_dv.norm() * m_contact->m_friction < m_total_tangent_dv.norm())
- {
- // dynamic friction
- // with dynamic friction, the impulse are still applied to the two objects colliding, however, it does not pose a constraint in the cg solve, hence the change to dv merely serves to update velocity in the contact iterations.
- m_static = false;
- if (m_total_tangent_dv.safeNorm() < SIMD_EPSILON)
- {
- m_total_tangent_dv = btVector3(0,0,0);
- }
- else
- {
- m_total_tangent_dv = m_total_tangent_dv.normalized() * m_total_normal_dv.safeNorm() * m_contact->m_friction;
- }
- impulse_tangent = -btScalar(1)/m_node->m_im * (m_total_tangent_dv - old_total_tangent_dv);
- }
- else
- {
- // static friction
- m_static = true;
- }
- }
- impulse = impulse_normal + impulse_tangent;
- // apply impulse to deformable nodes involved and change their velocities
- applyImpulse(impulse);
- return residualSquare;
+ btVector3 va = getVa();
+ btVector3 vb = getVb();
+ btVector3 vr = vb - va;
+ const btScalar dn = btDot(vr, m_contact->m_normal);
+ // dn is the normal component of velocity diffrerence. Approximates the residual. // todo xuchenhan@: this prob needs to be scaled by dt
+ btScalar residualSquare = dn * dn;
+ btVector3 impulse = m_contact->m_c0 * vr;
+ const btVector3 impulse_normal = m_contact->m_c0 * (m_contact->m_normal * dn);
+ btVector3 impulse_tangent = impulse - impulse_normal;
+
+ btVector3 old_total_tangent_dv = m_total_tangent_dv;
+ // m_c2 is the inverse mass of the deformable node/face
+ if (m_node->m_im > 0)
+ {
+ m_total_normal_dv -= impulse_normal * m_node->m_im;
+ m_total_tangent_dv -= impulse_tangent * m_node->m_im;
+ }
+ else
+ {
+ m_total_normal_dv -= impulse_normal * m_contact->m_imf;
+ m_total_tangent_dv -= impulse_tangent * m_contact->m_imf;
+ }
+
+ if (m_total_normal_dv.dot(m_contact->m_normal) > 0)
+ {
+ // separating in the normal direction
+ m_static = false;
+ m_total_tangent_dv = btVector3(0, 0, 0);
+ impulse_tangent.setZero();
+ }
+ else
+ {
+ if (m_total_normal_dv.norm() * m_contact->m_friction < m_total_tangent_dv.norm())
+ {
+ // dynamic friction
+ // with dynamic friction, the impulse are still applied to the two objects colliding, however, it does not pose a constraint in the cg solve, hence the change to dv merely serves to update velocity in the contact iterations.
+ m_static = false;
+ if (m_total_tangent_dv.safeNorm() < SIMD_EPSILON)
+ {
+ m_total_tangent_dv = btVector3(0, 0, 0);
+ }
+ else
+ {
+ m_total_tangent_dv = m_total_tangent_dv.normalized() * m_total_normal_dv.safeNorm() * m_contact->m_friction;
+ }
+ impulse_tangent = -btScalar(1) / m_node->m_im * (m_total_tangent_dv - old_total_tangent_dv);
+ }
+ else
+ {
+ // static friction
+ m_static = true;
+ }
+ }
+ impulse = impulse_normal + impulse_tangent;
+ // apply impulse to deformable nodes involved and change their velocities
+ applyImpulse(impulse);
+ return residualSquare;
}
void btDeformableFaceNodeContactConstraint::applyImpulse(const btVector3& impulse)
{
- const btSoftBody::DeformableFaceNodeContact* contact = getContact();
- btVector3 dva = impulse * contact->m_node->m_im;
- btVector3 dvb = impulse * contact->m_imf;
- if (contact->m_node->m_im > 0)
- {
- contact->m_node->m_v += dva;
- }
-
- btSoftBody::Face* face = contact->m_face;
- btVector3& v0 = face->m_n[0]->m_v;
- btVector3& v1 = face->m_n[1]->m_v;
- btVector3& v2 = face->m_n[2]->m_v;
- const btScalar& im0 = face->m_n[0]->m_im;
- const btScalar& im1 = face->m_n[1]->m_im;
- const btScalar& im2 = face->m_n[2]->m_im;
- if (im0 > 0)
- {
- v0 -= dvb * contact->m_weights[0];
- }
- if (im1 > 0)
- {
- v1 -= dvb * contact->m_weights[1];
- }
- if (im2 > 0)
- {
- v2 -= dvb * contact->m_weights[2];
- }
+ const btSoftBody::DeformableFaceNodeContact* contact = getContact();
+ btVector3 dva = impulse * contact->m_node->m_im;
+ btVector3 dvb = impulse * contact->m_imf;
+ if (contact->m_node->m_im > 0)
+ {
+ contact->m_node->m_v += dva;
+ }
+
+ btSoftBody::Face* face = contact->m_face;
+ btVector3& v0 = face->m_n[0]->m_v;
+ btVector3& v1 = face->m_n[1]->m_v;
+ btVector3& v2 = face->m_n[2]->m_v;
+ const btScalar& im0 = face->m_n[0]->m_im;
+ const btScalar& im1 = face->m_n[1]->m_im;
+ const btScalar& im2 = face->m_n[2]->m_im;
+ if (im0 > 0)
+ {
+ v0 -= dvb * contact->m_weights[0];
+ }
+ if (im1 > 0)
+ {
+ v1 -= dvb * contact->m_weights[1];
+ }
+ if (im2 > 0)
+ {
+ v2 -= dvb * contact->m_weights[2];
+ }
}
diff --git a/thirdparty/bullet/BulletSoftBody/btDeformableContactConstraint.h b/thirdparty/bullet/BulletSoftBody/btDeformableContactConstraint.h
index 9f9d5bf0a3..1e2c9f5bce 100644
--- a/thirdparty/bullet/BulletSoftBody/btDeformableContactConstraint.h
+++ b/thirdparty/bullet/BulletSoftBody/btDeformableContactConstraint.h
@@ -21,51 +21,49 @@
class btDeformableContactConstraint
{
public:
- // True if the friction is static
- // False if the friction is dynamic
- bool m_static;
+ // True if the friction is static
+ // False if the friction is dynamic
+ bool m_static;
const btContactSolverInfo* m_infoGlobal;
// normal of the contact
btVector3 m_normal;
- btDeformableContactConstraint(const btVector3& normal, const btContactSolverInfo& infoGlobal): m_static(false), m_normal(normal), m_infoGlobal(&infoGlobal)
+ btDeformableContactConstraint(const btVector3& normal, const btContactSolverInfo& infoGlobal) : m_static(false), m_normal(normal), m_infoGlobal(&infoGlobal)
{
}
- btDeformableContactConstraint(bool isStatic, const btVector3& normal, const btContactSolverInfo& infoGlobal): m_static(isStatic), m_normal(normal), m_infoGlobal(&infoGlobal)
+ btDeformableContactConstraint(bool isStatic, const btVector3& normal, const btContactSolverInfo& infoGlobal) : m_static(isStatic), m_normal(normal), m_infoGlobal(&infoGlobal)
{
}
-
- btDeformableContactConstraint(){}
+
+ btDeformableContactConstraint() {}
btDeformableContactConstraint(const btDeformableContactConstraint& other)
- : m_static(other.m_static)
- , m_normal(other.m_normal)
- , m_infoGlobal(other.m_infoGlobal)
+ : m_static(other.m_static), m_normal(other.m_normal), m_infoGlobal(other.m_infoGlobal)
{
}
- virtual ~btDeformableContactConstraint(){}
-
- // solve the constraint with inelastic impulse and return the error, which is the square of normal component of velocity diffrerence
- // the constraint is solved by calculating the impulse between object A and B in the contact and apply the impulse to both objects involved in the contact
- virtual btScalar solveConstraint(const btContactSolverInfo& infoGlobal) = 0;
-
- // get the velocity of the object A in the contact
- virtual btVector3 getVa() const = 0;
-
- // get the velocity of the object B in the contact
- virtual btVector3 getVb() const = 0;
-
- // get the velocity change of the soft body node in the constraint
- virtual btVector3 getDv(const btSoftBody::Node*) const = 0;
-
- // apply impulse to the soft body node and/or face involved
- virtual void applyImpulse(const btVector3& impulse) = 0;
-
- // scale the penetration depth by erp
- virtual void setPenetrationScale(btScalar scale) = 0;
+ virtual ~btDeformableContactConstraint() {}
+
+ // solve the constraint with inelastic impulse and return the error, which is the square of normal component of velocity diffrerence
+ // the constraint is solved by calculating the impulse between object A and B in the contact and apply the impulse to both objects involved in the contact
+ virtual btScalar solveConstraint(const btContactSolverInfo& infoGlobal) = 0;
+
+ // get the velocity of the object A in the contact
+ virtual btVector3 getVa() const = 0;
+
+ // get the velocity of the object B in the contact
+ virtual btVector3 getVb() const = 0;
+
+ // get the velocity change of the soft body node in the constraint
+ virtual btVector3 getDv(const btSoftBody::Node*) const = 0;
+
+ // apply impulse to the soft body node and/or face involved
+ virtual void applyImpulse(const btVector3& impulse) = 0;
+
+ // scale the penetration depth by erp
+ virtual void setPenetrationScale(btScalar scale) = 0;
};
//
@@ -73,42 +71,41 @@ public:
class btDeformableStaticConstraint : public btDeformableContactConstraint
{
public:
- btSoftBody::Node* m_node;
-
- btDeformableStaticConstraint(btSoftBody::Node* node, const btContactSolverInfo& infoGlobal): m_node(node), btDeformableContactConstraint(false, btVector3(0,0,0), infoGlobal)
- {
- }
- btDeformableStaticConstraint(){}
- btDeformableStaticConstraint(const btDeformableStaticConstraint& other)
- : m_node(other.m_node)
- , btDeformableContactConstraint(other)
- {
- }
-
- virtual ~btDeformableStaticConstraint(){}
-
- virtual btScalar solveConstraint(const btContactSolverInfo& infoGlobal)
- {
- return 0;
- }
-
- virtual btVector3 getVa() const
- {
- return btVector3(0,0,0);
- }
-
- virtual btVector3 getVb() const
- {
- return btVector3(0,0,0);
- }
-
- virtual btVector3 getDv(const btSoftBody::Node* n) const
- {
- return btVector3(0,0,0);
- }
-
- virtual void applyImpulse(const btVector3& impulse){}
- virtual void setPenetrationScale(btScalar scale){}
+ btSoftBody::Node* m_node;
+
+ btDeformableStaticConstraint(btSoftBody::Node* node, const btContactSolverInfo& infoGlobal) : m_node(node), btDeformableContactConstraint(false, btVector3(0, 0, 0), infoGlobal)
+ {
+ }
+ btDeformableStaticConstraint() {}
+ btDeformableStaticConstraint(const btDeformableStaticConstraint& other)
+ : m_node(other.m_node), btDeformableContactConstraint(other)
+ {
+ }
+
+ virtual ~btDeformableStaticConstraint() {}
+
+ virtual btScalar solveConstraint(const btContactSolverInfo& infoGlobal)
+ {
+ return 0;
+ }
+
+ virtual btVector3 getVa() const
+ {
+ return btVector3(0, 0, 0);
+ }
+
+ virtual btVector3 getVb() const
+ {
+ return btVector3(0, 0, 0);
+ }
+
+ virtual btVector3 getDv(const btSoftBody::Node* n) const
+ {
+ return btVector3(0, 0, 0);
+ }
+
+ virtual void applyImpulse(const btVector3& impulse) {}
+ virtual void setPenetrationScale(btScalar scale) {}
};
//
@@ -116,56 +113,67 @@ public:
class btDeformableNodeAnchorConstraint : public btDeformableContactConstraint
{
public:
- const btSoftBody::DeformableNodeRigidAnchor* m_anchor;
-
- btDeformableNodeAnchorConstraint(const btSoftBody::DeformableNodeRigidAnchor& c, const btContactSolverInfo& infoGlobal);
- btDeformableNodeAnchorConstraint(const btDeformableNodeAnchorConstraint& other);
- btDeformableNodeAnchorConstraint(){}
- virtual ~btDeformableNodeAnchorConstraint()
- {
- }
- virtual btScalar solveConstraint(const btContactSolverInfo& infoGlobal);
-
- // object A is the rigid/multi body, and object B is the deformable node/face
- virtual btVector3 getVa() const;
- // get the velocity of the deformable node in contact
- virtual btVector3 getVb() const;
- virtual btVector3 getDv(const btSoftBody::Node* n) const
- {
- return btVector3(0,0,0);
- }
- virtual void applyImpulse(const btVector3& impulse);
-
- virtual void setPenetrationScale(btScalar scale){}
-};
+ const btSoftBody::DeformableNodeRigidAnchor* m_anchor;
+ btDeformableNodeAnchorConstraint(const btSoftBody::DeformableNodeRigidAnchor& c, const btContactSolverInfo& infoGlobal);
+ btDeformableNodeAnchorConstraint(const btDeformableNodeAnchorConstraint& other);
+ btDeformableNodeAnchorConstraint() {}
+ virtual ~btDeformableNodeAnchorConstraint()
+ {
+ }
+ virtual btScalar solveConstraint(const btContactSolverInfo& infoGlobal);
+
+ // object A is the rigid/multi body, and object B is the deformable node/face
+ virtual btVector3 getVa() const;
+ // get the velocity of the deformable node in contact
+ virtual btVector3 getVb() const;
+ virtual btVector3 getDv(const btSoftBody::Node* n) const
+ {
+ return btVector3(0, 0, 0);
+ }
+ virtual void applyImpulse(const btVector3& impulse);
+
+ virtual void setPenetrationScale(btScalar scale) {}
+};
//
// Constraint between rigid/multi body and deformable objects
class btDeformableRigidContactConstraint : public btDeformableContactConstraint
{
public:
- btVector3 m_total_normal_dv;
- btVector3 m_total_tangent_dv;
- btScalar m_penetration;
- const btSoftBody::DeformableRigidContact* m_contact;
-
- btDeformableRigidContactConstraint(const btSoftBody::DeformableRigidContact& c, const btContactSolverInfo& infoGlobal);
- btDeformableRigidContactConstraint(const btDeformableRigidContactConstraint& other);
- btDeformableRigidContactConstraint(){}
- virtual ~btDeformableRigidContactConstraint()
- {
- }
-
- // object A is the rigid/multi body, and object B is the deformable node/face
- virtual btVector3 getVa() const;
-
- virtual btScalar solveConstraint(const btContactSolverInfo& infoGlobal);
-
- virtual void setPenetrationScale(btScalar scale)
- {
- m_penetration *= scale;
- }
+ btVector3 m_total_normal_dv;
+ btVector3 m_total_tangent_dv;
+ btScalar m_penetration;
+ btScalar m_total_split_impulse;
+ bool m_binding;
+ const btSoftBody::DeformableRigidContact* m_contact;
+
+ btDeformableRigidContactConstraint(const btSoftBody::DeformableRigidContact& c, const btContactSolverInfo& infoGlobal);
+ btDeformableRigidContactConstraint(const btDeformableRigidContactConstraint& other);
+ btDeformableRigidContactConstraint() {}
+ virtual ~btDeformableRigidContactConstraint()
+ {
+ }
+
+ // object A is the rigid/multi body, and object B is the deformable node/face
+ virtual btVector3 getVa() const;
+
+ // get the split impulse velocity of the deformable face at the contact point
+ virtual btVector3 getSplitVb() const = 0;
+
+ // get the split impulse velocity of the rigid/multibdoy at the contaft
+ virtual btVector3 getSplitVa() const;
+
+ virtual btScalar solveConstraint(const btContactSolverInfo& infoGlobal);
+
+ virtual void setPenetrationScale(btScalar scale)
+ {
+ m_penetration *= scale;
+ }
+
+ btScalar solveSplitImpulse(const btContactSolverInfo& infoGlobal);
+
+ virtual void applySplitImpulse(const btVector3& impulse) = 0;
};
//
@@ -173,29 +181,34 @@ public:
class btDeformableNodeRigidContactConstraint : public btDeformableRigidContactConstraint
{
public:
- // the deformable node in contact
- btSoftBody::Node* m_node;
-
- btDeformableNodeRigidContactConstraint(const btSoftBody::DeformableNodeRigidContact& contact, const btContactSolverInfo& infoGlobal);
- btDeformableNodeRigidContactConstraint(const btDeformableNodeRigidContactConstraint& other);
- btDeformableNodeRigidContactConstraint(){}
- virtual ~btDeformableNodeRigidContactConstraint()
- {
- }
-
- // get the velocity of the deformable node in contact
- virtual btVector3 getVb() const;
-
- // get the velocity change of the input soft body node in the constraint
- virtual btVector3 getDv(const btSoftBody::Node*) const;
-
- // cast the contact to the desired type
- const btSoftBody::DeformableNodeRigidContact* getContact() const
- {
- return static_cast<const btSoftBody::DeformableNodeRigidContact*>(m_contact);
- }
-
- virtual void applyImpulse(const btVector3& impulse);
+ // the deformable node in contact
+ btSoftBody::Node* m_node;
+
+ btDeformableNodeRigidContactConstraint(const btSoftBody::DeformableNodeRigidContact& contact, const btContactSolverInfo& infoGlobal);
+ btDeformableNodeRigidContactConstraint(const btDeformableNodeRigidContactConstraint& other);
+ btDeformableNodeRigidContactConstraint() {}
+ virtual ~btDeformableNodeRigidContactConstraint()
+ {
+ }
+
+ // get the velocity of the deformable node in contact
+ virtual btVector3 getVb() const;
+
+ // get the split impulse velocity of the deformable face at the contact point
+ virtual btVector3 getSplitVb() const;
+
+ // get the velocity change of the input soft body node in the constraint
+ virtual btVector3 getDv(const btSoftBody::Node*) const;
+
+ // cast the contact to the desired type
+ const btSoftBody::DeformableNodeRigidContact* getContact() const
+ {
+ return static_cast<const btSoftBody::DeformableNodeRigidContact*>(m_contact);
+ }
+
+ virtual void applyImpulse(const btVector3& impulse);
+
+ virtual void applySplitImpulse(const btVector3& impulse);
};
//
@@ -203,28 +216,33 @@ public:
class btDeformableFaceRigidContactConstraint : public btDeformableRigidContactConstraint
{
public:
- const btSoftBody::Face* m_face;
- bool m_useStrainLimiting;
- btDeformableFaceRigidContactConstraint(const btSoftBody::DeformableFaceRigidContact& contact, const btContactSolverInfo& infoGlobal, bool useStrainLimiting);
- btDeformableFaceRigidContactConstraint(const btDeformableFaceRigidContactConstraint& other);
- btDeformableFaceRigidContactConstraint(): m_useStrainLimiting(false) {}
- virtual ~btDeformableFaceRigidContactConstraint()
- {
- }
-
- // get the velocity of the deformable face at the contact point
- virtual btVector3 getVb() const;
-
- // get the velocity change of the input soft body node in the constraint
- virtual btVector3 getDv(const btSoftBody::Node*) const;
-
- // cast the contact to the desired type
- const btSoftBody::DeformableFaceRigidContact* getContact() const
- {
- return static_cast<const btSoftBody::DeformableFaceRigidContact*>(m_contact);
- }
-
- virtual void applyImpulse(const btVector3& impulse);
+ btSoftBody::Face* m_face;
+ bool m_useStrainLimiting;
+ btDeformableFaceRigidContactConstraint(const btSoftBody::DeformableFaceRigidContact& contact, const btContactSolverInfo& infoGlobal, bool useStrainLimiting);
+ btDeformableFaceRigidContactConstraint(const btDeformableFaceRigidContactConstraint& other);
+ btDeformableFaceRigidContactConstraint() : m_useStrainLimiting(false) {}
+ virtual ~btDeformableFaceRigidContactConstraint()
+ {
+ }
+
+ // get the velocity of the deformable face at the contact point
+ virtual btVector3 getVb() const;
+
+ // get the split impulse velocity of the deformable face at the contact point
+ virtual btVector3 getSplitVb() const;
+
+ // get the velocity change of the input soft body node in the constraint
+ virtual btVector3 getDv(const btSoftBody::Node*) const;
+
+ // cast the contact to the desired type
+ const btSoftBody::DeformableFaceRigidContact* getContact() const
+ {
+ return static_cast<const btSoftBody::DeformableFaceRigidContact*>(m_contact);
+ }
+
+ virtual void applyImpulse(const btVector3& impulse);
+
+ virtual void applySplitImpulse(const btVector3& impulse);
};
//
@@ -232,35 +250,35 @@ public:
class btDeformableFaceNodeContactConstraint : public btDeformableContactConstraint
{
public:
- btSoftBody::Node* m_node;
- btSoftBody::Face* m_face;
- const btSoftBody::DeformableFaceNodeContact* m_contact;
- btVector3 m_total_normal_dv;
- btVector3 m_total_tangent_dv;
-
- btDeformableFaceNodeContactConstraint(const btSoftBody::DeformableFaceNodeContact& contact, const btContactSolverInfo& infoGlobal);
- btDeformableFaceNodeContactConstraint(){}
- virtual ~btDeformableFaceNodeContactConstraint(){}
-
- virtual btScalar solveConstraint(const btContactSolverInfo& infoGlobal);
-
- // get the velocity of the object A in the contact
- virtual btVector3 getVa() const;
-
- // get the velocity of the object B in the contact
- virtual btVector3 getVb() const;
-
- // get the velocity change of the input soft body node in the constraint
- virtual btVector3 getDv(const btSoftBody::Node*) const;
-
- // cast the contact to the desired type
- const btSoftBody::DeformableFaceNodeContact* getContact() const
- {
- return static_cast<const btSoftBody::DeformableFaceNodeContact*>(m_contact);
- }
-
- virtual void applyImpulse(const btVector3& impulse);
-
- virtual void setPenetrationScale(btScalar scale){}
+ btSoftBody::Node* m_node;
+ btSoftBody::Face* m_face;
+ const btSoftBody::DeformableFaceNodeContact* m_contact;
+ btVector3 m_total_normal_dv;
+ btVector3 m_total_tangent_dv;
+
+ btDeformableFaceNodeContactConstraint(const btSoftBody::DeformableFaceNodeContact& contact, const btContactSolverInfo& infoGlobal);
+ btDeformableFaceNodeContactConstraint() {}
+ virtual ~btDeformableFaceNodeContactConstraint() {}
+
+ virtual btScalar solveConstraint(const btContactSolverInfo& infoGlobal);
+
+ // get the velocity of the object A in the contact
+ virtual btVector3 getVa() const;
+
+ // get the velocity of the object B in the contact
+ virtual btVector3 getVb() const;
+
+ // get the velocity change of the input soft body node in the constraint
+ virtual btVector3 getDv(const btSoftBody::Node*) const;
+
+ // cast the contact to the desired type
+ const btSoftBody::DeformableFaceNodeContact* getContact() const
+ {
+ return static_cast<const btSoftBody::DeformableFaceNodeContact*>(m_contact);
+ }
+
+ virtual void applyImpulse(const btVector3& impulse);
+
+ virtual void setPenetrationScale(btScalar scale) {}
};
#endif /* BT_DEFORMABLE_CONTACT_CONSTRAINT_H */
diff --git a/thirdparty/bullet/BulletSoftBody/btDeformableContactProjection.cpp b/thirdparty/bullet/BulletSoftBody/btDeformableContactProjection.cpp
index 22ca8bf582..7f67260ce6 100644
--- a/thirdparty/bullet/BulletSoftBody/btDeformableContactProjection.cpp
+++ b/thirdparty/bullet/BulletSoftBody/btDeformableContactProjection.cpp
@@ -17,7 +17,7 @@
#include "btDeformableMultiBodyDynamicsWorld.h"
#include <algorithm>
#include <cmath>
-btScalar btDeformableContactProjection::update(btCollisionObject** deformableBodies,int numDeformableBodies, const btContactSolverInfo& infoGlobal)
+btScalar btDeformableContactProjection::update(btCollisionObject** deformableBodies, int numDeformableBodies, const btContactSolverInfo& infoGlobal)
{
btScalar residualSquare = 0;
for (int i = 0; i < numDeformableBodies; ++i)
@@ -58,27 +58,37 @@ btScalar btDeformableContactProjection::update(btCollisionObject** deformableBod
return residualSquare;
}
-void btDeformableContactProjection::splitImpulseSetup(const btContactSolverInfo& infoGlobal)
+btScalar btDeformableContactProjection::solveSplitImpulse(btCollisionObject** deformableBodies, int numDeformableBodies, const btContactSolverInfo& infoGlobal)
{
- for (int i = 0; i < m_softBodies.size(); ++i)
+ btScalar residualSquare = 0;
+ for (int i = 0; i < numDeformableBodies; ++i)
{
- // node constraints
- for (int j = 0; j < m_nodeRigidConstraints[i].size(); ++j)
- {
- btDeformableNodeRigidContactConstraint& constraint = m_nodeRigidConstraints[i][j];
- constraint.setPenetrationScale(infoGlobal.m_deformable_erp);
- }
- // face constraints
- for (int j = 0; j < m_faceRigidConstraints[i].size(); ++j)
+ for (int j = 0; j < m_softBodies.size(); ++j)
{
- btDeformableFaceRigidContactConstraint& constraint = m_faceRigidConstraints[i][j];
- constraint.setPenetrationScale(infoGlobal.m_deformable_erp);
+ btCollisionObject* psb = m_softBodies[j];
+ if (psb != deformableBodies[i])
+ {
+ continue;
+ }
+ for (int k = 0; k < m_nodeRigidConstraints[j].size(); ++k)
+ {
+ btDeformableNodeRigidContactConstraint& constraint = m_nodeRigidConstraints[j][k];
+ btScalar localResidualSquare = constraint.solveSplitImpulse(infoGlobal);
+ residualSquare = btMax(residualSquare, localResidualSquare);
+ }
+ for (int k = 0; k < m_faceRigidConstraints[j].size(); ++k)
+ {
+ btDeformableFaceRigidContactConstraint& constraint = m_faceRigidConstraints[j][k];
+ btScalar localResidualSquare = constraint.solveSplitImpulse(infoGlobal);
+ residualSquare = btMax(residualSquare, localResidualSquare);
+ }
}
}
+ return residualSquare;
}
void btDeformableContactProjection::setConstraints(const btContactSolverInfo& infoGlobal)
-{
+{
BT_PROFILE("setConstraints");
for (int i = 0; i < m_softBodies.size(); ++i)
{
@@ -97,7 +107,7 @@ void btDeformableContactProjection::setConstraints(const btContactSolverInfo& in
m_staticConstraints[i].push_back(static_constraint);
}
}
-
+
// set up deformable anchors
for (int j = 0; j < psb->m_deformableAnchors.size(); ++j)
{
@@ -111,7 +121,7 @@ void btDeformableContactProjection::setConstraints(const btContactSolverInfo& in
btDeformableNodeAnchorConstraint constraint(anchor, infoGlobal);
m_nodeAnchorConstraints[i].push_back(constraint);
}
-
+
// set Deformable Node vs. Rigid constraint
for (int j = 0; j < psb->m_nodeRigidContacts.size(); ++j)
{
@@ -122,17 +132,9 @@ void btDeformableContactProjection::setConstraints(const btContactSolverInfo& in
continue;
}
btDeformableNodeRigidContactConstraint constraint(contact, infoGlobal);
- btVector3 va = constraint.getVa();
- btVector3 vb = constraint.getVb();
- const btVector3 vr = vb - va;
- const btSoftBody::sCti& cti = contact.m_cti;
- const btScalar dn = btDot(vr, cti.m_normal);
- if (dn < SIMD_EPSILON)
- {
- m_nodeRigidConstraints[i].push_back(constraint);
- }
+ m_nodeRigidConstraints[i].push_back(constraint);
}
-
+
// set Deformable Face vs. Rigid constraint
for (int j = 0; j < psb->m_faceRigidContacts.size(); ++j)
{
@@ -143,15 +145,7 @@ void btDeformableContactProjection::setConstraints(const btContactSolverInfo& in
continue;
}
btDeformableFaceRigidContactConstraint constraint(contact, infoGlobal, m_useStrainLimiting);
- btVector3 va = constraint.getVa();
- btVector3 vb = constraint.getVb();
- const btVector3 vr = vb - va;
- const btSoftBody::sCti& cti = contact.m_cti;
- const btScalar dn = btDot(vr, cti.m_normal);
- if (dn < SIMD_EPSILON)
- {
- m_faceRigidConstraints[i].push_back(constraint);
- }
+ m_faceRigidConstraints[i].push_back(constraint);
}
}
}
@@ -159,267 +153,269 @@ void btDeformableContactProjection::setConstraints(const btContactSolverInfo& in
void btDeformableContactProjection::project(TVStack& x)
{
#ifndef USE_MGS
- const int dim = 3;
- for (int index = 0; index < m_projectionsDict.size(); ++index)
- {
- btAlignedObjectArray<btVector3>& projectionDirs = *m_projectionsDict.getAtIndex(index);
- size_t i = m_projectionsDict.getKeyAtIndex(index).getUid1();
- if (projectionDirs.size() >= dim)
- {
- // static node
- x[i].setZero();
- continue;
- }
- else if (projectionDirs.size() == 2)
- {
- btVector3 dir0 = projectionDirs[0];
- btVector3 dir1 = projectionDirs[1];
- btVector3 free_dir = btCross(dir0, dir1);
- if (free_dir.safeNorm() < SIMD_EPSILON)
- {
- x[i] -= x[i].dot(dir0) * dir0;
- x[i] -= x[i].dot(dir1) * dir1;
- }
- else
- {
- free_dir.normalize();
- x[i] = x[i].dot(free_dir) * free_dir;
- }
- }
- else
- {
- btAssert(projectionDirs.size() == 1);
- btVector3 dir0 = projectionDirs[0];
- x[i] -= x[i].dot(dir0) * dir0;
- }
- }
+ const int dim = 3;
+ for (int index = 0; index < m_projectionsDict.size(); ++index)
+ {
+ btAlignedObjectArray<btVector3>& projectionDirs = *m_projectionsDict.getAtIndex(index);
+ size_t i = m_projectionsDict.getKeyAtIndex(index).getUid1();
+ if (projectionDirs.size() >= dim)
+ {
+ // static node
+ x[i].setZero();
+ continue;
+ }
+ else if (projectionDirs.size() == 2)
+ {
+ btVector3 dir0 = projectionDirs[0];
+ btVector3 dir1 = projectionDirs[1];
+ btVector3 free_dir = btCross(dir0, dir1);
+ if (free_dir.safeNorm() < SIMD_EPSILON)
+ {
+ x[i] -= x[i].dot(dir0) * dir0;
+ }
+ else
+ {
+ free_dir.normalize();
+ x[i] = x[i].dot(free_dir) * free_dir;
+ }
+ }
+ else
+ {
+ btAssert(projectionDirs.size() == 1);
+ btVector3 dir0 = projectionDirs[0];
+ x[i] -= x[i].dot(dir0) * dir0;
+ }
+ }
#else
- btReducedVector p(x.size());
- for (int i = 0; i < m_projections.size(); ++i)
- {
- p += (m_projections[i].dot(x) * m_projections[i]);
- }
- for (int i = 0; i < p.m_indices.size(); ++i)
- {
- x[p.m_indices[i]] -= p.m_vecs[i];
- }
+ btReducedVector p(x.size());
+ for (int i = 0; i < m_projections.size(); ++i)
+ {
+ p += (m_projections[i].dot(x) * m_projections[i]);
+ }
+ for (int i = 0; i < p.m_indices.size(); ++i)
+ {
+ x[p.m_indices[i]] -= p.m_vecs[i];
+ }
#endif
}
void btDeformableContactProjection::setProjection()
{
#ifndef USE_MGS
- BT_PROFILE("btDeformableContactProjection::setProjection");
- btAlignedObjectArray<btVector3> units;
- units.push_back(btVector3(1,0,0));
- units.push_back(btVector3(0,1,0));
- units.push_back(btVector3(0,0,1));
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- continue;
- }
- for (int j = 0; j < m_staticConstraints[i].size(); ++j)
- {
- int index = m_staticConstraints[i][j].m_node->index;
- m_staticConstraints[i][j].m_node->m_penetration = SIMD_INFINITY;
- if (m_projectionsDict.find(index) == NULL)
- {
- m_projectionsDict.insert(index, units);
- }
- else
- {
- btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index];
- for (int k = 0; k < 3; ++k)
- {
- projections.push_back(units[k]);
- }
- }
- }
- for (int j = 0; j < m_nodeAnchorConstraints[i].size(); ++j)
- {
- int index = m_nodeAnchorConstraints[i][j].m_anchor->m_node->index;
- m_nodeAnchorConstraints[i][j].m_anchor->m_node->m_penetration = SIMD_INFINITY;
- if (m_projectionsDict.find(index) == NULL)
- {
- m_projectionsDict.insert(index, units);
- }
- else
- {
- btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index];
- for (int k = 0; k < 3; ++k)
- {
- projections.push_back(units[k]);
- }
- }
- }
- for (int j = 0; j < m_nodeRigidConstraints[i].size(); ++j)
- {
- int index = m_nodeRigidConstraints[i][j].m_node->index;
- m_nodeRigidConstraints[i][j].m_node->m_penetration = -m_nodeRigidConstraints[i][j].getContact()->m_cti.m_offset;
- if (m_nodeRigidConstraints[i][j].m_static)
- {
- if (m_projectionsDict.find(index) == NULL)
- {
- m_projectionsDict.insert(index, units);
- }
- else
- {
- btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index];
- for (int k = 0; k < 3; ++k)
- {
- projections.push_back(units[k]);
- }
- }
- }
- else
- {
- if (m_projectionsDict.find(index) == NULL)
- {
- btAlignedObjectArray<btVector3> projections;
- projections.push_back(m_nodeRigidConstraints[i][j].m_normal);
- m_projectionsDict.insert(index, projections);
- }
- else
- {
- btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index];
- projections.push_back(m_nodeRigidConstraints[i][j].m_normal);
- }
- }
- }
- for (int j = 0; j < m_faceRigidConstraints[i].size(); ++j)
- {
- const btSoftBody::Face* face = m_faceRigidConstraints[i][j].m_face;
- btScalar penetration = -m_faceRigidConstraints[i][j].getContact()->m_cti.m_offset;
- for (int k = 0; k < 3; ++k)
- {
- face->m_n[k]->m_penetration = btMax(face->m_n[k]->m_penetration, penetration);
- }
- for (int k = 0; k < 3; ++k)
- {
- btSoftBody::Node* node = face->m_n[k];
- node->m_penetration = true;
- int index = node->index;
- if (m_faceRigidConstraints[i][j].m_static)
- {
- if (m_projectionsDict.find(index) == NULL)
- {
- m_projectionsDict.insert(index, units);
- }
- else
- {
- btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index];
- for (int k = 0; k < 3; ++k)
- {
- projections.push_back(units[k]);
- }
- }
- }
- else
- {
- if (m_projectionsDict.find(index) == NULL)
- {
- btAlignedObjectArray<btVector3> projections;
- projections.push_back(m_faceRigidConstraints[i][j].m_normal);
- m_projectionsDict.insert(index, projections);
- }
- else
- {
- btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index];
- projections.push_back(m_faceRigidConstraints[i][j].m_normal);
- }
- }
- }
- }
- }
+ BT_PROFILE("btDeformableContactProjection::setProjection");
+ btAlignedObjectArray<btVector3> units;
+ units.push_back(btVector3(1, 0, 0));
+ units.push_back(btVector3(0, 1, 0));
+ units.push_back(btVector3(0, 0, 1));
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ continue;
+ }
+ for (int j = 0; j < m_staticConstraints[i].size(); ++j)
+ {
+ int index = m_staticConstraints[i][j].m_node->index;
+ m_staticConstraints[i][j].m_node->m_constrained = true;
+ if (m_projectionsDict.find(index) == NULL)
+ {
+ m_projectionsDict.insert(index, units);
+ }
+ else
+ {
+ btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index];
+ for (int k = 0; k < 3; ++k)
+ {
+ projections.push_back(units[k]);
+ }
+ }
+ }
+ for (int j = 0; j < m_nodeAnchorConstraints[i].size(); ++j)
+ {
+ int index = m_nodeAnchorConstraints[i][j].m_anchor->m_node->index;
+ m_nodeAnchorConstraints[i][j].m_anchor->m_node->m_constrained = true;
+ if (m_projectionsDict.find(index) == NULL)
+ {
+ m_projectionsDict.insert(index, units);
+ }
+ else
+ {
+ btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index];
+ for (int k = 0; k < 3; ++k)
+ {
+ projections.push_back(units[k]);
+ }
+ }
+ }
+ for (int j = 0; j < m_nodeRigidConstraints[i].size(); ++j)
+ {
+ int index = m_nodeRigidConstraints[i][j].m_node->index;
+ m_nodeRigidConstraints[i][j].m_node->m_constrained = true;
+ if (m_nodeRigidConstraints[i][j].m_binding)
+ {
+ if (m_nodeRigidConstraints[i][j].m_static)
+ {
+ if (m_projectionsDict.find(index) == NULL)
+ {
+ m_projectionsDict.insert(index, units);
+ }
+ else
+ {
+ btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index];
+ for (int k = 0; k < 3; ++k)
+ {
+ projections.push_back(units[k]);
+ }
+ }
+ }
+ else
+ {
+ if (m_projectionsDict.find(index) == NULL)
+ {
+ btAlignedObjectArray<btVector3> projections;
+ projections.push_back(m_nodeRigidConstraints[i][j].m_normal);
+ m_projectionsDict.insert(index, projections);
+ }
+ else
+ {
+ btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index];
+ projections.push_back(m_nodeRigidConstraints[i][j].m_normal);
+ }
+ }
+ }
+ }
+ for (int j = 0; j < m_faceRigidConstraints[i].size(); ++j)
+ {
+ const btSoftBody::Face* face = m_faceRigidConstraints[i][j].m_face;
+ if (m_faceRigidConstraints[i][j].m_binding)
+ {
+ for (int k = 0; k < 3; ++k)
+ {
+ face->m_n[k]->m_constrained = true;
+ }
+ }
+ for (int k = 0; k < 3; ++k)
+ {
+ btSoftBody::Node* node = face->m_n[k];
+ int index = node->index;
+ if (m_faceRigidConstraints[i][j].m_static)
+ {
+ if (m_projectionsDict.find(index) == NULL)
+ {
+ m_projectionsDict.insert(index, units);
+ }
+ else
+ {
+ btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index];
+ for (int l = 0; l < 3; ++l)
+ {
+ projections.push_back(units[l]);
+ }
+ }
+ }
+ else
+ {
+ if (m_projectionsDict.find(index) == NULL)
+ {
+ btAlignedObjectArray<btVector3> projections;
+ projections.push_back(m_faceRigidConstraints[i][j].m_normal);
+ m_projectionsDict.insert(index, projections);
+ }
+ else
+ {
+ btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index];
+ projections.push_back(m_faceRigidConstraints[i][j].m_normal);
+ }
+ }
+ }
+ }
+ }
#else
- int dof = 0;
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- dof += m_softBodies[i]->m_nodes.size();
- }
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- continue;
- }
- for (int j = 0; j < m_staticConstraints[i].size(); ++j)
- {
- int index = m_staticConstraints[i][j].m_node->index;
- m_staticConstraints[i][j].m_node->m_penetration = SIMD_INFINITY;
- btAlignedObjectArray<int> indices;
- btAlignedObjectArray<btVector3> vecs1,vecs2,vecs3;
- indices.push_back(index);
- vecs1.push_back(btVector3(1,0,0));
- vecs2.push_back(btVector3(0,1,0));
- vecs3.push_back(btVector3(0,0,1));
- m_projections.push_back(btReducedVector(dof, indices, vecs1));
- m_projections.push_back(btReducedVector(dof, indices, vecs2));
- m_projections.push_back(btReducedVector(dof, indices, vecs3));
- }
-
- for (int j = 0; j < m_nodeAnchorConstraints[i].size(); ++j)
- {
- int index = m_nodeAnchorConstraints[i][j].m_anchor->m_node->index;
- m_nodeAnchorConstraints[i][j].m_anchor->m_node->m_penetration = SIMD_INFINITY;
- btAlignedObjectArray<int> indices;
- btAlignedObjectArray<btVector3> vecs1,vecs2,vecs3;
- indices.push_back(index);
- vecs1.push_back(btVector3(1,0,0));
- vecs2.push_back(btVector3(0,1,0));
- vecs3.push_back(btVector3(0,0,1));
- m_projections.push_back(btReducedVector(dof, indices, vecs1));
- m_projections.push_back(btReducedVector(dof, indices, vecs2));
- m_projections.push_back(btReducedVector(dof, indices, vecs3));
- }
- for (int j = 0; j < m_nodeRigidConstraints[i].size(); ++j)
- {
- int index = m_nodeRigidConstraints[i][j].m_node->index;
- m_nodeRigidConstraints[i][j].m_node->m_penetration = -m_nodeRigidConstraints[i][j].getContact()->m_cti.m_offset;
- btAlignedObjectArray<int> indices;
- indices.push_back(index);
- btAlignedObjectArray<btVector3> vecs1,vecs2,vecs3;
- if (m_nodeRigidConstraints[i][j].m_static)
- {
- vecs1.push_back(btVector3(1,0,0));
- vecs2.push_back(btVector3(0,1,0));
- vecs3.push_back(btVector3(0,0,1));
- m_projections.push_back(btReducedVector(dof, indices, vecs1));
- m_projections.push_back(btReducedVector(dof, indices, vecs2));
- m_projections.push_back(btReducedVector(dof, indices, vecs3));
- }
- else
- {
- vecs1.push_back(m_nodeRigidConstraints[i][j].m_normal);
- m_projections.push_back(btReducedVector(dof, indices, vecs1));
- }
- }
- for (int j = 0; j < m_faceRigidConstraints[i].size(); ++j)
- {
- const btSoftBody::Face* face = m_faceRigidConstraints[i][j].m_face;
+ int dof = 0;
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ dof += m_softBodies[i]->m_nodes.size();
+ }
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ continue;
+ }
+ for (int j = 0; j < m_staticConstraints[i].size(); ++j)
+ {
+ int index = m_staticConstraints[i][j].m_node->index;
+ m_staticConstraints[i][j].m_node->m_penetration = SIMD_INFINITY;
+ btAlignedObjectArray<int> indices;
+ btAlignedObjectArray<btVector3> vecs1, vecs2, vecs3;
+ indices.push_back(index);
+ vecs1.push_back(btVector3(1, 0, 0));
+ vecs2.push_back(btVector3(0, 1, 0));
+ vecs3.push_back(btVector3(0, 0, 1));
+ m_projections.push_back(btReducedVector(dof, indices, vecs1));
+ m_projections.push_back(btReducedVector(dof, indices, vecs2));
+ m_projections.push_back(btReducedVector(dof, indices, vecs3));
+ }
+
+ for (int j = 0; j < m_nodeAnchorConstraints[i].size(); ++j)
+ {
+ int index = m_nodeAnchorConstraints[i][j].m_anchor->m_node->index;
+ m_nodeAnchorConstraints[i][j].m_anchor->m_node->m_penetration = SIMD_INFINITY;
+ btAlignedObjectArray<int> indices;
+ btAlignedObjectArray<btVector3> vecs1, vecs2, vecs3;
+ indices.push_back(index);
+ vecs1.push_back(btVector3(1, 0, 0));
+ vecs2.push_back(btVector3(0, 1, 0));
+ vecs3.push_back(btVector3(0, 0, 1));
+ m_projections.push_back(btReducedVector(dof, indices, vecs1));
+ m_projections.push_back(btReducedVector(dof, indices, vecs2));
+ m_projections.push_back(btReducedVector(dof, indices, vecs3));
+ }
+ for (int j = 0; j < m_nodeRigidConstraints[i].size(); ++j)
+ {
+ int index = m_nodeRigidConstraints[i][j].m_node->index;
+ m_nodeRigidConstraints[i][j].m_node->m_penetration = -m_nodeRigidConstraints[i][j].getContact()->m_cti.m_offset;
+ btAlignedObjectArray<int> indices;
+ indices.push_back(index);
+ btAlignedObjectArray<btVector3> vecs1, vecs2, vecs3;
+ if (m_nodeRigidConstraints[i][j].m_static)
+ {
+ vecs1.push_back(btVector3(1, 0, 0));
+ vecs2.push_back(btVector3(0, 1, 0));
+ vecs3.push_back(btVector3(0, 0, 1));
+ m_projections.push_back(btReducedVector(dof, indices, vecs1));
+ m_projections.push_back(btReducedVector(dof, indices, vecs2));
+ m_projections.push_back(btReducedVector(dof, indices, vecs3));
+ }
+ else
+ {
+ vecs1.push_back(m_nodeRigidConstraints[i][j].m_normal);
+ m_projections.push_back(btReducedVector(dof, indices, vecs1));
+ }
+ }
+ for (int j = 0; j < m_faceRigidConstraints[i].size(); ++j)
+ {
+ const btSoftBody::Face* face = m_faceRigidConstraints[i][j].m_face;
btVector3 bary = m_faceRigidConstraints[i][j].getContact()->m_bary;
- btScalar penetration = -m_faceRigidConstraints[i][j].getContact()->m_cti.m_offset;
- for (int k = 0; k < 3; ++k)
- {
- face->m_n[k]->m_penetration = btMax(face->m_n[k]->m_penetration, penetration);
- }
+ btScalar penetration = -m_faceRigidConstraints[i][j].getContact()->m_cti.m_offset;
+ for (int k = 0; k < 3; ++k)
+ {
+ face->m_n[k]->m_penetration = btMax(face->m_n[k]->m_penetration, penetration);
+ }
if (m_faceRigidConstraints[i][j].m_static)
{
for (int l = 0; l < 3; ++l)
{
-
btReducedVector rv(dof);
for (int k = 0; k < 3; ++k)
{
rv.m_indices.push_back(face->m_n[k]->index);
- btVector3 v(0,0,0);
+ btVector3 v(0, 0, 0);
v[l] = bary[k];
rv.m_vecs.push_back(v);
- rv.sort();
+ rv.sort();
}
m_projections.push_back(rv);
}
@@ -431,121 +427,134 @@ void btDeformableContactProjection::setProjection()
{
rv.m_indices.push_back(face->m_n[k]->index);
rv.m_vecs.push_back(bary[k] * m_faceRigidConstraints[i][j].m_normal);
- rv.sort();
+ rv.sort();
}
m_projections.push_back(rv);
}
}
- }
- btModifiedGramSchmidt<btReducedVector> mgs(m_projections);
- mgs.solve();
- m_projections = mgs.m_out;
+ }
+ btModifiedGramSchmidt<btReducedVector> mgs(m_projections);
+ mgs.solve();
+ m_projections = mgs.m_out;
#endif
}
void btDeformableContactProjection::checkConstraints(const TVStack& x)
{
- for (int i = 0; i < m_lagrangeMultipliers.size(); ++i)
- {
- btVector3 d(0,0,0);
- const LagrangeMultiplier& lm = m_lagrangeMultipliers[i];
- for (int j = 0; j < lm.m_num_constraints; ++j)
- {
- for (int k = 0; k < lm.m_num_nodes; ++k)
- {
- d[j] += lm.m_weights[k] * x[lm.m_indices[k]].dot(lm.m_dirs[j]);
- }
- }
- printf("d = %f, %f, %f\n",d[0],d[1],d[2]);
- }
+ for (int i = 0; i < m_lagrangeMultipliers.size(); ++i)
+ {
+ btVector3 d(0, 0, 0);
+ const LagrangeMultiplier& lm = m_lagrangeMultipliers[i];
+ for (int j = 0; j < lm.m_num_constraints; ++j)
+ {
+ for (int k = 0; k < lm.m_num_nodes; ++k)
+ {
+ d[j] += lm.m_weights[k] * x[lm.m_indices[k]].dot(lm.m_dirs[j]);
+ }
+ }
+ // printf("d = %f, %f, %f\n", d[0], d[1], d[2]);
+ // printf("val = %f, %f, %f\n", lm.m_vals[0], lm.m_vals[1], lm.m_vals[2]);
+ }
}
void btDeformableContactProjection::setLagrangeMultiplier()
{
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- continue;
- }
- for (int j = 0; j < m_staticConstraints[i].size(); ++j)
- {
- int index = m_staticConstraints[i][j].m_node->index;
- m_staticConstraints[i][j].m_node->m_penetration = SIMD_INFINITY;
- LagrangeMultiplier lm;
- lm.m_num_nodes = 1;
- lm.m_indices[0] = index;
- lm.m_weights[0] = 1.0;
- lm.m_num_constraints = 3;
- lm.m_dirs[0] = btVector3(1,0,0);
- lm.m_dirs[1] = btVector3(0,1,0);
- lm.m_dirs[2] = btVector3(0,0,1);
- m_lagrangeMultipliers.push_back(lm);
- }
- for (int j = 0; j < m_nodeAnchorConstraints[i].size(); ++j)
- {
- int index = m_nodeAnchorConstraints[i][j].m_anchor->m_node->index;
- m_nodeAnchorConstraints[i][j].m_anchor->m_node->m_penetration = SIMD_INFINITY;
- LagrangeMultiplier lm;
- lm.m_num_nodes = 1;
- lm.m_indices[0] = index;
- lm.m_weights[0] = 1.0;
- lm.m_num_constraints = 3;
- lm.m_dirs[0] = btVector3(1,0,0);
- lm.m_dirs[1] = btVector3(0,1,0);
- lm.m_dirs[2] = btVector3(0,0,1);
- m_lagrangeMultipliers.push_back(lm);
- }
- for (int j = 0; j < m_nodeRigidConstraints[i].size(); ++j)
- {
- int index = m_nodeRigidConstraints[i][j].m_node->index;
- m_nodeRigidConstraints[i][j].m_node->m_penetration = -m_nodeRigidConstraints[i][j].getContact()->m_cti.m_offset;
- LagrangeMultiplier lm;
- lm.m_num_nodes = 1;
- lm.m_indices[0] = index;
- lm.m_weights[0] = 1.0;
- if (m_nodeRigidConstraints[i][j].m_static)
- {
- lm.m_num_constraints = 3;
- lm.m_dirs[0] = btVector3(1,0,0);
- lm.m_dirs[1] = btVector3(0,1,0);
- lm.m_dirs[2] = btVector3(0,0,1);
- }
- else
- {
- lm.m_num_constraints = 1;
- lm.m_dirs[0] = m_nodeRigidConstraints[i][j].m_normal;
- }
- m_lagrangeMultipliers.push_back(lm);
- }
- for (int j = 0; j < m_faceRigidConstraints[i].size(); ++j)
- {
- const btSoftBody::Face* face = m_faceRigidConstraints[i][j].m_face;
-
- btVector3 bary = m_faceRigidConstraints[i][j].getContact()->m_bary;
- btScalar penetration = -m_faceRigidConstraints[i][j].getContact()->m_cti.m_offset;
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ continue;
+ }
+ for (int j = 0; j < m_staticConstraints[i].size(); ++j)
+ {
+ int index = m_staticConstraints[i][j].m_node->index;
+ m_staticConstraints[i][j].m_node->m_constrained = true;
+ LagrangeMultiplier lm;
+ lm.m_num_nodes = 1;
+ lm.m_indices[0] = index;
+ lm.m_weights[0] = 1.0;
+ lm.m_num_constraints = 3;
+ lm.m_dirs[0] = btVector3(1, 0, 0);
+ lm.m_dirs[1] = btVector3(0, 1, 0);
+ lm.m_dirs[2] = btVector3(0, 0, 1);
+ m_lagrangeMultipliers.push_back(lm);
+ }
+ for (int j = 0; j < m_nodeAnchorConstraints[i].size(); ++j)
+ {
+ int index = m_nodeAnchorConstraints[i][j].m_anchor->m_node->index;
+ m_nodeAnchorConstraints[i][j].m_anchor->m_node->m_constrained = true;
+ LagrangeMultiplier lm;
+ lm.m_num_nodes = 1;
+ lm.m_indices[0] = index;
+ lm.m_weights[0] = 1.0;
+ lm.m_num_constraints = 3;
+ lm.m_dirs[0] = btVector3(1, 0, 0);
+ lm.m_dirs[1] = btVector3(0, 1, 0);
+ lm.m_dirs[2] = btVector3(0, 0, 1);
+ m_lagrangeMultipliers.push_back(lm);
+ }
+
+ for (int j = 0; j < m_nodeRigidConstraints[i].size(); ++j)
+ {
+ if (!m_nodeRigidConstraints[i][j].m_binding)
+ {
+ continue;
+ }
+ int index = m_nodeRigidConstraints[i][j].m_node->index;
+ m_nodeRigidConstraints[i][j].m_node->m_constrained = true;
+ LagrangeMultiplier lm;
+ lm.m_num_nodes = 1;
+ lm.m_indices[0] = index;
+ lm.m_weights[0] = 1.0;
+ if (m_nodeRigidConstraints[i][j].m_static)
+ {
+ lm.m_num_constraints = 3;
+ lm.m_dirs[0] = btVector3(1, 0, 0);
+ lm.m_dirs[1] = btVector3(0, 1, 0);
+ lm.m_dirs[2] = btVector3(0, 0, 1);
+ }
+ else
+ {
+ lm.m_num_constraints = 1;
+ lm.m_dirs[0] = m_nodeRigidConstraints[i][j].m_normal;
+ }
+ m_lagrangeMultipliers.push_back(lm);
+ }
+
+ for (int j = 0; j < m_faceRigidConstraints[i].size(); ++j)
+ {
+ if (!m_faceRigidConstraints[i][j].m_binding)
+ {
+ continue;
+ }
+ btSoftBody::Face* face = m_faceRigidConstraints[i][j].m_face;
+
+ btVector3 bary = m_faceRigidConstraints[i][j].getContact()->m_bary;
LagrangeMultiplier lm;
lm.m_num_nodes = 3;
- for (int k = 0; k<3; ++k)
+
+ for (int k = 0; k < 3; ++k)
{
- face->m_n[k]->m_penetration = btMax(face->m_n[k]->m_penetration, penetration);
+ face->m_n[k]->m_constrained = true;
lm.m_indices[k] = face->m_n[k]->index;
lm.m_weights[k] = bary[k];
}
- if (m_faceRigidConstraints[i][j].m_static)
- {
+ if (m_faceRigidConstraints[i][j].m_static)
+ {
+ face->m_pcontact[3] = 1;
lm.m_num_constraints = 3;
- lm.m_dirs[0] = btVector3(1,0,0);
- lm.m_dirs[1] = btVector3(0,1,0);
- lm.m_dirs[2] = btVector3(0,0,1);
+ lm.m_dirs[0] = btVector3(1, 0, 0);
+ lm.m_dirs[1] = btVector3(0, 1, 0);
+ lm.m_dirs[2] = btVector3(0, 0, 1);
}
else
{
+ face->m_pcontact[3] = 0;
lm.m_num_constraints = 1;
lm.m_dirs[0] = m_faceRigidConstraints[i][j].m_normal;
}
- m_lagrangeMultipliers.push_back(lm);
+ m_lagrangeMultipliers.push_back(lm);
}
}
}
@@ -562,7 +571,7 @@ void btDeformableContactProjection::applyDynamicFriction(TVStack& f)
if (node->m_im != 0)
{
int index = node->index;
- f[index] += constraint.getDv(node)* (1./node->m_im);
+ f[index] += constraint.getDv(node) * (1. / node->m_im);
}
}
for (int j = 0; j < m_faceRigidConstraints[i].size(); ++j)
@@ -575,7 +584,7 @@ void btDeformableContactProjection::applyDynamicFriction(TVStack& f)
if (node->m_im != 0)
{
int index = node->index;
- f[index] += constraint.getDv(node)* (1./node->m_im);
+ f[index] += constraint.getDv(node) * (1. / node->m_im);
}
}
}
@@ -587,7 +596,7 @@ void btDeformableContactProjection::applyDynamicFriction(TVStack& f)
if (node->m_im != 0)
{
int index = node->index;
- f[index] += constraint.getDv(node)* (1./node->m_im);
+ f[index] += constraint.getDv(node) * (1. / node->m_im);
}
for (int k = 0; k < 3; ++k)
{
@@ -595,7 +604,7 @@ void btDeformableContactProjection::applyDynamicFriction(TVStack& f)
if (node->m_im != 0)
{
int index = node->index;
- f[index] += constraint.getDv(node)* (1./node->m_im);
+ f[index] += constraint.getDv(node) * (1. / node->m_im);
}
}
}
@@ -612,9 +621,8 @@ void btDeformableContactProjection::reinitialize(bool nodeUpdated)
m_nodeRigidConstraints.resize(N);
m_faceRigidConstraints.resize(N);
m_deformableConstraints.resize(N);
-
}
- for (int i = 0 ; i < N; ++i)
+ for (int i = 0; i < N; ++i)
{
m_staticConstraints[i].clear();
m_nodeAnchorConstraints[i].clear();
@@ -623,12 +631,9 @@ void btDeformableContactProjection::reinitialize(bool nodeUpdated)
m_deformableConstraints[i].clear();
}
#ifndef USE_MGS
- m_projectionsDict.clear();
+ m_projectionsDict.clear();
#else
- m_projections.clear();
+ m_projections.clear();
#endif
- m_lagrangeMultipliers.clear();
+ m_lagrangeMultipliers.clear();
}
-
-
-
diff --git a/thirdparty/bullet/BulletSoftBody/btDeformableContactProjection.h b/thirdparty/bullet/BulletSoftBody/btDeformableContactProjection.h
index 8d7e94d4fb..4964eaf990 100644
--- a/thirdparty/bullet/BulletSoftBody/btDeformableContactProjection.h
+++ b/thirdparty/bullet/BulletSoftBody/btDeformableContactProjection.h
@@ -27,31 +27,30 @@
struct LagrangeMultiplier
{
- int m_num_constraints; // Number of constraints
- int m_num_nodes; // Number of nodes in these constraints
- btScalar m_weights[3]; // weights of the nodes involved, same size as m_num_nodes
- btVector3 m_dirs[3]; // Constraint directions, same size of m_num_constraints;
- int m_indices[3]; // indices of the nodes involved, same size as m_num_nodes;
+ int m_num_constraints; // Number of constraints
+ int m_num_nodes; // Number of nodes in these constraints
+ btScalar m_weights[3]; // weights of the nodes involved, same size as m_num_nodes
+ btVector3 m_dirs[3]; // Constraint directions, same size of m_num_constraints;
+ int m_indices[3]; // indices of the nodes involved, same size as m_num_nodes;
};
-
class btDeformableContactProjection
{
public:
- typedef btAlignedObjectArray<btVector3> TVStack;
- btAlignedObjectArray<btSoftBody *>& m_softBodies;
-
- // all constraints involving face
- btAlignedObjectArray<btDeformableContactConstraint*> m_allFaceConstraints;
+ typedef btAlignedObjectArray<btVector3> TVStack;
+ btAlignedObjectArray<btSoftBody*>& m_softBodies;
+
+ // all constraints involving face
+ btAlignedObjectArray<btDeformableContactConstraint*> m_allFaceConstraints;
#ifndef USE_MGS
- // map from node index to projection directions
- btHashMap<btHashInt, btAlignedObjectArray<btVector3> > m_projectionsDict;
+ // map from node index to projection directions
+ btHashMap<btHashInt, btAlignedObjectArray<btVector3> > m_projectionsDict;
#else
- btAlignedObjectArray<btReducedVector> m_projections;
+ btAlignedObjectArray<btReducedVector> m_projections;
#endif
-
- btAlignedObjectArray<LagrangeMultiplier> m_lagrangeMultipliers;
-
+
+ btAlignedObjectArray<LagrangeMultiplier> m_lagrangeMultipliers;
+
// map from node index to static constraint
btAlignedObjectArray<btAlignedObjectArray<btDeformableStaticConstraint> > m_staticConstraints;
// map from node index to node rigid constraint
@@ -62,39 +61,39 @@ public:
btAlignedObjectArray<btAlignedObjectArray<btDeformableFaceNodeContactConstraint> > m_deformableConstraints;
// map from node index to node anchor constraint
btAlignedObjectArray<btAlignedObjectArray<btDeformableNodeAnchorConstraint> > m_nodeAnchorConstraints;
-
- bool m_useStrainLimiting;
-
- btDeformableContactProjection(btAlignedObjectArray<btSoftBody *>& softBodies)
- : m_softBodies(softBodies)
- {
- }
-
- virtual ~btDeformableContactProjection()
- {
- }
-
- // apply the constraints to the rhs of the linear solve
- virtual void project(TVStack& x);
-
- // add friction force to the rhs of the linear solve
- virtual void applyDynamicFriction(TVStack& f);
-
- // update and solve the constraints
- virtual btScalar update(btCollisionObject** deformableBodies,int numDeformableBodies, const btContactSolverInfo& infoGlobal);
-
- // Add constraints to m_constraints. In addition, the constraints that each vertex own are recorded in m_constraintsDict.
- virtual void setConstraints(const btContactSolverInfo& infoGlobal);
-
- // Set up projections for each vertex by adding the projection direction to
- virtual void setProjection();
-
- virtual void reinitialize(bool nodeUpdated);
-
- virtual void splitImpulseSetup(const btContactSolverInfo& infoGlobal);
-
- virtual void setLagrangeMultiplier();
-
- void checkConstraints(const TVStack& x);
+
+ bool m_useStrainLimiting;
+
+ btDeformableContactProjection(btAlignedObjectArray<btSoftBody*>& softBodies)
+ : m_softBodies(softBodies)
+ {
+ }
+
+ virtual ~btDeformableContactProjection()
+ {
+ }
+
+ // apply the constraints to the rhs of the linear solve
+ virtual void project(TVStack& x);
+
+ // add friction force to the rhs of the linear solve
+ virtual void applyDynamicFriction(TVStack& f);
+
+ // update and solve the constraints
+ virtual btScalar update(btCollisionObject** deformableBodies, int numDeformableBodies, const btContactSolverInfo& infoGlobal);
+
+ // Add constraints to m_constraints. In addition, the constraints that each vertex own are recorded in m_constraintsDict.
+ virtual void setConstraints(const btContactSolverInfo& infoGlobal);
+
+ // Set up projections for each vertex by adding the projection direction to
+ virtual void setProjection();
+
+ virtual void reinitialize(bool nodeUpdated);
+
+ btScalar solveSplitImpulse(btCollisionObject** deformableBodies, int numDeformableBodies, const btContactSolverInfo& infoGlobal);
+
+ virtual void setLagrangeMultiplier();
+
+ void checkConstraints(const TVStack& x);
};
#endif /* btDeformableContactProjection_h */
diff --git a/thirdparty/bullet/BulletSoftBody/btDeformableCorotatedForce.h b/thirdparty/bullet/BulletSoftBody/btDeformableCorotatedForce.h
index 2d042df729..dfd85523bc 100644
--- a/thirdparty/bullet/BulletSoftBody/btDeformableCorotatedForce.h
+++ b/thirdparty/bullet/BulletSoftBody/btDeformableCorotatedForce.h
@@ -21,107 +21,104 @@
static inline int PolarDecomposition(const btMatrix3x3& m, btMatrix3x3& q, btMatrix3x3& s)
{
- static const btPolarDecomposition polar;
- return polar.decompose(m, q, s);
+ static const btPolarDecomposition polar;
+ return polar.decompose(m, q, s);
}
class btDeformableCorotatedForce : public btDeformableLagrangianForce
{
public:
- typedef btAlignedObjectArray<btVector3> TVStack;
- btScalar m_mu, m_lambda;
- btDeformableCorotatedForce(): m_mu(1), m_lambda(1)
- {
-
- }
-
- btDeformableCorotatedForce(btScalar mu, btScalar lambda): m_mu(mu), m_lambda(lambda)
- {
- }
-
- virtual void addScaledForces(btScalar scale, TVStack& force)
- {
- addScaledElasticForce(scale, force);
- }
-
- virtual void addScaledExplicitForce(btScalar scale, TVStack& force)
- {
- addScaledElasticForce(scale, force);
- }
-
- virtual void addScaledDampingForce(btScalar scale, TVStack& force)
- {
- }
-
- virtual void addScaledElasticForce(btScalar scale, TVStack& force)
- {
- int numNodes = getNumNodes();
- btAssert(numNodes <= force.size());
- btVector3 grad_N_hat_1st_col = btVector3(-1,-1,-1);
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- for (int j = 0; j < psb->m_tetras.size(); ++j)
- {
- btSoftBody::Tetra& tetra = psb->m_tetras[j];
- btMatrix3x3 P;
- firstPiola(tetra.m_F,P);
- btVector3 force_on_node0 = P * (tetra.m_Dm_inverse.transpose()*grad_N_hat_1st_col);
- btMatrix3x3 force_on_node123 = P * tetra.m_Dm_inverse.transpose();
-
- btSoftBody::Node* node0 = tetra.m_n[0];
- btSoftBody::Node* node1 = tetra.m_n[1];
- btSoftBody::Node* node2 = tetra.m_n[2];
- btSoftBody::Node* node3 = tetra.m_n[3];
- size_t id0 = node0->index;
- size_t id1 = node1->index;
- size_t id2 = node2->index;
- size_t id3 = node3->index;
-
- // elastic force
- // explicit elastic force
- btScalar scale1 = scale * tetra.m_element_measure;
- force[id0] -= scale1 * force_on_node0;
- force[id1] -= scale1 * force_on_node123.getColumn(0);
- force[id2] -= scale1 * force_on_node123.getColumn(1);
- force[id3] -= scale1 * force_on_node123.getColumn(2);
- }
- }
- }
-
- void firstPiola(const btMatrix3x3& F, btMatrix3x3& P)
- {
- // btMatrix3x3 JFinvT = F.adjoint();
- btScalar J = F.determinant();
- P = F.adjoint().transpose() * (m_lambda * (J-1));
- if (m_mu > SIMD_EPSILON)
- {
- btMatrix3x3 R,S;
- if (J < 1024 * SIMD_EPSILON)
- R.setIdentity();
- else
- PolarDecomposition(F, R, S); // this QR is not robust, consider using implicit shift svd
- /*https://fuchuyuan.github.io/research/svd/paper.pdf*/
- P += (F-R) * 2 * m_mu;
- }
- }
-
- virtual void addScaledElasticForceDifferential(btScalar scale, const TVStack& dx, TVStack& df)
- {
- }
-
- virtual void addScaledDampingForceDifferential(btScalar scale, const TVStack& dv, TVStack& df)
- {
- }
-
- virtual void buildDampingForceDifferentialDiagonal(btScalar scale, TVStack& diagA){}
-
- virtual btDeformableLagrangianForceType getForceType()
- {
- return BT_COROTATED_FORCE;
- }
-
-};
+ typedef btAlignedObjectArray<btVector3> TVStack;
+ btScalar m_mu, m_lambda;
+ btDeformableCorotatedForce() : m_mu(1), m_lambda(1)
+ {
+ }
+
+ btDeformableCorotatedForce(btScalar mu, btScalar lambda) : m_mu(mu), m_lambda(lambda)
+ {
+ }
+
+ virtual void addScaledForces(btScalar scale, TVStack& force)
+ {
+ addScaledElasticForce(scale, force);
+ }
+
+ virtual void addScaledExplicitForce(btScalar scale, TVStack& force)
+ {
+ addScaledElasticForce(scale, force);
+ }
+
+ virtual void addScaledDampingForce(btScalar scale, TVStack& force)
+ {
+ }
+
+ virtual void addScaledElasticForce(btScalar scale, TVStack& force)
+ {
+ int numNodes = getNumNodes();
+ btAssert(numNodes <= force.size());
+ btVector3 grad_N_hat_1st_col = btVector3(-1, -1, -1);
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_tetras.size(); ++j)
+ {
+ btSoftBody::Tetra& tetra = psb->m_tetras[j];
+ btMatrix3x3 P;
+ firstPiola(tetra.m_F, P);
+ btVector3 force_on_node0 = P * (tetra.m_Dm_inverse.transpose() * grad_N_hat_1st_col);
+ btMatrix3x3 force_on_node123 = P * tetra.m_Dm_inverse.transpose();
+
+ btSoftBody::Node* node0 = tetra.m_n[0];
+ btSoftBody::Node* node1 = tetra.m_n[1];
+ btSoftBody::Node* node2 = tetra.m_n[2];
+ btSoftBody::Node* node3 = tetra.m_n[3];
+ size_t id0 = node0->index;
+ size_t id1 = node1->index;
+ size_t id2 = node2->index;
+ size_t id3 = node3->index;
+ // elastic force
+ // explicit elastic force
+ btScalar scale1 = scale * tetra.m_element_measure;
+ force[id0] -= scale1 * force_on_node0;
+ force[id1] -= scale1 * force_on_node123.getColumn(0);
+ force[id2] -= scale1 * force_on_node123.getColumn(1);
+ force[id3] -= scale1 * force_on_node123.getColumn(2);
+ }
+ }
+ }
+
+ void firstPiola(const btMatrix3x3& F, btMatrix3x3& P)
+ {
+ // btMatrix3x3 JFinvT = F.adjoint();
+ btScalar J = F.determinant();
+ P = F.adjoint().transpose() * (m_lambda * (J - 1));
+ if (m_mu > SIMD_EPSILON)
+ {
+ btMatrix3x3 R, S;
+ if (J < 1024 * SIMD_EPSILON)
+ R.setIdentity();
+ else
+ PolarDecomposition(F, R, S); // this QR is not robust, consider using implicit shift svd
+ /*https://fuchuyuan.github.io/research/svd/paper.pdf*/
+ P += (F - R) * 2 * m_mu;
+ }
+ }
+
+ virtual void addScaledElasticForceDifferential(btScalar scale, const TVStack& dx, TVStack& df)
+ {
+ }
+
+ virtual void addScaledDampingForceDifferential(btScalar scale, const TVStack& dv, TVStack& df)
+ {
+ }
+
+ virtual void buildDampingForceDifferentialDiagonal(btScalar scale, TVStack& diagA) {}
+
+ virtual btDeformableLagrangianForceType getForceType()
+ {
+ return BT_COROTATED_FORCE;
+ }
+};
#endif /* btCorotated_h */
diff --git a/thirdparty/bullet/BulletSoftBody/btDeformableGravityForce.h b/thirdparty/bullet/BulletSoftBody/btDeformableGravityForce.h
index 13ee3eacb6..d91867f457 100644
--- a/thirdparty/bullet/BulletSoftBody/btDeformableGravityForce.h
+++ b/thirdparty/bullet/BulletSoftBody/btDeformableGravityForce.h
@@ -21,87 +21,85 @@
class btDeformableGravityForce : public btDeformableLagrangianForce
{
public:
- typedef btAlignedObjectArray<btVector3> TVStack;
- btVector3 m_gravity;
-
- btDeformableGravityForce(const btVector3& g) : m_gravity(g)
- {
- }
-
- virtual void addScaledForces(btScalar scale, TVStack& force)
- {
- addScaledGravityForce(scale, force);
- }
-
- virtual void addScaledExplicitForce(btScalar scale, TVStack& force)
- {
- addScaledGravityForce(scale, force);
- }
-
- virtual void addScaledDampingForce(btScalar scale, TVStack& force)
- {
- }
-
- virtual void addScaledElasticForceDifferential(btScalar scale, const TVStack& dx, TVStack& df)
- {
- }
-
- virtual void addScaledDampingForceDifferential(btScalar scale, const TVStack& dv, TVStack& df)
- {
- }
-
- virtual void buildDampingForceDifferentialDiagonal(btScalar scale, TVStack& diagA){}
-
- virtual void addScaledGravityForce(btScalar scale, TVStack& force)
- {
- int numNodes = getNumNodes();
- btAssert(numNodes <= force.size());
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- continue;
- }
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- btSoftBody::Node& n = psb->m_nodes[j];
- size_t id = n.index;
- btScalar mass = (n.m_im == 0) ? 0 : 1. / n.m_im;
- btVector3 scaled_force = scale * m_gravity * mass;
- force[id] += scaled_force;
- }
- }
- }
-
- virtual btDeformableLagrangianForceType getForceType()
- {
- return BT_GRAVITY_FORCE;
- }
+ typedef btAlignedObjectArray<btVector3> TVStack;
+ btVector3 m_gravity;
- // the gravitational potential energy
- virtual double totalEnergy(btScalar dt)
- {
- double e = 0;
- for (int i = 0; i<m_softBodies.size();++i)
- {
- btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- continue;
- }
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- const btSoftBody::Node& node = psb->m_nodes[j];
- if (node.m_im > 0)
- {
- e -= m_gravity.dot(node.m_q)/node.m_im;
- }
- }
- }
- return e;
- }
-
-
+ btDeformableGravityForce(const btVector3& g) : m_gravity(g)
+ {
+ }
+
+ virtual void addScaledForces(btScalar scale, TVStack& force)
+ {
+ addScaledGravityForce(scale, force);
+ }
+
+ virtual void addScaledExplicitForce(btScalar scale, TVStack& force)
+ {
+ addScaledGravityForce(scale, force);
+ }
+
+ virtual void addScaledDampingForce(btScalar scale, TVStack& force)
+ {
+ }
+
+ virtual void addScaledElasticForceDifferential(btScalar scale, const TVStack& dx, TVStack& df)
+ {
+ }
+
+ virtual void addScaledDampingForceDifferential(btScalar scale, const TVStack& dv, TVStack& df)
+ {
+ }
+
+ virtual void buildDampingForceDifferentialDiagonal(btScalar scale, TVStack& diagA) {}
+
+ virtual void addScaledGravityForce(btScalar scale, TVStack& force)
+ {
+ int numNodes = getNumNodes();
+ btAssert(numNodes <= force.size());
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ continue;
+ }
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ btSoftBody::Node& n = psb->m_nodes[j];
+ size_t id = n.index;
+ btScalar mass = (n.m_im == 0) ? 0 : 1. / n.m_im;
+ btVector3 scaled_force = scale * m_gravity * mass * m_softBodies[i]->m_gravityFactor;
+ force[id] += scaled_force;
+ }
+ }
+ }
+
+ virtual btDeformableLagrangianForceType getForceType()
+ {
+ return BT_GRAVITY_FORCE;
+ }
+
+ // the gravitational potential energy
+ virtual double totalEnergy(btScalar dt)
+ {
+ double e = 0;
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ continue;
+ }
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ const btSoftBody::Node& node = psb->m_nodes[j];
+ if (node.m_im > 0)
+ {
+ e -= m_gravity.dot(node.m_q) / node.m_im;
+ }
+ }
+ }
+ return e;
+ }
};
#endif /* BT_DEFORMABLE_GRAVITY_FORCE_H */
diff --git a/thirdparty/bullet/BulletSoftBody/btDeformableLagrangianForce.h b/thirdparty/bullet/BulletSoftBody/btDeformableLagrangianForce.h
index 0b6447442d..d58d825d1c 100644
--- a/thirdparty/bullet/BulletSoftBody/btDeformableLagrangianForce.h
+++ b/thirdparty/bullet/BulletSoftBody/btDeformableLagrangianForce.h
@@ -22,352 +22,351 @@
enum btDeformableLagrangianForceType
{
- BT_GRAVITY_FORCE = 1,
- BT_MASSSPRING_FORCE = 2,
- BT_COROTATED_FORCE = 3,
- BT_NEOHOOKEAN_FORCE = 4,
- BT_LINEAR_ELASTICITY_FORCE = 5,
- BT_MOUSE_PICKING_FORCE = 6
+ BT_GRAVITY_FORCE = 1,
+ BT_MASSSPRING_FORCE = 2,
+ BT_COROTATED_FORCE = 3,
+ BT_NEOHOOKEAN_FORCE = 4,
+ BT_LINEAR_ELASTICITY_FORCE = 5,
+ BT_MOUSE_PICKING_FORCE = 6
};
static inline double randomDouble(double low, double high)
{
- return low + static_cast<double>(rand()) / RAND_MAX * (high - low);
+ return low + static_cast<double>(rand()) / RAND_MAX * (high - low);
}
class btDeformableLagrangianForce
{
public:
- typedef btAlignedObjectArray<btVector3> TVStack;
- btAlignedObjectArray<btSoftBody *> m_softBodies;
- const btAlignedObjectArray<btSoftBody::Node*>* m_nodes;
-
- btDeformableLagrangianForce()
- {
- }
-
- virtual ~btDeformableLagrangianForce(){}
-
- // add all forces
- virtual void addScaledForces(btScalar scale, TVStack& force) = 0;
-
- // add damping df
- virtual void addScaledDampingForceDifferential(btScalar scale, const TVStack& dv, TVStack& df) = 0;
-
- // build diagonal of A matrix
- virtual void buildDampingForceDifferentialDiagonal(btScalar scale, TVStack& diagA) = 0;
-
- // add elastic df
- virtual void addScaledElasticForceDifferential(btScalar scale, const TVStack& dx, TVStack& df) = 0;
-
- // add all forces that are explicit in explicit solve
- virtual void addScaledExplicitForce(btScalar scale, TVStack& force) = 0;
-
- // add all damping forces
- virtual void addScaledDampingForce(btScalar scale, TVStack& force) = 0;
-
- virtual btDeformableLagrangianForceType getForceType() = 0;
-
- virtual void reinitialize(bool nodeUpdated)
- {
- }
-
- // get number of nodes that have the force
- virtual int getNumNodes()
- {
- int numNodes = 0;
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- numNodes += m_softBodies[i]->m_nodes.size();
- }
- return numNodes;
- }
-
- // add a soft body to be affected by the particular lagrangian force
- virtual void addSoftBody(btSoftBody* psb)
- {
- m_softBodies.push_back(psb);
- }
-
- virtual void removeSoftBody(btSoftBody* psb)
- {
- m_softBodies.remove(psb);
- }
-
- virtual void setIndices(const btAlignedObjectArray<btSoftBody::Node*>* nodes)
- {
- m_nodes = nodes;
- }
-
- // Calculate the incremental deformable generated from the input dx
- virtual btMatrix3x3 Ds(int id0, int id1, int id2, int id3, const TVStack& dx)
- {
- btVector3 c1 = dx[id1] - dx[id0];
- btVector3 c2 = dx[id2] - dx[id0];
- btVector3 c3 = dx[id3] - dx[id0];
- return btMatrix3x3(c1,c2,c3).transpose();
- }
-
- // Calculate the incremental deformable generated from the current velocity
- virtual btMatrix3x3 DsFromVelocity(const btSoftBody::Node* n0, const btSoftBody::Node* n1, const btSoftBody::Node* n2, const btSoftBody::Node* n3)
- {
- btVector3 c1 = n1->m_v - n0->m_v;
- btVector3 c2 = n2->m_v - n0->m_v;
- btVector3 c3 = n3->m_v - n0->m_v;
- return btMatrix3x3(c1,c2,c3).transpose();
- }
-
- // test for addScaledElasticForce function
- virtual void testDerivative()
- {
- for (int i = 0; i<m_softBodies.size();++i)
- {
- btSoftBody* psb = m_softBodies[i];
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- psb->m_nodes[j].m_q += btVector3(randomDouble(-.1, .1), randomDouble(-.1, .1), randomDouble(-.1, .1));
- }
- psb->updateDeformation();
- }
-
- TVStack dx;
- dx.resize(getNumNodes());
- TVStack dphi_dx;
- dphi_dx.resize(dx.size());
- for (int i =0; i < dphi_dx.size();++i)
- {
- dphi_dx[i].setZero();
- }
- addScaledForces(-1, dphi_dx);
-
- // write down the current position
- TVStack x;
- x.resize(dx.size());
- int counter = 0;
- for (int i = 0; i<m_softBodies.size();++i)
- {
- btSoftBody* psb = m_softBodies[i];
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- x[counter] = psb->m_nodes[j].m_q;
- counter++;
- }
- }
- counter = 0;
-
- // populate dx with random vectors
- for (int i = 0; i < dx.size(); ++i)
- {
- dx[i].setX(randomDouble(-1, 1));
- dx[i].setY(randomDouble(-1, 1));
- dx[i].setZ(randomDouble(-1, 1));
- }
-
- btAlignedObjectArray<double> errors;
- for (int it = 0; it < 10; ++it)
- {
- for (int i = 0; i < dx.size(); ++i)
- {
- dx[i] *= 0.5;
- }
-
- // get dphi/dx * dx
- double dphi = 0;
- for (int i = 0; i < dx.size(); ++i)
- {
- dphi += dphi_dx[i].dot(dx[i]);
- }
-
-
- for (int i = 0; i<m_softBodies.size();++i)
- {
- btSoftBody* psb = m_softBodies[i];
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- psb->m_nodes[j].m_q = x[counter] + dx[counter];
- counter++;
- }
- psb->updateDeformation();
- }
- counter = 0;
- double f1 = totalElasticEnergy(0);
-
- for (int i = 0; i<m_softBodies.size();++i)
- {
- btSoftBody* psb = m_softBodies[i];
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- psb->m_nodes[j].m_q = x[counter] - dx[counter];
- counter++;
- }
- psb->updateDeformation();
- }
- counter = 0;
-
- double f2 = totalElasticEnergy(0);
-
- //restore m_q
- for (int i = 0; i<m_softBodies.size();++i)
- {
- btSoftBody* psb = m_softBodies[i];
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- psb->m_nodes[j].m_q = x[counter];
- counter++;
- }
- psb->updateDeformation();
- }
- counter = 0;
- double error = f1-f2-2*dphi;
- errors.push_back(error);
- std::cout << "Iteration = " << it <<", f1 = " << f1 << ", f2 = " << f2 << ", error = " << error << std::endl;
- }
- for (int i = 1; i < errors.size(); ++i)
- {
- std::cout << "Iteration = " << i << ", ratio = " << errors[i-1]/errors[i] << std::endl;
- }
- }
-
- // test for addScaledElasticForce function
- virtual void testHessian()
- {
- for (int i = 0; i<m_softBodies.size();++i)
- {
- btSoftBody* psb = m_softBodies[i];
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- psb->m_nodes[j].m_q += btVector3(randomDouble(-.1, .1), randomDouble(-.1, .1), randomDouble(-.1, .1));
- }
- psb->updateDeformation();
- }
-
-
- TVStack dx;
- dx.resize(getNumNodes());
- TVStack df;
- df.resize(dx.size());
- TVStack f1;
- f1.resize(dx.size());
- TVStack f2;
- f2.resize(dx.size());
-
-
- // write down the current position
- TVStack x;
- x.resize(dx.size());
- int counter = 0;
- for (int i = 0; i<m_softBodies.size();++i)
- {
- btSoftBody* psb = m_softBodies[i];
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- x[counter] = psb->m_nodes[j].m_q;
- counter++;
- }
- }
- counter = 0;
-
- // populate dx with random vectors
- for (int i = 0; i < dx.size(); ++i)
- {
- dx[i].setX(randomDouble(-1, 1));
- dx[i].setY(randomDouble(-1, 1));
- dx[i].setZ(randomDouble(-1, 1));
- }
-
- btAlignedObjectArray<double> errors;
- for (int it = 0; it < 10; ++it)
- {
- for (int i = 0; i < dx.size(); ++i)
- {
- dx[i] *= 0.5;
- }
-
- // get df
- for (int i =0; i < df.size();++i)
- {
- df[i].setZero();
- f1[i].setZero();
- f2[i].setZero();
- }
-
- //set df
- addScaledElasticForceDifferential(-1, dx, df);
-
- for (int i = 0; i<m_softBodies.size();++i)
- {
- btSoftBody* psb = m_softBodies[i];
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- psb->m_nodes[j].m_q = x[counter] + dx[counter];
- counter++;
- }
- psb->updateDeformation();
- }
- counter = 0;
-
- //set f1
- addScaledForces(-1, f1);
-
- for (int i = 0; i<m_softBodies.size();++i)
- {
- btSoftBody* psb = m_softBodies[i];
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- psb->m_nodes[j].m_q = x[counter] - dx[counter];
- counter++;
- }
- psb->updateDeformation();
- }
- counter = 0;
-
- //set f2
- addScaledForces(-1, f2);
-
- //restore m_q
- for (int i = 0; i<m_softBodies.size();++i)
- {
- btSoftBody* psb = m_softBodies[i];
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- psb->m_nodes[j].m_q = x[counter];
- counter++;
- }
- psb->updateDeformation();
- }
- counter = 0;
- double error = 0;
- for (int i = 0; i < df.size();++i)
- {
- btVector3 error_vector = f1[i]-f2[i]-2*df[i];
- error += error_vector.length2();
- }
- error = btSqrt(error);
- errors.push_back(error);
- std::cout << "Iteration = " << it << ", error = " << error << std::endl;
- }
- for (int i = 1; i < errors.size(); ++i)
- {
- std::cout << "Iteration = " << i << ", ratio = " << errors[i-1]/errors[i] << std::endl;
- }
- }
-
- //
- virtual double totalElasticEnergy(btScalar dt)
- {
- return 0;
- }
-
- //
- virtual double totalDampingEnergy(btScalar dt)
- {
- return 0;
- }
-
- // total Energy takes dt as input because certain energies depend on dt
- virtual double totalEnergy(btScalar dt)
- {
- return totalElasticEnergy(dt) + totalDampingEnergy(dt);
- }
+ typedef btAlignedObjectArray<btVector3> TVStack;
+ btAlignedObjectArray<btSoftBody*> m_softBodies;
+ const btAlignedObjectArray<btSoftBody::Node*>* m_nodes;
+
+ btDeformableLagrangianForce()
+ {
+ }
+
+ virtual ~btDeformableLagrangianForce() {}
+
+ // add all forces
+ virtual void addScaledForces(btScalar scale, TVStack& force) = 0;
+
+ // add damping df
+ virtual void addScaledDampingForceDifferential(btScalar scale, const TVStack& dv, TVStack& df) = 0;
+
+ // build diagonal of A matrix
+ virtual void buildDampingForceDifferentialDiagonal(btScalar scale, TVStack& diagA) = 0;
+
+ // add elastic df
+ virtual void addScaledElasticForceDifferential(btScalar scale, const TVStack& dx, TVStack& df) = 0;
+
+ // add all forces that are explicit in explicit solve
+ virtual void addScaledExplicitForce(btScalar scale, TVStack& force) = 0;
+
+ // add all damping forces
+ virtual void addScaledDampingForce(btScalar scale, TVStack& force) = 0;
+
+ virtual void addScaledHessian(btScalar scale) {}
+
+ virtual btDeformableLagrangianForceType getForceType() = 0;
+
+ virtual void reinitialize(bool nodeUpdated)
+ {
+ }
+
+ // get number of nodes that have the force
+ virtual int getNumNodes()
+ {
+ int numNodes = 0;
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ numNodes += m_softBodies[i]->m_nodes.size();
+ }
+ return numNodes;
+ }
+
+ // add a soft body to be affected by the particular lagrangian force
+ virtual void addSoftBody(btSoftBody* psb)
+ {
+ m_softBodies.push_back(psb);
+ }
+
+ virtual void removeSoftBody(btSoftBody* psb)
+ {
+ m_softBodies.remove(psb);
+ }
+
+ virtual void setIndices(const btAlignedObjectArray<btSoftBody::Node*>* nodes)
+ {
+ m_nodes = nodes;
+ }
+
+ // Calculate the incremental deformable generated from the input dx
+ virtual btMatrix3x3 Ds(int id0, int id1, int id2, int id3, const TVStack& dx)
+ {
+ btVector3 c1 = dx[id1] - dx[id0];
+ btVector3 c2 = dx[id2] - dx[id0];
+ btVector3 c3 = dx[id3] - dx[id0];
+ return btMatrix3x3(c1, c2, c3).transpose();
+ }
+
+ // Calculate the incremental deformable generated from the current velocity
+ virtual btMatrix3x3 DsFromVelocity(const btSoftBody::Node* n0, const btSoftBody::Node* n1, const btSoftBody::Node* n2, const btSoftBody::Node* n3)
+ {
+ btVector3 c1 = n1->m_v - n0->m_v;
+ btVector3 c2 = n2->m_v - n0->m_v;
+ btVector3 c3 = n3->m_v - n0->m_v;
+ return btMatrix3x3(c1, c2, c3).transpose();
+ }
+
+ // test for addScaledElasticForce function
+ virtual void testDerivative()
+ {
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ psb->m_nodes[j].m_q += btVector3(randomDouble(-.1, .1), randomDouble(-.1, .1), randomDouble(-.1, .1));
+ }
+ psb->updateDeformation();
+ }
+
+ TVStack dx;
+ dx.resize(getNumNodes());
+ TVStack dphi_dx;
+ dphi_dx.resize(dx.size());
+ for (int i = 0; i < dphi_dx.size(); ++i)
+ {
+ dphi_dx[i].setZero();
+ }
+ addScaledForces(-1, dphi_dx);
+
+ // write down the current position
+ TVStack x;
+ x.resize(dx.size());
+ int counter = 0;
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ x[counter] = psb->m_nodes[j].m_q;
+ counter++;
+ }
+ }
+ counter = 0;
+
+ // populate dx with random vectors
+ for (int i = 0; i < dx.size(); ++i)
+ {
+ dx[i].setX(randomDouble(-1, 1));
+ dx[i].setY(randomDouble(-1, 1));
+ dx[i].setZ(randomDouble(-1, 1));
+ }
+
+ btAlignedObjectArray<double> errors;
+ for (int it = 0; it < 10; ++it)
+ {
+ for (int i = 0; i < dx.size(); ++i)
+ {
+ dx[i] *= 0.5;
+ }
+
+ // get dphi/dx * dx
+ double dphi = 0;
+ for (int i = 0; i < dx.size(); ++i)
+ {
+ dphi += dphi_dx[i].dot(dx[i]);
+ }
+
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ psb->m_nodes[j].m_q = x[counter] + dx[counter];
+ counter++;
+ }
+ psb->updateDeformation();
+ }
+ counter = 0;
+ double f1 = totalElasticEnergy(0);
+
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ psb->m_nodes[j].m_q = x[counter] - dx[counter];
+ counter++;
+ }
+ psb->updateDeformation();
+ }
+ counter = 0;
+
+ double f2 = totalElasticEnergy(0);
+
+ //restore m_q
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ psb->m_nodes[j].m_q = x[counter];
+ counter++;
+ }
+ psb->updateDeformation();
+ }
+ counter = 0;
+ double error = f1 - f2 - 2 * dphi;
+ errors.push_back(error);
+ std::cout << "Iteration = " << it << ", f1 = " << f1 << ", f2 = " << f2 << ", error = " << error << std::endl;
+ }
+ for (int i = 1; i < errors.size(); ++i)
+ {
+ std::cout << "Iteration = " << i << ", ratio = " << errors[i - 1] / errors[i] << std::endl;
+ }
+ }
+
+ // test for addScaledElasticForce function
+ virtual void testHessian()
+ {
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ psb->m_nodes[j].m_q += btVector3(randomDouble(-.1, .1), randomDouble(-.1, .1), randomDouble(-.1, .1));
+ }
+ psb->updateDeformation();
+ }
+
+ TVStack dx;
+ dx.resize(getNumNodes());
+ TVStack df;
+ df.resize(dx.size());
+ TVStack f1;
+ f1.resize(dx.size());
+ TVStack f2;
+ f2.resize(dx.size());
+
+ // write down the current position
+ TVStack x;
+ x.resize(dx.size());
+ int counter = 0;
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ x[counter] = psb->m_nodes[j].m_q;
+ counter++;
+ }
+ }
+ counter = 0;
+
+ // populate dx with random vectors
+ for (int i = 0; i < dx.size(); ++i)
+ {
+ dx[i].setX(randomDouble(-1, 1));
+ dx[i].setY(randomDouble(-1, 1));
+ dx[i].setZ(randomDouble(-1, 1));
+ }
+
+ btAlignedObjectArray<double> errors;
+ for (int it = 0; it < 10; ++it)
+ {
+ for (int i = 0; i < dx.size(); ++i)
+ {
+ dx[i] *= 0.5;
+ }
+
+ // get df
+ for (int i = 0; i < df.size(); ++i)
+ {
+ df[i].setZero();
+ f1[i].setZero();
+ f2[i].setZero();
+ }
+
+ //set df
+ addScaledElasticForceDifferential(-1, dx, df);
+
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ psb->m_nodes[j].m_q = x[counter] + dx[counter];
+ counter++;
+ }
+ psb->updateDeformation();
+ }
+ counter = 0;
+
+ //set f1
+ addScaledForces(-1, f1);
+
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ psb->m_nodes[j].m_q = x[counter] - dx[counter];
+ counter++;
+ }
+ psb->updateDeformation();
+ }
+ counter = 0;
+
+ //set f2
+ addScaledForces(-1, f2);
+
+ //restore m_q
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ psb->m_nodes[j].m_q = x[counter];
+ counter++;
+ }
+ psb->updateDeformation();
+ }
+ counter = 0;
+ double error = 0;
+ for (int i = 0; i < df.size(); ++i)
+ {
+ btVector3 error_vector = f1[i] - f2[i] - 2 * df[i];
+ error += error_vector.length2();
+ }
+ error = btSqrt(error);
+ errors.push_back(error);
+ std::cout << "Iteration = " << it << ", error = " << error << std::endl;
+ }
+ for (int i = 1; i < errors.size(); ++i)
+ {
+ std::cout << "Iteration = " << i << ", ratio = " << errors[i - 1] / errors[i] << std::endl;
+ }
+ }
+
+ //
+ virtual double totalElasticEnergy(btScalar dt)
+ {
+ return 0;
+ }
+
+ //
+ virtual double totalDampingEnergy(btScalar dt)
+ {
+ return 0;
+ }
+
+ // total Energy takes dt as input because certain energies depend on dt
+ virtual double totalEnergy(btScalar dt)
+ {
+ return totalElasticEnergy(dt) + totalDampingEnergy(dt);
+ }
};
#endif /* BT_DEFORMABLE_LAGRANGIAN_FORCE */
diff --git a/thirdparty/bullet/BulletSoftBody/btDeformableLinearElasticityForce.h b/thirdparty/bullet/BulletSoftBody/btDeformableLinearElasticityForce.h
index 106dc10ad6..971192050b 100644
--- a/thirdparty/bullet/BulletSoftBody/btDeformableLinearElasticityForce.h
+++ b/thirdparty/bullet/BulletSoftBody/btDeformableLinearElasticityForce.h
@@ -18,323 +18,445 @@
#include "btDeformableLagrangianForce.h"
#include "LinearMath/btQuickprof.h"
+#include "btSoftBodyInternals.h"
+#define TETRA_FLAT_THRESHOLD 0.01
class btDeformableLinearElasticityForce : public btDeformableLagrangianForce
{
public:
- typedef btAlignedObjectArray<btVector3> TVStack;
- btScalar m_mu, m_lambda;
- btScalar m_mu_damp, m_lambda_damp;
- btDeformableLinearElasticityForce(): m_mu(1), m_lambda(1)
- {
- btScalar damping = 0.05;
- m_mu_damp = damping * m_mu;
- m_lambda_damp = damping * m_lambda;
- }
-
- btDeformableLinearElasticityForce(btScalar mu, btScalar lambda, btScalar damping = 0.05): m_mu(mu), m_lambda(lambda)
- {
- m_mu_damp = damping * m_mu;
- m_lambda_damp = damping * m_lambda;
- }
-
- virtual void addScaledForces(btScalar scale, TVStack& force)
- {
- addScaledDampingForce(scale, force);
- addScaledElasticForce(scale, force);
- }
-
- virtual void addScaledExplicitForce(btScalar scale, TVStack& force)
- {
- addScaledElasticForce(scale, force);
- }
-
- // The damping matrix is calculated using the time n state as described in https://www.math.ucla.edu/~jteran/papers/GSSJT15.pdf to allow line search
- virtual void addScaledDampingForce(btScalar scale, TVStack& force)
- {
- if (m_mu_damp == 0 && m_lambda_damp == 0)
- return;
- int numNodes = getNumNodes();
- btAssert(numNodes <= force.size());
- btVector3 grad_N_hat_1st_col = btVector3(-1,-1,-1);
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- continue;
- }
- for (int j = 0; j < psb->m_tetras.size(); ++j)
- {
- btSoftBody::Tetra& tetra = psb->m_tetras[j];
- btSoftBody::Node* node0 = tetra.m_n[0];
- btSoftBody::Node* node1 = tetra.m_n[1];
- btSoftBody::Node* node2 = tetra.m_n[2];
- btSoftBody::Node* node3 = tetra.m_n[3];
- size_t id0 = node0->index;
- size_t id1 = node1->index;
- size_t id2 = node2->index;
- size_t id3 = node3->index;
- btMatrix3x3 dF = DsFromVelocity(node0, node1, node2, node3) * tetra.m_Dm_inverse;
- btMatrix3x3 I;
- I.setIdentity();
- btMatrix3x3 dP = (dF + dF.transpose()) * m_mu_damp + I * (dF[0][0]+dF[1][1]+dF[2][2]) * m_lambda_damp;
- // firstPiolaDampingDifferential(psb->m_tetraScratchesTn[j], dF, dP);
- btVector3 df_on_node0 = dP * (tetra.m_Dm_inverse.transpose()*grad_N_hat_1st_col);
- btMatrix3x3 df_on_node123 = dP * tetra.m_Dm_inverse.transpose();
-
- // damping force differential
- btScalar scale1 = scale * tetra.m_element_measure;
- force[id0] -= scale1 * df_on_node0;
- force[id1] -= scale1 * df_on_node123.getColumn(0);
- force[id2] -= scale1 * df_on_node123.getColumn(1);
- force[id3] -= scale1 * df_on_node123.getColumn(2);
- }
- }
- }
-
- virtual double totalElasticEnergy(btScalar dt)
- {
- double energy = 0;
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- continue;
- }
- for (int j = 0; j < psb->m_tetraScratches.size(); ++j)
- {
- btSoftBody::Tetra& tetra = psb->m_tetras[j];
- btSoftBody::TetraScratch& s = psb->m_tetraScratches[j];
- energy += tetra.m_element_measure * elasticEnergyDensity(s);
- }
- }
- return energy;
- }
-
- // The damping energy is formulated as in https://www.math.ucla.edu/~jteran/papers/GSSJT15.pdf to allow line search
- virtual double totalDampingEnergy(btScalar dt)
- {
- double energy = 0;
- int sz = 0;
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- continue;
- }
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- sz = btMax(sz, psb->m_nodes[j].index);
- }
- }
- TVStack dampingForce;
- dampingForce.resize(sz+1);
- for (int i = 0; i < dampingForce.size(); ++i)
- dampingForce[i].setZero();
- addScaledDampingForce(0.5, dampingForce);
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- const btSoftBody::Node& node = psb->m_nodes[j];
- energy -= dampingForce[node.index].dot(node.m_v) / dt;
- }
- }
- return energy;
- }
-
- double elasticEnergyDensity(const btSoftBody::TetraScratch& s)
- {
- double density = 0;
- btMatrix3x3 epsilon = (s.m_F + s.m_F.transpose()) * 0.5 - btMatrix3x3::getIdentity();
- btScalar trace = epsilon[0][0] + epsilon[1][1] + epsilon[2][2];
- density += m_mu * (epsilon[0].length2() + epsilon[1].length2() + epsilon[2].length2());
- density += m_lambda * trace * trace * 0.5;
- return density;
- }
-
- virtual void addScaledElasticForce(btScalar scale, TVStack& force)
- {
- int numNodes = getNumNodes();
- btAssert(numNodes <= force.size());
- btVector3 grad_N_hat_1st_col = btVector3(-1,-1,-1);
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- continue;
- }
- btScalar max_p = psb->m_cfg.m_maxStress;
- for (int j = 0; j < psb->m_tetras.size(); ++j)
- {
- btSoftBody::Tetra& tetra = psb->m_tetras[j];
- btMatrix3x3 P;
- firstPiola(psb->m_tetraScratches[j],P);
+ typedef btAlignedObjectArray<btVector3> TVStack;
+ btScalar m_mu, m_lambda;
+ btScalar m_E, m_nu; // Young's modulus and Poisson ratio
+ btScalar m_damping_alpha, m_damping_beta;
+ btDeformableLinearElasticityForce() : m_mu(1), m_lambda(1), m_damping_alpha(0.01), m_damping_beta(0.01)
+ {
+ updateYoungsModulusAndPoissonRatio();
+ }
+
+ btDeformableLinearElasticityForce(btScalar mu, btScalar lambda, btScalar damping_alpha = 0.01, btScalar damping_beta = 0.01) : m_mu(mu), m_lambda(lambda), m_damping_alpha(damping_alpha), m_damping_beta(damping_beta)
+ {
+ updateYoungsModulusAndPoissonRatio();
+ }
+
+ void updateYoungsModulusAndPoissonRatio()
+ {
+ // conversion from Lame Parameters to Young's modulus and Poisson ratio
+ // https://en.wikipedia.org/wiki/Lam%C3%A9_parameters
+ m_E = m_mu * (3 * m_lambda + 2 * m_mu) / (m_lambda + m_mu);
+ m_nu = m_lambda * 0.5 / (m_mu + m_lambda);
+ }
+
+ void updateLameParameters()
+ {
+ // conversion from Young's modulus and Poisson ratio to Lame Parameters
+ // https://en.wikipedia.org/wiki/Lam%C3%A9_parameters
+ m_mu = m_E * 0.5 / (1 + m_nu);
+ m_lambda = m_E * m_nu / ((1 + m_nu) * (1 - 2 * m_nu));
+ }
+
+ void setYoungsModulus(btScalar E)
+ {
+ m_E = E;
+ updateLameParameters();
+ }
+
+ void setPoissonRatio(btScalar nu)
+ {
+ m_nu = nu;
+ updateLameParameters();
+ }
+
+ void setDamping(btScalar damping_alpha, btScalar damping_beta)
+ {
+ m_damping_alpha = damping_alpha;
+ m_damping_beta = damping_beta;
+ }
+
+ void setLameParameters(btScalar mu, btScalar lambda)
+ {
+ m_mu = mu;
+ m_lambda = lambda;
+ updateYoungsModulusAndPoissonRatio();
+ }
+
+ virtual void addScaledForces(btScalar scale, TVStack& force)
+ {
+ addScaledDampingForce(scale, force);
+ addScaledElasticForce(scale, force);
+ }
+
+ virtual void addScaledExplicitForce(btScalar scale, TVStack& force)
+ {
+ addScaledElasticForce(scale, force);
+ }
+
+ // The damping matrix is calculated using the time n state as described in https://www.math.ucla.edu/~jteran/papers/GSSJT15.pdf to allow line search
+ virtual void addScaledDampingForce(btScalar scale, TVStack& force)
+ {
+ if (m_damping_alpha == 0 && m_damping_beta == 0)
+ return;
+ btScalar mu_damp = m_damping_beta * m_mu;
+ btScalar lambda_damp = m_damping_beta * m_lambda;
+ int numNodes = getNumNodes();
+ btAssert(numNodes <= force.size());
+ btVector3 grad_N_hat_1st_col = btVector3(-1, -1, -1);
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ continue;
+ }
+ for (int j = 0; j < psb->m_tetras.size(); ++j)
+ {
+ bool close_to_flat = (psb->m_tetraScratches[j].m_J < TETRA_FLAT_THRESHOLD);
+ btSoftBody::Tetra& tetra = psb->m_tetras[j];
+ btSoftBody::Node* node0 = tetra.m_n[0];
+ btSoftBody::Node* node1 = tetra.m_n[1];
+ btSoftBody::Node* node2 = tetra.m_n[2];
+ btSoftBody::Node* node3 = tetra.m_n[3];
+ size_t id0 = node0->index;
+ size_t id1 = node1->index;
+ size_t id2 = node2->index;
+ size_t id3 = node3->index;
+ btMatrix3x3 dF = DsFromVelocity(node0, node1, node2, node3) * tetra.m_Dm_inverse;
+ if (!close_to_flat)
+ {
+ dF = psb->m_tetraScratches[j].m_corotation.transpose() * dF;
+ }
+ btMatrix3x3 I;
+ I.setIdentity();
+ btMatrix3x3 dP = (dF + dF.transpose()) * mu_damp + I * ((dF[0][0] + dF[1][1] + dF[2][2]) * lambda_damp);
+ btMatrix3x3 df_on_node123 = dP * tetra.m_Dm_inverse.transpose();
+ if (!close_to_flat)
+ {
+ df_on_node123 = psb->m_tetraScratches[j].m_corotation * df_on_node123;
+ }
+ btVector3 df_on_node0 = df_on_node123 * grad_N_hat_1st_col;
+ // damping force differential
+ btScalar scale1 = scale * tetra.m_element_measure;
+ force[id0] -= scale1 * df_on_node0;
+ force[id1] -= scale1 * df_on_node123.getColumn(0);
+ force[id2] -= scale1 * df_on_node123.getColumn(1);
+ force[id3] -= scale1 * df_on_node123.getColumn(2);
+ }
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ const btSoftBody::Node& node = psb->m_nodes[j];
+ size_t id = node.index;
+ if (node.m_im > 0)
+ {
+ force[id] -= scale * node.m_v / node.m_im * m_damping_alpha;
+ }
+ }
+ }
+ }
+
+ virtual double totalElasticEnergy(btScalar dt)
+ {
+ double energy = 0;
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ continue;
+ }
+ for (int j = 0; j < psb->m_tetraScratches.size(); ++j)
+ {
+ btSoftBody::Tetra& tetra = psb->m_tetras[j];
+ btSoftBody::TetraScratch& s = psb->m_tetraScratches[j];
+ energy += tetra.m_element_measure * elasticEnergyDensity(s);
+ }
+ }
+ return energy;
+ }
+
+ // The damping energy is formulated as in https://www.math.ucla.edu/~jteran/papers/GSSJT15.pdf to allow line search
+ virtual double totalDampingEnergy(btScalar dt)
+ {
+ double energy = 0;
+ int sz = 0;
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ continue;
+ }
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ sz = btMax(sz, psb->m_nodes[j].index);
+ }
+ }
+ TVStack dampingForce;
+ dampingForce.resize(sz + 1);
+ for (int i = 0; i < dampingForce.size(); ++i)
+ dampingForce[i].setZero();
+ addScaledDampingForce(0.5, dampingForce);
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ const btSoftBody::Node& node = psb->m_nodes[j];
+ energy -= dampingForce[node.index].dot(node.m_v) / dt;
+ }
+ }
+ return energy;
+ }
+
+ double elasticEnergyDensity(const btSoftBody::TetraScratch& s)
+ {
+ double density = 0;
+ btMatrix3x3 epsilon = (s.m_F + s.m_F.transpose()) * 0.5 - btMatrix3x3::getIdentity();
+ btScalar trace = epsilon[0][0] + epsilon[1][1] + epsilon[2][2];
+ density += m_mu * (epsilon[0].length2() + epsilon[1].length2() + epsilon[2].length2());
+ density += m_lambda * trace * trace * 0.5;
+ return density;
+ }
+
+ virtual void addScaledElasticForce(btScalar scale, TVStack& force)
+ {
+ int numNodes = getNumNodes();
+ btAssert(numNodes <= force.size());
+ btVector3 grad_N_hat_1st_col = btVector3(-1, -1, -1);
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ continue;
+ }
+ btScalar max_p = psb->m_cfg.m_maxStress;
+ for (int j = 0; j < psb->m_tetras.size(); ++j)
+ {
+ btSoftBody::Tetra& tetra = psb->m_tetras[j];
+ btMatrix3x3 P;
+ firstPiola(psb->m_tetraScratches[j], P);
#if USE_SVD
- if (max_p > 0)
- {
- // since we want to clamp the principal stress to max_p, we only need to
- // calculate SVD when sigma_0^2 + sigma_1^2 + sigma_2^2 > max_p * max_p
- btScalar trPTP = (P[0].length2() + P[1].length2() + P[2].length2());
- if (trPTP > max_p * max_p)
- {
- btMatrix3x3 U, V;
- btVector3 sigma;
- singularValueDecomposition(P, U, sigma, V);
- sigma[0] = btMin(sigma[0], max_p);
- sigma[1] = btMin(sigma[1], max_p);
- sigma[2] = btMin(sigma[2], max_p);
- sigma[0] = btMax(sigma[0], -max_p);
- sigma[1] = btMax(sigma[1], -max_p);
- sigma[2] = btMax(sigma[2], -max_p);
- btMatrix3x3 Sigma;
- Sigma.setIdentity();
- Sigma[0][0] = sigma[0];
- Sigma[1][1] = sigma[1];
- Sigma[2][2] = sigma[2];
- P = U * Sigma * V.transpose();
- }
- }
+ if (max_p > 0)
+ {
+ // since we want to clamp the principal stress to max_p, we only need to
+ // calculate SVD when sigma_0^2 + sigma_1^2 + sigma_2^2 > max_p * max_p
+ btScalar trPTP = (P[0].length2() + P[1].length2() + P[2].length2());
+ if (trPTP > max_p * max_p)
+ {
+ btMatrix3x3 U, V;
+ btVector3 sigma;
+ singularValueDecomposition(P, U, sigma, V);
+ sigma[0] = btMin(sigma[0], max_p);
+ sigma[1] = btMin(sigma[1], max_p);
+ sigma[2] = btMin(sigma[2], max_p);
+ sigma[0] = btMax(sigma[0], -max_p);
+ sigma[1] = btMax(sigma[1], -max_p);
+ sigma[2] = btMax(sigma[2], -max_p);
+ btMatrix3x3 Sigma;
+ Sigma.setIdentity();
+ Sigma[0][0] = sigma[0];
+ Sigma[1][1] = sigma[1];
+ Sigma[2][2] = sigma[2];
+ P = U * Sigma * V.transpose();
+ }
+ }
#endif
- // btVector3 force_on_node0 = P * (tetra.m_Dm_inverse.transpose()*grad_N_hat_1st_col);
- btMatrix3x3 force_on_node123 = P * tetra.m_Dm_inverse.transpose();
- btVector3 force_on_node0 = force_on_node123 * grad_N_hat_1st_col;
-
- btSoftBody::Node* node0 = tetra.m_n[0];
- btSoftBody::Node* node1 = tetra.m_n[1];
- btSoftBody::Node* node2 = tetra.m_n[2];
- btSoftBody::Node* node3 = tetra.m_n[3];
- size_t id0 = node0->index;
- size_t id1 = node1->index;
- size_t id2 = node2->index;
- size_t id3 = node3->index;
-
- // elastic force
- btScalar scale1 = scale * tetra.m_element_measure;
- force[id0] -= scale1 * force_on_node0;
- force[id1] -= scale1 * force_on_node123.getColumn(0);
- force[id2] -= scale1 * force_on_node123.getColumn(1);
- force[id3] -= scale1 * force_on_node123.getColumn(2);
- }
- }
- }
-
- // The damping matrix is calculated using the time n state as described in https://www.math.ucla.edu/~jteran/papers/GSSJT15.pdf to allow line search
- virtual void addScaledDampingForceDifferential(btScalar scale, const TVStack& dv, TVStack& df)
- {
- if (m_mu_damp == 0 && m_lambda_damp == 0)
- return;
- int numNodes = getNumNodes();
- btAssert(numNodes <= df.size());
- btVector3 grad_N_hat_1st_col = btVector3(-1,-1,-1);
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- continue;
- }
- for (int j = 0; j < psb->m_tetras.size(); ++j)
- {
- btSoftBody::Tetra& tetra = psb->m_tetras[j];
- btSoftBody::Node* node0 = tetra.m_n[0];
- btSoftBody::Node* node1 = tetra.m_n[1];
- btSoftBody::Node* node2 = tetra.m_n[2];
- btSoftBody::Node* node3 = tetra.m_n[3];
- size_t id0 = node0->index;
- size_t id1 = node1->index;
- size_t id2 = node2->index;
- size_t id3 = node3->index;
- btMatrix3x3 dF = Ds(id0, id1, id2, id3, dv) * tetra.m_Dm_inverse;
- btMatrix3x3 I;
- I.setIdentity();
- btMatrix3x3 dP = (dF + dF.transpose()) * m_mu_damp + I * (dF[0][0]+dF[1][1]+dF[2][2]) * m_lambda_damp;
- // firstPiolaDampingDifferential(psb->m_tetraScratchesTn[j], dF, dP);
- // btVector3 df_on_node0 = dP * (tetra.m_Dm_inverse.transpose()*grad_N_hat_1st_col);
- btMatrix3x3 df_on_node123 = dP * tetra.m_Dm_inverse.transpose();
- btVector3 df_on_node0 = df_on_node123 * grad_N_hat_1st_col;
-
- // damping force differential
- btScalar scale1 = scale * tetra.m_element_measure;
- df[id0] -= scale1 * df_on_node0;
- df[id1] -= scale1 * df_on_node123.getColumn(0);
- df[id2] -= scale1 * df_on_node123.getColumn(1);
- df[id3] -= scale1 * df_on_node123.getColumn(2);
- }
- }
- }
-
- virtual void addScaledElasticForceDifferential(btScalar scale, const TVStack& dx, TVStack& df)
- {
- int numNodes = getNumNodes();
- btAssert(numNodes <= df.size());
- btVector3 grad_N_hat_1st_col = btVector3(-1,-1,-1);
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- continue;
- }
- for (int j = 0; j < psb->m_tetras.size(); ++j)
- {
- btSoftBody::Tetra& tetra = psb->m_tetras[j];
- btSoftBody::Node* node0 = tetra.m_n[0];
- btSoftBody::Node* node1 = tetra.m_n[1];
- btSoftBody::Node* node2 = tetra.m_n[2];
- btSoftBody::Node* node3 = tetra.m_n[3];
- size_t id0 = node0->index;
- size_t id1 = node1->index;
- size_t id2 = node2->index;
- size_t id3 = node3->index;
- btMatrix3x3 dF = Ds(id0, id1, id2, id3, dx) * tetra.m_Dm_inverse;
- btMatrix3x3 dP;
- firstPiolaDifferential(psb->m_tetraScratches[j], dF, dP);
- // btVector3 df_on_node0 = dP * (tetra.m_Dm_inverse.transpose()*grad_N_hat_1st_col);
- btMatrix3x3 df_on_node123 = dP * tetra.m_Dm_inverse.transpose();
- btVector3 df_on_node0 = df_on_node123 * grad_N_hat_1st_col;
-
- // elastic force differential
- btScalar scale1 = scale * tetra.m_element_measure;
- df[id0] -= scale1 * df_on_node0;
- df[id1] -= scale1 * df_on_node123.getColumn(0);
- df[id2] -= scale1 * df_on_node123.getColumn(1);
- df[id3] -= scale1 * df_on_node123.getColumn(2);
- }
- }
- }
-
- void firstPiola(const btSoftBody::TetraScratch& s, btMatrix3x3& P)
- {
- btMatrix3x3 epsilon = (s.m_F + s.m_F.transpose()) * 0.5 - btMatrix3x3::getIdentity();
- btScalar trace = epsilon[0][0] + epsilon[1][1] + epsilon[2][2];
- P = epsilon * btScalar(2) * m_mu + btMatrix3x3::getIdentity() * m_lambda * trace;
- }
-
- // Let P be the first piola stress.
- // This function calculates the dP = dP/dF * dF
- void firstPiolaDifferential(const btSoftBody::TetraScratch& s, const btMatrix3x3& dF, btMatrix3x3& dP)
- {
- btScalar trace = (dF[0][0] + dF[1][1] + dF[2][2]);
- dP = (dF + dF.transpose()) * m_mu + btMatrix3x3::getIdentity() * m_lambda * trace;
- }
-
- // Let Q be the damping stress.
- // This function calculates the dP = dQ/dF * dF
- void firstPiolaDampingDifferential(const btSoftBody::TetraScratch& s, const btMatrix3x3& dF, btMatrix3x3& dP)
- {
- btScalar trace = (dF[0][0] + dF[1][1] + dF[2][2]);
- dP = (dF + dF.transpose()) * m_mu_damp + btMatrix3x3::getIdentity() * m_lambda_damp * trace;
- }
-
- virtual btDeformableLagrangianForceType getForceType()
- {
- return BT_LINEAR_ELASTICITY_FORCE;
- }
-
+ // btVector3 force_on_node0 = P * (tetra.m_Dm_inverse.transpose()*grad_N_hat_1st_col);
+ btMatrix3x3 force_on_node123 = psb->m_tetraScratches[j].m_corotation * P * tetra.m_Dm_inverse.transpose();
+ btVector3 force_on_node0 = force_on_node123 * grad_N_hat_1st_col;
+
+ btSoftBody::Node* node0 = tetra.m_n[0];
+ btSoftBody::Node* node1 = tetra.m_n[1];
+ btSoftBody::Node* node2 = tetra.m_n[2];
+ btSoftBody::Node* node3 = tetra.m_n[3];
+ size_t id0 = node0->index;
+ size_t id1 = node1->index;
+ size_t id2 = node2->index;
+ size_t id3 = node3->index;
+
+ // elastic force
+ btScalar scale1 = scale * tetra.m_element_measure;
+ force[id0] -= scale1 * force_on_node0;
+ force[id1] -= scale1 * force_on_node123.getColumn(0);
+ force[id2] -= scale1 * force_on_node123.getColumn(1);
+ force[id3] -= scale1 * force_on_node123.getColumn(2);
+ }
+ }
+ }
+
+ virtual void buildDampingForceDifferentialDiagonal(btScalar scale, TVStack& diagA) {}
+
+ // The damping matrix is calculated using the time n state as described in https://www.math.ucla.edu/~jteran/papers/GSSJT15.pdf to allow line search
+ virtual void addScaledDampingForceDifferential(btScalar scale, const TVStack& dv, TVStack& df)
+ {
+ if (m_damping_alpha == 0 && m_damping_beta == 0)
+ return;
+ btScalar mu_damp = m_damping_beta * m_mu;
+ btScalar lambda_damp = m_damping_beta * m_lambda;
+ int numNodes = getNumNodes();
+ btAssert(numNodes <= df.size());
+ btVector3 grad_N_hat_1st_col = btVector3(-1, -1, -1);
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ continue;
+ }
+ for (int j = 0; j < psb->m_tetras.size(); ++j)
+ {
+ bool close_to_flat = (psb->m_tetraScratches[j].m_J < TETRA_FLAT_THRESHOLD);
+ btSoftBody::Tetra& tetra = psb->m_tetras[j];
+ btSoftBody::Node* node0 = tetra.m_n[0];
+ btSoftBody::Node* node1 = tetra.m_n[1];
+ btSoftBody::Node* node2 = tetra.m_n[2];
+ btSoftBody::Node* node3 = tetra.m_n[3];
+ size_t id0 = node0->index;
+ size_t id1 = node1->index;
+ size_t id2 = node2->index;
+ size_t id3 = node3->index;
+ btMatrix3x3 dF = Ds(id0, id1, id2, id3, dv) * tetra.m_Dm_inverse;
+ if (!close_to_flat)
+ {
+ dF = psb->m_tetraScratches[j].m_corotation.transpose() * dF;
+ }
+ btMatrix3x3 I;
+ I.setIdentity();
+ btMatrix3x3 dP = (dF + dF.transpose()) * mu_damp + I * ((dF[0][0] + dF[1][1] + dF[2][2]) * lambda_damp);
+ btMatrix3x3 df_on_node123 = dP * tetra.m_Dm_inverse.transpose();
+ if (!close_to_flat)
+ {
+ df_on_node123 = psb->m_tetraScratches[j].m_corotation * df_on_node123;
+ }
+ btVector3 df_on_node0 = df_on_node123 * grad_N_hat_1st_col;
+
+ // damping force differential
+ btScalar scale1 = scale * tetra.m_element_measure;
+ df[id0] -= scale1 * df_on_node0;
+ df[id1] -= scale1 * df_on_node123.getColumn(0);
+ df[id2] -= scale1 * df_on_node123.getColumn(1);
+ df[id3] -= scale1 * df_on_node123.getColumn(2);
+ }
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ const btSoftBody::Node& node = psb->m_nodes[j];
+ size_t id = node.index;
+ if (node.m_im > 0)
+ {
+ df[id] -= scale * dv[id] / node.m_im * m_damping_alpha;
+ }
+ }
+ }
+ }
+
+ virtual void addScaledElasticForceDifferential(btScalar scale, const TVStack& dx, TVStack& df)
+ {
+ int numNodes = getNumNodes();
+ btAssert(numNodes <= df.size());
+ btVector3 grad_N_hat_1st_col = btVector3(-1, -1, -1);
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ continue;
+ }
+ for (int j = 0; j < psb->m_tetras.size(); ++j)
+ {
+ btSoftBody::Tetra& tetra = psb->m_tetras[j];
+ btSoftBody::Node* node0 = tetra.m_n[0];
+ btSoftBody::Node* node1 = tetra.m_n[1];
+ btSoftBody::Node* node2 = tetra.m_n[2];
+ btSoftBody::Node* node3 = tetra.m_n[3];
+ size_t id0 = node0->index;
+ size_t id1 = node1->index;
+ size_t id2 = node2->index;
+ size_t id3 = node3->index;
+ btMatrix3x3 dF = psb->m_tetraScratches[j].m_corotation.transpose() * Ds(id0, id1, id2, id3, dx) * tetra.m_Dm_inverse;
+ btMatrix3x3 dP;
+ firstPiolaDifferential(psb->m_tetraScratches[j], dF, dP);
+ // btVector3 df_on_node0 = dP * (tetra.m_Dm_inverse.transpose()*grad_N_hat_1st_col);
+ btMatrix3x3 df_on_node123 = psb->m_tetraScratches[j].m_corotation * dP * tetra.m_Dm_inverse.transpose();
+ btVector3 df_on_node0 = df_on_node123 * grad_N_hat_1st_col;
+
+ // elastic force differential
+ btScalar scale1 = scale * tetra.m_element_measure;
+ df[id0] -= scale1 * df_on_node0;
+ df[id1] -= scale1 * df_on_node123.getColumn(0);
+ df[id2] -= scale1 * df_on_node123.getColumn(1);
+ df[id3] -= scale1 * df_on_node123.getColumn(2);
+ }
+ }
+ }
+
+ void firstPiola(const btSoftBody::TetraScratch& s, btMatrix3x3& P)
+ {
+ btMatrix3x3 corotated_F = s.m_corotation.transpose() * s.m_F;
+
+ btMatrix3x3 epsilon = (corotated_F + corotated_F.transpose()) * 0.5 - btMatrix3x3::getIdentity();
+ btScalar trace = epsilon[0][0] + epsilon[1][1] + epsilon[2][2];
+ P = epsilon * btScalar(2) * m_mu + btMatrix3x3::getIdentity() * m_lambda * trace;
+ }
+
+ // Let P be the first piola stress.
+ // This function calculates the dP = dP/dF * dF
+ void firstPiolaDifferential(const btSoftBody::TetraScratch& s, const btMatrix3x3& dF, btMatrix3x3& dP)
+ {
+ btScalar trace = (dF[0][0] + dF[1][1] + dF[2][2]);
+ dP = (dF + dF.transpose()) * m_mu + btMatrix3x3::getIdentity() * m_lambda * trace;
+ }
+
+ // Let Q be the damping stress.
+ // This function calculates the dP = dQ/dF * dF
+ void firstPiolaDampingDifferential(const btSoftBody::TetraScratch& s, const btMatrix3x3& dF, btMatrix3x3& dP)
+ {
+ btScalar mu_damp = m_damping_beta * m_mu;
+ btScalar lambda_damp = m_damping_beta * m_lambda;
+ btScalar trace = (dF[0][0] + dF[1][1] + dF[2][2]);
+ dP = (dF + dF.transpose()) * mu_damp + btMatrix3x3::getIdentity() * lambda_damp * trace;
+ }
+
+ virtual void addScaledHessian(btScalar scale)
+ {
+ btVector3 grad_N_hat_1st_col = btVector3(-1, -1, -1);
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ continue;
+ }
+ for (int j = 0; j < psb->m_tetras.size(); ++j)
+ {
+ btSoftBody::Tetra& tetra = psb->m_tetras[j];
+ btMatrix3x3 P;
+ firstPiola(psb->m_tetraScratches[j], P); // make sure scratch is evaluated at x_n + dt * vn
+ btMatrix3x3 force_on_node123 = psb->m_tetraScratches[j].m_corotation * P * tetra.m_Dm_inverse.transpose();
+ btVector3 force_on_node0 = force_on_node123 * grad_N_hat_1st_col;
+ btSoftBody::Node* node0 = tetra.m_n[0];
+ btSoftBody::Node* node1 = tetra.m_n[1];
+ btSoftBody::Node* node2 = tetra.m_n[2];
+ btSoftBody::Node* node3 = tetra.m_n[3];
+ btScalar scale1 = scale * (scale + m_damping_beta) * tetra.m_element_measure; // stiff and stiffness-damping terms;
+ node0->m_effectiveMass += OuterProduct(force_on_node0, force_on_node0) * scale1;
+ node1->m_effectiveMass += OuterProduct(force_on_node123.getColumn(0), force_on_node123.getColumn(0)) * scale1;
+ node2->m_effectiveMass += OuterProduct(force_on_node123.getColumn(1), force_on_node123.getColumn(1)) * scale1;
+ node3->m_effectiveMass += OuterProduct(force_on_node123.getColumn(2), force_on_node123.getColumn(2)) * scale1;
+ }
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ btSoftBody::Node& node = psb->m_nodes[j];
+ if (node.m_im > 0)
+ {
+ btMatrix3x3 I;
+ I.setIdentity();
+ node.m_effectiveMass += I * (scale * (1.0 / node.m_im) * m_damping_alpha);
+ }
+ }
+ }
+ }
+
+ virtual btDeformableLagrangianForceType getForceType()
+ {
+ return BT_LINEAR_ELASTICITY_FORCE;
+ }
};
#endif /* BT_LINEAR_ELASTICITY_H */
diff --git a/thirdparty/bullet/BulletSoftBody/btDeformableMassSpringForce.h b/thirdparty/bullet/BulletSoftBody/btDeformableMassSpringForce.h
index b128df92cc..8c97bd1ba8 100644
--- a/thirdparty/bullet/BulletSoftBody/btDeformableMassSpringForce.h
+++ b/thirdparty/bullet/BulletSoftBody/btDeformableMassSpringForce.h
@@ -20,282 +20,282 @@
class btDeformableMassSpringForce : public btDeformableLagrangianForce
{
- // If true, the damping force will be in the direction of the spring
- // If false, the damping force will be in the direction of the velocity
- bool m_momentum_conserving;
- btScalar m_elasticStiffness, m_dampingStiffness, m_bendingStiffness;
+ // If true, the damping force will be in the direction of the spring
+ // If false, the damping force will be in the direction of the velocity
+ bool m_momentum_conserving;
+ btScalar m_elasticStiffness, m_dampingStiffness, m_bendingStiffness;
+
public:
- typedef btAlignedObjectArray<btVector3> TVStack;
- btDeformableMassSpringForce() : m_momentum_conserving(false), m_elasticStiffness(1), m_dampingStiffness(0.05)
- {
- }
- btDeformableMassSpringForce(btScalar k, btScalar d, bool conserve_angular = true, double bending_k = -1) : m_momentum_conserving(conserve_angular), m_elasticStiffness(k), m_dampingStiffness(d), m_bendingStiffness(bending_k)
- {
- if (m_bendingStiffness < btScalar(0))
- {
- m_bendingStiffness = m_elasticStiffness;
- }
- }
-
- virtual void addScaledForces(btScalar scale, TVStack& force)
- {
- addScaledDampingForce(scale, force);
- addScaledElasticForce(scale, force);
- }
-
- virtual void addScaledExplicitForce(btScalar scale, TVStack& force)
- {
- addScaledElasticForce(scale, force);
- }
-
- virtual void addScaledDampingForce(btScalar scale, TVStack& force)
- {
- int numNodes = getNumNodes();
- btAssert(numNodes <= force.size());
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- const btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- continue;
- }
- for (int j = 0; j < psb->m_links.size(); ++j)
- {
- const btSoftBody::Link& link = psb->m_links[j];
- btSoftBody::Node* node1 = link.m_n[0];
- btSoftBody::Node* node2 = link.m_n[1];
- size_t id1 = node1->index;
- size_t id2 = node2->index;
-
- // damping force
- btVector3 v_diff = (node2->m_v - node1->m_v);
- btVector3 scaled_force = scale * m_dampingStiffness * v_diff;
- if (m_momentum_conserving)
- {
- if ((node2->m_x - node1->m_x).norm() > SIMD_EPSILON)
- {
- btVector3 dir = (node2->m_x - node1->m_x).normalized();
- scaled_force = scale * m_dampingStiffness * v_diff.dot(dir) * dir;
- }
- }
- force[id1] += scaled_force;
- force[id2] -= scaled_force;
- }
- }
- }
-
- virtual void addScaledElasticForce(btScalar scale, TVStack& force)
- {
- int numNodes = getNumNodes();
- btAssert(numNodes <= force.size());
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- const btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- continue;
- }
- for (int j = 0; j < psb->m_links.size(); ++j)
- {
- const btSoftBody::Link& link = psb->m_links[j];
- btSoftBody::Node* node1 = link.m_n[0];
- btSoftBody::Node* node2 = link.m_n[1];
- btScalar r = link.m_rl;
- size_t id1 = node1->index;
- size_t id2 = node2->index;
-
- // elastic force
- btVector3 dir = (node2->m_q - node1->m_q);
- btVector3 dir_normalized = (dir.norm() > SIMD_EPSILON) ? dir.normalized() : btVector3(0,0,0);
- btScalar scaled_stiffness = scale * (link.m_bbending ? m_bendingStiffness : m_elasticStiffness);
- btVector3 scaled_force = scaled_stiffness * (dir - dir_normalized * r);
- force[id1] += scaled_force;
- force[id2] -= scaled_force;
- }
- }
- }
-
- virtual void addScaledDampingForceDifferential(btScalar scale, const TVStack& dv, TVStack& df)
- {
- // implicit damping force differential
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- continue;
- }
- btScalar scaled_k_damp = m_dampingStiffness * scale;
- for (int j = 0; j < psb->m_links.size(); ++j)
- {
- const btSoftBody::Link& link = psb->m_links[j];
- btSoftBody::Node* node1 = link.m_n[0];
- btSoftBody::Node* node2 = link.m_n[1];
- size_t id1 = node1->index;
- size_t id2 = node2->index;
+ typedef btAlignedObjectArray<btVector3> TVStack;
+ btDeformableMassSpringForce() : m_momentum_conserving(false), m_elasticStiffness(1), m_dampingStiffness(0.05)
+ {
+ }
+ btDeformableMassSpringForce(btScalar k, btScalar d, bool conserve_angular = true, double bending_k = -1) : m_momentum_conserving(conserve_angular), m_elasticStiffness(k), m_dampingStiffness(d), m_bendingStiffness(bending_k)
+ {
+ if (m_bendingStiffness < btScalar(0))
+ {
+ m_bendingStiffness = m_elasticStiffness;
+ }
+ }
+
+ virtual void addScaledForces(btScalar scale, TVStack& force)
+ {
+ addScaledDampingForce(scale, force);
+ addScaledElasticForce(scale, force);
+ }
+
+ virtual void addScaledExplicitForce(btScalar scale, TVStack& force)
+ {
+ addScaledElasticForce(scale, force);
+ }
+
+ virtual void addScaledDampingForce(btScalar scale, TVStack& force)
+ {
+ int numNodes = getNumNodes();
+ btAssert(numNodes <= force.size());
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ const btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ continue;
+ }
+ for (int j = 0; j < psb->m_links.size(); ++j)
+ {
+ const btSoftBody::Link& link = psb->m_links[j];
+ btSoftBody::Node* node1 = link.m_n[0];
+ btSoftBody::Node* node2 = link.m_n[1];
+ size_t id1 = node1->index;
+ size_t id2 = node2->index;
+
+ // damping force
+ btVector3 v_diff = (node2->m_v - node1->m_v);
+ btVector3 scaled_force = scale * m_dampingStiffness * v_diff;
+ if (m_momentum_conserving)
+ {
+ if ((node2->m_x - node1->m_x).norm() > SIMD_EPSILON)
+ {
+ btVector3 dir = (node2->m_x - node1->m_x).normalized();
+ scaled_force = scale * m_dampingStiffness * v_diff.dot(dir) * dir;
+ }
+ }
+ force[id1] += scaled_force;
+ force[id2] -= scaled_force;
+ }
+ }
+ }
+
+ virtual void addScaledElasticForce(btScalar scale, TVStack& force)
+ {
+ int numNodes = getNumNodes();
+ btAssert(numNodes <= force.size());
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ const btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ continue;
+ }
+ for (int j = 0; j < psb->m_links.size(); ++j)
+ {
+ const btSoftBody::Link& link = psb->m_links[j];
+ btSoftBody::Node* node1 = link.m_n[0];
+ btSoftBody::Node* node2 = link.m_n[1];
+ btScalar r = link.m_rl;
+ size_t id1 = node1->index;
+ size_t id2 = node2->index;
+
+ // elastic force
+ btVector3 dir = (node2->m_q - node1->m_q);
+ btVector3 dir_normalized = (dir.norm() > SIMD_EPSILON) ? dir.normalized() : btVector3(0, 0, 0);
+ btScalar scaled_stiffness = scale * (link.m_bbending ? m_bendingStiffness : m_elasticStiffness);
+ btVector3 scaled_force = scaled_stiffness * (dir - dir_normalized * r);
+ force[id1] += scaled_force;
+ force[id2] -= scaled_force;
+ }
+ }
+ }
+
+ virtual void addScaledDampingForceDifferential(btScalar scale, const TVStack& dv, TVStack& df)
+ {
+ // implicit damping force differential
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ continue;
+ }
+ btScalar scaled_k_damp = m_dampingStiffness * scale;
+ for (int j = 0; j < psb->m_links.size(); ++j)
+ {
+ const btSoftBody::Link& link = psb->m_links[j];
+ btSoftBody::Node* node1 = link.m_n[0];
+ btSoftBody::Node* node2 = link.m_n[1];
+ size_t id1 = node1->index;
+ size_t id2 = node2->index;
+
+ btVector3 local_scaled_df = scaled_k_damp * (dv[id2] - dv[id1]);
+ if (m_momentum_conserving)
+ {
+ if ((node2->m_x - node1->m_x).norm() > SIMD_EPSILON)
+ {
+ btVector3 dir = (node2->m_x - node1->m_x).normalized();
+ local_scaled_df = scaled_k_damp * (dv[id2] - dv[id1]).dot(dir) * dir;
+ }
+ }
+ df[id1] += local_scaled_df;
+ df[id2] -= local_scaled_df;
+ }
+ }
+ }
+
+ virtual void buildDampingForceDifferentialDiagonal(btScalar scale, TVStack& diagA)
+ {
+ // implicit damping force differential
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ continue;
+ }
+ btScalar scaled_k_damp = m_dampingStiffness * scale;
+ for (int j = 0; j < psb->m_links.size(); ++j)
+ {
+ const btSoftBody::Link& link = psb->m_links[j];
+ btSoftBody::Node* node1 = link.m_n[0];
+ btSoftBody::Node* node2 = link.m_n[1];
+ size_t id1 = node1->index;
+ size_t id2 = node2->index;
+ if (m_momentum_conserving)
+ {
+ if ((node2->m_x - node1->m_x).norm() > SIMD_EPSILON)
+ {
+ btVector3 dir = (node2->m_x - node1->m_x).normalized();
+ for (int d = 0; d < 3; ++d)
+ {
+ if (node1->m_im > 0)
+ diagA[id1][d] -= scaled_k_damp * dir[d] * dir[d];
+ if (node2->m_im > 0)
+ diagA[id2][d] -= scaled_k_damp * dir[d] * dir[d];
+ }
+ }
+ }
+ else
+ {
+ for (int d = 0; d < 3; ++d)
+ {
+ if (node1->m_im > 0)
+ diagA[id1][d] -= scaled_k_damp;
+ if (node2->m_im > 0)
+ diagA[id2][d] -= scaled_k_damp;
+ }
+ }
+ }
+ }
+ }
+
+ virtual double totalElasticEnergy(btScalar dt)
+ {
+ double energy = 0;
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ const btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ continue;
+ }
+ for (int j = 0; j < psb->m_links.size(); ++j)
+ {
+ const btSoftBody::Link& link = psb->m_links[j];
+ btSoftBody::Node* node1 = link.m_n[0];
+ btSoftBody::Node* node2 = link.m_n[1];
+ btScalar r = link.m_rl;
+
+ // elastic force
+ btVector3 dir = (node2->m_q - node1->m_q);
+ energy += 0.5 * m_elasticStiffness * (dir.norm() - r) * (dir.norm() - r);
+ }
+ }
+ return energy;
+ }
+
+ virtual double totalDampingEnergy(btScalar dt)
+ {
+ double energy = 0;
+ int sz = 0;
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ continue;
+ }
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ sz = btMax(sz, psb->m_nodes[j].index);
+ }
+ }
+ TVStack dampingForce;
+ dampingForce.resize(sz + 1);
+ for (int i = 0; i < dampingForce.size(); ++i)
+ dampingForce[i].setZero();
+ addScaledDampingForce(0.5, dampingForce);
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ const btSoftBody::Node& node = psb->m_nodes[j];
+ energy -= dampingForce[node.index].dot(node.m_v) / dt;
+ }
+ }
+ return energy;
+ }
+
+ virtual void addScaledElasticForceDifferential(btScalar scale, const TVStack& dx, TVStack& df)
+ {
+ // implicit damping force differential
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ const btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ continue;
+ }
+ for (int j = 0; j < psb->m_links.size(); ++j)
+ {
+ const btSoftBody::Link& link = psb->m_links[j];
+ btSoftBody::Node* node1 = link.m_n[0];
+ btSoftBody::Node* node2 = link.m_n[1];
+ size_t id1 = node1->index;
+ size_t id2 = node2->index;
+ btScalar r = link.m_rl;
- btVector3 local_scaled_df = scaled_k_damp * (dv[id2] - dv[id1]);
- if (m_momentum_conserving)
- {
- if ((node2->m_x - node1->m_x).norm() > SIMD_EPSILON)
- {
- btVector3 dir = (node2->m_x - node1->m_x).normalized();
- local_scaled_df= scaled_k_damp * (dv[id2] - dv[id1]).dot(dir) * dir;
- }
- }
- df[id1] += local_scaled_df;
- df[id2] -= local_scaled_df;
- }
- }
- }
-
- virtual void buildDampingForceDifferentialDiagonal(btScalar scale, TVStack& diagA)
- {
- // implicit damping force differential
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- continue;
- }
- btScalar scaled_k_damp = m_dampingStiffness * scale;
- for (int j = 0; j < psb->m_links.size(); ++j)
- {
- const btSoftBody::Link& link = psb->m_links[j];
- btSoftBody::Node* node1 = link.m_n[0];
- btSoftBody::Node* node2 = link.m_n[1];
- size_t id1 = node1->index;
- size_t id2 = node2->index;
- if (m_momentum_conserving)
- {
- if ((node2->m_x - node1->m_x).norm() > SIMD_EPSILON)
- {
- btVector3 dir = (node2->m_x - node1->m_x).normalized();
- for (int d = 0; d < 3; ++d)
- {
- if (node1->m_im > 0)
- diagA[id1][d] -= scaled_k_damp * dir[d] * dir[d];
- if (node2->m_im > 0)
- diagA[id2][d] -= scaled_k_damp * dir[d] * dir[d];
- }
- }
- }
- else
- {
- for (int d = 0; d < 3; ++d)
- {
- if (node1->m_im > 0)
- diagA[id1][d] -= scaled_k_damp;
- if (node2->m_im > 0)
- diagA[id2][d] -= scaled_k_damp;
- }
- }
- }
- }
- }
-
- virtual double totalElasticEnergy(btScalar dt)
- {
- double energy = 0;
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- const btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- continue;
- }
- for (int j = 0; j < psb->m_links.size(); ++j)
- {
- const btSoftBody::Link& link = psb->m_links[j];
- btSoftBody::Node* node1 = link.m_n[0];
- btSoftBody::Node* node2 = link.m_n[1];
- btScalar r = link.m_rl;
+ btVector3 dir = (node1->m_q - node2->m_q);
+ btScalar dir_norm = dir.norm();
+ btVector3 dir_normalized = (dir_norm > SIMD_EPSILON) ? dir.normalized() : btVector3(0, 0, 0);
+ btVector3 dx_diff = dx[id1] - dx[id2];
+ btVector3 scaled_df = btVector3(0, 0, 0);
+ btScalar scaled_k = scale * (link.m_bbending ? m_bendingStiffness : m_elasticStiffness);
+ if (dir_norm > SIMD_EPSILON)
+ {
+ scaled_df -= scaled_k * dir_normalized.dot(dx_diff) * dir_normalized;
+ scaled_df += scaled_k * dir_normalized.dot(dx_diff) * ((dir_norm - r) / dir_norm) * dir_normalized;
+ scaled_df -= scaled_k * ((dir_norm - r) / dir_norm) * dx_diff;
+ }
- // elastic force
- btVector3 dir = (node2->m_q - node1->m_q);
- energy += 0.5 * m_elasticStiffness * (dir.norm() - r) * (dir.norm() -r);
- }
- }
- return energy;
- }
-
- virtual double totalDampingEnergy(btScalar dt)
- {
- double energy = 0;
- int sz = 0;
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- continue;
- }
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- sz = btMax(sz, psb->m_nodes[j].index);
- }
- }
- TVStack dampingForce;
- dampingForce.resize(sz+1);
- for (int i = 0; i < dampingForce.size(); ++i)
- dampingForce[i].setZero();
- addScaledDampingForce(0.5, dampingForce);
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- const btSoftBody::Node& node = psb->m_nodes[j];
- energy -= dampingForce[node.index].dot(node.m_v) / dt;
- }
- }
- return energy;
- }
-
- virtual void addScaledElasticForceDifferential(btScalar scale, const TVStack& dx, TVStack& df)
- {
- // implicit damping force differential
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- const btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- continue;
- }
- for (int j = 0; j < psb->m_links.size(); ++j)
- {
- const btSoftBody::Link& link = psb->m_links[j];
- btSoftBody::Node* node1 = link.m_n[0];
- btSoftBody::Node* node2 = link.m_n[1];
- size_t id1 = node1->index;
- size_t id2 = node2->index;
- btScalar r = link.m_rl;
+ df[id1] += scaled_df;
+ df[id2] -= scaled_df;
+ }
+ }
+ }
- btVector3 dir = (node1->m_q - node2->m_q);
- btScalar dir_norm = dir.norm();
- btVector3 dir_normalized = (dir_norm > SIMD_EPSILON) ? dir.normalized() : btVector3(0,0,0);
- btVector3 dx_diff = dx[id1] - dx[id2];
- btVector3 scaled_df = btVector3(0,0,0);
- btScalar scaled_k = scale * (link.m_bbending ? m_bendingStiffness : m_elasticStiffness);
- if (dir_norm > SIMD_EPSILON)
- {
- scaled_df -= scaled_k * dir_normalized.dot(dx_diff) * dir_normalized;
- scaled_df += scaled_k * dir_normalized.dot(dx_diff) * ((dir_norm-r)/dir_norm) * dir_normalized;
- scaled_df -= scaled_k * ((dir_norm-r)/dir_norm) * dx_diff;
- }
-
- df[id1] += scaled_df;
- df[id2] -= scaled_df;
- }
- }
- }
-
- virtual btDeformableLagrangianForceType getForceType()
- {
- return BT_MASSSPRING_FORCE;
- }
-
+ virtual btDeformableLagrangianForceType getForceType()
+ {
+ return BT_MASSSPRING_FORCE;
+ }
};
#endif /* btMassSpring_h */
diff --git a/thirdparty/bullet/BulletSoftBody/btDeformableMousePickingForce.h b/thirdparty/bullet/BulletSoftBody/btDeformableMousePickingForce.h
index 07c10935f4..d218d96214 100644
--- a/thirdparty/bullet/BulletSoftBody/btDeformableMousePickingForce.h
+++ b/thirdparty/bullet/BulletSoftBody/btDeformableMousePickingForce.h
@@ -20,126 +20,143 @@
class btDeformableMousePickingForce : public btDeformableLagrangianForce
{
- // If true, the damping force will be in the direction of the spring
- // If false, the damping force will be in the direction of the velocity
- btScalar m_elasticStiffness, m_dampingStiffness;
- const btSoftBody::Face& m_face;
- btVector3 m_mouse_pos;
- btScalar m_maxForce;
+ // If true, the damping force will be in the direction of the spring
+ // If false, the damping force will be in the direction of the velocity
+ btScalar m_elasticStiffness, m_dampingStiffness;
+ const btSoftBody::Face& m_face;
+ btVector3 m_mouse_pos;
+ btScalar m_maxForce;
+
public:
- typedef btAlignedObjectArray<btVector3> TVStack;
- btDeformableMousePickingForce(btScalar k, btScalar d, const btSoftBody::Face& face, btVector3 mouse_pos, btScalar maxForce = 0.3) : m_elasticStiffness(k), m_dampingStiffness(d), m_face(face), m_mouse_pos(mouse_pos), m_maxForce(maxForce)
- {
- }
-
- virtual void addScaledForces(btScalar scale, TVStack& force)
- {
- addScaledDampingForce(scale, force);
- addScaledElasticForce(scale, force);
- }
-
- virtual void addScaledExplicitForce(btScalar scale, TVStack& force)
- {
- addScaledElasticForce(scale, force);
- }
-
- virtual void addScaledDampingForce(btScalar scale, TVStack& force)
- {
- for (int i = 0; i < 3; ++i)
- {
- btVector3 v_diff = m_face.m_n[i]->m_v;
- btVector3 scaled_force = scale * m_dampingStiffness * v_diff;
- if ((m_face.m_n[i]->m_x - m_mouse_pos).norm() > SIMD_EPSILON)
- {
- btVector3 dir = (m_face.m_n[i]->m_x - m_mouse_pos).normalized();
- scaled_force = scale * m_dampingStiffness * v_diff.dot(dir) * dir;
- }
- force[m_face.m_n[i]->index] -= scaled_force;
- }
- }
-
- virtual void addScaledElasticForce(btScalar scale, TVStack& force)
- {
- btScalar scaled_stiffness = scale * m_elasticStiffness;
- for (int i = 0; i < 3; ++i)
- {
- btVector3 dir = (m_face.m_n[i]->m_q - m_mouse_pos);
- btVector3 scaled_force = scaled_stiffness * dir;
- if (scaled_force.safeNorm() > m_maxForce)
- {
- scaled_force.safeNormalize();
- scaled_force *= m_maxForce;
- }
- force[m_face.m_n[i]->index] -= scaled_force;
- }
- }
-
- virtual void addScaledDampingForceDifferential(btScalar scale, const TVStack& dv, TVStack& df)
- {
- btScalar scaled_k_damp = m_dampingStiffness * scale;
- for (int i = 0; i < 3; ++i)
- {
- btVector3 local_scaled_df = scaled_k_damp * dv[m_face.m_n[i]->index];
- if ((m_face.m_n[i]->m_x - m_mouse_pos).norm() > SIMD_EPSILON)
- {
- btVector3 dir = (m_face.m_n[i]->m_x - m_mouse_pos).normalized();
- local_scaled_df= scaled_k_damp * dv[m_face.m_n[i]->index].dot(dir) * dir;
- }
- df[m_face.m_n[i]->index] -= local_scaled_df;
- }
- }
-
- virtual void buildDampingForceDifferentialDiagonal(btScalar scale, TVStack& diagA){}
-
- virtual double totalElasticEnergy(btScalar dt)
- {
- double energy = 0;
- for (int i = 0; i < 3; ++i)
- {
- btVector3 dir = (m_face.m_n[i]->m_q - m_mouse_pos);
- btVector3 scaled_force = m_elasticStiffness * dir;
- if (scaled_force.safeNorm() > m_maxForce)
- {
- scaled_force.safeNormalize();
- scaled_force *= m_maxForce;
- }
- energy += 0.5 * scaled_force.dot(dir);
- }
- return energy;
- }
-
- virtual double totalDampingEnergy(btScalar dt)
- {
- double energy = 0;
- for (int i = 0; i < 3; ++i)
- {
- btVector3 v_diff = m_face.m_n[i]->m_v;
- btVector3 scaled_force = m_dampingStiffness * v_diff;
- if ((m_face.m_n[i]->m_x - m_mouse_pos).norm() > SIMD_EPSILON)
- {
- btVector3 dir = (m_face.m_n[i]->m_x - m_mouse_pos).normalized();
- scaled_force = m_dampingStiffness * v_diff.dot(dir) * dir;
- }
- energy -= scaled_force.dot(m_face.m_n[i]->m_v) / dt;
- }
- return energy;
- }
-
- virtual void addScaledElasticForceDifferential(btScalar scale, const TVStack& dx, TVStack& df)
- {
- //TODO
- }
-
- void setMousePos(const btVector3& p)
- {
- m_mouse_pos = p;
- }
-
- virtual btDeformableLagrangianForceType getForceType()
- {
- return BT_MOUSE_PICKING_FORCE;
- }
-
+ typedef btAlignedObjectArray<btVector3> TVStack;
+ btDeformableMousePickingForce(btScalar k, btScalar d, const btSoftBody::Face& face, btVector3 mouse_pos, btScalar maxForce = 0.3) : m_elasticStiffness(k), m_dampingStiffness(d), m_face(face), m_mouse_pos(mouse_pos), m_maxForce(maxForce)
+ {
+ }
+
+ virtual void addScaledForces(btScalar scale, TVStack& force)
+ {
+ addScaledDampingForce(scale, force);
+ addScaledElasticForce(scale, force);
+ }
+
+ virtual void addScaledExplicitForce(btScalar scale, TVStack& force)
+ {
+ addScaledElasticForce(scale, force);
+ }
+
+ virtual void addScaledDampingForce(btScalar scale, TVStack& force)
+ {
+ for (int i = 0; i < 3; ++i)
+ {
+ btVector3 v_diff = m_face.m_n[i]->m_v;
+ btVector3 scaled_force = scale * m_dampingStiffness * v_diff;
+ if ((m_face.m_n[i]->m_x - m_mouse_pos).norm() > SIMD_EPSILON)
+ {
+ btVector3 dir = (m_face.m_n[i]->m_x - m_mouse_pos).normalized();
+ scaled_force = scale * m_dampingStiffness * v_diff.dot(dir) * dir;
+ }
+ force[m_face.m_n[i]->index] -= scaled_force;
+ }
+ }
+
+ virtual void addScaledElasticForce(btScalar scale, TVStack& force)
+ {
+ btScalar scaled_stiffness = scale * m_elasticStiffness;
+ for (int i = 0; i < 3; ++i)
+ {
+ btVector3 dir = (m_face.m_n[i]->m_q - m_mouse_pos);
+ btVector3 scaled_force = scaled_stiffness * dir;
+ if (scaled_force.safeNorm() > m_maxForce)
+ {
+ scaled_force.safeNormalize();
+ scaled_force *= m_maxForce;
+ }
+ force[m_face.m_n[i]->index] -= scaled_force;
+ }
+ }
+
+ virtual void addScaledDampingForceDifferential(btScalar scale, const TVStack& dv, TVStack& df)
+ {
+ btScalar scaled_k_damp = m_dampingStiffness * scale;
+ for (int i = 0; i < 3; ++i)
+ {
+ btVector3 local_scaled_df = scaled_k_damp * dv[m_face.m_n[i]->index];
+ if ((m_face.m_n[i]->m_x - m_mouse_pos).norm() > SIMD_EPSILON)
+ {
+ btVector3 dir = (m_face.m_n[i]->m_x - m_mouse_pos).normalized();
+ local_scaled_df = scaled_k_damp * dv[m_face.m_n[i]->index].dot(dir) * dir;
+ }
+ df[m_face.m_n[i]->index] -= local_scaled_df;
+ }
+ }
+
+ virtual void buildDampingForceDifferentialDiagonal(btScalar scale, TVStack& diagA) {}
+
+ virtual double totalElasticEnergy(btScalar dt)
+ {
+ double energy = 0;
+ for (int i = 0; i < 3; ++i)
+ {
+ btVector3 dir = (m_face.m_n[i]->m_q - m_mouse_pos);
+ btVector3 scaled_force = m_elasticStiffness * dir;
+ if (scaled_force.safeNorm() > m_maxForce)
+ {
+ scaled_force.safeNormalize();
+ scaled_force *= m_maxForce;
+ }
+ energy += 0.5 * scaled_force.dot(dir);
+ }
+ return energy;
+ }
+
+ virtual double totalDampingEnergy(btScalar dt)
+ {
+ double energy = 0;
+ for (int i = 0; i < 3; ++i)
+ {
+ btVector3 v_diff = m_face.m_n[i]->m_v;
+ btVector3 scaled_force = m_dampingStiffness * v_diff;
+ if ((m_face.m_n[i]->m_x - m_mouse_pos).norm() > SIMD_EPSILON)
+ {
+ btVector3 dir = (m_face.m_n[i]->m_x - m_mouse_pos).normalized();
+ scaled_force = m_dampingStiffness * v_diff.dot(dir) * dir;
+ }
+ energy -= scaled_force.dot(m_face.m_n[i]->m_v) / dt;
+ }
+ return energy;
+ }
+
+ virtual void addScaledElasticForceDifferential(btScalar scale, const TVStack& dx, TVStack& df)
+ {
+ btScalar scaled_stiffness = scale * m_elasticStiffness;
+ for (int i = 0; i < 3; ++i)
+ {
+ btVector3 dir = (m_face.m_n[i]->m_q - m_mouse_pos);
+ btScalar dir_norm = dir.norm();
+ btVector3 dir_normalized = (dir_norm > SIMD_EPSILON) ? dir.normalized() : btVector3(0, 0, 0);
+ int id = m_face.m_n[i]->index;
+ btVector3 dx_diff = dx[id];
+ btScalar r = 0; // rest length is 0 for picking spring
+ btVector3 scaled_df = btVector3(0, 0, 0);
+ if (dir_norm > SIMD_EPSILON)
+ {
+ scaled_df -= scaled_stiffness * dir_normalized.dot(dx_diff) * dir_normalized;
+ scaled_df += scaled_stiffness * dir_normalized.dot(dx_diff) * ((dir_norm - r) / dir_norm) * dir_normalized;
+ scaled_df -= scaled_stiffness * ((dir_norm - r) / dir_norm) * dx_diff;
+ }
+ df[id] += scaled_df;
+ }
+ }
+
+ void setMousePos(const btVector3& p)
+ {
+ m_mouse_pos = p;
+ }
+
+ virtual btDeformableLagrangianForceType getForceType()
+ {
+ return BT_MOUSE_PICKING_FORCE;
+ }
};
#endif /* btMassSpring_h */
diff --git a/thirdparty/bullet/BulletSoftBody/btDeformableMultiBodyConstraintSolver.cpp b/thirdparty/bullet/BulletSoftBody/btDeformableMultiBodyConstraintSolver.cpp
index c8cc47923e..631fd5fbed 100644
--- a/thirdparty/bullet/BulletSoftBody/btDeformableMultiBodyConstraintSolver.cpp
+++ b/thirdparty/bullet/BulletSoftBody/btDeformableMultiBodyConstraintSolver.cpp
@@ -13,131 +13,132 @@
3. This notice may not be removed or altered from any source distribution.
*/
-
#include "btDeformableMultiBodyConstraintSolver.h"
#include <iostream>
// override the iterations method to include deformable/multibody contact
-btScalar btDeformableMultiBodyConstraintSolver::solveDeformableGroupIterations(btCollisionObject** bodies,int numBodies,btCollisionObject** deformableBodies,int numDeformableBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer)
+btScalar btDeformableMultiBodyConstraintSolver::solveDeformableGroupIterations(btCollisionObject** bodies, int numBodies, btCollisionObject** deformableBodies, int numDeformableBodies, btPersistentManifold** manifoldPtr, int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& infoGlobal, btIDebugDraw* debugDrawer)
{
- {
- ///this is a special step to resolve penetrations (just for contacts)
- solveGroupCacheFriendlySplitImpulseIterations(bodies, numBodies, manifoldPtr, numManifolds, constraints, numConstraints, infoGlobal, debugDrawer);
+ {
+ ///this is a special step to resolve penetrations (just for contacts)
+ solveGroupCacheFriendlySplitImpulseIterations(bodies, numBodies, deformableBodies, numDeformableBodies, manifoldPtr, numManifolds, constraints, numConstraints, infoGlobal, debugDrawer);
+
+ int maxIterations = m_maxOverrideNumSolverIterations > infoGlobal.m_numIterations ? m_maxOverrideNumSolverIterations : infoGlobal.m_numIterations;
+ for (int iteration = 0; iteration < maxIterations; iteration++)
+ {
+ // rigid bodies are solved using solver body velocity, but rigid/deformable contact directly uses the velocity of the actual rigid body. So we have to do the following: Solve one iteration of the rigid/rigid contact, get the updated velocity in the solver body and update the velocity of the underlying rigid body. Then solve the rigid/deformable contact. Finally, grab the (once again) updated rigid velocity and update the velocity of the wrapping solver body
- int maxIterations = m_maxOverrideNumSolverIterations > infoGlobal.m_numIterations ? m_maxOverrideNumSolverIterations : infoGlobal.m_numIterations;
- for (int iteration = 0; iteration < maxIterations; iteration++)
- {
- // rigid bodies are solved using solver body velocity, but rigid/deformable contact directly uses the velocity of the actual rigid body. So we have to do the following: Solve one iteration of the rigid/rigid contact, get the updated velocity in the solver body and update the velocity of the underlying rigid body. Then solve the rigid/deformable contact. Finally, grab the (once again) updated rigid velocity and update the velocity of the wrapping solver body
-
- // solve rigid/rigid in solver body
- m_leastSquaresResidual = solveSingleIteration(iteration, bodies, numBodies, manifoldPtr, numManifolds, constraints, numConstraints, infoGlobal, debugDrawer);
- // solver body velocity -> rigid body velocity
- solverBodyWriteBack(infoGlobal);
- btScalar deformableResidual = m_deformableSolver->solveContactConstraints(deformableBodies,numDeformableBodies, infoGlobal);
- // update rigid body velocity in rigid/deformable contact
- m_leastSquaresResidual = btMax(m_leastSquaresResidual, deformableResidual);
- // solver body velocity <- rigid body velocity
- writeToSolverBody(bodies, numBodies, infoGlobal);
-
- if (m_leastSquaresResidual <= infoGlobal.m_leastSquaresResidualThreshold || (iteration >= (maxIterations - 1)))
- {
+ // solve rigid/rigid in solver body
+ m_leastSquaresResidual = solveSingleIteration(iteration, bodies, numBodies, manifoldPtr, numManifolds, constraints, numConstraints, infoGlobal, debugDrawer);
+ // solver body velocity -> rigid body velocity
+ solverBodyWriteBack(infoGlobal);
+ btScalar deformableResidual = m_deformableSolver->solveContactConstraints(deformableBodies, numDeformableBodies, infoGlobal);
+ // update rigid body velocity in rigid/deformable contact
+ m_leastSquaresResidual = btMax(m_leastSquaresResidual, deformableResidual);
+ // solver body velocity <- rigid body velocity
+ writeToSolverBody(bodies, numBodies, infoGlobal);
+
+ if (m_leastSquaresResidual <= infoGlobal.m_leastSquaresResidualThreshold || (iteration >= (maxIterations - 1)))
+ {
#ifdef VERBOSE_RESIDUAL_PRINTF
- printf("residual = %f at iteration #%d\n", m_leastSquaresResidual, iteration);
+ if (iteration >= (maxIterations - 1))
+ printf("residual = %f at iteration #%d\n", m_leastSquaresResidual, iteration);
#endif
- m_analyticsData.m_numSolverCalls++;
- m_analyticsData.m_numIterationsUsed = iteration+1;
- m_analyticsData.m_islandId = -2;
- if (numBodies>0)
- m_analyticsData.m_islandId = bodies[0]->getCompanionId();
- m_analyticsData.m_numBodies = numBodies;
- m_analyticsData.m_numContactManifolds = numManifolds;
- m_analyticsData.m_remainingLeastSquaresResidual = m_leastSquaresResidual;
- break;
- }
- }
- }
- return 0.f;
+ m_analyticsData.m_numSolverCalls++;
+ m_analyticsData.m_numIterationsUsed = iteration + 1;
+ m_analyticsData.m_islandId = -2;
+ if (numBodies > 0)
+ m_analyticsData.m_islandId = bodies[0]->getCompanionId();
+ m_analyticsData.m_numBodies = numBodies;
+ m_analyticsData.m_numContactManifolds = numManifolds;
+ m_analyticsData.m_remainingLeastSquaresResidual = m_leastSquaresResidual;
+ break;
+ }
+ }
+ }
+ return 0.f;
}
-void btDeformableMultiBodyConstraintSolver::solveDeformableBodyGroup(btCollisionObject * *bodies, int numBodies, btCollisionObject * *deformableBodies, int numDeformableBodies, btPersistentManifold** manifold, int numManifolds, btTypedConstraint** constraints, int numConstraints, btMultiBodyConstraint** multiBodyConstraints, int numMultiBodyConstraints, const btContactSolverInfo& info, btIDebugDraw* debugDrawer, btDispatcher* dispatcher)
+void btDeformableMultiBodyConstraintSolver::solveDeformableBodyGroup(btCollisionObject** bodies, int numBodies, btCollisionObject** deformableBodies, int numDeformableBodies, btPersistentManifold** manifold, int numManifolds, btTypedConstraint** constraints, int numConstraints, btMultiBodyConstraint** multiBodyConstraints, int numMultiBodyConstraints, const btContactSolverInfo& info, btIDebugDraw* debugDrawer, btDispatcher* dispatcher)
{
- m_tmpMultiBodyConstraints = multiBodyConstraints;
- m_tmpNumMultiBodyConstraints = numMultiBodyConstraints;
-
- // inherited from MultiBodyConstraintSolver
- solveGroupCacheFriendlySetup(bodies, numBodies, manifold, numManifolds, constraints, numConstraints, info, debugDrawer);
-
- // overriden
- solveDeformableGroupIterations(bodies, numBodies, deformableBodies, numDeformableBodies, manifold, numManifolds, constraints, numConstraints, info, debugDrawer);
-
- // inherited from MultiBodyConstraintSolver
- solveGroupCacheFriendlyFinish(bodies, numBodies, info);
-
- m_tmpMultiBodyConstraints = 0;
- m_tmpNumMultiBodyConstraints = 0;
+ m_tmpMultiBodyConstraints = multiBodyConstraints;
+ m_tmpNumMultiBodyConstraints = numMultiBodyConstraints;
+
+ // inherited from MultiBodyConstraintSolver
+ solveGroupCacheFriendlySetup(bodies, numBodies, manifold, numManifolds, constraints, numConstraints, info, debugDrawer);
+
+ // overriden
+ solveDeformableGroupIterations(bodies, numBodies, deformableBodies, numDeformableBodies, manifold, numManifolds, constraints, numConstraints, info, debugDrawer);
+
+ // inherited from MultiBodyConstraintSolver
+ solveGroupCacheFriendlyFinish(bodies, numBodies, info);
+
+ m_tmpMultiBodyConstraints = 0;
+ m_tmpNumMultiBodyConstraints = 0;
}
void btDeformableMultiBodyConstraintSolver::writeToSolverBody(btCollisionObject** bodies, int numBodies, const btContactSolverInfo& infoGlobal)
{
- for (int i = 0; i < numBodies; i++)
- {
- int bodyId = getOrInitSolverBody(*bodies[i], infoGlobal.m_timeStep);
+ for (int i = 0; i < numBodies; i++)
+ {
+ int bodyId = getOrInitSolverBody(*bodies[i], infoGlobal.m_timeStep);
- btRigidBody* body = btRigidBody::upcast(bodies[i]);
- if (body && body->getInvMass())
- {
- btSolverBody& solverBody = m_tmpSolverBodyPool[bodyId];
- solverBody.m_linearVelocity = body->getLinearVelocity() - solverBody.m_deltaLinearVelocity;
- solverBody.m_angularVelocity = body->getAngularVelocity() - solverBody.m_deltaAngularVelocity;
- }
- }
+ btRigidBody* body = btRigidBody::upcast(bodies[i]);
+ if (body && body->getInvMass())
+ {
+ btSolverBody& solverBody = m_tmpSolverBodyPool[bodyId];
+ solverBody.m_linearVelocity = body->getLinearVelocity() - solverBody.m_deltaLinearVelocity;
+ solverBody.m_angularVelocity = body->getAngularVelocity() - solverBody.m_deltaAngularVelocity;
+ }
+ }
}
void btDeformableMultiBodyConstraintSolver::solverBodyWriteBack(const btContactSolverInfo& infoGlobal)
{
- for (int i = 0; i < m_tmpSolverBodyPool.size(); i++)
- {
- btRigidBody* body = m_tmpSolverBodyPool[i].m_originalBody;
- if (body)
- {
- m_tmpSolverBodyPool[i].m_originalBody->setLinearVelocity(m_tmpSolverBodyPool[i].m_linearVelocity + m_tmpSolverBodyPool[i].m_deltaLinearVelocity);
- m_tmpSolverBodyPool[i].m_originalBody->setAngularVelocity(m_tmpSolverBodyPool[i].m_angularVelocity+m_tmpSolverBodyPool[i].m_deltaAngularVelocity);
- }
- }
+ for (int i = 0; i < m_tmpSolverBodyPool.size(); i++)
+ {
+ btRigidBody* body = m_tmpSolverBodyPool[i].m_originalBody;
+ if (body)
+ {
+ m_tmpSolverBodyPool[i].m_originalBody->setLinearVelocity(m_tmpSolverBodyPool[i].m_linearVelocity + m_tmpSolverBodyPool[i].m_deltaLinearVelocity);
+ m_tmpSolverBodyPool[i].m_originalBody->setAngularVelocity(m_tmpSolverBodyPool[i].m_angularVelocity + m_tmpSolverBodyPool[i].m_deltaAngularVelocity);
+ }
+ }
}
-void btDeformableMultiBodyConstraintSolver::solveGroupCacheFriendlySplitImpulseIterations(btCollisionObject** bodies, int numBodies, btPersistentManifold** manifoldPtr, int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& infoGlobal, btIDebugDraw* debugDrawer)
+void btDeformableMultiBodyConstraintSolver::solveGroupCacheFriendlySplitImpulseIterations(btCollisionObject** bodies, int numBodies, btCollisionObject** deformableBodies, int numDeformableBodies, btPersistentManifold** manifoldPtr, int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& infoGlobal, btIDebugDraw* debugDrawer)
{
- BT_PROFILE("solveGroupCacheFriendlySplitImpulseIterations");
- int iteration;
- if (infoGlobal.m_splitImpulse)
- {
- {
-// m_deformableSolver->splitImpulseSetup(infoGlobal);
- for (iteration = 0; iteration < infoGlobal.m_numIterations; iteration++)
- {
- btScalar leastSquaresResidual = 0.f;
- {
- int numPoolConstraints = m_tmpSolverContactConstraintPool.size();
- int j;
- for (j = 0; j < numPoolConstraints; j++)
- {
- const btSolverConstraint& solveManifold = m_tmpSolverContactConstraintPool[m_orderTmpConstraintPool[j]];
-
- btScalar residual = resolveSplitPenetrationImpulse(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA], m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB], solveManifold);
- leastSquaresResidual = btMax(leastSquaresResidual, residual * residual);
- }
- // solve the position correction between deformable and rigid/multibody
-// btScalar residual = m_deformableSolver->solveSplitImpulse(infoGlobal);
-// leastSquaresResidual = btMax(leastSquaresResidual, residual * residual);
- }
- if (leastSquaresResidual <= infoGlobal.m_leastSquaresResidualThreshold || iteration >= (infoGlobal.m_numIterations - 1))
- {
+ BT_PROFILE("solveGroupCacheFriendlySplitImpulseIterations");
+ int iteration;
+ if (infoGlobal.m_splitImpulse)
+ {
+ {
+ for (iteration = 0; iteration < infoGlobal.m_numIterations; iteration++)
+ {
+ btScalar leastSquaresResidual = 0.f;
+ {
+ int numPoolConstraints = m_tmpSolverContactConstraintPool.size();
+ int j;
+ for (j = 0; j < numPoolConstraints; j++)
+ {
+ const btSolverConstraint& solveManifold = m_tmpSolverContactConstraintPool[m_orderTmpConstraintPool[j]];
+
+ btScalar residual = resolveSplitPenetrationImpulse(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA], m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB], solveManifold);
+ leastSquaresResidual = btMax(leastSquaresResidual, residual * residual);
+ }
+ // solve the position correction between deformable and rigid/multibody
+ // btScalar residual = m_deformableSolver->solveSplitImpulse(infoGlobal);
+ btScalar residual = m_deformableSolver->m_objective->m_projection.solveSplitImpulse(deformableBodies, numDeformableBodies, infoGlobal);
+ leastSquaresResidual = btMax(leastSquaresResidual, residual * residual);
+ }
+ if (leastSquaresResidual <= infoGlobal.m_leastSquaresResidualThreshold || iteration >= (infoGlobal.m_numIterations - 1))
+ {
#ifdef VERBOSE_RESIDUAL_PRINTF
- printf("residual = %f at iteration #%d\n", leastSquaresResidual, iteration);
+ if (iteration >= (infoGlobal.m_numIterations - 1))
+ printf("split impulse residual = %f at iteration #%d\n", leastSquaresResidual, iteration);
#endif
- break;
- }
- }
- }
- }
+ break;
+ }
+ }
+ }
+ }
}
diff --git a/thirdparty/bullet/BulletSoftBody/btDeformableMultiBodyConstraintSolver.h b/thirdparty/bullet/BulletSoftBody/btDeformableMultiBodyConstraintSolver.h
index 0c7cc26a83..94aabce838 100644
--- a/thirdparty/bullet/BulletSoftBody/btDeformableMultiBodyConstraintSolver.h
+++ b/thirdparty/bullet/BulletSoftBody/btDeformableMultiBodyConstraintSolver.h
@@ -13,7 +13,6 @@
3. This notice may not be removed or altered from any source distribution.
*/
-
#ifndef BT_DEFORMABLE_MULTIBODY_CONSTRAINT_SOLVER_H
#define BT_DEFORMABLE_MULTIBODY_CONSTRAINT_SOLVER_H
@@ -32,30 +31,31 @@ class btDeformableBodySolver;
ATTRIBUTE_ALIGNED16(class)
btDeformableMultiBodyConstraintSolver : public btMultiBodyConstraintSolver
{
- btDeformableBodySolver* m_deformableSolver;
-
+ btDeformableBodySolver* m_deformableSolver;
+
protected:
- // override the iterations method to include deformable/multibody contact
-// virtual btScalar solveGroupCacheFriendlyIterations(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer);
-
- // write the velocity of the the solver body to the underlying rigid body
- void solverBodyWriteBack(const btContactSolverInfo& infoGlobal);
-
- // write the velocity of the underlying rigid body to the the the solver body
- void writeToSolverBody(btCollisionObject** bodies, int numBodies, const btContactSolverInfo& infoGlobal);
-
- virtual void solveGroupCacheFriendlySplitImpulseIterations(btCollisionObject** bodies, int numBodies, btPersistentManifold** manifoldPtr, int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& infoGlobal, btIDebugDraw* debugDrawer);
-
- virtual btScalar solveDeformableGroupIterations(btCollisionObject** bodies,int numBodies,btCollisionObject** deformableBodies,int numDeformableBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer);
+ // override the iterations method to include deformable/multibody contact
+ // virtual btScalar solveGroupCacheFriendlyIterations(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer);
+
+ // write the velocity of the the solver body to the underlying rigid body
+ void solverBodyWriteBack(const btContactSolverInfo& infoGlobal);
+
+ // write the velocity of the underlying rigid body to the the the solver body
+ void writeToSolverBody(btCollisionObject * *bodies, int numBodies, const btContactSolverInfo& infoGlobal);
+
+ virtual void solveGroupCacheFriendlySplitImpulseIterations(btCollisionObject * *bodies, int numBodies, btCollisionObject** deformableBodies, int numDeformableBodies, btPersistentManifold** manifoldPtr, int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& infoGlobal, btIDebugDraw* debugDrawer);
+
+ virtual btScalar solveDeformableGroupIterations(btCollisionObject * *bodies, int numBodies, btCollisionObject** deformableBodies, int numDeformableBodies, btPersistentManifold** manifoldPtr, int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& infoGlobal, btIDebugDraw* debugDrawer);
+
public:
- BT_DECLARE_ALIGNED_ALLOCATOR();
-
- void setDeformableSolver(btDeformableBodySolver* deformableSolver)
- {
- m_deformableSolver = deformableSolver;
- }
-
- virtual void solveDeformableBodyGroup(btCollisionObject * *bodies, int numBodies, btCollisionObject * *deformableBodies, int numDeformableBodies, btPersistentManifold** manifold, int numManifolds, btTypedConstraint** constraints, int numConstraints, btMultiBodyConstraint** multiBodyConstraints, int numMultiBodyConstraints, const btContactSolverInfo& info, btIDebugDraw* debugDrawer, btDispatcher* dispatcher);
+ BT_DECLARE_ALIGNED_ALLOCATOR();
+
+ void setDeformableSolver(btDeformableBodySolver * deformableSolver)
+ {
+ m_deformableSolver = deformableSolver;
+ }
+
+ virtual void solveDeformableBodyGroup(btCollisionObject * *bodies, int numBodies, btCollisionObject** deformableBodies, int numDeformableBodies, btPersistentManifold** manifold, int numManifolds, btTypedConstraint** constraints, int numConstraints, btMultiBodyConstraint** multiBodyConstraints, int numMultiBodyConstraints, const btContactSolverInfo& info, btIDebugDraw* debugDrawer, btDispatcher* dispatcher);
};
#endif /* BT_DEFORMABLE_MULTIBODY_CONSTRAINT_SOLVER_H */
diff --git a/thirdparty/bullet/BulletSoftBody/btDeformableMultiBodyDynamicsWorld.cpp b/thirdparty/bullet/BulletSoftBody/btDeformableMultiBodyDynamicsWorld.cpp
index 6b742978ef..983e622b5f 100644
--- a/thirdparty/bullet/BulletSoftBody/btDeformableMultiBodyDynamicsWorld.cpp
+++ b/thirdparty/bullet/BulletSoftBody/btDeformableMultiBodyDynamicsWorld.cpp
@@ -40,8 +40,9 @@ The algorithm also closely resembles the one in http://physbam.stanford.edu/~fed
#include "LinearMath/btQuickprof.h"
#include "btSoftBodyInternals.h"
btDeformableMultiBodyDynamicsWorld::btDeformableMultiBodyDynamicsWorld(btDispatcher* dispatcher, btBroadphaseInterface* pairCache, btDeformableMultiBodyConstraintSolver* constraintSolver, btCollisionConfiguration* collisionConfiguration, btDeformableBodySolver* deformableBodySolver)
-: btMultiBodyDynamicsWorld(dispatcher, pairCache, (btMultiBodyConstraintSolver*)constraintSolver, collisionConfiguration),
-m_deformableBodySolver(deformableBodySolver), m_solverCallback(0)
+ : btMultiBodyDynamicsWorld(dispatcher, pairCache, (btMultiBodyConstraintSolver*)constraintSolver, collisionConfiguration),
+ m_deformableBodySolver(deformableBodySolver),
+ m_solverCallback(0)
{
m_drawFlags = fDrawFlags::Std;
m_drawNodeTree = true;
@@ -52,7 +53,7 @@ m_deformableBodySolver(deformableBodySolver), m_solverCallback(0)
m_sbi.m_sparsesdf.Initialize();
m_sbi.m_sparsesdf.setDefaultVoxelsz(0.005);
m_sbi.m_sparsesdf.Reset();
-
+
m_sbi.air_density = (btScalar)1.2;
m_sbi.water_density = 0;
m_sbi.water_offset = 0;
@@ -61,57 +62,57 @@ m_deformableBodySolver(deformableBodySolver), m_solverCallback(0)
m_internalTime = 0.0;
m_implicit = false;
m_lineSearch = false;
- m_useProjection = true;
+ m_useProjection = false;
m_ccdIterations = 5;
m_solverDeformableBodyIslandCallback = new DeformableBodyInplaceSolverIslandCallback(constraintSolver, dispatcher);
}
btDeformableMultiBodyDynamicsWorld::~btDeformableMultiBodyDynamicsWorld()
{
- delete m_solverDeformableBodyIslandCallback;
+ delete m_solverDeformableBodyIslandCallback;
}
void btDeformableMultiBodyDynamicsWorld::internalSingleStepSimulation(btScalar timeStep)
{
- BT_PROFILE("internalSingleStepSimulation");
- if (0 != m_internalPreTickCallback)
- {
- (*m_internalPreTickCallback)(this, timeStep);
- }
- reinitialize(timeStep);
-
- // add gravity to velocity of rigid and multi bodys
- applyRigidBodyGravity(timeStep);
-
- ///apply gravity and explicit force to velocity, predict motion
- predictUnconstraintMotion(timeStep);
-
- ///perform collision detection that involves rigid/multi bodies
- btMultiBodyDynamicsWorld::performDiscreteCollisionDetection();
-
- btMultiBodyDynamicsWorld::calculateSimulationIslands();
-
- beforeSolverCallbacks(timeStep);
-
- ///solve contact constraints and then deformable bodies momemtum equation
- solveConstraints(timeStep);
-
- afterSolverCallbacks(timeStep);
+ BT_PROFILE("internalSingleStepSimulation");
+ if (0 != m_internalPreTickCallback)
+ {
+ (*m_internalPreTickCallback)(this, timeStep);
+ }
+ reinitialize(timeStep);
+
+ // add gravity to velocity of rigid and multi bodys
+ applyRigidBodyGravity(timeStep);
+
+ ///apply gravity and explicit force to velocity, predict motion
+ predictUnconstraintMotion(timeStep);
+
+ ///perform collision detection that involves rigid/multi bodies
+ btMultiBodyDynamicsWorld::performDiscreteCollisionDetection();
+
+ btMultiBodyDynamicsWorld::calculateSimulationIslands();
+
+ beforeSolverCallbacks(timeStep);
+
+ ///solve contact constraints and then deformable bodies momemtum equation
+ solveConstraints(timeStep);
+
+ afterSolverCallbacks(timeStep);
performDeformableCollisionDetection();
- applyRepulsionForce(timeStep);
+ applyRepulsionForce(timeStep);
+
+ performGeometricCollisions(timeStep);
+
+ integrateTransforms(timeStep);
- performGeometricCollisions(timeStep);
+ ///update vehicle simulation
+ btMultiBodyDynamicsWorld::updateActions(timeStep);
- integrateTransforms(timeStep);
-
- ///update vehicle simulation
- btMultiBodyDynamicsWorld::updateActions(timeStep);
-
- updateActivationState(timeStep);
- // End solver-wise simulation step
- // ///////////////////////////////
+ updateActivationState(timeStep);
+ // End solver-wise simulation step
+ // ///////////////////////////////
}
void btDeformableMultiBodyDynamicsWorld::performDeformableCollisionDetection()
@@ -120,7 +121,7 @@ void btDeformableMultiBodyDynamicsWorld::performDeformableCollisionDetection()
{
m_softBodies[i]->m_softSoftCollision = true;
}
-
+
for (int i = 0; i < m_softBodies.size(); ++i)
{
for (int j = i; j < m_softBodies.size(); ++j)
@@ -128,7 +129,7 @@ void btDeformableMultiBodyDynamicsWorld::performDeformableCollisionDetection()
m_softBodies[i]->defaultCollisionHandler(m_softBodies[j]);
}
}
-
+
for (int i = 0; i < m_softBodies.size(); ++i)
{
m_softBodies[i]->m_softSoftCollision = false;
@@ -137,45 +138,45 @@ void btDeformableMultiBodyDynamicsWorld::performDeformableCollisionDetection()
void btDeformableMultiBodyDynamicsWorld::updateActivationState(btScalar timeStep)
{
- for (int i = 0; i < m_softBodies.size(); i++)
- {
- btSoftBody* psb = m_softBodies[i];
- psb->updateDeactivation(timeStep);
- if (psb->wantsSleeping())
- {
- if (psb->getActivationState() == ACTIVE_TAG)
- psb->setActivationState(WANTS_DEACTIVATION);
- if (psb->getActivationState() == ISLAND_SLEEPING)
- {
- psb->setZeroVelocity();
- }
- }
- else
- {
- if (psb->getActivationState() != DISABLE_DEACTIVATION)
- psb->setActivationState(ACTIVE_TAG);
- }
- }
- btMultiBodyDynamicsWorld::updateActivationState(timeStep);
+ for (int i = 0; i < m_softBodies.size(); i++)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ psb->updateDeactivation(timeStep);
+ if (psb->wantsSleeping())
+ {
+ if (psb->getActivationState() == ACTIVE_TAG)
+ psb->setActivationState(WANTS_DEACTIVATION);
+ if (psb->getActivationState() == ISLAND_SLEEPING)
+ {
+ psb->setZeroVelocity();
+ }
+ }
+ else
+ {
+ if (psb->getActivationState() != DISABLE_DEACTIVATION)
+ psb->setActivationState(ACTIVE_TAG);
+ }
+ }
+ btMultiBodyDynamicsWorld::updateActivationState(timeStep);
}
void btDeformableMultiBodyDynamicsWorld::applyRepulsionForce(btScalar timeStep)
{
- BT_PROFILE("btDeformableMultiBodyDynamicsWorld::applyRepulsionForce");
- for (int i = 0; i < m_softBodies.size(); i++)
- {
- btSoftBody* psb = m_softBodies[i];
- if (psb->isActive())
- {
+ BT_PROFILE("btDeformableMultiBodyDynamicsWorld::applyRepulsionForce");
+ for (int i = 0; i < m_softBodies.size(); i++)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (psb->isActive())
+ {
psb->applyRepulsionForce(timeStep, true);
- }
- }
+ }
+ }
}
void btDeformableMultiBodyDynamicsWorld::performGeometricCollisions(btScalar timeStep)
{
BT_PROFILE("btDeformableMultiBodyDynamicsWorld::performGeometricCollisions");
- // refit the BVH tree for CCD
+ // refit the BVH tree for CCD
for (int i = 0; i < m_softBodies.size(); ++i)
{
btSoftBody* psb = m_softBodies[i];
@@ -214,7 +215,7 @@ void btDeformableMultiBodyDynamicsWorld::performGeometricCollisions(btScalar tim
f.m_vn = (f.m_n[1]->m_v - f.m_n[0]->m_v).cross(f.m_n[2]->m_v - f.m_n[0]->m_v) * timeStep * timeStep;
}
}
- }
+ }
// apply CCD to register new contact points
for (int i = 0; i < m_softBodies.size(); ++i)
@@ -228,7 +229,7 @@ void btDeformableMultiBodyDynamicsWorld::performGeometricCollisions(btScalar tim
m_softBodies[i]->geometricCollisionHandler(m_softBodies[j]);
}
}
- }
+ }
int penetration_count = 0;
for (int i = 0; i < m_softBodies.size(); ++i)
@@ -258,294 +259,292 @@ void btDeformableMultiBodyDynamicsWorld::performGeometricCollisions(btScalar tim
void btDeformableMultiBodyDynamicsWorld::softBodySelfCollision()
{
- BT_PROFILE("btDeformableMultiBodyDynamicsWorld::softBodySelfCollision");
- for (int i = 0; i < m_softBodies.size(); i++)
- {
- btSoftBody* psb = m_softBodies[i];
- if (psb->isActive())
- {
- psb->defaultCollisionHandler(psb);
- }
- }
+ BT_PROFILE("btDeformableMultiBodyDynamicsWorld::softBodySelfCollision");
+ for (int i = 0; i < m_softBodies.size(); i++)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (psb->isActive())
+ {
+ psb->defaultCollisionHandler(psb);
+ }
+ }
}
void btDeformableMultiBodyDynamicsWorld::positionCorrection(btScalar timeStep)
{
- // correct the position of rigid bodies with temporary velocity generated from split impulse
- btContactSolverInfo infoGlobal;
- btVector3 zero(0,0,0);
- for (int i = 0; i < m_nonStaticRigidBodies.size(); ++i)
- {
- btRigidBody* rb = m_nonStaticRigidBodies[i];
- //correct the position/orientation based on push/turn recovery
- btTransform newTransform;
- btVector3 pushVelocity = rb->getPushVelocity();
- btVector3 turnVelocity = rb->getTurnVelocity();
- if (pushVelocity[0] != 0.f || pushVelocity[1] != 0 || pushVelocity[2] != 0 || turnVelocity[0] != 0.f || turnVelocity[1] != 0 || turnVelocity[2] != 0)
- {
- btTransformUtil::integrateTransform(rb->getWorldTransform(), pushVelocity, turnVelocity * infoGlobal.m_splitImpulseTurnErp, timeStep, newTransform);
- rb->setWorldTransform(newTransform);
- rb->setPushVelocity(zero);
- rb->setTurnVelocity(zero);
- }
- }
+ // correct the position of rigid bodies with temporary velocity generated from split impulse
+ btContactSolverInfo infoGlobal;
+ btVector3 zero(0, 0, 0);
+ for (int i = 0; i < m_nonStaticRigidBodies.size(); ++i)
+ {
+ btRigidBody* rb = m_nonStaticRigidBodies[i];
+ //correct the position/orientation based on push/turn recovery
+ btTransform newTransform;
+ btVector3 pushVelocity = rb->getPushVelocity();
+ btVector3 turnVelocity = rb->getTurnVelocity();
+ if (pushVelocity[0] != 0.f || pushVelocity[1] != 0 || pushVelocity[2] != 0 || turnVelocity[0] != 0.f || turnVelocity[1] != 0 || turnVelocity[2] != 0)
+ {
+ btTransformUtil::integrateTransform(rb->getWorldTransform(), pushVelocity, turnVelocity * infoGlobal.m_splitImpulseTurnErp, timeStep, newTransform);
+ rb->setWorldTransform(newTransform);
+ rb->setPushVelocity(zero);
+ rb->setTurnVelocity(zero);
+ }
+ }
}
void btDeformableMultiBodyDynamicsWorld::integrateTransforms(btScalar timeStep)
{
- BT_PROFILE("integrateTransforms");
- positionCorrection(timeStep);
- btMultiBodyDynamicsWorld::integrateTransforms(timeStep);
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- btSoftBody::Node& node = psb->m_nodes[j];
- btScalar maxDisplacement = psb->getWorldInfo()->m_maxDisplacement;
- btScalar clampDeltaV = maxDisplacement / timeStep;
- for (int c = 0; c < 3; c++)
- {
- if (node.m_v[c] > clampDeltaV)
- {
- node.m_v[c] = clampDeltaV;
- }
- if (node.m_v[c] < -clampDeltaV)
- {
- node.m_v[c] = -clampDeltaV;
- }
- }
- node.m_x = node.m_x + timeStep * node.m_v;
- node.m_q = node.m_x;
- node.m_vn = node.m_v;
- }
- // enforce anchor constraints
- for (int j = 0; j < psb->m_deformableAnchors.size();++j)
- {
- btSoftBody::DeformableNodeRigidAnchor& a = psb->m_deformableAnchors[j];
- btSoftBody::Node* n = a.m_node;
- n->m_x = a.m_cti.m_colObj->getWorldTransform() * a.m_local;
-
- // update multibody anchor info
- if (a.m_cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
- {
- btMultiBodyLinkCollider* multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(a.m_cti.m_colObj);
- if (multibodyLinkCol)
- {
- btVector3 nrm;
- const btCollisionShape* shp = multibodyLinkCol->getCollisionShape();
- const btTransform& wtr = multibodyLinkCol->getWorldTransform();
- psb->m_worldInfo->m_sparsesdf.Evaluate(
- wtr.invXform(n->m_x),
- shp,
- nrm,
- 0);
- a.m_cti.m_normal = wtr.getBasis() * nrm;
- btVector3 normal = a.m_cti.m_normal;
- btVector3 t1 = generateUnitOrthogonalVector(normal);
- btVector3 t2 = btCross(normal, t1);
- btMultiBodyJacobianData jacobianData_normal, jacobianData_t1, jacobianData_t2;
- findJacobian(multibodyLinkCol, jacobianData_normal, a.m_node->m_x, normal);
- findJacobian(multibodyLinkCol, jacobianData_t1, a.m_node->m_x, t1);
- findJacobian(multibodyLinkCol, jacobianData_t2, a.m_node->m_x, t2);
-
- btScalar* J_n = &jacobianData_normal.m_jacobians[0];
- btScalar* J_t1 = &jacobianData_t1.m_jacobians[0];
- btScalar* J_t2 = &jacobianData_t2.m_jacobians[0];
-
- btScalar* u_n = &jacobianData_normal.m_deltaVelocitiesUnitImpulse[0];
- btScalar* u_t1 = &jacobianData_t1.m_deltaVelocitiesUnitImpulse[0];
- btScalar* u_t2 = &jacobianData_t2.m_deltaVelocitiesUnitImpulse[0];
-
- btMatrix3x3 rot(normal.getX(), normal.getY(), normal.getZ(),
- t1.getX(), t1.getY(), t1.getZ(),
- t2.getX(), t2.getY(), t2.getZ()); // world frame to local frame
- const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6;
- btMatrix3x3 local_impulse_matrix = (Diagonal(n->m_im) + OuterProduct(J_n, J_t1, J_t2, u_n, u_t1, u_t2, ndof)).inverse();
- a.m_c0 = rot.transpose() * local_impulse_matrix * rot;
- a.jacobianData_normal = jacobianData_normal;
- a.jacobianData_t1 = jacobianData_t1;
- a.jacobianData_t2 = jacobianData_t2;
- a.t1 = t1;
- a.t2 = t2;
- }
- }
- }
- psb->interpolateRenderMesh();
- }
+ BT_PROFILE("integrateTransforms");
+ positionCorrection(timeStep);
+ btMultiBodyDynamicsWorld::integrateTransforms(timeStep);
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ btSoftBody::Node& node = psb->m_nodes[j];
+ btScalar maxDisplacement = psb->getWorldInfo()->m_maxDisplacement;
+ btScalar clampDeltaV = maxDisplacement / timeStep;
+ for (int c = 0; c < 3; c++)
+ {
+ if (node.m_v[c] > clampDeltaV)
+ {
+ node.m_v[c] = clampDeltaV;
+ }
+ if (node.m_v[c] < -clampDeltaV)
+ {
+ node.m_v[c] = -clampDeltaV;
+ }
+ }
+ node.m_x = node.m_x + timeStep * (node.m_v + node.m_splitv);
+ node.m_q = node.m_x;
+ node.m_vn = node.m_v;
+ }
+ // enforce anchor constraints
+ for (int j = 0; j < psb->m_deformableAnchors.size(); ++j)
+ {
+ btSoftBody::DeformableNodeRigidAnchor& a = psb->m_deformableAnchors[j];
+ btSoftBody::Node* n = a.m_node;
+ n->m_x = a.m_cti.m_colObj->getWorldTransform() * a.m_local;
+
+ // update multibody anchor info
+ if (a.m_cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
+ {
+ btMultiBodyLinkCollider* multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(a.m_cti.m_colObj);
+ if (multibodyLinkCol)
+ {
+ btVector3 nrm;
+ const btCollisionShape* shp = multibodyLinkCol->getCollisionShape();
+ const btTransform& wtr = multibodyLinkCol->getWorldTransform();
+ psb->m_worldInfo->m_sparsesdf.Evaluate(
+ wtr.invXform(n->m_x),
+ shp,
+ nrm,
+ 0);
+ a.m_cti.m_normal = wtr.getBasis() * nrm;
+ btVector3 normal = a.m_cti.m_normal;
+ btVector3 t1 = generateUnitOrthogonalVector(normal);
+ btVector3 t2 = btCross(normal, t1);
+ btMultiBodyJacobianData jacobianData_normal, jacobianData_t1, jacobianData_t2;
+ findJacobian(multibodyLinkCol, jacobianData_normal, a.m_node->m_x, normal);
+ findJacobian(multibodyLinkCol, jacobianData_t1, a.m_node->m_x, t1);
+ findJacobian(multibodyLinkCol, jacobianData_t2, a.m_node->m_x, t2);
+
+ btScalar* J_n = &jacobianData_normal.m_jacobians[0];
+ btScalar* J_t1 = &jacobianData_t1.m_jacobians[0];
+ btScalar* J_t2 = &jacobianData_t2.m_jacobians[0];
+
+ btScalar* u_n = &jacobianData_normal.m_deltaVelocitiesUnitImpulse[0];
+ btScalar* u_t1 = &jacobianData_t1.m_deltaVelocitiesUnitImpulse[0];
+ btScalar* u_t2 = &jacobianData_t2.m_deltaVelocitiesUnitImpulse[0];
+
+ btMatrix3x3 rot(normal.getX(), normal.getY(), normal.getZ(),
+ t1.getX(), t1.getY(), t1.getZ(),
+ t2.getX(), t2.getY(), t2.getZ()); // world frame to local frame
+ const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6;
+ btMatrix3x3 local_impulse_matrix = (Diagonal(n->m_im) + OuterProduct(J_n, J_t1, J_t2, u_n, u_t1, u_t2, ndof)).inverse();
+ a.m_c0 = rot.transpose() * local_impulse_matrix * rot;
+ a.jacobianData_normal = jacobianData_normal;
+ a.jacobianData_t1 = jacobianData_t1;
+ a.jacobianData_t2 = jacobianData_t2;
+ a.t1 = t1;
+ a.t2 = t2;
+ }
+ }
+ }
+ psb->interpolateRenderMesh();
+ }
}
void btDeformableMultiBodyDynamicsWorld::solveConstraints(btScalar timeStep)
{
- BT_PROFILE("btDeformableMultiBodyDynamicsWorld::solveConstraints");
- // save v_{n+1}^* velocity after explicit forces
- m_deformableBodySolver->backupVelocity();
-
- // set up constraints among multibodies and between multibodies and deformable bodies
- setupConstraints();
-
- // solve contact constraints
- solveContactConstraints();
-
- // set up the directions in which the velocity does not change in the momentum solve
- if (m_useProjection)
- m_deformableBodySolver->m_objective->m_projection.setProjection();
- else
- m_deformableBodySolver->m_objective->m_projection.setLagrangeMultiplier();
-
- // for explicit scheme, m_backupVelocity = v_{n+1}^*
- // for implicit scheme, m_backupVelocity = v_n
- // Here, set dv = v_{n+1} - v_n for nodes in contact
- m_deformableBodySolver->setupDeformableSolve(m_implicit);
-
- // At this point, dv should be golden for nodes in contact
- // proceed to solve deformable momentum equation
- m_deformableBodySolver->solveDeformableConstraints(timeStep);
+ BT_PROFILE("btDeformableMultiBodyDynamicsWorld::solveConstraints");
+ // save v_{n+1}^* velocity after explicit forces
+ m_deformableBodySolver->backupVelocity();
+
+ // set up constraints among multibodies and between multibodies and deformable bodies
+ setupConstraints();
+
+ // solve contact constraints
+ solveContactConstraints();
+
+ // set up the directions in which the velocity does not change in the momentum solve
+ if (m_useProjection)
+ m_deformableBodySolver->m_objective->m_projection.setProjection();
+ else
+ m_deformableBodySolver->m_objective->m_projection.setLagrangeMultiplier();
+
+ // for explicit scheme, m_backupVelocity = v_{n+1}^*
+ // for implicit scheme, m_backupVelocity = v_n
+ // Here, set dv = v_{n+1} - v_n for nodes in contact
+ m_deformableBodySolver->setupDeformableSolve(m_implicit);
+
+ // At this point, dv should be golden for nodes in contact
+ // proceed to solve deformable momentum equation
+ m_deformableBodySolver->solveDeformableConstraints(timeStep);
}
void btDeformableMultiBodyDynamicsWorld::setupConstraints()
{
- // set up constraints between multibody and deformable bodies
- m_deformableBodySolver->setConstraints(m_solverInfo);
-
- // set up constraints among multibodies
- {
- sortConstraints();
- // setup the solver callback
- btMultiBodyConstraint** sortedMultiBodyConstraints = m_sortedMultiBodyConstraints.size() ? &m_sortedMultiBodyConstraints[0] : 0;
- btTypedConstraint** constraintsPtr = getNumConstraints() ? &m_sortedConstraints[0] : 0;
- m_solverDeformableBodyIslandCallback->setup(&m_solverInfo, constraintsPtr, m_sortedConstraints.size(), sortedMultiBodyConstraints, m_sortedMultiBodyConstraints.size(), getDebugDrawer());
-
- // build islands
- m_islandManager->buildIslands(getCollisionWorld()->getDispatcher(), getCollisionWorld());
- }
+ // set up constraints between multibody and deformable bodies
+ m_deformableBodySolver->setConstraints(m_solverInfo);
+
+ // set up constraints among multibodies
+ {
+ sortConstraints();
+ // setup the solver callback
+ btMultiBodyConstraint** sortedMultiBodyConstraints = m_sortedMultiBodyConstraints.size() ? &m_sortedMultiBodyConstraints[0] : 0;
+ btTypedConstraint** constraintsPtr = getNumConstraints() ? &m_sortedConstraints[0] : 0;
+ m_solverDeformableBodyIslandCallback->setup(&m_solverInfo, constraintsPtr, m_sortedConstraints.size(), sortedMultiBodyConstraints, m_sortedMultiBodyConstraints.size(), getDebugDrawer());
+
+ // build islands
+ m_islandManager->buildIslands(getCollisionWorld()->getDispatcher(), getCollisionWorld());
+ }
}
void btDeformableMultiBodyDynamicsWorld::sortConstraints()
{
- m_sortedConstraints.resize(m_constraints.size());
- int i;
- for (i = 0; i < getNumConstraints(); i++)
- {
- m_sortedConstraints[i] = m_constraints[i];
- }
- m_sortedConstraints.quickSort(btSortConstraintOnIslandPredicate2());
-
- m_sortedMultiBodyConstraints.resize(m_multiBodyConstraints.size());
- for (i = 0; i < m_multiBodyConstraints.size(); i++)
- {
- m_sortedMultiBodyConstraints[i] = m_multiBodyConstraints[i];
- }
- m_sortedMultiBodyConstraints.quickSort(btSortMultiBodyConstraintOnIslandPredicate());
+ m_sortedConstraints.resize(m_constraints.size());
+ int i;
+ for (i = 0; i < getNumConstraints(); i++)
+ {
+ m_sortedConstraints[i] = m_constraints[i];
+ }
+ m_sortedConstraints.quickSort(btSortConstraintOnIslandPredicate2());
+
+ m_sortedMultiBodyConstraints.resize(m_multiBodyConstraints.size());
+ for (i = 0; i < m_multiBodyConstraints.size(); i++)
+ {
+ m_sortedMultiBodyConstraints[i] = m_multiBodyConstraints[i];
+ }
+ m_sortedMultiBodyConstraints.quickSort(btSortMultiBodyConstraintOnIslandPredicate());
}
-
-
+
void btDeformableMultiBodyDynamicsWorld::solveContactConstraints()
{
- // process constraints on each island
- m_islandManager->processIslands(getCollisionWorld()->getDispatcher(), getCollisionWorld(), m_solverDeformableBodyIslandCallback);
-
- // process deferred
- m_solverDeformableBodyIslandCallback->processConstraints();
- m_constraintSolver->allSolved(m_solverInfo, m_debugDrawer);
-
- // write joint feedback
- {
- for (int i = 0; i < this->m_multiBodies.size(); i++)
- {
- btMultiBody* bod = m_multiBodies[i];
-
- bool isSleeping = false;
-
- if (bod->getBaseCollider() && bod->getBaseCollider()->getActivationState() == ISLAND_SLEEPING)
- {
- isSleeping = true;
- }
- for (int b = 0; b < bod->getNumLinks(); b++)
- {
- if (bod->getLink(b).m_collider && bod->getLink(b).m_collider->getActivationState() == ISLAND_SLEEPING)
- isSleeping = true;
- }
-
- if (!isSleeping)
- {
- //useless? they get resized in stepVelocities once again (AND DIFFERENTLY)
- m_scratch_r.resize(bod->getNumLinks() + 1); //multidof? ("Y"s use it and it is used to store qdd)
- m_scratch_v.resize(bod->getNumLinks() + 1);
- m_scratch_m.resize(bod->getNumLinks() + 1);
-
- if (bod->internalNeedsJointFeedback())
- {
- if (!bod->isUsingRK4Integration())
- {
- if (bod->internalNeedsJointFeedback())
- {
- bool isConstraintPass = true;
- bod->computeAccelerationsArticulatedBodyAlgorithmMultiDof(m_solverInfo.m_timeStep, m_scratch_r, m_scratch_v, m_scratch_m, isConstraintPass,
- getSolverInfo().m_jointFeedbackInWorldSpace,
- getSolverInfo().m_jointFeedbackInJointFrame);
- }
- }
- }
- }
- }
- }
-
- for (int i = 0; i < this->m_multiBodies.size(); i++)
- {
- btMultiBody* bod = m_multiBodies[i];
- bod->processDeltaVeeMultiDof2();
- }
+ // process constraints on each island
+ m_islandManager->processIslands(getCollisionWorld()->getDispatcher(), getCollisionWorld(), m_solverDeformableBodyIslandCallback);
+
+ // process deferred
+ m_solverDeformableBodyIslandCallback->processConstraints();
+ m_constraintSolver->allSolved(m_solverInfo, m_debugDrawer);
+
+ // write joint feedback
+ {
+ for (int i = 0; i < this->m_multiBodies.size(); i++)
+ {
+ btMultiBody* bod = m_multiBodies[i];
+
+ bool isSleeping = false;
+
+ if (bod->getBaseCollider() && bod->getBaseCollider()->getActivationState() == ISLAND_SLEEPING)
+ {
+ isSleeping = true;
+ }
+ for (int b = 0; b < bod->getNumLinks(); b++)
+ {
+ if (bod->getLink(b).m_collider && bod->getLink(b).m_collider->getActivationState() == ISLAND_SLEEPING)
+ isSleeping = true;
+ }
+
+ if (!isSleeping)
+ {
+ //useless? they get resized in stepVelocities once again (AND DIFFERENTLY)
+ m_scratch_r.resize(bod->getNumLinks() + 1); //multidof? ("Y"s use it and it is used to store qdd)
+ m_scratch_v.resize(bod->getNumLinks() + 1);
+ m_scratch_m.resize(bod->getNumLinks() + 1);
+
+ if (bod->internalNeedsJointFeedback())
+ {
+ if (!bod->isUsingRK4Integration())
+ {
+ if (bod->internalNeedsJointFeedback())
+ {
+ bool isConstraintPass = true;
+ bod->computeAccelerationsArticulatedBodyAlgorithmMultiDof(m_solverInfo.m_timeStep, m_scratch_r, m_scratch_v, m_scratch_m, isConstraintPass,
+ getSolverInfo().m_jointFeedbackInWorldSpace,
+ getSolverInfo().m_jointFeedbackInJointFrame);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < this->m_multiBodies.size(); i++)
+ {
+ btMultiBody* bod = m_multiBodies[i];
+ bod->processDeltaVeeMultiDof2();
+ }
}
void btDeformableMultiBodyDynamicsWorld::addSoftBody(btSoftBody* body, int collisionFilterGroup, int collisionFilterMask)
{
- m_softBodies.push_back(body);
-
- // Set the soft body solver that will deal with this body
- // to be the world's solver
- body->setSoftBodySolver(m_deformableBodySolver);
-
- btCollisionWorld::addCollisionObject(body,
- collisionFilterGroup,
- collisionFilterMask);
+ m_softBodies.push_back(body);
+
+ // Set the soft body solver that will deal with this body
+ // to be the world's solver
+ body->setSoftBodySolver(m_deformableBodySolver);
+
+ btCollisionWorld::addCollisionObject(body,
+ collisionFilterGroup,
+ collisionFilterMask);
}
void btDeformableMultiBodyDynamicsWorld::predictUnconstraintMotion(btScalar timeStep)
{
- BT_PROFILE("predictUnconstraintMotion");
- btMultiBodyDynamicsWorld::predictUnconstraintMotion(timeStep);
- m_deformableBodySolver->predictMotion(timeStep);
+ BT_PROFILE("predictUnconstraintMotion");
+ btMultiBodyDynamicsWorld::predictUnconstraintMotion(timeStep);
+ m_deformableBodySolver->predictMotion(timeStep);
}
void btDeformableMultiBodyDynamicsWorld::reinitialize(btScalar timeStep)
{
- m_internalTime += timeStep;
- m_deformableBodySolver->setImplicit(m_implicit);
- m_deformableBodySolver->setLineSearch(m_lineSearch);
- m_deformableBodySolver->reinitialize(m_softBodies, timeStep);
- btDispatcherInfo& dispatchInfo = btMultiBodyDynamicsWorld::getDispatchInfo();
- dispatchInfo.m_timeStep = timeStep;
- dispatchInfo.m_stepCount = 0;
- dispatchInfo.m_debugDraw = btMultiBodyDynamicsWorld::getDebugDrawer();
- btMultiBodyDynamicsWorld::getSolverInfo().m_timeStep = timeStep;
- if (m_useProjection)
- {
- m_deformableBodySolver->m_useProjection = true;
-// m_deformableBodySolver->m_objective->m_projection.m_useStrainLimiting = true;
- m_deformableBodySolver->m_objective->m_preconditioner = m_deformableBodySolver->m_objective->m_massPreconditioner;
- }
- else
- {
- m_deformableBodySolver->m_objective->m_preconditioner = m_deformableBodySolver->m_objective->m_KKTPreconditioner;
- }
-
+ m_internalTime += timeStep;
+ m_deformableBodySolver->setImplicit(m_implicit);
+ m_deformableBodySolver->setLineSearch(m_lineSearch);
+ m_deformableBodySolver->reinitialize(m_softBodies, timeStep);
+ btDispatcherInfo& dispatchInfo = btMultiBodyDynamicsWorld::getDispatchInfo();
+ dispatchInfo.m_timeStep = timeStep;
+ dispatchInfo.m_stepCount = 0;
+ dispatchInfo.m_debugDraw = btMultiBodyDynamicsWorld::getDebugDrawer();
+ btMultiBodyDynamicsWorld::getSolverInfo().m_timeStep = timeStep;
+ if (m_useProjection)
+ {
+ m_deformableBodySolver->m_useProjection = true;
+ m_deformableBodySolver->m_objective->m_projection.m_useStrainLimiting = true;
+ m_deformableBodySolver->m_objective->m_preconditioner = m_deformableBodySolver->m_objective->m_massPreconditioner;
+ }
+ else
+ {
+ m_deformableBodySolver->m_useProjection = false;
+ m_deformableBodySolver->m_objective->m_projection.m_useStrainLimiting = false;
+ m_deformableBodySolver->m_objective->m_preconditioner = m_deformableBodySolver->m_objective->m_KKTPreconditioner;
+ }
}
-
void btDeformableMultiBodyDynamicsWorld::debugDrawWorld()
{
-
btMultiBodyDynamicsWorld::debugDrawWorld();
for (int i = 0; i < getSoftBodyArray().size(); i++)
@@ -556,253 +555,260 @@ void btDeformableMultiBodyDynamicsWorld::debugDrawWorld()
btSoftBodyHelpers::Draw(psb, getDebugDrawer(), getDrawFlags());
}
}
-
-
}
void btDeformableMultiBodyDynamicsWorld::applyRigidBodyGravity(btScalar timeStep)
{
- // Gravity is applied in stepSimulation and then cleared here and then applied here and then cleared here again
- // so that 1) gravity is applied to velocity before constraint solve and 2) gravity is applied in each substep
- // when there are multiple substeps
- btMultiBodyDynamicsWorld::applyGravity();
- // integrate rigid body gravity
- for (int i = 0; i < m_nonStaticRigidBodies.size(); ++i)
- {
- btRigidBody* rb = m_nonStaticRigidBodies[i];
- rb->integrateVelocities(timeStep);
- }
-
- // integrate multibody gravity
- {
- forwardKinematics();
- clearMultiBodyConstraintForces();
- {
- for (int i = 0; i < this->m_multiBodies.size(); i++)
- {
- btMultiBody* bod = m_multiBodies[i];
-
- bool isSleeping = false;
-
- if (bod->getBaseCollider() && bod->getBaseCollider()->getActivationState() == ISLAND_SLEEPING)
- {
- isSleeping = true;
- }
- for (int b = 0; b < bod->getNumLinks(); b++)
- {
- if (bod->getLink(b).m_collider && bod->getLink(b).m_collider->getActivationState() == ISLAND_SLEEPING)
- isSleeping = true;
- }
-
- if (!isSleeping)
- {
- m_scratch_r.resize(bod->getNumLinks() + 1);
- m_scratch_v.resize(bod->getNumLinks() + 1);
- m_scratch_m.resize(bod->getNumLinks() + 1);
- bool isConstraintPass = false;
- {
- if (!bod->isUsingRK4Integration())
- {
- bod->computeAccelerationsArticulatedBodyAlgorithmMultiDof(m_solverInfo.m_timeStep,
- m_scratch_r, m_scratch_v, m_scratch_m,isConstraintPass,
- getSolverInfo().m_jointFeedbackInWorldSpace,
- getSolverInfo().m_jointFeedbackInJointFrame);
- }
- else
- {
- btAssert(" RK4Integration is not supported" );
- }
- }
- }
- }
- }
- }
- clearGravity();
+ // Gravity is applied in stepSimulation and then cleared here and then applied here and then cleared here again
+ // so that 1) gravity is applied to velocity before constraint solve and 2) gravity is applied in each substep
+ // when there are multiple substeps
+ btMultiBodyDynamicsWorld::applyGravity();
+ // integrate rigid body gravity
+ for (int i = 0; i < m_nonStaticRigidBodies.size(); ++i)
+ {
+ btRigidBody* rb = m_nonStaticRigidBodies[i];
+ rb->integrateVelocities(timeStep);
+ }
+
+ // integrate multibody gravity
+ {
+ forwardKinematics();
+ clearMultiBodyConstraintForces();
+ {
+ for (int i = 0; i < this->m_multiBodies.size(); i++)
+ {
+ btMultiBody* bod = m_multiBodies[i];
+
+ bool isSleeping = false;
+
+ if (bod->getBaseCollider() && bod->getBaseCollider()->getActivationState() == ISLAND_SLEEPING)
+ {
+ isSleeping = true;
+ }
+ for (int b = 0; b < bod->getNumLinks(); b++)
+ {
+ if (bod->getLink(b).m_collider && bod->getLink(b).m_collider->getActivationState() == ISLAND_SLEEPING)
+ isSleeping = true;
+ }
+
+ if (!isSleeping)
+ {
+ m_scratch_r.resize(bod->getNumLinks() + 1);
+ m_scratch_v.resize(bod->getNumLinks() + 1);
+ m_scratch_m.resize(bod->getNumLinks() + 1);
+ bool isConstraintPass = false;
+ {
+ if (!bod->isUsingRK4Integration())
+ {
+ bod->computeAccelerationsArticulatedBodyAlgorithmMultiDof(m_solverInfo.m_timeStep,
+ m_scratch_r, m_scratch_v, m_scratch_m, isConstraintPass,
+ getSolverInfo().m_jointFeedbackInWorldSpace,
+ getSolverInfo().m_jointFeedbackInJointFrame);
+ }
+ else
+ {
+ btAssert(" RK4Integration is not supported");
+ }
+ }
+ }
+ }
+ }
+ }
+ clearGravity();
}
void btDeformableMultiBodyDynamicsWorld::clearGravity()
{
- BT_PROFILE("btMultiBody clearGravity");
- // clear rigid body gravity
- for (int i = 0; i < m_nonStaticRigidBodies.size(); i++)
- {
- btRigidBody* body = m_nonStaticRigidBodies[i];
- if (body->isActive())
- {
- body->clearGravity();
- }
- }
- // clear multibody gravity
- for (int i = 0; i < this->m_multiBodies.size(); i++)
- {
- btMultiBody* bod = m_multiBodies[i];
-
- bool isSleeping = false;
-
- if (bod->getBaseCollider() && bod->getBaseCollider()->getActivationState() == ISLAND_SLEEPING)
- {
- isSleeping = true;
- }
- for (int b = 0; b < bod->getNumLinks(); b++)
- {
- if (bod->getLink(b).m_collider && bod->getLink(b).m_collider->getActivationState() == ISLAND_SLEEPING)
- isSleeping = true;
- }
-
- if (!isSleeping)
- {
- bod->addBaseForce(-m_gravity * bod->getBaseMass());
-
- for (int j = 0; j < bod->getNumLinks(); ++j)
- {
- bod->addLinkForce(j, -m_gravity * bod->getLinkMass(j));
- }
- }
- }
+ BT_PROFILE("btMultiBody clearGravity");
+ // clear rigid body gravity
+ for (int i = 0; i < m_nonStaticRigidBodies.size(); i++)
+ {
+ btRigidBody* body = m_nonStaticRigidBodies[i];
+ if (body->isActive())
+ {
+ body->clearGravity();
+ }
+ }
+ // clear multibody gravity
+ for (int i = 0; i < this->m_multiBodies.size(); i++)
+ {
+ btMultiBody* bod = m_multiBodies[i];
+
+ bool isSleeping = false;
+
+ if (bod->getBaseCollider() && bod->getBaseCollider()->getActivationState() == ISLAND_SLEEPING)
+ {
+ isSleeping = true;
+ }
+ for (int b = 0; b < bod->getNumLinks(); b++)
+ {
+ if (bod->getLink(b).m_collider && bod->getLink(b).m_collider->getActivationState() == ISLAND_SLEEPING)
+ isSleeping = true;
+ }
+
+ if (!isSleeping)
+ {
+ bod->addBaseForce(-m_gravity * bod->getBaseMass());
+
+ for (int j = 0; j < bod->getNumLinks(); ++j)
+ {
+ bod->addLinkForce(j, -m_gravity * bod->getLinkMass(j));
+ }
+ }
+ }
}
void btDeformableMultiBodyDynamicsWorld::beforeSolverCallbacks(btScalar timeStep)
{
- if (0 != m_internalTickCallback)
- {
- (*m_internalTickCallback)(this, timeStep);
- }
-
- if (0 != m_solverCallback)
- {
- (*m_solverCallback)(m_internalTime, this);
- }
+ if (0 != m_internalTickCallback)
+ {
+ (*m_internalTickCallback)(this, timeStep);
+ }
+
+ if (0 != m_solverCallback)
+ {
+ (*m_solverCallback)(m_internalTime, this);
+ }
}
void btDeformableMultiBodyDynamicsWorld::afterSolverCallbacks(btScalar timeStep)
{
- if (0 != m_solverCallback)
- {
- (*m_solverCallback)(m_internalTime, this);
- }
+ if (0 != m_solverCallback)
+ {
+ (*m_solverCallback)(m_internalTime, this);
+ }
}
void btDeformableMultiBodyDynamicsWorld::addForce(btSoftBody* psb, btDeformableLagrangianForce* force)
{
- btAlignedObjectArray<btDeformableLagrangianForce*>& forces = m_deformableBodySolver->m_objective->m_lf;
- bool added = false;
- for (int i = 0; i < forces.size(); ++i)
- {
- if (forces[i]->getForceType() == force->getForceType())
- {
- forces[i]->addSoftBody(psb);
- added = true;
- break;
- }
- }
- if (!added)
- {
- force->addSoftBody(psb);
- force->setIndices(m_deformableBodySolver->m_objective->getIndices());
- forces.push_back(force);
- }
+ btAlignedObjectArray<btDeformableLagrangianForce*>& forces = m_deformableBodySolver->m_objective->m_lf;
+ bool added = false;
+ for (int i = 0; i < forces.size(); ++i)
+ {
+ if (forces[i]->getForceType() == force->getForceType())
+ {
+ forces[i]->addSoftBody(psb);
+ added = true;
+ break;
+ }
+ }
+ if (!added)
+ {
+ force->addSoftBody(psb);
+ force->setIndices(m_deformableBodySolver->m_objective->getIndices());
+ forces.push_back(force);
+ }
}
void btDeformableMultiBodyDynamicsWorld::removeForce(btSoftBody* psb, btDeformableLagrangianForce* force)
{
- btAlignedObjectArray<btDeformableLagrangianForce*>& forces = m_deformableBodySolver->m_objective->m_lf;
- int removed_index = -1;
- for (int i = 0; i < forces.size(); ++i)
- {
- if (forces[i]->getForceType() == force->getForceType())
- {
- forces[i]->removeSoftBody(psb);
- if (forces[i]->m_softBodies.size() == 0)
- removed_index = i;
- break;
- }
- }
- if (removed_index >= 0)
- forces.removeAtIndex(removed_index);
+ btAlignedObjectArray<btDeformableLagrangianForce*>& forces = m_deformableBodySolver->m_objective->m_lf;
+ int removed_index = -1;
+ for (int i = 0; i < forces.size(); ++i)
+ {
+ if (forces[i]->getForceType() == force->getForceType())
+ {
+ forces[i]->removeSoftBody(psb);
+ if (forces[i]->m_softBodies.size() == 0)
+ removed_index = i;
+ break;
+ }
+ }
+ if (removed_index >= 0)
+ forces.removeAtIndex(removed_index);
+}
+
+void btDeformableMultiBodyDynamicsWorld::removeSoftBodyForce(btSoftBody* psb)
+{
+ btAlignedObjectArray<btDeformableLagrangianForce*>& forces = m_deformableBodySolver->m_objective->m_lf;
+ for (int i = 0; i < forces.size(); ++i)
+ {
+ forces[i]->removeSoftBody(psb);
+ }
}
void btDeformableMultiBodyDynamicsWorld::removeSoftBody(btSoftBody* body)
{
- m_softBodies.remove(body);
- btCollisionWorld::removeCollisionObject(body);
- // force a reinitialize so that node indices get updated.
- m_deformableBodySolver->reinitialize(m_softBodies, btScalar(-1));
+ removeSoftBodyForce(body);
+ m_softBodies.remove(body);
+ btCollisionWorld::removeCollisionObject(body);
+ // force a reinitialize so that node indices get updated.
+ m_deformableBodySolver->reinitialize(m_softBodies, btScalar(-1));
}
void btDeformableMultiBodyDynamicsWorld::removeCollisionObject(btCollisionObject* collisionObject)
{
- btSoftBody* body = btSoftBody::upcast(collisionObject);
- if (body)
- removeSoftBody(body);
- else
- btDiscreteDynamicsWorld::removeCollisionObject(collisionObject);
+ btSoftBody* body = btSoftBody::upcast(collisionObject);
+ if (body)
+ removeSoftBody(body);
+ else
+ btDiscreteDynamicsWorld::removeCollisionObject(collisionObject);
}
-
int btDeformableMultiBodyDynamicsWorld::stepSimulation(btScalar timeStep, int maxSubSteps, btScalar fixedTimeStep)
{
- startProfiling(timeStep);
-
- int numSimulationSubSteps = 0;
-
- if (maxSubSteps)
- {
- //fixed timestep with interpolation
- m_fixedTimeStep = fixedTimeStep;
- m_localTime += timeStep;
- if (m_localTime >= fixedTimeStep)
- {
- numSimulationSubSteps = int(m_localTime / fixedTimeStep);
- m_localTime -= numSimulationSubSteps * fixedTimeStep;
- }
- }
- else
- {
- //variable timestep
- fixedTimeStep = timeStep;
- m_localTime = m_latencyMotionStateInterpolation ? 0 : timeStep;
- m_fixedTimeStep = 0;
- if (btFuzzyZero(timeStep))
- {
- numSimulationSubSteps = 0;
- maxSubSteps = 0;
- }
- else
- {
- numSimulationSubSteps = 1;
- maxSubSteps = 1;
- }
- }
-
- //process some debugging flags
- if (getDebugDrawer())
- {
- btIDebugDraw* debugDrawer = getDebugDrawer();
- gDisableDeactivation = (debugDrawer->getDebugMode() & btIDebugDraw::DBG_NoDeactivation) != 0;
- }
- if (numSimulationSubSteps)
- {
- //clamp the number of substeps, to prevent simulation grinding spiralling down to a halt
- int clampedSimulationSteps = (numSimulationSubSteps > maxSubSteps) ? maxSubSteps : numSimulationSubSteps;
-
- saveKinematicState(fixedTimeStep * clampedSimulationSteps);
-
- for (int i = 0; i < clampedSimulationSteps; i++)
- {
- internalSingleStepSimulation(fixedTimeStep);
- synchronizeMotionStates();
- }
- }
- else
- {
- synchronizeMotionStates();
- }
-
- clearForces();
-
+ startProfiling(timeStep);
+
+ int numSimulationSubSteps = 0;
+
+ if (maxSubSteps)
+ {
+ //fixed timestep with interpolation
+ m_fixedTimeStep = fixedTimeStep;
+ m_localTime += timeStep;
+ if (m_localTime >= fixedTimeStep)
+ {
+ numSimulationSubSteps = int(m_localTime / fixedTimeStep);
+ m_localTime -= numSimulationSubSteps * fixedTimeStep;
+ }
+ }
+ else
+ {
+ //variable timestep
+ fixedTimeStep = timeStep;
+ m_localTime = m_latencyMotionStateInterpolation ? 0 : timeStep;
+ m_fixedTimeStep = 0;
+ if (btFuzzyZero(timeStep))
+ {
+ numSimulationSubSteps = 0;
+ maxSubSteps = 0;
+ }
+ else
+ {
+ numSimulationSubSteps = 1;
+ maxSubSteps = 1;
+ }
+ }
+
+ //process some debugging flags
+ if (getDebugDrawer())
+ {
+ btIDebugDraw* debugDrawer = getDebugDrawer();
+ gDisableDeactivation = (debugDrawer->getDebugMode() & btIDebugDraw::DBG_NoDeactivation) != 0;
+ }
+ if (numSimulationSubSteps)
+ {
+ //clamp the number of substeps, to prevent simulation grinding spiralling down to a halt
+ int clampedSimulationSteps = (numSimulationSubSteps > maxSubSteps) ? maxSubSteps : numSimulationSubSteps;
+
+ saveKinematicState(fixedTimeStep * clampedSimulationSteps);
+
+ for (int i = 0; i < clampedSimulationSteps; i++)
+ {
+ internalSingleStepSimulation(fixedTimeStep);
+ synchronizeMotionStates();
+ }
+ }
+ else
+ {
+ synchronizeMotionStates();
+ }
+
+ clearForces();
+
#ifndef BT_NO_PROFILE
- CProfileManager::Increment_Frame_Counter();
+ CProfileManager::Increment_Frame_Counter();
#endif //BT_NO_PROFILE
-
- return numSimulationSubSteps;
+
+ return numSimulationSubSteps;
}
diff --git a/thirdparty/bullet/BulletSoftBody/btDeformableMultiBodyDynamicsWorld.h b/thirdparty/bullet/BulletSoftBody/btDeformableMultiBodyDynamicsWorld.h
index 76b58a0378..4b7069aac7 100644
--- a/thirdparty/bullet/BulletSoftBody/btDeformableMultiBodyDynamicsWorld.h
+++ b/thirdparty/bullet/BulletSoftBody/btDeformableMultiBodyDynamicsWorld.h
@@ -36,185 +36,192 @@ typedef btAlignedObjectArray<btSoftBody*> btSoftBodyArray;
class btDeformableMultiBodyDynamicsWorld : public btMultiBodyDynamicsWorld
{
- typedef btAlignedObjectArray<btVector3> TVStack;
- ///Solver classes that encapsulate multiple deformable bodies for solving
- btDeformableBodySolver* m_deformableBodySolver;
- btSoftBodyArray m_softBodies;
- int m_drawFlags;
- bool m_drawNodeTree;
- bool m_drawFaceTree;
- bool m_drawClusterTree;
- btSoftBodyWorldInfo m_sbi;
- btScalar m_internalTime;
- int m_ccdIterations;
- bool m_implicit;
- bool m_lineSearch;
- bool m_useProjection;
- DeformableBodyInplaceSolverIslandCallback* m_solverDeformableBodyIslandCallback;
-
- typedef void (*btSolverCallback)(btScalar time, btDeformableMultiBodyDynamicsWorld* world);
- btSolverCallback m_solverCallback;
-
+ typedef btAlignedObjectArray<btVector3> TVStack;
+ ///Solver classes that encapsulate multiple deformable bodies for solving
+ btDeformableBodySolver* m_deformableBodySolver;
+ btSoftBodyArray m_softBodies;
+ int m_drawFlags;
+ bool m_drawNodeTree;
+ bool m_drawFaceTree;
+ bool m_drawClusterTree;
+ btSoftBodyWorldInfo m_sbi;
+ btScalar m_internalTime;
+ int m_ccdIterations;
+ bool m_implicit;
+ bool m_lineSearch;
+ bool m_useProjection;
+ DeformableBodyInplaceSolverIslandCallback* m_solverDeformableBodyIslandCallback;
+
+ typedef void (*btSolverCallback)(btScalar time, btDeformableMultiBodyDynamicsWorld* world);
+ btSolverCallback m_solverCallback;
+
protected:
- virtual void internalSingleStepSimulation(btScalar timeStep);
-
- virtual void integrateTransforms(btScalar timeStep);
-
- void positionCorrection(btScalar timeStep);
-
- void solveConstraints(btScalar timeStep);
-
- void updateActivationState(btScalar timeStep);
-
- void clearGravity();
-
+ virtual void internalSingleStepSimulation(btScalar timeStep);
+
+ virtual void integrateTransforms(btScalar timeStep);
+
+ void positionCorrection(btScalar timeStep);
+
+ void solveConstraints(btScalar timeStep);
+
+ void updateActivationState(btScalar timeStep);
+
+ void clearGravity();
+
public:
btDeformableMultiBodyDynamicsWorld(btDispatcher* dispatcher, btBroadphaseInterface* pairCache, btDeformableMultiBodyConstraintSolver* constraintSolver, btCollisionConfiguration* collisionConfiguration, btDeformableBodySolver* deformableBodySolver = 0);
- virtual int stepSimulation(btScalar timeStep, int maxSubSteps = 1, btScalar fixedTimeStep = btScalar(1.) / btScalar(60.));
+ virtual int stepSimulation(btScalar timeStep, int maxSubSteps = 1, btScalar fixedTimeStep = btScalar(1.) / btScalar(60.));
virtual void debugDrawWorld();
- void setSolverCallback(btSolverCallback cb)
- {
- m_solverCallback = cb;
- }
-
- virtual ~btDeformableMultiBodyDynamicsWorld();
-
- virtual btMultiBodyDynamicsWorld* getMultiBodyDynamicsWorld()
- {
- return (btMultiBodyDynamicsWorld*)(this);
- }
-
- virtual const btMultiBodyDynamicsWorld* getMultiBodyDynamicsWorld() const
- {
- return (const btMultiBodyDynamicsWorld*)(this);
- }
-
- virtual btDynamicsWorldType getWorldType() const
- {
- return BT_DEFORMABLE_MULTIBODY_DYNAMICS_WORLD;
- }
-
- virtual void predictUnconstraintMotion(btScalar timeStep);
-
- virtual void addSoftBody(btSoftBody* body, int collisionFilterGroup = btBroadphaseProxy::DefaultFilter, int collisionFilterMask = btBroadphaseProxy::AllFilter);
-
- btSoftBodyArray& getSoftBodyArray()
- {
- return m_softBodies;
- }
-
- const btSoftBodyArray& getSoftBodyArray() const
- {
- return m_softBodies;
- }
-
- btSoftBodyWorldInfo& getWorldInfo()
- {
- return m_sbi;
- }
-
- const btSoftBodyWorldInfo& getWorldInfo() const
- {
- return m_sbi;
- }
-
- void reinitialize(btScalar timeStep);
-
- void applyRigidBodyGravity(btScalar timeStep);
-
- void beforeSolverCallbacks(btScalar timeStep);
-
- void afterSolverCallbacks(btScalar timeStep);
-
- void addForce(btSoftBody* psb, btDeformableLagrangianForce* force);
-
- void removeForce(btSoftBody* psb, btDeformableLagrangianForce* force);
-
- void removeSoftBody(btSoftBody* body);
-
- void removeCollisionObject(btCollisionObject* collisionObject);
-
- int getDrawFlags() const { return (m_drawFlags); }
- void setDrawFlags(int f) { m_drawFlags = f; }
-
- void setupConstraints();
-
- void performDeformableCollisionDetection();
-
- void solveMultiBodyConstraints();
-
- void solveContactConstraints();
-
- void sortConstraints();
-
- void softBodySelfCollision();
-
- void setImplicit(bool implicit)
- {
- m_implicit = implicit;
- }
-
- void setLineSearch(bool lineSearch)
- {
- m_lineSearch = lineSearch;
- }
-
- void applyRepulsionForce(btScalar timeStep);
-
- void performGeometricCollisions(btScalar timeStep);
-
- struct btDeformableSingleRayCallback : public btBroadphaseRayCallback
- {
- btVector3 m_rayFromWorld;
- btVector3 m_rayToWorld;
- btTransform m_rayFromTrans;
- btTransform m_rayToTrans;
- btVector3 m_hitNormal;
-
- const btDeformableMultiBodyDynamicsWorld* m_world;
- btCollisionWorld::RayResultCallback& m_resultCallback;
-
- btDeformableSingleRayCallback(const btVector3& rayFromWorld, const btVector3& rayToWorld, const btDeformableMultiBodyDynamicsWorld* world, btCollisionWorld::RayResultCallback& resultCallback)
- : m_rayFromWorld(rayFromWorld),
- m_rayToWorld(rayToWorld),
- m_world(world),
- m_resultCallback(resultCallback)
- {
- m_rayFromTrans.setIdentity();
- m_rayFromTrans.setOrigin(m_rayFromWorld);
- m_rayToTrans.setIdentity();
- m_rayToTrans.setOrigin(m_rayToWorld);
-
- btVector3 rayDir = (rayToWorld - rayFromWorld);
-
- rayDir.normalize();
- ///what about division by zero? --> just set rayDirection[i] to INF/1e30
- m_rayDirectionInverse[0] = rayDir[0] == btScalar(0.0) ? btScalar(1e30) : btScalar(1.0) / rayDir[0];
- m_rayDirectionInverse[1] = rayDir[1] == btScalar(0.0) ? btScalar(1e30) : btScalar(1.0) / rayDir[1];
- m_rayDirectionInverse[2] = rayDir[2] == btScalar(0.0) ? btScalar(1e30) : btScalar(1.0) / rayDir[2];
- m_signs[0] = m_rayDirectionInverse[0] < 0.0;
- m_signs[1] = m_rayDirectionInverse[1] < 0.0;
- m_signs[2] = m_rayDirectionInverse[2] < 0.0;
-
- m_lambda_max = rayDir.dot(m_rayToWorld - m_rayFromWorld);
- }
-
- virtual bool process(const btBroadphaseProxy* proxy)
- {
- ///terminate further ray tests, once the closestHitFraction reached zero
- if (m_resultCallback.m_closestHitFraction == btScalar(0.f))
- return false;
-
- btCollisionObject* collisionObject = (btCollisionObject*)proxy->m_clientObject;
-
- //only perform raycast if filterMask matches
- if (m_resultCallback.needsCollision(collisionObject->getBroadphaseHandle()))
- {
- //RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject();
- //btVector3 collisionObjectAabbMin,collisionObjectAabbMax;
+ void setSolverCallback(btSolverCallback cb)
+ {
+ m_solverCallback = cb;
+ }
+
+ virtual ~btDeformableMultiBodyDynamicsWorld();
+
+ virtual btMultiBodyDynamicsWorld* getMultiBodyDynamicsWorld()
+ {
+ return (btMultiBodyDynamicsWorld*)(this);
+ }
+
+ virtual const btMultiBodyDynamicsWorld* getMultiBodyDynamicsWorld() const
+ {
+ return (const btMultiBodyDynamicsWorld*)(this);
+ }
+
+ virtual btDynamicsWorldType getWorldType() const
+ {
+ return BT_DEFORMABLE_MULTIBODY_DYNAMICS_WORLD;
+ }
+
+ virtual void predictUnconstraintMotion(btScalar timeStep);
+
+ virtual void addSoftBody(btSoftBody* body, int collisionFilterGroup = btBroadphaseProxy::DefaultFilter, int collisionFilterMask = btBroadphaseProxy::AllFilter);
+
+ btSoftBodyArray& getSoftBodyArray()
+ {
+ return m_softBodies;
+ }
+
+ const btSoftBodyArray& getSoftBodyArray() const
+ {
+ return m_softBodies;
+ }
+
+ btSoftBodyWorldInfo& getWorldInfo()
+ {
+ return m_sbi;
+ }
+
+ const btSoftBodyWorldInfo& getWorldInfo() const
+ {
+ return m_sbi;
+ }
+
+ void reinitialize(btScalar timeStep);
+
+ void applyRigidBodyGravity(btScalar timeStep);
+
+ void beforeSolverCallbacks(btScalar timeStep);
+
+ void afterSolverCallbacks(btScalar timeStep);
+
+ void addForce(btSoftBody* psb, btDeformableLagrangianForce* force);
+
+ void removeForce(btSoftBody* psb, btDeformableLagrangianForce* force);
+
+ void removeSoftBodyForce(btSoftBody* psb);
+
+ void removeSoftBody(btSoftBody* body);
+
+ void removeCollisionObject(btCollisionObject* collisionObject);
+
+ int getDrawFlags() const { return (m_drawFlags); }
+ void setDrawFlags(int f) { m_drawFlags = f; }
+
+ void setupConstraints();
+
+ void performDeformableCollisionDetection();
+
+ void solveMultiBodyConstraints();
+
+ void solveContactConstraints();
+
+ void sortConstraints();
+
+ void softBodySelfCollision();
+
+ void setImplicit(bool implicit)
+ {
+ m_implicit = implicit;
+ }
+
+ void setLineSearch(bool lineSearch)
+ {
+ m_lineSearch = lineSearch;
+ }
+
+ void setUseProjection(bool useProjection)
+ {
+ m_useProjection = useProjection;
+ }
+
+ void applyRepulsionForce(btScalar timeStep);
+
+ void performGeometricCollisions(btScalar timeStep);
+
+ struct btDeformableSingleRayCallback : public btBroadphaseRayCallback
+ {
+ btVector3 m_rayFromWorld;
+ btVector3 m_rayToWorld;
+ btTransform m_rayFromTrans;
+ btTransform m_rayToTrans;
+ btVector3 m_hitNormal;
+
+ const btDeformableMultiBodyDynamicsWorld* m_world;
+ btCollisionWorld::RayResultCallback& m_resultCallback;
+
+ btDeformableSingleRayCallback(const btVector3& rayFromWorld, const btVector3& rayToWorld, const btDeformableMultiBodyDynamicsWorld* world, btCollisionWorld::RayResultCallback& resultCallback)
+ : m_rayFromWorld(rayFromWorld),
+ m_rayToWorld(rayToWorld),
+ m_world(world),
+ m_resultCallback(resultCallback)
+ {
+ m_rayFromTrans.setIdentity();
+ m_rayFromTrans.setOrigin(m_rayFromWorld);
+ m_rayToTrans.setIdentity();
+ m_rayToTrans.setOrigin(m_rayToWorld);
+
+ btVector3 rayDir = (rayToWorld - rayFromWorld);
+
+ rayDir.normalize();
+ ///what about division by zero? --> just set rayDirection[i] to INF/1e30
+ m_rayDirectionInverse[0] = rayDir[0] == btScalar(0.0) ? btScalar(1e30) : btScalar(1.0) / rayDir[0];
+ m_rayDirectionInverse[1] = rayDir[1] == btScalar(0.0) ? btScalar(1e30) : btScalar(1.0) / rayDir[1];
+ m_rayDirectionInverse[2] = rayDir[2] == btScalar(0.0) ? btScalar(1e30) : btScalar(1.0) / rayDir[2];
+ m_signs[0] = m_rayDirectionInverse[0] < 0.0;
+ m_signs[1] = m_rayDirectionInverse[1] < 0.0;
+ m_signs[2] = m_rayDirectionInverse[2] < 0.0;
+
+ m_lambda_max = rayDir.dot(m_rayToWorld - m_rayFromWorld);
+ }
+
+ virtual bool process(const btBroadphaseProxy* proxy)
+ {
+ ///terminate further ray tests, once the closestHitFraction reached zero
+ if (m_resultCallback.m_closestHitFraction == btScalar(0.f))
+ return false;
+
+ btCollisionObject* collisionObject = (btCollisionObject*)proxy->m_clientObject;
+
+ //only perform raycast if filterMask matches
+ if (m_resultCallback.needsCollision(collisionObject->getBroadphaseHandle()))
+ {
+ //RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject();
+ //btVector3 collisionObjectAabbMin,collisionObjectAabbMax;
#if 0
#ifdef RECALCULATE_AABB
btVector3 collisionObjectAabbMin,collisionObjectAabbMax;
@@ -225,87 +232,85 @@ public:
const btVector3& collisionObjectAabbMax = collisionObject->getBroadphaseHandle()->m_aabbMax;
#endif
#endif
- //btScalar hitLambda = m_resultCallback.m_closestHitFraction;
- //culling already done by broadphase
- //if (btRayAabb(m_rayFromWorld,m_rayToWorld,collisionObjectAabbMin,collisionObjectAabbMax,hitLambda,m_hitNormal))
- {
- m_world->rayTestSingle(m_rayFromTrans, m_rayToTrans,
- collisionObject,
- collisionObject->getCollisionShape(),
- collisionObject->getWorldTransform(),
- m_resultCallback);
- }
- }
- return true;
- }
- };
-
-
-
- void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback) const
- {
- BT_PROFILE("rayTest");
- /// use the broadphase to accelerate the search for objects, based on their aabb
- /// and for each object with ray-aabb overlap, perform an exact ray test
- btDeformableSingleRayCallback rayCB(rayFromWorld, rayToWorld, this, resultCallback);
-
+ //btScalar hitLambda = m_resultCallback.m_closestHitFraction;
+ //culling already done by broadphase
+ //if (btRayAabb(m_rayFromWorld,m_rayToWorld,collisionObjectAabbMin,collisionObjectAabbMax,hitLambda,m_hitNormal))
+ {
+ m_world->rayTestSingle(m_rayFromTrans, m_rayToTrans,
+ collisionObject,
+ collisionObject->getCollisionShape(),
+ collisionObject->getWorldTransform(),
+ m_resultCallback);
+ }
+ }
+ return true;
+ }
+ };
+
+ void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback) const
+ {
+ BT_PROFILE("rayTest");
+ /// use the broadphase to accelerate the search for objects, based on their aabb
+ /// and for each object with ray-aabb overlap, perform an exact ray test
+ btDeformableSingleRayCallback rayCB(rayFromWorld, rayToWorld, this, resultCallback);
+
#ifndef USE_BRUTEFORCE_RAYBROADPHASE
- m_broadphasePairCache->rayTest(rayFromWorld, rayToWorld, rayCB);
+ m_broadphasePairCache->rayTest(rayFromWorld, rayToWorld, rayCB);
#else
- for (int i = 0; i < this->getNumCollisionObjects(); i++)
- {
- rayCB.process(m_collisionObjects[i]->getBroadphaseHandle());
- }
+ for (int i = 0; i < this->getNumCollisionObjects(); i++)
+ {
+ rayCB.process(m_collisionObjects[i]->getBroadphaseHandle());
+ }
#endif //USE_BRUTEFORCE_RAYBROADPHASE
- }
-
- void rayTestSingle(const btTransform& rayFromTrans, const btTransform& rayToTrans,
- btCollisionObject* collisionObject,
- const btCollisionShape* collisionShape,
- const btTransform& colObjWorldTransform,
- RayResultCallback& resultCallback) const
- {
- if (collisionShape->isSoftBody())
- {
- btSoftBody* softBody = btSoftBody::upcast(collisionObject);
- if (softBody)
- {
- btSoftBody::sRayCast softResult;
- if (softBody->rayFaceTest(rayFromTrans.getOrigin(), rayToTrans.getOrigin(), softResult))
- {
- if (softResult.fraction <= resultCallback.m_closestHitFraction)
- {
- btCollisionWorld::LocalShapeInfo shapeInfo;
- shapeInfo.m_shapePart = 0;
- shapeInfo.m_triangleIndex = softResult.index;
- // get the normal
- btVector3 rayDir = rayToTrans.getOrigin() - rayFromTrans.getOrigin();
- btVector3 normal = -rayDir;
- normal.normalize();
- {
- normal = softBody->m_faces[softResult.index].m_normal;
- if (normal.dot(rayDir) > 0)
- {
- // normal always point toward origin of the ray
- normal = -normal;
- }
- }
-
- btCollisionWorld::LocalRayResult rayResult(collisionObject,
- &shapeInfo,
- normal,
- softResult.fraction);
- bool normalInWorldSpace = true;
- resultCallback.addSingleResult(rayResult, normalInWorldSpace);
- }
- }
- }
- }
- else
- {
- btCollisionWorld::rayTestSingle(rayFromTrans, rayToTrans, collisionObject, collisionShape, colObjWorldTransform, resultCallback);
- }
- }
+ }
+
+ void rayTestSingle(const btTransform& rayFromTrans, const btTransform& rayToTrans,
+ btCollisionObject* collisionObject,
+ const btCollisionShape* collisionShape,
+ const btTransform& colObjWorldTransform,
+ RayResultCallback& resultCallback) const
+ {
+ if (collisionShape->isSoftBody())
+ {
+ btSoftBody* softBody = btSoftBody::upcast(collisionObject);
+ if (softBody)
+ {
+ btSoftBody::sRayCast softResult;
+ if (softBody->rayFaceTest(rayFromTrans.getOrigin(), rayToTrans.getOrigin(), softResult))
+ {
+ if (softResult.fraction <= resultCallback.m_closestHitFraction)
+ {
+ btCollisionWorld::LocalShapeInfo shapeInfo;
+ shapeInfo.m_shapePart = 0;
+ shapeInfo.m_triangleIndex = softResult.index;
+ // get the normal
+ btVector3 rayDir = rayToTrans.getOrigin() - rayFromTrans.getOrigin();
+ btVector3 normal = -rayDir;
+ normal.normalize();
+ {
+ normal = softBody->m_faces[softResult.index].m_normal;
+ if (normal.dot(rayDir) > 0)
+ {
+ // normal always point toward origin of the ray
+ normal = -normal;
+ }
+ }
+
+ btCollisionWorld::LocalRayResult rayResult(collisionObject,
+ &shapeInfo,
+ normal,
+ softResult.fraction);
+ bool normalInWorldSpace = true;
+ resultCallback.addSingleResult(rayResult, normalInWorldSpace);
+ }
+ }
+ }
+ }
+ else
+ {
+ btCollisionWorld::rayTestSingle(rayFromTrans, rayToTrans, collisionObject, collisionShape, colObjWorldTransform, resultCallback);
+ }
+ }
};
#endif //BT_DEFORMABLE_MULTIBODY_DYNAMICS_WORLD_H
diff --git a/thirdparty/bullet/BulletSoftBody/btDeformableNeoHookeanForce.h b/thirdparty/bullet/BulletSoftBody/btDeformableNeoHookeanForce.h
index d89bc4aca4..60798c5bcd 100644
--- a/thirdparty/bullet/BulletSoftBody/btDeformableNeoHookeanForce.h
+++ b/thirdparty/bullet/BulletSoftBody/btDeformableNeoHookeanForce.h
@@ -23,30 +23,30 @@ subject to the following restrictions:
class btDeformableNeoHookeanForce : public btDeformableLagrangianForce
{
public:
- typedef btAlignedObjectArray<btVector3> TVStack;
- btScalar m_mu, m_lambda; // Lame Parameters
- btScalar m_E, m_nu; // Young's modulus and Poisson ratio
- btScalar m_mu_damp, m_lambda_damp;
- btDeformableNeoHookeanForce(): m_mu(1), m_lambda(1)
- {
- btScalar damping = 0.05;
- m_mu_damp = damping * m_mu;
- m_lambda_damp = damping * m_lambda;
+ typedef btAlignedObjectArray<btVector3> TVStack;
+ btScalar m_mu, m_lambda; // Lame Parameters
+ btScalar m_E, m_nu; // Young's modulus and Poisson ratio
+ btScalar m_mu_damp, m_lambda_damp;
+ btDeformableNeoHookeanForce() : m_mu(1), m_lambda(1)
+ {
+ btScalar damping = 0.05;
+ m_mu_damp = damping * m_mu;
+ m_lambda_damp = damping * m_lambda;
updateYoungsModulusAndPoissonRatio();
- }
-
- btDeformableNeoHookeanForce(btScalar mu, btScalar lambda, btScalar damping = 0.05): m_mu(mu), m_lambda(lambda)
- {
- m_mu_damp = damping * m_mu;
- m_lambda_damp = damping * m_lambda;
+ }
+
+ btDeformableNeoHookeanForce(btScalar mu, btScalar lambda, btScalar damping = 0.05) : m_mu(mu), m_lambda(lambda)
+ {
+ m_mu_damp = damping * m_mu;
+ m_lambda_damp = damping * m_lambda;
updateYoungsModulusAndPoissonRatio();
- }
+ }
void updateYoungsModulusAndPoissonRatio()
{
// conversion from Lame Parameters to Young's modulus and Poisson ratio
// https://en.wikipedia.org/wiki/Lam%C3%A9_parameters
- m_E = m_mu * (3*m_lambda + 2*m_mu)/(m_lambda + m_mu);
+ m_E = m_mu * (3 * m_lambda + 2 * m_mu) / (m_lambda + m_mu);
m_nu = m_lambda * 0.5 / (m_mu + m_lambda);
}
@@ -55,21 +55,21 @@ public:
// conversion from Young's modulus and Poisson ratio to Lame Parameters
// https://en.wikipedia.org/wiki/Lam%C3%A9_parameters
m_mu = m_E * 0.5 / (1 + m_nu);
- m_lambda = m_E * m_nu / ((1 + m_nu) * (1- 2*m_nu));
+ m_lambda = m_E * m_nu / ((1 + m_nu) * (1 - 2 * m_nu));
}
- void setYoungsModulus(btScalar E)
- {
+ void setYoungsModulus(btScalar E)
+ {
m_E = E;
updateLameParameters();
- }
+ }
void setPoissonRatio(btScalar nu)
{
m_nu = nu;
updateLameParameters();
}
-
+
void setDamping(btScalar damping)
{
m_mu_damp = damping * m_mu;
@@ -83,339 +83,338 @@ public:
updateYoungsModulusAndPoissonRatio();
}
- virtual void addScaledForces(btScalar scale, TVStack& force)
- {
- addScaledDampingForce(scale, force);
- addScaledElasticForce(scale, force);
- }
-
- virtual void addScaledExplicitForce(btScalar scale, TVStack& force)
- {
- addScaledElasticForce(scale, force);
- }
-
- // The damping matrix is calculated using the time n state as described in https://www.math.ucla.edu/~jteran/papers/GSSJT15.pdf to allow line search
- virtual void addScaledDampingForce(btScalar scale, TVStack& force)
- {
- if (m_mu_damp == 0 && m_lambda_damp == 0)
- return;
- int numNodes = getNumNodes();
- btAssert(numNodes <= force.size());
- btVector3 grad_N_hat_1st_col = btVector3(-1,-1,-1);
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- continue;
- }
- for (int j = 0; j < psb->m_tetras.size(); ++j)
- {
- btSoftBody::Tetra& tetra = psb->m_tetras[j];
- btSoftBody::Node* node0 = tetra.m_n[0];
- btSoftBody::Node* node1 = tetra.m_n[1];
- btSoftBody::Node* node2 = tetra.m_n[2];
- btSoftBody::Node* node3 = tetra.m_n[3];
- size_t id0 = node0->index;
- size_t id1 = node1->index;
- size_t id2 = node2->index;
- size_t id3 = node3->index;
- btMatrix3x3 dF = DsFromVelocity(node0, node1, node2, node3) * tetra.m_Dm_inverse;
- btMatrix3x3 I;
- I.setIdentity();
- btMatrix3x3 dP = (dF + dF.transpose()) * m_mu_damp + I * (dF[0][0]+dF[1][1]+dF[2][2]) * m_lambda_damp;
-// firstPiolaDampingDifferential(psb->m_tetraScratchesTn[j], dF, dP);
- btVector3 df_on_node0 = dP * (tetra.m_Dm_inverse.transpose()*grad_N_hat_1st_col);
- btMatrix3x3 df_on_node123 = dP * tetra.m_Dm_inverse.transpose();
+ virtual void addScaledForces(btScalar scale, TVStack& force)
+ {
+ addScaledDampingForce(scale, force);
+ addScaledElasticForce(scale, force);
+ }
+
+ virtual void addScaledExplicitForce(btScalar scale, TVStack& force)
+ {
+ addScaledElasticForce(scale, force);
+ }
+
+ // The damping matrix is calculated using the time n state as described in https://www.math.ucla.edu/~jteran/papers/GSSJT15.pdf to allow line search
+ virtual void addScaledDampingForce(btScalar scale, TVStack& force)
+ {
+ if (m_mu_damp == 0 && m_lambda_damp == 0)
+ return;
+ int numNodes = getNumNodes();
+ btAssert(numNodes <= force.size());
+ btVector3 grad_N_hat_1st_col = btVector3(-1, -1, -1);
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ continue;
+ }
+ for (int j = 0; j < psb->m_tetras.size(); ++j)
+ {
+ btSoftBody::Tetra& tetra = psb->m_tetras[j];
+ btSoftBody::Node* node0 = tetra.m_n[0];
+ btSoftBody::Node* node1 = tetra.m_n[1];
+ btSoftBody::Node* node2 = tetra.m_n[2];
+ btSoftBody::Node* node3 = tetra.m_n[3];
+ size_t id0 = node0->index;
+ size_t id1 = node1->index;
+ size_t id2 = node2->index;
+ size_t id3 = node3->index;
+ btMatrix3x3 dF = DsFromVelocity(node0, node1, node2, node3) * tetra.m_Dm_inverse;
+ btMatrix3x3 I;
+ I.setIdentity();
+ btMatrix3x3 dP = (dF + dF.transpose()) * m_mu_damp + I * (dF[0][0] + dF[1][1] + dF[2][2]) * m_lambda_damp;
+ // firstPiolaDampingDifferential(psb->m_tetraScratchesTn[j], dF, dP);
+ btVector3 df_on_node0 = dP * (tetra.m_Dm_inverse.transpose() * grad_N_hat_1st_col);
+ btMatrix3x3 df_on_node123 = dP * tetra.m_Dm_inverse.transpose();
+
+ // damping force differential
+ btScalar scale1 = scale * tetra.m_element_measure;
+ force[id0] -= scale1 * df_on_node0;
+ force[id1] -= scale1 * df_on_node123.getColumn(0);
+ force[id2] -= scale1 * df_on_node123.getColumn(1);
+ force[id3] -= scale1 * df_on_node123.getColumn(2);
+ }
+ }
+ }
+
+ virtual double totalElasticEnergy(btScalar dt)
+ {
+ double energy = 0;
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ continue;
+ }
+ for (int j = 0; j < psb->m_tetraScratches.size(); ++j)
+ {
+ btSoftBody::Tetra& tetra = psb->m_tetras[j];
+ btSoftBody::TetraScratch& s = psb->m_tetraScratches[j];
+ energy += tetra.m_element_measure * elasticEnergyDensity(s);
+ }
+ }
+ return energy;
+ }
+
+ // The damping energy is formulated as in https://www.math.ucla.edu/~jteran/papers/GSSJT15.pdf to allow line search
+ virtual double totalDampingEnergy(btScalar dt)
+ {
+ double energy = 0;
+ int sz = 0;
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ continue;
+ }
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ sz = btMax(sz, psb->m_nodes[j].index);
+ }
+ }
+ TVStack dampingForce;
+ dampingForce.resize(sz + 1);
+ for (int i = 0; i < dampingForce.size(); ++i)
+ dampingForce[i].setZero();
+ addScaledDampingForce(0.5, dampingForce);
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ const btSoftBody::Node& node = psb->m_nodes[j];
+ energy -= dampingForce[node.index].dot(node.m_v) / dt;
+ }
+ }
+ return energy;
+ }
+
+ double elasticEnergyDensity(const btSoftBody::TetraScratch& s)
+ {
+ double density = 0;
+ density += m_mu * 0.5 * (s.m_trace - 3.);
+ density += m_lambda * 0.5 * (s.m_J - 1. - 0.75 * m_mu / m_lambda) * (s.m_J - 1. - 0.75 * m_mu / m_lambda);
+ density -= m_mu * 0.5 * log(s.m_trace + 1);
+ return density;
+ }
- // damping force differential
- btScalar scale1 = scale * tetra.m_element_measure;
- force[id0] -= scale1 * df_on_node0;
- force[id1] -= scale1 * df_on_node123.getColumn(0);
- force[id2] -= scale1 * df_on_node123.getColumn(1);
- force[id3] -= scale1 * df_on_node123.getColumn(2);
- }
- }
- }
-
- virtual double totalElasticEnergy(btScalar dt)
- {
- double energy = 0;
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- continue;
- }
- for (int j = 0; j < psb->m_tetraScratches.size(); ++j)
- {
- btSoftBody::Tetra& tetra = psb->m_tetras[j];
- btSoftBody::TetraScratch& s = psb->m_tetraScratches[j];
- energy += tetra.m_element_measure * elasticEnergyDensity(s);
- }
- }
- return energy;
- }
-
- // The damping energy is formulated as in https://www.math.ucla.edu/~jteran/papers/GSSJT15.pdf to allow line search
- virtual double totalDampingEnergy(btScalar dt)
- {
- double energy = 0;
- int sz = 0;
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- continue;
- }
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- sz = btMax(sz, psb->m_nodes[j].index);
- }
- }
- TVStack dampingForce;
- dampingForce.resize(sz+1);
- for (int i = 0; i < dampingForce.size(); ++i)
- dampingForce[i].setZero();
- addScaledDampingForce(0.5, dampingForce);
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- const btSoftBody::Node& node = psb->m_nodes[j];
- energy -= dampingForce[node.index].dot(node.m_v) / dt;
- }
- }
- return energy;
- }
-
- double elasticEnergyDensity(const btSoftBody::TetraScratch& s)
- {
- double density = 0;
- density += m_mu * 0.5 * (s.m_trace - 3.);
- density += m_lambda * 0.5 * (s.m_J - 1. - 0.75 * m_mu / m_lambda)* (s.m_J - 1. - 0.75 * m_mu / m_lambda);
- density -= m_mu * 0.5 * log(s.m_trace+1);
- return density;
- }
-
- virtual void addScaledElasticForce(btScalar scale, TVStack& force)
- {
- int numNodes = getNumNodes();
- btAssert(numNodes <= force.size());
- btVector3 grad_N_hat_1st_col = btVector3(-1,-1,-1);
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- continue;
- }
- btScalar max_p = psb->m_cfg.m_maxStress;
- for (int j = 0; j < psb->m_tetras.size(); ++j)
- {
- btSoftBody::Tetra& tetra = psb->m_tetras[j];
- btMatrix3x3 P;
- firstPiola(psb->m_tetraScratches[j],P);
+ virtual void addScaledElasticForce(btScalar scale, TVStack& force)
+ {
+ int numNodes = getNumNodes();
+ btAssert(numNodes <= force.size());
+ btVector3 grad_N_hat_1st_col = btVector3(-1, -1, -1);
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ continue;
+ }
+ btScalar max_p = psb->m_cfg.m_maxStress;
+ for (int j = 0; j < psb->m_tetras.size(); ++j)
+ {
+ btSoftBody::Tetra& tetra = psb->m_tetras[j];
+ btMatrix3x3 P;
+ firstPiola(psb->m_tetraScratches[j], P);
#ifdef USE_SVD
- if (max_p > 0)
- {
- // since we want to clamp the principal stress to max_p, we only need to
- // calculate SVD when sigma_0^2 + sigma_1^2 + sigma_2^2 > max_p * max_p
- btScalar trPTP = (P[0].length2() + P[1].length2() + P[2].length2());
- if (trPTP > max_p * max_p)
- {
- btMatrix3x3 U, V;
- btVector3 sigma;
- singularValueDecomposition(P, U, sigma, V);
- sigma[0] = btMin(sigma[0], max_p);
- sigma[1] = btMin(sigma[1], max_p);
- sigma[2] = btMin(sigma[2], max_p);
- sigma[0] = btMax(sigma[0], -max_p);
- sigma[1] = btMax(sigma[1], -max_p);
- sigma[2] = btMax(sigma[2], -max_p);
- btMatrix3x3 Sigma;
- Sigma.setIdentity();
- Sigma[0][0] = sigma[0];
- Sigma[1][1] = sigma[1];
- Sigma[2][2] = sigma[2];
- P = U * Sigma * V.transpose();
- }
- }
+ if (max_p > 0)
+ {
+ // since we want to clamp the principal stress to max_p, we only need to
+ // calculate SVD when sigma_0^2 + sigma_1^2 + sigma_2^2 > max_p * max_p
+ btScalar trPTP = (P[0].length2() + P[1].length2() + P[2].length2());
+ if (trPTP > max_p * max_p)
+ {
+ btMatrix3x3 U, V;
+ btVector3 sigma;
+ singularValueDecomposition(P, U, sigma, V);
+ sigma[0] = btMin(sigma[0], max_p);
+ sigma[1] = btMin(sigma[1], max_p);
+ sigma[2] = btMin(sigma[2], max_p);
+ sigma[0] = btMax(sigma[0], -max_p);
+ sigma[1] = btMax(sigma[1], -max_p);
+ sigma[2] = btMax(sigma[2], -max_p);
+ btMatrix3x3 Sigma;
+ Sigma.setIdentity();
+ Sigma[0][0] = sigma[0];
+ Sigma[1][1] = sigma[1];
+ Sigma[2][2] = sigma[2];
+ P = U * Sigma * V.transpose();
+ }
+ }
#endif
-// btVector3 force_on_node0 = P * (tetra.m_Dm_inverse.transpose()*grad_N_hat_1st_col);
- btMatrix3x3 force_on_node123 = P * tetra.m_Dm_inverse.transpose();
- btVector3 force_on_node0 = force_on_node123 * grad_N_hat_1st_col;
-
- btSoftBody::Node* node0 = tetra.m_n[0];
- btSoftBody::Node* node1 = tetra.m_n[1];
- btSoftBody::Node* node2 = tetra.m_n[2];
- btSoftBody::Node* node3 = tetra.m_n[3];
- size_t id0 = node0->index;
- size_t id1 = node1->index;
- size_t id2 = node2->index;
- size_t id3 = node3->index;
-
- // elastic force
- btScalar scale1 = scale * tetra.m_element_measure;
- force[id0] -= scale1 * force_on_node0;
- force[id1] -= scale1 * force_on_node123.getColumn(0);
- force[id2] -= scale1 * force_on_node123.getColumn(1);
- force[id3] -= scale1 * force_on_node123.getColumn(2);
- }
- }
- }
-
- // The damping matrix is calculated using the time n state as described in https://www.math.ucla.edu/~jteran/papers/GSSJT15.pdf to allow line search
- virtual void addScaledDampingForceDifferential(btScalar scale, const TVStack& dv, TVStack& df)
- {
- if (m_mu_damp == 0 && m_lambda_damp == 0)
- return;
- int numNodes = getNumNodes();
- btAssert(numNodes <= df.size());
- btVector3 grad_N_hat_1st_col = btVector3(-1,-1,-1);
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- continue;
- }
- for (int j = 0; j < psb->m_tetras.size(); ++j)
- {
- btSoftBody::Tetra& tetra = psb->m_tetras[j];
- btSoftBody::Node* node0 = tetra.m_n[0];
- btSoftBody::Node* node1 = tetra.m_n[1];
- btSoftBody::Node* node2 = tetra.m_n[2];
- btSoftBody::Node* node3 = tetra.m_n[3];
- size_t id0 = node0->index;
- size_t id1 = node1->index;
- size_t id2 = node2->index;
- size_t id3 = node3->index;
- btMatrix3x3 dF = Ds(id0, id1, id2, id3, dv) * tetra.m_Dm_inverse;
- btMatrix3x3 I;
- I.setIdentity();
- btMatrix3x3 dP = (dF + dF.transpose()) * m_mu_damp + I * (dF[0][0]+dF[1][1]+dF[2][2]) * m_lambda_damp;
-// firstPiolaDampingDifferential(psb->m_tetraScratchesTn[j], dF, dP);
-// btVector3 df_on_node0 = dP * (tetra.m_Dm_inverse.transpose()*grad_N_hat_1st_col);
- btMatrix3x3 df_on_node123 = dP * tetra.m_Dm_inverse.transpose();
- btVector3 df_on_node0 = df_on_node123 * grad_N_hat_1st_col;
+ // btVector3 force_on_node0 = P * (tetra.m_Dm_inverse.transpose()*grad_N_hat_1st_col);
+ btMatrix3x3 force_on_node123 = P * tetra.m_Dm_inverse.transpose();
+ btVector3 force_on_node0 = force_on_node123 * grad_N_hat_1st_col;
+
+ btSoftBody::Node* node0 = tetra.m_n[0];
+ btSoftBody::Node* node1 = tetra.m_n[1];
+ btSoftBody::Node* node2 = tetra.m_n[2];
+ btSoftBody::Node* node3 = tetra.m_n[3];
+ size_t id0 = node0->index;
+ size_t id1 = node1->index;
+ size_t id2 = node2->index;
+ size_t id3 = node3->index;
+
+ // elastic force
+ btScalar scale1 = scale * tetra.m_element_measure;
+ force[id0] -= scale1 * force_on_node0;
+ force[id1] -= scale1 * force_on_node123.getColumn(0);
+ force[id2] -= scale1 * force_on_node123.getColumn(1);
+ force[id3] -= scale1 * force_on_node123.getColumn(2);
+ }
+ }
+ }
+
+ // The damping matrix is calculated using the time n state as described in https://www.math.ucla.edu/~jteran/papers/GSSJT15.pdf to allow line search
+ virtual void addScaledDampingForceDifferential(btScalar scale, const TVStack& dv, TVStack& df)
+ {
+ if (m_mu_damp == 0 && m_lambda_damp == 0)
+ return;
+ int numNodes = getNumNodes();
+ btAssert(numNodes <= df.size());
+ btVector3 grad_N_hat_1st_col = btVector3(-1, -1, -1);
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ continue;
+ }
+ for (int j = 0; j < psb->m_tetras.size(); ++j)
+ {
+ btSoftBody::Tetra& tetra = psb->m_tetras[j];
+ btSoftBody::Node* node0 = tetra.m_n[0];
+ btSoftBody::Node* node1 = tetra.m_n[1];
+ btSoftBody::Node* node2 = tetra.m_n[2];
+ btSoftBody::Node* node3 = tetra.m_n[3];
+ size_t id0 = node0->index;
+ size_t id1 = node1->index;
+ size_t id2 = node2->index;
+ size_t id3 = node3->index;
+ btMatrix3x3 dF = Ds(id0, id1, id2, id3, dv) * tetra.m_Dm_inverse;
+ btMatrix3x3 I;
+ I.setIdentity();
+ btMatrix3x3 dP = (dF + dF.transpose()) * m_mu_damp + I * (dF[0][0] + dF[1][1] + dF[2][2]) * m_lambda_damp;
+ // firstPiolaDampingDifferential(psb->m_tetraScratchesTn[j], dF, dP);
+ // btVector3 df_on_node0 = dP * (tetra.m_Dm_inverse.transpose()*grad_N_hat_1st_col);
+ btMatrix3x3 df_on_node123 = dP * tetra.m_Dm_inverse.transpose();
+ btVector3 df_on_node0 = df_on_node123 * grad_N_hat_1st_col;
+
+ // damping force differential
+ btScalar scale1 = scale * tetra.m_element_measure;
+ df[id0] -= scale1 * df_on_node0;
+ df[id1] -= scale1 * df_on_node123.getColumn(0);
+ df[id2] -= scale1 * df_on_node123.getColumn(1);
+ df[id3] -= scale1 * df_on_node123.getColumn(2);
+ }
+ }
+ }
+
+ virtual void buildDampingForceDifferentialDiagonal(btScalar scale, TVStack& diagA) {}
+
+ virtual void addScaledElasticForceDifferential(btScalar scale, const TVStack& dx, TVStack& df)
+ {
+ int numNodes = getNumNodes();
+ btAssert(numNodes <= df.size());
+ btVector3 grad_N_hat_1st_col = btVector3(-1, -1, -1);
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ if (!psb->isActive())
+ {
+ continue;
+ }
+ for (int j = 0; j < psb->m_tetras.size(); ++j)
+ {
+ btSoftBody::Tetra& tetra = psb->m_tetras[j];
+ btSoftBody::Node* node0 = tetra.m_n[0];
+ btSoftBody::Node* node1 = tetra.m_n[1];
+ btSoftBody::Node* node2 = tetra.m_n[2];
+ btSoftBody::Node* node3 = tetra.m_n[3];
+ size_t id0 = node0->index;
+ size_t id1 = node1->index;
+ size_t id2 = node2->index;
+ size_t id3 = node3->index;
+ btMatrix3x3 dF = Ds(id0, id1, id2, id3, dx) * tetra.m_Dm_inverse;
+ btMatrix3x3 dP;
+ firstPiolaDifferential(psb->m_tetraScratches[j], dF, dP);
+ // btVector3 df_on_node0 = dP * (tetra.m_Dm_inverse.transpose()*grad_N_hat_1st_col);
+ btMatrix3x3 df_on_node123 = dP * tetra.m_Dm_inverse.transpose();
+ btVector3 df_on_node0 = df_on_node123 * grad_N_hat_1st_col;
+
+ // elastic force differential
+ btScalar scale1 = scale * tetra.m_element_measure;
+ df[id0] -= scale1 * df_on_node0;
+ df[id1] -= scale1 * df_on_node123.getColumn(0);
+ df[id2] -= scale1 * df_on_node123.getColumn(1);
+ df[id3] -= scale1 * df_on_node123.getColumn(2);
+ }
+ }
+ }
+
+ void firstPiola(const btSoftBody::TetraScratch& s, btMatrix3x3& P)
+ {
+ btScalar c1 = (m_mu * (1. - 1. / (s.m_trace + 1.)));
+ btScalar c2 = (m_lambda * (s.m_J - 1.) - 0.75 * m_mu);
+ P = s.m_F * c1 + s.m_cofF * c2;
+ }
+
+ // Let P be the first piola stress.
+ // This function calculates the dP = dP/dF * dF
+ void firstPiolaDifferential(const btSoftBody::TetraScratch& s, const btMatrix3x3& dF, btMatrix3x3& dP)
+ {
+ btScalar c1 = m_mu * (1. - 1. / (s.m_trace + 1.));
+ btScalar c2 = (2. * m_mu) * DotProduct(s.m_F, dF) * (1. / ((1. + s.m_trace) * (1. + s.m_trace)));
+ btScalar c3 = (m_lambda * DotProduct(s.m_cofF, dF));
+ dP = dF * c1 + s.m_F * c2;
+ addScaledCofactorMatrixDifferential(s.m_F, dF, m_lambda * (s.m_J - 1.) - 0.75 * m_mu, dP);
+ dP += s.m_cofF * c3;
+ }
- // damping force differential
- btScalar scale1 = scale * tetra.m_element_measure;
- df[id0] -= scale1 * df_on_node0;
- df[id1] -= scale1 * df_on_node123.getColumn(0);
- df[id2] -= scale1 * df_on_node123.getColumn(1);
- df[id3] -= scale1 * df_on_node123.getColumn(2);
- }
- }
- }
-
- virtual void buildDampingForceDifferentialDiagonal(btScalar scale, TVStack& diagA){}
-
- virtual void addScaledElasticForceDifferential(btScalar scale, const TVStack& dx, TVStack& df)
- {
- int numNodes = getNumNodes();
- btAssert(numNodes <= df.size());
- btVector3 grad_N_hat_1st_col = btVector3(-1,-1,-1);
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- if (!psb->isActive())
- {
- continue;
- }
- for (int j = 0; j < psb->m_tetras.size(); ++j)
- {
- btSoftBody::Tetra& tetra = psb->m_tetras[j];
- btSoftBody::Node* node0 = tetra.m_n[0];
- btSoftBody::Node* node1 = tetra.m_n[1];
- btSoftBody::Node* node2 = tetra.m_n[2];
- btSoftBody::Node* node3 = tetra.m_n[3];
- size_t id0 = node0->index;
- size_t id1 = node1->index;
- size_t id2 = node2->index;
- size_t id3 = node3->index;
- btMatrix3x3 dF = Ds(id0, id1, id2, id3, dx) * tetra.m_Dm_inverse;
- btMatrix3x3 dP;
- firstPiolaDifferential(psb->m_tetraScratches[j], dF, dP);
-// btVector3 df_on_node0 = dP * (tetra.m_Dm_inverse.transpose()*grad_N_hat_1st_col);
- btMatrix3x3 df_on_node123 = dP * tetra.m_Dm_inverse.transpose();
- btVector3 df_on_node0 = df_on_node123 * grad_N_hat_1st_col;
-
- // elastic force differential
- btScalar scale1 = scale * tetra.m_element_measure;
- df[id0] -= scale1 * df_on_node0;
- df[id1] -= scale1 * df_on_node123.getColumn(0);
- df[id2] -= scale1 * df_on_node123.getColumn(1);
- df[id3] -= scale1 * df_on_node123.getColumn(2);
- }
- }
- }
-
- void firstPiola(const btSoftBody::TetraScratch& s, btMatrix3x3& P)
- {
- btScalar c1 = (m_mu * ( 1. - 1. / (s.m_trace + 1.)));
- btScalar c2 = (m_lambda * (s.m_J - 1.) - 0.75 * m_mu);
- P = s.m_F * c1 + s.m_cofF * c2;
- }
-
- // Let P be the first piola stress.
- // This function calculates the dP = dP/dF * dF
- void firstPiolaDifferential(const btSoftBody::TetraScratch& s, const btMatrix3x3& dF, btMatrix3x3& dP)
- {
- btScalar c1 = m_mu * ( 1. - 1. / (s.m_trace + 1.));
- btScalar c2 = (2.*m_mu) * DotProduct(s.m_F, dF) * (1./((1.+s.m_trace)*(1.+s.m_trace)));
- btScalar c3 = (m_lambda * DotProduct(s.m_cofF, dF));
- dP = dF * c1 + s.m_F * c2;
- addScaledCofactorMatrixDifferential(s.m_F, dF, m_lambda*(s.m_J-1.) - 0.75*m_mu, dP);
- dP += s.m_cofF * c3;
- }
-
- // Let Q be the damping stress.
- // This function calculates the dP = dQ/dF * dF
- void firstPiolaDampingDifferential(const btSoftBody::TetraScratch& s, const btMatrix3x3& dF, btMatrix3x3& dP)
- {
- btScalar c1 = (m_mu_damp * ( 1. - 1. / (s.m_trace + 1.)));
- btScalar c2 = ((2.*m_mu_damp) * DotProduct(s.m_F, dF) *(1./((1.+s.m_trace)*(1.+s.m_trace))));
- btScalar c3 = (m_lambda_damp * DotProduct(s.m_cofF, dF));
- dP = dF * c1 + s.m_F * c2;
- addScaledCofactorMatrixDifferential(s.m_F, dF, m_lambda_damp*(s.m_J-1.) - 0.75*m_mu_damp, dP);
- dP += s.m_cofF * c3;
- }
-
- btScalar DotProduct(const btMatrix3x3& A, const btMatrix3x3& B)
- {
- btScalar ans = 0;
- for (int i = 0; i < 3; ++i)
- {
- ans += A[i].dot(B[i]);
- }
- return ans;
- }
-
- // Let C(A) be the cofactor of the matrix A
- // Let H = the derivative of C(A) with respect to A evaluated at F = A
- // This function calculates H*dF
- void addScaledCofactorMatrixDifferential(const btMatrix3x3& F, const btMatrix3x3& dF, btScalar scale, btMatrix3x3& M)
- {
- M[0][0] += scale * (dF[1][1] * F[2][2] + F[1][1] * dF[2][2] - dF[2][1] * F[1][2] - F[2][1] * dF[1][2]);
- M[1][0] += scale * (dF[2][1] * F[0][2] + F[2][1] * dF[0][2] - dF[0][1] * F[2][2] - F[0][1] * dF[2][2]);
- M[2][0] += scale * (dF[0][1] * F[1][2] + F[0][1] * dF[1][2] - dF[1][1] * F[0][2] - F[1][1] * dF[0][2]);
- M[0][1] += scale * (dF[2][0] * F[1][2] + F[2][0] * dF[1][2] - dF[1][0] * F[2][2] - F[1][0] * dF[2][2]);
- M[1][1] += scale * (dF[0][0] * F[2][2] + F[0][0] * dF[2][2] - dF[2][0] * F[0][2] - F[2][0] * dF[0][2]);
- M[2][1] += scale * (dF[1][0] * F[0][2] + F[1][0] * dF[0][2] - dF[0][0] * F[1][2] - F[0][0] * dF[1][2]);
- M[0][2] += scale * (dF[1][0] * F[2][1] + F[1][0] * dF[2][1] - dF[2][0] * F[1][1] - F[2][0] * dF[1][1]);
- M[1][2] += scale * (dF[2][0] * F[0][1] + F[2][0] * dF[0][1] - dF[0][0] * F[2][1] - F[0][0] * dF[2][1]);
- M[2][2] += scale * (dF[0][0] * F[1][1] + F[0][0] * dF[1][1] - dF[1][0] * F[0][1] - F[1][0] * dF[0][1]);
- }
-
- virtual btDeformableLagrangianForceType getForceType()
- {
- return BT_NEOHOOKEAN_FORCE;
- }
-
+ // Let Q be the damping stress.
+ // This function calculates the dP = dQ/dF * dF
+ void firstPiolaDampingDifferential(const btSoftBody::TetraScratch& s, const btMatrix3x3& dF, btMatrix3x3& dP)
+ {
+ btScalar c1 = (m_mu_damp * (1. - 1. / (s.m_trace + 1.)));
+ btScalar c2 = ((2. * m_mu_damp) * DotProduct(s.m_F, dF) * (1. / ((1. + s.m_trace) * (1. + s.m_trace))));
+ btScalar c3 = (m_lambda_damp * DotProduct(s.m_cofF, dF));
+ dP = dF * c1 + s.m_F * c2;
+ addScaledCofactorMatrixDifferential(s.m_F, dF, m_lambda_damp * (s.m_J - 1.) - 0.75 * m_mu_damp, dP);
+ dP += s.m_cofF * c3;
+ }
+
+ btScalar DotProduct(const btMatrix3x3& A, const btMatrix3x3& B)
+ {
+ btScalar ans = 0;
+ for (int i = 0; i < 3; ++i)
+ {
+ ans += A[i].dot(B[i]);
+ }
+ return ans;
+ }
+
+ // Let C(A) be the cofactor of the matrix A
+ // Let H = the derivative of C(A) with respect to A evaluated at F = A
+ // This function calculates H*dF
+ void addScaledCofactorMatrixDifferential(const btMatrix3x3& F, const btMatrix3x3& dF, btScalar scale, btMatrix3x3& M)
+ {
+ M[0][0] += scale * (dF[1][1] * F[2][2] + F[1][1] * dF[2][2] - dF[2][1] * F[1][2] - F[2][1] * dF[1][2]);
+ M[1][0] += scale * (dF[2][1] * F[0][2] + F[2][1] * dF[0][2] - dF[0][1] * F[2][2] - F[0][1] * dF[2][2]);
+ M[2][0] += scale * (dF[0][1] * F[1][2] + F[0][1] * dF[1][2] - dF[1][1] * F[0][2] - F[1][1] * dF[0][2]);
+ M[0][1] += scale * (dF[2][0] * F[1][2] + F[2][0] * dF[1][2] - dF[1][0] * F[2][2] - F[1][0] * dF[2][2]);
+ M[1][1] += scale * (dF[0][0] * F[2][2] + F[0][0] * dF[2][2] - dF[2][0] * F[0][2] - F[2][0] * dF[0][2]);
+ M[2][1] += scale * (dF[1][0] * F[0][2] + F[1][0] * dF[0][2] - dF[0][0] * F[1][2] - F[0][0] * dF[1][2]);
+ M[0][2] += scale * (dF[1][0] * F[2][1] + F[1][0] * dF[2][1] - dF[2][0] * F[1][1] - F[2][0] * dF[1][1]);
+ M[1][2] += scale * (dF[2][0] * F[0][1] + F[2][0] * dF[0][1] - dF[0][0] * F[2][1] - F[0][0] * dF[2][1]);
+ M[2][2] += scale * (dF[0][0] * F[1][1] + F[0][0] * dF[1][1] - dF[1][0] * F[0][1] - F[1][0] * dF[0][1]);
+ }
+
+ virtual btDeformableLagrangianForceType getForceType()
+ {
+ return BT_NEOHOOKEAN_FORCE;
+ }
};
#endif /* BT_NEOHOOKEAN_H */
diff --git a/thirdparty/bullet/BulletSoftBody/btKrylovSolver.h b/thirdparty/bullet/BulletSoftBody/btKrylovSolver.h
new file mode 100644
index 0000000000..59126b47ae
--- /dev/null
+++ b/thirdparty/bullet/BulletSoftBody/btKrylovSolver.h
@@ -0,0 +1,107 @@
+/*
+ Written by Xuchen Han <xuchenhan2015@u.northwestern.edu>
+
+ Bullet Continuous Collision Detection and Physics Library
+ Copyright (c) 2019 Google Inc. http://bulletphysics.org
+ This software is provided 'as-is', without any express or implied warranty.
+ In no event will the authors be held liable for any damages arising from the use of this software.
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it freely,
+ subject to the following restrictions:
+ 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+ */
+
+#ifndef BT_KRYLOV_SOLVER_H
+#define BT_KRYLOV_SOLVER_H
+#include <iostream>
+#include <cmath>
+#include <limits>
+#include <LinearMath/btAlignedObjectArray.h>
+#include <LinearMath/btVector3.h>
+#include <LinearMath/btScalar.h>
+#include "LinearMath/btQuickprof.h"
+
+template <class MatrixX>
+class btKrylovSolver
+{
+ typedef btAlignedObjectArray<btVector3> TVStack;
+
+public:
+ int m_maxIterations;
+ btScalar m_tolerance;
+ btKrylovSolver(int maxIterations, btScalar tolerance)
+ : m_maxIterations(maxIterations), m_tolerance(tolerance)
+ {
+ }
+
+ virtual ~btKrylovSolver() {}
+
+ virtual int solve(MatrixX& A, TVStack& x, const TVStack& b, bool verbose = false) = 0;
+
+ virtual void reinitialize(const TVStack& b) = 0;
+
+ virtual SIMD_FORCE_INLINE TVStack sub(const TVStack& a, const TVStack& b)
+ {
+ // c = a-b
+ btAssert(a.size() == b.size());
+ TVStack c;
+ c.resize(a.size());
+ for (int i = 0; i < a.size(); ++i)
+ {
+ c[i] = a[i] - b[i];
+ }
+ return c;
+ }
+
+ virtual SIMD_FORCE_INLINE btScalar squaredNorm(const TVStack& a)
+ {
+ return dot(a, a);
+ }
+
+ virtual SIMD_FORCE_INLINE btScalar norm(const TVStack& a)
+ {
+ btScalar ret = 0;
+ for (int i = 0; i < a.size(); ++i)
+ {
+ for (int d = 0; d < 3; ++d)
+ {
+ ret = btMax(ret, btFabs(a[i][d]));
+ }
+ }
+ return ret;
+ }
+
+ virtual SIMD_FORCE_INLINE btScalar dot(const TVStack& a, const TVStack& b)
+ {
+ btScalar ans(0);
+ for (int i = 0; i < a.size(); ++i)
+ ans += a[i].dot(b[i]);
+ return ans;
+ }
+
+ virtual SIMD_FORCE_INLINE void multAndAddTo(btScalar s, const TVStack& a, TVStack& result)
+ {
+ // result += s*a
+ btAssert(a.size() == result.size());
+ for (int i = 0; i < a.size(); ++i)
+ result[i] += s * a[i];
+ }
+
+ virtual SIMD_FORCE_INLINE TVStack multAndAdd(btScalar s, const TVStack& a, const TVStack& b)
+ {
+ // result = a*s + b
+ TVStack result;
+ result.resize(a.size());
+ for (int i = 0; i < a.size(); ++i)
+ result[i] = s * a[i] + b[i];
+ return result;
+ }
+
+ virtual SIMD_FORCE_INLINE void setTolerance(btScalar tolerance)
+ {
+ m_tolerance = tolerance;
+ }
+};
+#endif /* BT_KRYLOV_SOLVER_H */
diff --git a/thirdparty/bullet/BulletSoftBody/btPreconditioner.h b/thirdparty/bullet/BulletSoftBody/btPreconditioner.h
index c2db448ef8..21c1106a42 100644
--- a/thirdparty/bullet/BulletSoftBody/btPreconditioner.h
+++ b/thirdparty/bullet/BulletSoftBody/btPreconditioner.h
@@ -19,269 +19,266 @@
class Preconditioner
{
public:
- typedef btAlignedObjectArray<btVector3> TVStack;
- virtual void operator()(const TVStack& x, TVStack& b) = 0;
- virtual void reinitialize(bool nodeUpdated) = 0;
- virtual ~Preconditioner(){}
+ typedef btAlignedObjectArray<btVector3> TVStack;
+ virtual void operator()(const TVStack& x, TVStack& b) = 0;
+ virtual void reinitialize(bool nodeUpdated) = 0;
+ virtual ~Preconditioner() {}
};
class DefaultPreconditioner : public Preconditioner
{
public:
- virtual void operator()(const TVStack& x, TVStack& b)
- {
- btAssert(b.size() == x.size());
- for (int i = 0; i < b.size(); ++i)
- b[i] = x[i];
- }
- virtual void reinitialize(bool nodeUpdated)
- {
- }
-
- virtual ~DefaultPreconditioner(){}
+ virtual void operator()(const TVStack& x, TVStack& b)
+ {
+ btAssert(b.size() == x.size());
+ for (int i = 0; i < b.size(); ++i)
+ b[i] = x[i];
+ }
+ virtual void reinitialize(bool nodeUpdated)
+ {
+ }
+
+ virtual ~DefaultPreconditioner() {}
};
class MassPreconditioner : public Preconditioner
{
- btAlignedObjectArray<btScalar> m_inv_mass;
- const btAlignedObjectArray<btSoftBody *>& m_softBodies;
+ btAlignedObjectArray<btScalar> m_inv_mass;
+ const btAlignedObjectArray<btSoftBody*>& m_softBodies;
+
public:
- MassPreconditioner(const btAlignedObjectArray<btSoftBody *>& softBodies)
- : m_softBodies(softBodies)
- {
- }
-
- virtual void reinitialize(bool nodeUpdated)
- {
- if (nodeUpdated)
- {
- m_inv_mass.clear();
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- m_inv_mass.push_back(psb->m_nodes[j].m_im);
- }
- }
- }
-
- virtual void operator()(const TVStack& x, TVStack& b)
- {
- btAssert(b.size() == x.size());
- btAssert(m_inv_mass.size() <= x.size());
- for (int i = 0; i < m_inv_mass.size(); ++i)
- {
- b[i] = x[i] * m_inv_mass[i];
- }
- for (int i = m_inv_mass.size(); i < b.size(); ++i)
- {
- b[i] = x[i];
- }
- }
-};
+ MassPreconditioner(const btAlignedObjectArray<btSoftBody*>& softBodies)
+ : m_softBodies(softBodies)
+ {
+ }
+ virtual void reinitialize(bool nodeUpdated)
+ {
+ if (nodeUpdated)
+ {
+ m_inv_mass.clear();
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ m_inv_mass.push_back(psb->m_nodes[j].m_im);
+ }
+ }
+ }
+
+ virtual void operator()(const TVStack& x, TVStack& b)
+ {
+ btAssert(b.size() == x.size());
+ btAssert(m_inv_mass.size() <= x.size());
+ for (int i = 0; i < m_inv_mass.size(); ++i)
+ {
+ b[i] = x[i] * m_inv_mass[i];
+ }
+ for (int i = m_inv_mass.size(); i < b.size(); ++i)
+ {
+ b[i] = x[i];
+ }
+ }
+};
class KKTPreconditioner : public Preconditioner
{
- const btAlignedObjectArray<btSoftBody *>& m_softBodies;
- const btDeformableContactProjection& m_projections;
- const btAlignedObjectArray<btDeformableLagrangianForce*>& m_lf;
- TVStack m_inv_A, m_inv_S;
- const btScalar& m_dt;
- const bool& m_implicit;
+ const btAlignedObjectArray<btSoftBody*>& m_softBodies;
+ const btDeformableContactProjection& m_projections;
+ const btAlignedObjectArray<btDeformableLagrangianForce*>& m_lf;
+ TVStack m_inv_A, m_inv_S;
+ const btScalar& m_dt;
+ const bool& m_implicit;
+
public:
- KKTPreconditioner(const btAlignedObjectArray<btSoftBody *>& softBodies, const btDeformableContactProjection& projections, const btAlignedObjectArray<btDeformableLagrangianForce*>& lf, const btScalar& dt, const bool& implicit)
- : m_softBodies(softBodies)
- , m_projections(projections)
- , m_lf(lf)
- , m_dt(dt)
- , m_implicit(implicit)
- {
- }
-
- virtual void reinitialize(bool nodeUpdated)
- {
- if (nodeUpdated)
- {
- int num_nodes = 0;
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- num_nodes += psb->m_nodes.size();
- }
- m_inv_A.resize(num_nodes);
- }
- buildDiagonalA(m_inv_A);
- for (int i = 0; i < m_inv_A.size(); ++i)
- {
-// printf("A[%d] = %f, %f, %f \n", i, m_inv_A[i][0], m_inv_A[i][1], m_inv_A[i][2]);
- for (int d = 0; d < 3; ++d)
- {
- m_inv_A[i][d] = (m_inv_A[i][d] == 0) ? 0.0 : 1.0/ m_inv_A[i][d];
- }
- }
- m_inv_S.resize(m_projections.m_lagrangeMultipliers.size());
-// printf("S.size() = %d \n", m_inv_S.size());
- buildDiagonalS(m_inv_A, m_inv_S);
- for (int i = 0; i < m_inv_S.size(); ++i)
- {
-// printf("S[%d] = %f, %f, %f \n", i, m_inv_S[i][0], m_inv_S[i][1], m_inv_S[i][2]);
- for (int d = 0; d < 3; ++d)
- {
- m_inv_S[i][d] = (m_inv_S[i][d] == 0) ? 0.0 : 1.0/ m_inv_S[i][d];
- }
- }
- }
-
- void buildDiagonalA(TVStack& diagA) const
- {
- size_t counter = 0;
- for (int i = 0; i < m_softBodies.size(); ++i)
- {
- btSoftBody* psb = m_softBodies[i];
- for (int j = 0; j < psb->m_nodes.size(); ++j)
- {
- const btSoftBody::Node& node = psb->m_nodes[j];
- diagA[counter] = (node.m_im == 0) ? btVector3(0,0,0) : btVector3(1.0/node.m_im, 1.0 / node.m_im, 1.0 / node.m_im);
- ++counter;
- }
- }
- if (m_implicit)
- {
- printf("implicit not implemented\n");
- btAssert(false);
- }
- for (int i = 0; i < m_lf.size(); ++i)
- {
- // add damping matrix
- m_lf[i]->buildDampingForceDifferentialDiagonal(-m_dt, diagA);
- }
- }
-
- void buildDiagonalS(const TVStack& inv_A, TVStack& diagS)
- {
- for (int c = 0; c < m_projections.m_lagrangeMultipliers.size(); ++c)
- {
- // S[k,k] = e_k^T * C A_d^-1 C^T * e_k
- const LagrangeMultiplier& lm = m_projections.m_lagrangeMultipliers[c];
- btVector3& t = diagS[c];
- t.setZero();
- for (int j = 0; j < lm.m_num_constraints; ++j)
- {
- for (int i = 0; i < lm.m_num_nodes; ++i)
- {
- for (int d = 0; d < 3; ++d)
- {
- t[j] += inv_A[lm.m_indices[i]][d] * lm.m_dirs[j][d] * lm.m_dirs[j][d] * lm.m_weights[i] * lm.m_weights[i];
- }
- }
- }
- }
- }
-#define USE_FULL_PRECONDITIONER
+ KKTPreconditioner(const btAlignedObjectArray<btSoftBody*>& softBodies, const btDeformableContactProjection& projections, const btAlignedObjectArray<btDeformableLagrangianForce*>& lf, const btScalar& dt, const bool& implicit)
+ : m_softBodies(softBodies), m_projections(projections), m_lf(lf), m_dt(dt), m_implicit(implicit)
+ {
+ }
+
+ virtual void reinitialize(bool nodeUpdated)
+ {
+ if (nodeUpdated)
+ {
+ int num_nodes = 0;
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ num_nodes += psb->m_nodes.size();
+ }
+ m_inv_A.resize(num_nodes);
+ }
+ buildDiagonalA(m_inv_A);
+ for (int i = 0; i < m_inv_A.size(); ++i)
+ {
+ // printf("A[%d] = %f, %f, %f \n", i, m_inv_A[i][0], m_inv_A[i][1], m_inv_A[i][2]);
+ for (int d = 0; d < 3; ++d)
+ {
+ m_inv_A[i][d] = (m_inv_A[i][d] == 0) ? 0.0 : 1.0 / m_inv_A[i][d];
+ }
+ }
+ m_inv_S.resize(m_projections.m_lagrangeMultipliers.size());
+ // printf("S.size() = %d \n", m_inv_S.size());
+ buildDiagonalS(m_inv_A, m_inv_S);
+ for (int i = 0; i < m_inv_S.size(); ++i)
+ {
+ // printf("S[%d] = %f, %f, %f \n", i, m_inv_S[i][0], m_inv_S[i][1], m_inv_S[i][2]);
+ for (int d = 0; d < 3; ++d)
+ {
+ m_inv_S[i][d] = (m_inv_S[i][d] == 0) ? 0.0 : 1.0 / m_inv_S[i][d];
+ }
+ }
+ }
+
+ void buildDiagonalA(TVStack& diagA) const
+ {
+ size_t counter = 0;
+ for (int i = 0; i < m_softBodies.size(); ++i)
+ {
+ btSoftBody* psb = m_softBodies[i];
+ for (int j = 0; j < psb->m_nodes.size(); ++j)
+ {
+ const btSoftBody::Node& node = psb->m_nodes[j];
+ diagA[counter] = (node.m_im == 0) ? btVector3(0, 0, 0) : btVector3(1.0 / node.m_im, 1.0 / node.m_im, 1.0 / node.m_im);
+ ++counter;
+ }
+ }
+ if (m_implicit)
+ {
+ printf("implicit not implemented\n");
+ btAssert(false);
+ }
+ for (int i = 0; i < m_lf.size(); ++i)
+ {
+ // add damping matrix
+ m_lf[i]->buildDampingForceDifferentialDiagonal(-m_dt, diagA);
+ }
+ }
+
+ void buildDiagonalS(const TVStack& inv_A, TVStack& diagS)
+ {
+ for (int c = 0; c < m_projections.m_lagrangeMultipliers.size(); ++c)
+ {
+ // S[k,k] = e_k^T * C A_d^-1 C^T * e_k
+ const LagrangeMultiplier& lm = m_projections.m_lagrangeMultipliers[c];
+ btVector3& t = diagS[c];
+ t.setZero();
+ for (int j = 0; j < lm.m_num_constraints; ++j)
+ {
+ for (int i = 0; i < lm.m_num_nodes; ++i)
+ {
+ for (int d = 0; d < 3; ++d)
+ {
+ t[j] += inv_A[lm.m_indices[i]][d] * lm.m_dirs[j][d] * lm.m_dirs[j][d] * lm.m_weights[i] * lm.m_weights[i];
+ }
+ }
+ }
+ }
+ }
+//#define USE_FULL_PRECONDITIONER
#ifndef USE_FULL_PRECONDITIONER
- virtual void operator()(const TVStack& x, TVStack& b)
- {
- btAssert(b.size() == x.size());
- for (int i = 0; i < m_inv_A.size(); ++i)
- {
- b[i] = x[i] * m_inv_A[i];
- }
- int offset = m_inv_A.size();
- for (int i = 0; i < m_inv_S.size(); ++i)
- {
- b[i+offset] = x[i+offset] * m_inv_S[i];
- }
- }
+ virtual void operator()(const TVStack& x, TVStack& b)
+ {
+ btAssert(b.size() == x.size());
+ for (int i = 0; i < m_inv_A.size(); ++i)
+ {
+ b[i] = x[i] * m_inv_A[i];
+ }
+ int offset = m_inv_A.size();
+ for (int i = 0; i < m_inv_S.size(); ++i)
+ {
+ b[i + offset] = x[i + offset] * m_inv_S[i];
+ }
+ }
#else
- virtual void operator()(const TVStack& x, TVStack& b)
- {
- btAssert(b.size() == x.size());
- int offset = m_inv_A.size();
+ virtual void operator()(const TVStack& x, TVStack& b)
+ {
+ btAssert(b.size() == x.size());
+ int offset = m_inv_A.size();
- for (int i = 0; i < m_inv_A.size(); ++i)
- {
- b[i] = x[i] * m_inv_A[i];
- }
+ for (int i = 0; i < m_inv_A.size(); ++i)
+ {
+ b[i] = x[i] * m_inv_A[i];
+ }
- for (int i = 0; i < m_inv_S.size(); ++i)
- {
- b[i+offset].setZero();
- }
+ for (int i = 0; i < m_inv_S.size(); ++i)
+ {
+ b[i + offset].setZero();
+ }
- for (int c = 0; c < m_projections.m_lagrangeMultipliers.size(); ++c)
- {
- const LagrangeMultiplier& lm = m_projections.m_lagrangeMultipliers[c];
- // C * x
- for (int d = 0; d < lm.m_num_constraints; ++d)
- {
- for (int i = 0; i < lm.m_num_nodes; ++i)
- {
- b[offset+c][d] += lm.m_weights[i] * b[lm.m_indices[i]].dot(lm.m_dirs[d]);
- }
- }
- }
+ for (int c = 0; c < m_projections.m_lagrangeMultipliers.size(); ++c)
+ {
+ const LagrangeMultiplier& lm = m_projections.m_lagrangeMultipliers[c];
+ // C * x
+ for (int d = 0; d < lm.m_num_constraints; ++d)
+ {
+ for (int i = 0; i < lm.m_num_nodes; ++i)
+ {
+ b[offset + c][d] += lm.m_weights[i] * b[lm.m_indices[i]].dot(lm.m_dirs[d]);
+ }
+ }
+ }
- for (int i = 0; i < m_inv_S.size(); ++i)
- {
- b[i+offset] = b[i+offset] * m_inv_S[i];
- }
+ for (int i = 0; i < m_inv_S.size(); ++i)
+ {
+ b[i + offset] = b[i + offset] * m_inv_S[i];
+ }
- for (int i = 0; i < m_inv_A.size(); ++i)
- {
- b[i].setZero();
- }
+ for (int i = 0; i < m_inv_A.size(); ++i)
+ {
+ b[i].setZero();
+ }
- for (int c = 0; c < m_projections.m_lagrangeMultipliers.size(); ++c)
- {
- // C^T * lambda
- const LagrangeMultiplier& lm = m_projections.m_lagrangeMultipliers[c];
- for (int i = 0; i < lm.m_num_nodes; ++i)
- {
- for (int j = 0; j < lm.m_num_constraints; ++j)
- {
- b[lm.m_indices[i]] += b[offset+c][j] * lm.m_weights[i] * lm.m_dirs[j];
- }
- }
- }
+ for (int c = 0; c < m_projections.m_lagrangeMultipliers.size(); ++c)
+ {
+ // C^T * lambda
+ const LagrangeMultiplier& lm = m_projections.m_lagrangeMultipliers[c];
+ for (int i = 0; i < lm.m_num_nodes; ++i)
+ {
+ for (int j = 0; j < lm.m_num_constraints; ++j)
+ {
+ b[lm.m_indices[i]] += b[offset + c][j] * lm.m_weights[i] * lm.m_dirs[j];
+ }
+ }
+ }
- for (int i = 0; i < m_inv_A.size(); ++i)
- {
- b[i] = (x[i] - b[i]) * m_inv_A[i];
- }
+ for (int i = 0; i < m_inv_A.size(); ++i)
+ {
+ b[i] = (x[i] - b[i]) * m_inv_A[i];
+ }
- TVStack t;
- t.resize(b.size());
- for (int i = 0; i < m_inv_S.size(); ++i)
- {
- t[i+offset] = x[i+offset] * m_inv_S[i];
- }
- for (int i = 0; i < m_inv_A.size(); ++i)
- {
- t[i].setZero();
- }
- for (int c = 0; c < m_projections.m_lagrangeMultipliers.size(); ++c)
- {
- // C^T * lambda
- const LagrangeMultiplier& lm = m_projections.m_lagrangeMultipliers[c];
- for (int i = 0; i < lm.m_num_nodes; ++i)
- {
- for (int j = 0; j < lm.m_num_constraints; ++j)
- {
- t[lm.m_indices[i]] += t[offset+c][j] * lm.m_weights[i] * lm.m_dirs[j];
- }
- }
- }
- for (int i = 0; i < m_inv_A.size(); ++i)
- {
- b[i] += t[i] * m_inv_A[i];
- }
+ TVStack t;
+ t.resize(b.size());
+ for (int i = 0; i < m_inv_S.size(); ++i)
+ {
+ t[i + offset] = x[i + offset] * m_inv_S[i];
+ }
+ for (int i = 0; i < m_inv_A.size(); ++i)
+ {
+ t[i].setZero();
+ }
+ for (int c = 0; c < m_projections.m_lagrangeMultipliers.size(); ++c)
+ {
+ // C^T * lambda
+ const LagrangeMultiplier& lm = m_projections.m_lagrangeMultipliers[c];
+ for (int i = 0; i < lm.m_num_nodes; ++i)
+ {
+ for (int j = 0; j < lm.m_num_constraints; ++j)
+ {
+ t[lm.m_indices[i]] += t[offset + c][j] * lm.m_weights[i] * lm.m_dirs[j];
+ }
+ }
+ }
+ for (int i = 0; i < m_inv_A.size(); ++i)
+ {
+ b[i] += t[i] * m_inv_A[i];
+ }
- for (int i = 0; i < m_inv_S.size(); ++i)
- {
- b[i+offset] -= x[i+offset] * m_inv_S[i];
- }
- }
+ for (int i = 0; i < m_inv_S.size(); ++i)
+ {
+ b[i + offset] -= x[i + offset] * m_inv_S[i];
+ }
+ }
#endif
};
diff --git a/thirdparty/bullet/BulletSoftBody/btSoftBody.cpp b/thirdparty/bullet/BulletSoftBody/btSoftBody.cpp
index 81b846d7f8..d1980ea6c5 100644
--- a/thirdparty/bullet/BulletSoftBody/btSoftBody.cpp
+++ b/thirdparty/bullet/BulletSoftBody/btSoftBody.cpp
@@ -37,12 +37,12 @@ static inline btDbvtNode* buildTreeBottomUp(btAlignedObjectArray<btDbvtNode*>& l
{
btAlignedObjectArray<bool> marked;
btAlignedObjectArray<btDbvtNode*> newLeafNodes;
- btAlignedObjectArray<std::pair<int,int> > childIds;
+ btAlignedObjectArray<std::pair<int, int> > childIds;
btAlignedObjectArray<btAlignedObjectArray<int> > newAdj;
marked.resize(N);
for (int i = 0; i < N; ++i)
marked[i] = false;
-
+
// pair adjacent nodes into new(parent) node
for (int i = 0; i < N; ++i)
{
@@ -61,7 +61,7 @@ static inline btDbvtNode* buildTreeBottomUp(btAlignedObjectArray<btDbvtNode*>& l
leafNodes[i]->parent = node;
leafNodes[n]->parent = node;
newLeafNodes.push_back(node);
- childIds.push_back(std::make_pair(i,n));
+ childIds.push_back(std::make_pair(i, n));
merged = true;
marked[n] = true;
break;
@@ -70,7 +70,7 @@ static inline btDbvtNode* buildTreeBottomUp(btAlignedObjectArray<btDbvtNode*>& l
if (!merged)
{
newLeafNodes.push_back(leafNodes[i]);
- childIds.push_back(std::make_pair(i,-1));
+ childIds.push_back(std::make_pair(i, -1));
}
marked[i] = true;
}
@@ -78,7 +78,7 @@ static inline btDbvtNode* buildTreeBottomUp(btAlignedObjectArray<btDbvtNode*>& l
newAdj.resize(newLeafNodes.size());
for (int i = 0; i < newLeafNodes.size(); ++i)
{
- for (int j = i+1; j < newLeafNodes.size(); ++j)
+ for (int j = i + 1; j < newLeafNodes.size(); ++j)
{
bool neighbor = false;
const btAlignedObjectArray<int>& leftChildNeighbors = adj[childIds[i].first];
@@ -143,7 +143,7 @@ btSoftBody::btSoftBody(btSoftBodyWorldInfo* worldInfo, int node_count, const btV
/* Nodes */
const btScalar margin = getCollisionShape()->getMargin();
m_nodes.resize(node_count);
- m_X.resize(node_count);
+ m_X.resize(node_count);
for (int i = 0, ni = node_count; i < ni; ++i)
{
Node& n = m_nodes[i];
@@ -154,7 +154,7 @@ btSoftBody::btSoftBody(btSoftBodyWorldInfo* worldInfo, int node_count, const btV
n.m_im = n.m_im > 0 ? 1 / n.m_im : 0;
n.m_leaf = m_ndbvt.insert(btDbvtVolume::FromCR(n.m_x, margin), &n);
n.m_material = pm;
- m_X[i] = n.m_x;
+ m_X[i] = n.m_x;
}
updateBounds();
setCollisionQuadrature(3);
@@ -195,8 +195,8 @@ void btSoftBody::initDefaults()
m_cfg.piterations = 1;
m_cfg.diterations = 0;
m_cfg.citerations = 4;
- m_cfg.drag = 0;
- m_cfg.m_maxStress = 0;
+ m_cfg.drag = 0;
+ m_cfg.m_maxStress = 0;
m_cfg.collisions = fCollision::Default;
m_pose.m_bvolume = false;
m_pose.m_bframe = false;
@@ -222,12 +222,14 @@ void btSoftBody::initDefaults()
m_windVelocity = btVector3(0, 0, 0);
m_restLengthScale = btScalar(1.0);
m_dampingCoefficient = 1.0;
- m_sleepingThreshold = .4;
+ m_sleepingThreshold = .04;
m_useSelfCollision = false;
m_collisionFlags = 0;
m_softSoftCollision = false;
m_maxSpeedSquared = 0;
m_repulsionStiffness = 0.5;
+ m_gravityFactor = 1;
+ m_cacheBarycenter = false;
m_fdbvnt = 0;
}
@@ -436,7 +438,7 @@ void btSoftBody::appendFace(int model, Material* mat)
ZeroInitialize(f);
f.m_material = mat ? mat : m_materials[0];
}
- m_faces.push_back(f);
+ m_faces.push_back(f);
}
//
@@ -525,94 +527,111 @@ void btSoftBody::appendAnchor(int node, btRigidBody* body, const btVector3& loca
//
void btSoftBody::appendDeformableAnchor(int node, btRigidBody* body)
{
- DeformableNodeRigidAnchor c;
- btSoftBody::Node& n = m_nodes[node];
- const btScalar ima = n.m_im;
- const btScalar imb = body->getInvMass();
- btVector3 nrm;
- const btCollisionShape* shp = body->getCollisionShape();
- const btTransform& wtr = body->getWorldTransform();
- btScalar dst =
- m_worldInfo->m_sparsesdf.Evaluate(
- wtr.invXform(m_nodes[node].m_x),
- shp,
- nrm,
- 0);
-
- c.m_cti.m_colObj = body;
- c.m_cti.m_normal = wtr.getBasis() * nrm;
- c.m_cti.m_offset = dst;
- c.m_node = &m_nodes[node];
- const btScalar fc = m_cfg.kDF * body->getFriction();
- c.m_c2 = ima;
- c.m_c3 = fc;
- c.m_c4 = body->isStaticOrKinematicObject() ? m_cfg.kKHR : m_cfg.kCHR;
- static const btMatrix3x3 iwiStatic(0, 0, 0, 0, 0, 0, 0, 0, 0);
- const btMatrix3x3& iwi = body->getInvInertiaTensorWorld();
- const btVector3 ra = n.m_x - wtr.getOrigin();
-
- c.m_c0 = ImpulseMatrix(1, ima, imb, iwi, ra);
- c.m_c1 = ra;
- c.m_local = body->getWorldTransform().inverse() * m_nodes[node].m_x;
- c.m_node->m_battach = 1;
- m_deformableAnchors.push_back(c);
+ DeformableNodeRigidAnchor c;
+ btSoftBody::Node& n = m_nodes[node];
+ const btScalar ima = n.m_im;
+ const btScalar imb = body->getInvMass();
+ btVector3 nrm;
+ const btCollisionShape* shp = body->getCollisionShape();
+ const btTransform& wtr = body->getWorldTransform();
+ btScalar dst =
+ m_worldInfo->m_sparsesdf.Evaluate(
+ wtr.invXform(m_nodes[node].m_x),
+ shp,
+ nrm,
+ 0);
+
+ c.m_cti.m_colObj = body;
+ c.m_cti.m_normal = wtr.getBasis() * nrm;
+ c.m_cti.m_offset = dst;
+ c.m_node = &m_nodes[node];
+ const btScalar fc = m_cfg.kDF * body->getFriction();
+ c.m_c2 = ima;
+ c.m_c3 = fc;
+ c.m_c4 = body->isStaticOrKinematicObject() ? m_cfg.kKHR : m_cfg.kCHR;
+ static const btMatrix3x3 iwiStatic(0, 0, 0, 0, 0, 0, 0, 0, 0);
+ const btMatrix3x3& iwi = body->getInvInertiaTensorWorld();
+ const btVector3 ra = n.m_x - wtr.getOrigin();
+
+ c.m_c0 = ImpulseMatrix(1, ima, imb, iwi, ra);
+ c.m_c1 = ra;
+ c.m_local = body->getWorldTransform().inverse() * m_nodes[node].m_x;
+ c.m_node->m_battach = 1;
+ m_deformableAnchors.push_back(c);
+}
+
+void btSoftBody::removeAnchor(int node)
+{
+ const btSoftBody::Node& n = m_nodes[node];
+ for (int i = 0; i < m_deformableAnchors.size();)
+ {
+ const DeformableNodeRigidAnchor& c = m_deformableAnchors[i];
+ if (c.m_node == &n)
+ {
+ m_deformableAnchors.removeAtIndex(i);
+ }
+ else
+ {
+ i++;
+ }
+ }
}
//
void btSoftBody::appendDeformableAnchor(int node, btMultiBodyLinkCollider* link)
{
- DeformableNodeRigidAnchor c;
- btSoftBody::Node& n = m_nodes[node];
- const btScalar ima = n.m_im;
- btVector3 nrm;
- const btCollisionShape* shp = link->getCollisionShape();
- const btTransform& wtr = link->getWorldTransform();
- btScalar dst =
- m_worldInfo->m_sparsesdf.Evaluate(
- wtr.invXform(m_nodes[node].m_x),
- shp,
- nrm,
- 0);
- c.m_cti.m_colObj = link;
- c.m_cti.m_normal = wtr.getBasis() * nrm;
- c.m_cti.m_offset = dst;
- c.m_node = &m_nodes[node];
- const btScalar fc = m_cfg.kDF * link->getFriction();
- c.m_c2 = ima;
- c.m_c3 = fc;
- c.m_c4 = link->isStaticOrKinematicObject() ? m_cfg.kKHR : m_cfg.kCHR;
- btVector3 normal = c.m_cti.m_normal;
- btVector3 t1 = generateUnitOrthogonalVector(normal);
- btVector3 t2 = btCross(normal, t1);
- btMultiBodyJacobianData jacobianData_normal, jacobianData_t1, jacobianData_t2;
- findJacobian(link, jacobianData_normal, c.m_node->m_x, normal);
- findJacobian(link, jacobianData_t1, c.m_node->m_x, t1);
- findJacobian(link, jacobianData_t2, c.m_node->m_x, t2);
-
- btScalar* J_n = &jacobianData_normal.m_jacobians[0];
- btScalar* J_t1 = &jacobianData_t1.m_jacobians[0];
- btScalar* J_t2 = &jacobianData_t2.m_jacobians[0];
-
- btScalar* u_n = &jacobianData_normal.m_deltaVelocitiesUnitImpulse[0];
- btScalar* u_t1 = &jacobianData_t1.m_deltaVelocitiesUnitImpulse[0];
- btScalar* u_t2 = &jacobianData_t2.m_deltaVelocitiesUnitImpulse[0];
-
- btMatrix3x3 rot(normal.getX(), normal.getY(), normal.getZ(),
- t1.getX(), t1.getY(), t1.getZ(),
- t2.getX(), t2.getY(), t2.getZ()); // world frame to local frame
- const int ndof = link->m_multiBody->getNumDofs() + 6;
- btMatrix3x3 local_impulse_matrix = (Diagonal(n.m_im) + OuterProduct(J_n, J_t1, J_t2, u_n, u_t1, u_t2, ndof)).inverse();
- c.m_c0 = rot.transpose() * local_impulse_matrix * rot;
- c.jacobianData_normal = jacobianData_normal;
- c.jacobianData_t1 = jacobianData_t1;
- c.jacobianData_t2 = jacobianData_t2;
- c.t1 = t1;
- c.t2 = t2;
- const btVector3 ra = n.m_x - wtr.getOrigin();
- c.m_c1 = ra;
- c.m_local = link->getWorldTransform().inverse() * m_nodes[node].m_x;
- c.m_node->m_battach = 1;
- m_deformableAnchors.push_back(c);
+ DeformableNodeRigidAnchor c;
+ btSoftBody::Node& n = m_nodes[node];
+ const btScalar ima = n.m_im;
+ btVector3 nrm;
+ const btCollisionShape* shp = link->getCollisionShape();
+ const btTransform& wtr = link->getWorldTransform();
+ btScalar dst =
+ m_worldInfo->m_sparsesdf.Evaluate(
+ wtr.invXform(m_nodes[node].m_x),
+ shp,
+ nrm,
+ 0);
+ c.m_cti.m_colObj = link;
+ c.m_cti.m_normal = wtr.getBasis() * nrm;
+ c.m_cti.m_offset = dst;
+ c.m_node = &m_nodes[node];
+ const btScalar fc = m_cfg.kDF * link->getFriction();
+ c.m_c2 = ima;
+ c.m_c3 = fc;
+ c.m_c4 = link->isStaticOrKinematicObject() ? m_cfg.kKHR : m_cfg.kCHR;
+ btVector3 normal = c.m_cti.m_normal;
+ btVector3 t1 = generateUnitOrthogonalVector(normal);
+ btVector3 t2 = btCross(normal, t1);
+ btMultiBodyJacobianData jacobianData_normal, jacobianData_t1, jacobianData_t2;
+ findJacobian(link, jacobianData_normal, c.m_node->m_x, normal);
+ findJacobian(link, jacobianData_t1, c.m_node->m_x, t1);
+ findJacobian(link, jacobianData_t2, c.m_node->m_x, t2);
+
+ btScalar* J_n = &jacobianData_normal.m_jacobians[0];
+ btScalar* J_t1 = &jacobianData_t1.m_jacobians[0];
+ btScalar* J_t2 = &jacobianData_t2.m_jacobians[0];
+
+ btScalar* u_n = &jacobianData_normal.m_deltaVelocitiesUnitImpulse[0];
+ btScalar* u_t1 = &jacobianData_t1.m_deltaVelocitiesUnitImpulse[0];
+ btScalar* u_t2 = &jacobianData_t2.m_deltaVelocitiesUnitImpulse[0];
+
+ btMatrix3x3 rot(normal.getX(), normal.getY(), normal.getZ(),
+ t1.getX(), t1.getY(), t1.getZ(),
+ t2.getX(), t2.getY(), t2.getZ()); // world frame to local frame
+ const int ndof = link->m_multiBody->getNumDofs() + 6;
+ btMatrix3x3 local_impulse_matrix = (Diagonal(n.m_im) + OuterProduct(J_n, J_t1, J_t2, u_n, u_t1, u_t2, ndof)).inverse();
+ c.m_c0 = rot.transpose() * local_impulse_matrix * rot;
+ c.jacobianData_normal = jacobianData_normal;
+ c.jacobianData_t1 = jacobianData_t1;
+ c.jacobianData_t2 = jacobianData_t2;
+ c.t1 = t1;
+ c.t2 = t2;
+ const btVector3 ra = n.m_x - wtr.getOrigin();
+ c.m_c1 = ra;
+ c.m_local = link->getWorldTransform().inverse() * m_nodes[node].m_x;
+ c.m_node->m_battach = 1;
+ m_deformableAnchors.push_back(c);
}
//
void btSoftBody::appendLinearJoint(const LJoint::Specs& specs, Cluster* body0, Body body1)
@@ -731,7 +750,7 @@ void btSoftBody::addAeroForceToNode(const btVector3& windVelocity, int nodeIndex
fDrag = 0.5f * kDG * medium.m_density * rel_v2 * tri_area * n_dot_v * (-rel_v_nrm);
// Check angle of attack
- // cos(10º) = 0.98480
+ // cos(10º) = 0.98480
if (0 < n_dot_v && n_dot_v < 0.98480f)
fLift = 0.5f * kLF * medium.m_density * rel_v_len * tri_area * btSqrt(1.0f - n_dot_v * n_dot_v) * (nrm.cross(rel_v_nrm).cross(rel_v_nrm));
@@ -817,7 +836,7 @@ void btSoftBody::addAeroForceToFace(const btVector3& windVelocity, int faceIndex
fDrag = 0.5f * kDG * medium.m_density * rel_v2 * tri_area * n_dot_v * (-rel_v_nrm);
// Check angle of attack
- // cos(10º) = 0.98480
+ // cos(10º) = 0.98480
if (0 < n_dot_v && n_dot_v < 0.98480f)
fLift = 0.5f * kLF * medium.m_density * rel_v_len * tri_area * btSqrt(1.0f - n_dot_v * n_dot_v) * (nrm.cross(rel_v_nrm).cross(rel_v_nrm));
@@ -882,6 +901,7 @@ void btSoftBody::setVelocity(const btVector3& velocity)
if (n.m_im > 0)
{
n.m_v = velocity;
+ n.m_vn = velocity;
}
}
}
@@ -1010,66 +1030,70 @@ void btSoftBody::setVolumeDensity(btScalar density)
//
btVector3 btSoftBody::getLinearVelocity()
{
- btVector3 total_momentum = btVector3(0,0,0);
- for (int i = 0; i < m_nodes.size(); ++i)
- {
- btScalar mass = m_nodes[i].m_im == 0 ? 0 : 1.0/m_nodes[i].m_im;
- total_momentum += mass * m_nodes[i].m_v;
- }
- btScalar total_mass = getTotalMass();
- return total_mass == 0 ? total_momentum : total_momentum / total_mass;
+ btVector3 total_momentum = btVector3(0, 0, 0);
+ for (int i = 0; i < m_nodes.size(); ++i)
+ {
+ btScalar mass = m_nodes[i].m_im == 0 ? 0 : 1.0 / m_nodes[i].m_im;
+ total_momentum += mass * m_nodes[i].m_v;
+ }
+ btScalar total_mass = getTotalMass();
+ return total_mass == 0 ? total_momentum : total_momentum / total_mass;
}
//
void btSoftBody::setLinearVelocity(const btVector3& linVel)
{
- btVector3 old_vel = getLinearVelocity();
- btVector3 diff = linVel - old_vel;
- for (int i = 0; i < m_nodes.size(); ++i)
- m_nodes[i].m_v += diff;
+ btVector3 old_vel = getLinearVelocity();
+ btVector3 diff = linVel - old_vel;
+ for (int i = 0; i < m_nodes.size(); ++i)
+ m_nodes[i].m_v += diff;
}
//
void btSoftBody::setAngularVelocity(const btVector3& angVel)
{
- btVector3 old_vel = getLinearVelocity();
- btVector3 com = getCenterOfMass();
- for (int i = 0; i < m_nodes.size(); ++i)
- {
- m_nodes[i].m_v = angVel.cross(m_nodes[i].m_x - com) + old_vel;
- }
+ btVector3 old_vel = getLinearVelocity();
+ btVector3 com = getCenterOfMass();
+ for (int i = 0; i < m_nodes.size(); ++i)
+ {
+ m_nodes[i].m_v = angVel.cross(m_nodes[i].m_x - com) + old_vel;
+ }
}
//
btTransform btSoftBody::getRigidTransform()
{
- btVector3 t = getCenterOfMass();
- btMatrix3x3 S;
- S.setZero();
- // get rotation that minimizes L2 difference: \sum_i || RX_i + t - x_i ||
- for (int i = 0; i < m_nodes.size(); ++i)
- {
- S += OuterProduct(m_X[i], t-m_nodes[i].m_x);
- }
- btVector3 sigma;
- btMatrix3x3 U,V;
- singularValueDecomposition(S,U,sigma,V);
- btMatrix3x3 R = V * U.transpose();
- btTransform trs;
- trs.setIdentity();
- trs.setOrigin(t);
- trs.setBasis(R);
- return trs;
+ btVector3 t = getCenterOfMass();
+ btMatrix3x3 S;
+ S.setZero();
+ // Get rotation that minimizes L2 difference: \sum_i || RX_i + t - x_i ||
+ // It's important to make sure that S has the correct signs.
+ // SVD is only unique up to the ordering of singular values.
+ // SVD will manipulate U and V to ensure the ordering of singular values. If all three singular
+ // vaues are negative, SVD will permute colums of U to make two of them positive.
+ for (int i = 0; i < m_nodes.size(); ++i)
+ {
+ S -= OuterProduct(m_X[i], t - m_nodes[i].m_x);
+ }
+ btVector3 sigma;
+ btMatrix3x3 U, V;
+ singularValueDecomposition(S, U, sigma, V);
+ btMatrix3x3 R = V * U.transpose();
+ btTransform trs;
+ trs.setIdentity();
+ trs.setOrigin(t);
+ trs.setBasis(R);
+ return trs;
}
//
void btSoftBody::transformTo(const btTransform& trs)
{
- // get the current best rigid fit
- btTransform current_transform = getRigidTransform();
- // apply transform in material space
- btTransform new_transform = trs * current_transform.inverse();
- transform(new_transform);
+ // get the current best rigid fit
+ btTransform current_transform = getRigidTransform();
+ // apply transform in material space
+ btTransform new_transform = trs * current_transform.inverse();
+ transform(new_transform);
}
//
@@ -1130,7 +1154,7 @@ void btSoftBody::scale(const btVector3& scl)
updateNormals();
updateBounds();
updateConstants();
- initializeDmInverse();
+ initializeDmInverse();
}
//
@@ -2010,22 +2034,22 @@ bool btSoftBody::rayTest(const btVector3& rayFrom,
}
bool btSoftBody::rayFaceTest(const btVector3& rayFrom,
- const btVector3& rayTo,
- sRayCast& results)
+ const btVector3& rayTo,
+ sRayCast& results)
{
if (m_faces.size() == 0)
return false;
else
{
- if (m_fdbvt.empty())
- initializeFaceTree();
+ if (m_fdbvt.empty())
+ initializeFaceTree();
}
-
- results.body = this;
- results.fraction = 1.f;
- results.index = -1;
-
- return (rayFaceTest(rayFrom, rayTo, results.fraction, results.index) != 0);
+
+ results.body = this;
+ results.fraction = 1.f;
+ results.index = -1;
+
+ return (rayFaceTest(rayFrom, rayTo, results.fraction, results.index) != 0);
}
//
@@ -2056,112 +2080,111 @@ void btSoftBody::setSolver(eSolverPresets::_ preset)
void btSoftBody::predictMotion(btScalar dt)
{
- int i, ni;
-
- /* Update */
- if (m_bUpdateRtCst)
- {
- m_bUpdateRtCst = false;
- updateConstants();
- m_fdbvt.clear();
- if (m_cfg.collisions & fCollision::VF_SS)
- {
- initializeFaceTree();
- }
- }
-
- /* Prepare */
- m_sst.sdt = dt * m_cfg.timescale;
- m_sst.isdt = 1 / m_sst.sdt;
- m_sst.velmrg = m_sst.sdt * 3;
- m_sst.radmrg = getCollisionShape()->getMargin();
- m_sst.updmrg = m_sst.radmrg * (btScalar)0.25;
- /* Forces */
- addVelocity(m_worldInfo->m_gravity * m_sst.sdt);
- applyForces();
- /* Integrate */
- for (i = 0, ni = m_nodes.size(); i < ni; ++i)
- {
- Node& n = m_nodes[i];
- n.m_q = n.m_x;
- btVector3 deltaV = n.m_f * n.m_im * m_sst.sdt;
- {
- btScalar maxDisplacement = m_worldInfo->m_maxDisplacement;
- btScalar clampDeltaV = maxDisplacement / m_sst.sdt;
- for (int c = 0; c < 3; c++)
- {
- if (deltaV[c] > clampDeltaV)
- {
- deltaV[c] = clampDeltaV;
- }
- if (deltaV[c] < -clampDeltaV)
- {
- deltaV[c] = -clampDeltaV;
- }
- }
- }
- n.m_v += deltaV;
- n.m_x += n.m_v * m_sst.sdt;
- n.m_f = btVector3(0, 0, 0);
- }
- /* Clusters */
- updateClusters();
- /* Bounds */
- updateBounds();
- /* Nodes */
- ATTRIBUTE_ALIGNED16(btDbvtVolume)
- vol;
- for (i = 0, ni = m_nodes.size(); i < ni; ++i)
- {
- Node& n = m_nodes[i];
- vol = btDbvtVolume::FromCR(n.m_x, m_sst.radmrg);
- m_ndbvt.update(n.m_leaf,
- vol,
- n.m_v * m_sst.velmrg,
- m_sst.updmrg);
- }
- /* Faces */
- if (!m_fdbvt.empty())
- {
- for (int i = 0; i < m_faces.size(); ++i)
- {
- Face& f = m_faces[i];
- const btVector3 v = (f.m_n[0]->m_v +
- f.m_n[1]->m_v +
- f.m_n[2]->m_v) /
- 3;
- vol = VolumeOf(f, m_sst.radmrg);
- m_fdbvt.update(f.m_leaf,
- vol,
- v * m_sst.velmrg,
- m_sst.updmrg);
- }
- }
- /* Pose */
- updatePose();
- /* Match */
- if (m_pose.m_bframe && (m_cfg.kMT > 0))
- {
- const btMatrix3x3 posetrs = m_pose.m_rot;
- for (int i = 0, ni = m_nodes.size(); i < ni; ++i)
- {
- Node& n = m_nodes[i];
- if (n.m_im > 0)
- {
- const btVector3 x = posetrs * m_pose.m_pos[i] + m_pose.m_com;
- n.m_x = Lerp(n.m_x, x, m_cfg.kMT);
- }
- }
- }
- /* Clear contacts */
- m_rcontacts.resize(0);
- m_scontacts.resize(0);
- /* Optimize dbvt's */
- m_ndbvt.optimizeIncremental(1);
- m_fdbvt.optimizeIncremental(1);
- m_cdbvt.optimizeIncremental(1);
-}
+ int i, ni;
+ /* Update */
+ if (m_bUpdateRtCst)
+ {
+ m_bUpdateRtCst = false;
+ updateConstants();
+ m_fdbvt.clear();
+ if (m_cfg.collisions & fCollision::VF_SS)
+ {
+ initializeFaceTree();
+ }
+ }
+
+ /* Prepare */
+ m_sst.sdt = dt * m_cfg.timescale;
+ m_sst.isdt = 1 / m_sst.sdt;
+ m_sst.velmrg = m_sst.sdt * 3;
+ m_sst.radmrg = getCollisionShape()->getMargin();
+ m_sst.updmrg = m_sst.radmrg * (btScalar)0.25;
+ /* Forces */
+ addVelocity(m_worldInfo->m_gravity * m_sst.sdt);
+ applyForces();
+ /* Integrate */
+ for (i = 0, ni = m_nodes.size(); i < ni; ++i)
+ {
+ Node& n = m_nodes[i];
+ n.m_q = n.m_x;
+ btVector3 deltaV = n.m_f * n.m_im * m_sst.sdt;
+ {
+ btScalar maxDisplacement = m_worldInfo->m_maxDisplacement;
+ btScalar clampDeltaV = maxDisplacement / m_sst.sdt;
+ for (int c = 0; c < 3; c++)
+ {
+ if (deltaV[c] > clampDeltaV)
+ {
+ deltaV[c] = clampDeltaV;
+ }
+ if (deltaV[c] < -clampDeltaV)
+ {
+ deltaV[c] = -clampDeltaV;
+ }
+ }
+ }
+ n.m_v += deltaV;
+ n.m_x += n.m_v * m_sst.sdt;
+ n.m_f = btVector3(0, 0, 0);
+ }
+ /* Clusters */
+ updateClusters();
+ /* Bounds */
+ updateBounds();
+ /* Nodes */
+ ATTRIBUTE_ALIGNED16(btDbvtVolume)
+ vol;
+ for (i = 0, ni = m_nodes.size(); i < ni; ++i)
+ {
+ Node& n = m_nodes[i];
+ vol = btDbvtVolume::FromCR(n.m_x, m_sst.radmrg);
+ m_ndbvt.update(n.m_leaf,
+ vol,
+ n.m_v * m_sst.velmrg,
+ m_sst.updmrg);
+ }
+ /* Faces */
+ if (!m_fdbvt.empty())
+ {
+ for (int i = 0; i < m_faces.size(); ++i)
+ {
+ Face& f = m_faces[i];
+ const btVector3 v = (f.m_n[0]->m_v +
+ f.m_n[1]->m_v +
+ f.m_n[2]->m_v) /
+ 3;
+ vol = VolumeOf(f, m_sst.radmrg);
+ m_fdbvt.update(f.m_leaf,
+ vol,
+ v * m_sst.velmrg,
+ m_sst.updmrg);
+ }
+ }
+ /* Pose */
+ updatePose();
+ /* Match */
+ if (m_pose.m_bframe && (m_cfg.kMT > 0))
+ {
+ const btMatrix3x3 posetrs = m_pose.m_rot;
+ for (int i = 0, ni = m_nodes.size(); i < ni; ++i)
+ {
+ Node& n = m_nodes[i];
+ if (n.m_im > 0)
+ {
+ const btVector3 x = posetrs * m_pose.m_pos[i] + m_pose.m_com;
+ n.m_x = Lerp(n.m_x, x, m_cfg.kMT);
+ }
+ }
+ }
+ /* Clear contacts */
+ m_rcontacts.resize(0);
+ m_scontacts.resize(0);
+ /* Optimize dbvt's */
+ m_ndbvt.optimizeIncremental(1);
+ m_fdbvt.optimizeIncremental(1);
+ m_cdbvt.optimizeIncremental(1);
+}
//
void btSoftBody::solveConstraints()
@@ -2534,12 +2557,12 @@ int btSoftBody::rayTest(const btVector3& rayFrom, const btVector3& rayTo,
}
int btSoftBody::rayFaceTest(const btVector3& rayFrom, const btVector3& rayTo,
- btScalar& mint, int& index) const
+ btScalar& mint, int& index) const
{
int cnt = 0;
{ /* Use dbvt */
RayFromToCaster collider(rayFrom, rayTo, mint);
-
+
btDbvt::rayTest(m_fdbvt.m_root, rayFrom, rayTo, collider);
if (collider.m_face)
{
@@ -2551,7 +2574,6 @@ int btSoftBody::rayFaceTest(const btVector3& rayFrom, const btVector3& rayTo,
return (cnt);
}
-
//
static inline btDbvntNode* copyToDbvnt(const btDbvtNode* n)
{
@@ -2580,7 +2602,7 @@ static inline void calculateNormalCone(btDbvntNode* root)
}
else
{
- btVector3 n0(0,0,0), n1(0,0,0);
+ btVector3 n0(0, 0, 0), n1(0, 0, 0);
btScalar a0 = 0, a1 = 0;
if (root->childs[0])
{
@@ -2594,8 +2616,8 @@ static inline void calculateNormalCone(btDbvntNode* root)
n1 = root->childs[1]->normal;
a1 = root->childs[1]->angle;
}
- root->normal = (n0+n1).safeNormalize();
- root->angle = btMax(a0,a1) + btAngle(n0, n1)*0.5;
+ root->normal = (n0 + n1).safeNormalize();
+ root->angle = btMax(a0, a1) + btAngle(n0, n1) * 0.5;
}
}
@@ -2609,7 +2631,8 @@ void btSoftBody::initializeFaceTree()
for (int i = 0; i < m_faces.size(); ++i)
{
Face& f = m_faces[i];
- ATTRIBUTE_ALIGNED16(btDbvtVolume) vol = VolumeOf(f, 0);
+ ATTRIBUTE_ALIGNED16(btDbvtVolume)
+ vol = VolumeOf(f, 0);
btDbvtNode* node = new (btAlignedAlloc(sizeof(btDbvtNode), 16)) btDbvtNode();
node->parent = NULL;
node->data = &f;
@@ -2623,7 +2646,7 @@ void btSoftBody::initializeFaceTree()
// construct the adjacency list for triangles
for (int i = 0; i < adj.size(); ++i)
{
- for (int j = i+1; j < adj.size(); ++j)
+ for (int j = i + 1; j < adj.size(); ++j)
{
int dup = 0;
for (int k = 0; k < 3; ++k)
@@ -2661,7 +2684,8 @@ void btSoftBody::rebuildNodeTree()
for (int i = 0; i < m_nodes.size(); ++i)
{
Node& n = m_nodes[i];
- ATTRIBUTE_ALIGNED16(btDbvtVolume) vol = btDbvtVolume::FromCR(n.m_x, 0);
+ ATTRIBUTE_ALIGNED16(btDbvtVolume)
+ vol = btDbvtVolume::FromCR(n.m_x, 0);
btDbvtNode* node = new (btAlignedAlloc(sizeof(btDbvtNode), 16)) btDbvtNode();
node->parent = NULL;
node->data = &n;
@@ -2704,61 +2728,61 @@ btVector3 btSoftBody::evaluateCom() const
}
bool btSoftBody::checkContact(const btCollisionObjectWrapper* colObjWrap,
- const btVector3& x,
- btScalar margin,
- btSoftBody::sCti& cti) const
-{
- btVector3 nrm;
- const btCollisionShape* shp = colObjWrap->getCollisionShape();
- // const btRigidBody *tmpRigid = btRigidBody::upcast(colObjWrap->getCollisionObject());
- //const btTransform &wtr = tmpRigid ? tmpRigid->getWorldTransform() : colObjWrap->getWorldTransform();
- const btTransform& wtr = colObjWrap->getWorldTransform();
- //todo: check which transform is needed here
-
- btScalar dst =
- m_worldInfo->m_sparsesdf.Evaluate(
- wtr.invXform(x),
- shp,
- nrm,
- margin);
- if (dst < 0)
- {
- cti.m_colObj = colObjWrap->getCollisionObject();
- cti.m_normal = wtr.getBasis() * nrm;
- cti.m_offset = -btDot(cti.m_normal, x - cti.m_normal * dst);
- return (true);
- }
- return (false);
+ const btVector3& x,
+ btScalar margin,
+ btSoftBody::sCti& cti) const
+{
+ btVector3 nrm;
+ const btCollisionShape* shp = colObjWrap->getCollisionShape();
+ // const btRigidBody *tmpRigid = btRigidBody::upcast(colObjWrap->getCollisionObject());
+ //const btTransform &wtr = tmpRigid ? tmpRigid->getWorldTransform() : colObjWrap->getWorldTransform();
+ const btTransform& wtr = colObjWrap->getWorldTransform();
+ //todo: check which transform is needed here
+
+ btScalar dst =
+ m_worldInfo->m_sparsesdf.Evaluate(
+ wtr.invXform(x),
+ shp,
+ nrm,
+ margin);
+ if (dst < 0)
+ {
+ cti.m_colObj = colObjWrap->getCollisionObject();
+ cti.m_normal = wtr.getBasis() * nrm;
+ cti.m_offset = -btDot(cti.m_normal, x - cti.m_normal * dst);
+ return (true);
+ }
+ return (false);
}
//
bool btSoftBody::checkDeformableContact(const btCollisionObjectWrapper* colObjWrap,
- const btVector3& x,
- btScalar margin,
- btSoftBody::sCti& cti, bool predict) const
+ const btVector3& x,
+ btScalar margin,
+ btSoftBody::sCti& cti, bool predict) const
{
btVector3 nrm;
const btCollisionShape* shp = colObjWrap->getCollisionShape();
- const btCollisionObject* tmpCollisionObj = colObjWrap->getCollisionObject();
- // use the position x_{n+1}^* = x_n + dt * v_{n+1}^* where v_{n+1}^* = v_n + dtg for collision detect
- // but resolve contact at x_n
- btTransform wtr = (predict) ?
- (colObjWrap->m_preTransform != NULL ? tmpCollisionObj->getInterpolationWorldTransform()*(*colObjWrap->m_preTransform) : tmpCollisionObj->getInterpolationWorldTransform())
- : colObjWrap->getWorldTransform();
+ const btCollisionObject* tmpCollisionObj = colObjWrap->getCollisionObject();
+ // use the position x_{n+1}^* = x_n + dt * v_{n+1}^* where v_{n+1}^* = v_n + dtg for collision detect
+ // but resolve contact at x_n
+ btTransform wtr = (predict) ? (colObjWrap->m_preTransform != NULL ? tmpCollisionObj->getInterpolationWorldTransform() * (*colObjWrap->m_preTransform) : tmpCollisionObj->getInterpolationWorldTransform())
+ : colObjWrap->getWorldTransform();
btScalar dst =
m_worldInfo->m_sparsesdf.Evaluate(
wtr.invXform(x),
shp,
nrm,
margin);
+
if (!predict)
{
cti.m_colObj = colObjWrap->getCollisionObject();
cti.m_normal = wtr.getBasis() * nrm;
- cti.m_offset = dst;
+ cti.m_offset = dst;
}
- if (dst < 0)
- return true;
+ if (dst < 0)
+ return true;
return (false);
}
@@ -2767,175 +2791,131 @@ bool btSoftBody::checkDeformableContact(const btCollisionObjectWrapper* colObjWr
// point p with respect to triangle (a, b, c)
static void getBarycentric(const btVector3& p, btVector3& a, btVector3& b, btVector3& c, btVector3& bary)
{
- btVector3 v0 = b - a, v1 = c - a, v2 = p - a;
- btScalar d00 = v0.dot(v0);
- btScalar d01 = v0.dot(v1);
- btScalar d11 = v1.dot(v1);
- btScalar d20 = v2.dot(v0);
- btScalar d21 = v2.dot(v1);
- btScalar denom = d00 * d11 - d01 * d01;
- bary.setY((d11 * d20 - d01 * d21) / denom);
- bary.setZ((d00 * d21 - d01 * d20) / denom);
- bary.setX(btScalar(1) - bary.getY() - bary.getZ());
+ btVector3 v0 = b - a, v1 = c - a, v2 = p - a;
+ btScalar d00 = v0.dot(v0);
+ btScalar d01 = v0.dot(v1);
+ btScalar d11 = v1.dot(v1);
+ btScalar d20 = v2.dot(v0);
+ btScalar d21 = v2.dot(v1);
+ btScalar denom = d00 * d11 - d01 * d01;
+ bary.setY((d11 * d20 - d01 * d21) / denom);
+ bary.setZ((d00 * d21 - d01 * d20) / denom);
+ bary.setX(btScalar(1) - bary.getY() - bary.getZ());
}
//
bool btSoftBody::checkDeformableFaceContact(const btCollisionObjectWrapper* colObjWrap,
- Face& f,
- btVector3& contact_point,
- btVector3& bary,
- btScalar margin,
- btSoftBody::sCti& cti, bool predict) const
-{
- btVector3 nrm;
- const btCollisionShape* shp = colObjWrap->getCollisionShape();
- const btCollisionObject* tmpCollisionObj = colObjWrap->getCollisionObject();
- // use the position x_{n+1}^* = x_n + dt * v_{n+1}^* where v_{n+1}^* = v_n + dtg for collision detect
- // but resolve contact at x_n
- btTransform wtr = (predict) ?
- (colObjWrap->m_preTransform != NULL ? tmpCollisionObj->getInterpolationWorldTransform()*(*colObjWrap->m_preTransform) : tmpCollisionObj->getInterpolationWorldTransform())
- : colObjWrap->getWorldTransform();
- btScalar dst;
-
-//#define USE_QUADRATURE 1
-//#define CACHE_PREV_COLLISION
-
- // use the contact position of the previous collision
-#ifdef CACHE_PREV_COLLISION
- if (f.m_pcontact[3] != 0)
- {
- for (int i = 0; i < 3; ++i)
- bary[i] = f.m_pcontact[i];
- contact_point = BaryEval(f.m_n[0]->m_x, f.m_n[1]->m_x, f.m_n[2]->m_x, bary);
- dst = m_worldInfo->m_sparsesdf.Evaluate(
- wtr.invXform(contact_point),
- shp,
- nrm,
- margin);
- nrm = wtr.getBasis() * nrm;
- cti.m_colObj = colObjWrap->getCollisionObject();
- // use cached contact point
- }
- else
- {
- btGjkEpaSolver2::sResults results;
- btTransform triangle_transform;
- triangle_transform.setIdentity();
- triangle_transform.setOrigin(f.m_n[0]->m_x);
- btTriangleShape triangle(btVector3(0,0,0), f.m_n[1]->m_x-f.m_n[0]->m_x, f.m_n[2]->m_x-f.m_n[0]->m_x);
- btVector3 guess(0,0,0);
- const btConvexShape* csh = static_cast<const btConvexShape*>(shp);
- btGjkEpaSolver2::SignedDistance(&triangle, triangle_transform, csh, wtr, guess, results);
- dst = results.distance - margin;
- contact_point = results.witnesses[0];
- getBarycentric(contact_point, f.m_n[0]->m_x, f.m_n[1]->m_x, f.m_n[2]->m_x, bary);
- nrm = results.normal;
- cti.m_colObj = colObjWrap->getCollisionObject();
- for (int i = 0; i < 3; ++i)
- f.m_pcontact[i] = bary[i];
- }
- return (dst < 0);
-#endif
+ Face& f,
+ btVector3& contact_point,
+ btVector3& bary,
+ btScalar margin,
+ btSoftBody::sCti& cti, bool predict) const
+{
+ btVector3 nrm;
+ const btCollisionShape* shp = colObjWrap->getCollisionShape();
+ const btCollisionObject* tmpCollisionObj = colObjWrap->getCollisionObject();
+ // use the position x_{n+1}^* = x_n + dt * v_{n+1}^* where v_{n+1}^* = v_n + dtg for collision detect
+ // but resolve contact at x_n
+ btTransform wtr = (predict) ? (colObjWrap->m_preTransform != NULL ? tmpCollisionObj->getInterpolationWorldTransform() * (*colObjWrap->m_preTransform) : tmpCollisionObj->getInterpolationWorldTransform())
+ : colObjWrap->getWorldTransform();
+ btScalar dst;
+ btGjkEpaSolver2::sResults results;
+
+// #define USE_QUADRATURE 1
- // use collision quadrature point
+ // use collision quadrature point
#ifdef USE_QUADRATURE
- {
- dst = SIMD_INFINITY;
- btVector3 local_nrm;
- for (int q = 0; q < m_quads.size(); ++q)
- {
- btVector3 p;
- if (predict)
- p = BaryEval(f.m_n[0]->m_q, f.m_n[1]->m_q, f.m_n[2]->m_q, m_quads[q]);
- else
- p = BaryEval(f.m_n[0]->m_x, f.m_n[1]->m_x, f.m_n[2]->m_x, m_quads[q]);
- btScalar local_dst = m_worldInfo->m_sparsesdf.Evaluate(
- wtr.invXform(p),
- shp,
- local_nrm,
- margin);
- if (local_dst < dst)
- {
- if (local_dst < 0 && predict)
- return true;
- dst = local_dst;
- contact_point = p;
- bary = m_quads[q];
- nrm = local_nrm;
- }
- if (!predict)
- {
- cti.m_colObj = colObjWrap->getCollisionObject();
- cti.m_normal = wtr.getBasis() * nrm;
- cti.m_offset = dst;
- }
- }
- return (dst < 0);
- }
+ {
+ dst = SIMD_INFINITY;
+ btVector3 local_nrm;
+ for (int q = 0; q < m_quads.size(); ++q)
+ {
+ btVector3 p;
+ if (predict)
+ p = BaryEval(f.m_n[0]->m_q, f.m_n[1]->m_q, f.m_n[2]->m_q, m_quads[q]);
+ else
+ p = BaryEval(f.m_n[0]->m_x, f.m_n[1]->m_x, f.m_n[2]->m_x, m_quads[q]);
+ btScalar local_dst = m_worldInfo->m_sparsesdf.Evaluate(
+ wtr.invXform(p),
+ shp,
+ local_nrm,
+ margin);
+ if (local_dst < dst)
+ {
+ if (local_dst < 0 && predict)
+ return true;
+ dst = local_dst;
+ contact_point = p;
+ bary = m_quads[q];
+ nrm = local_nrm;
+ }
+ if (!predict)
+ {
+ cti.m_colObj = colObjWrap->getCollisionObject();
+ cti.m_normal = wtr.getBasis() * nrm;
+ cti.m_offset = dst;
+ }
+ }
+ return (dst < 0);
+ }
#endif
-
-// // regular face contact
-// {
-// btGjkEpaSolver2::sResults results;
-// btTransform triangle_transform;
-// triangle_transform.setIdentity();
-// triangle_transform.setOrigin(f.m_n[0]->m_x);
-// btTriangleShape triangle(btVector3(0,0,0), f.m_n[1]->m_x-f.m_n[0]->m_x, f.m_n[2]->m_x-f.m_n[0]->m_x);
-// btVector3 guess(0,0,0);
-// if (predict)
-// {
-// triangle_transform.setOrigin(f.m_n[0]->m_q);
-// triangle = btTriangleShape(btVector3(0,0,0), f.m_n[1]->m_q-f.m_n[0]->m_q, f.m_n[2]->m_q-f.m_n[0]->m_q);
-// }
-// const btConvexShape* csh = static_cast<const btConvexShape*>(shp);
-//// btGjkEpaSolver2::SignedDistance(&triangle, triangle_transform, csh, wtr, guess, results);
-//// dst = results.distance - margin;
-//// contact_point = results.witnesses[0];
-// btGjkEpaSolver2::Penetration(&triangle, triangle_transform, csh, wtr, guess, results);
-// if (results.status == btGjkEpaSolver2::sResults::Separated)
-// return false;
-// dst = results.distance - margin;
-// contact_point = results.witnesses[1];
-// getBarycentric(contact_point, f.m_n[0]->m_x, f.m_n[1]->m_x, f.m_n[2]->m_x, bary);
-// nrm = results.normal;
-// for (int i = 0; i < 3; ++i)
-// f.m_pcontact[i] = bary[i];
-// }
-//
-// if (!predict)
-// {
-// cti.m_colObj = colObjWrap->getCollisionObject();
-// cti.m_normal = nrm;
-// cti.m_offset = dst;
-// }
-//
-
- // regular face contact
- {
- btGjkEpaSolver2::sResults results;
- btTransform triangle_transform;
- triangle_transform.setIdentity();
- triangle_transform.setOrigin(f.m_n[0]->m_q);
- btTriangleShape triangle(btVector3(0,0,0), f.m_n[1]->m_q-f.m_n[0]->m_q, f.m_n[2]->m_q-f.m_n[0]->m_q);
- btVector3 guess(0,0,0);
- const btConvexShape* csh = static_cast<const btConvexShape*>(shp);
- btGjkEpaSolver2::SignedDistance(&triangle, triangle_transform, csh, wtr, guess, results);
- dst = results.distance-csh->getMargin();
- dst -= margin;
- if (dst >= 0)
- return false;
- contact_point = results.witnesses[0];
- getBarycentric(contact_point, f.m_n[0]->m_q, f.m_n[1]->m_q, f.m_n[2]->m_q, bary);
- btVector3 curr = BaryEval(f.m_n[0]->m_x, f.m_n[1]->m_x, f.m_n[2]->m_x, bary);
- nrm = results.normal;
- cti.m_colObj = colObjWrap->getCollisionObject();
- cti.m_normal = nrm;
- cti.m_offset = dst + (curr - contact_point).dot(nrm);
- }
- return (dst < 0);
+
+ // collision detection using x*
+ btTransform triangle_transform;
+ triangle_transform.setIdentity();
+ triangle_transform.setOrigin(f.m_n[0]->m_q);
+ btTriangleShape triangle(btVector3(0, 0, 0), f.m_n[1]->m_q - f.m_n[0]->m_q, f.m_n[2]->m_q - f.m_n[0]->m_q);
+ btVector3 guess(0, 0, 0);
+ const btConvexShape* csh = static_cast<const btConvexShape*>(shp);
+ btGjkEpaSolver2::SignedDistance(&triangle, triangle_transform, csh, wtr, guess, results);
+ dst = results.distance - 2.0 * csh->getMargin() - margin; // margin padding so that the distance = the actual distance between face and rigid - margin of rigid - margin of deformable
+ if (dst >= 0)
+ return false;
+
+ // Use consistent barycenter to recalculate distance.
+ if (this->m_cacheBarycenter)
+ {
+ if (f.m_pcontact[3] != 0)
+ {
+ for (int i = 0; i < 3; ++i)
+ bary[i] = f.m_pcontact[i];
+ contact_point = BaryEval(f.m_n[0]->m_x, f.m_n[1]->m_x, f.m_n[2]->m_x, bary);
+ const btConvexShape* csh = static_cast<const btConvexShape*>(shp);
+ btGjkEpaSolver2::SignedDistance(contact_point, margin, csh, wtr, results);
+ cti.m_colObj = colObjWrap->getCollisionObject();
+ dst = results.distance;
+ cti.m_normal = results.normal;
+ cti.m_offset = dst;
+
+ //point-convex CD
+ wtr = colObjWrap->getWorldTransform();
+ btTriangleShape triangle2(btVector3(0, 0, 0), f.m_n[1]->m_x - f.m_n[0]->m_x, f.m_n[2]->m_x - f.m_n[0]->m_x);
+ triangle_transform.setOrigin(f.m_n[0]->m_x);
+ btGjkEpaSolver2::SignedDistance(&triangle2, triangle_transform, csh, wtr, guess, results);
+
+ dst = results.distance - csh->getMargin() - margin;
+ return true;
+ }
+ }
+
+ // Use triangle-convex CD.
+ wtr = colObjWrap->getWorldTransform();
+ btTriangleShape triangle2(btVector3(0, 0, 0), f.m_n[1]->m_x - f.m_n[0]->m_x, f.m_n[2]->m_x - f.m_n[0]->m_x);
+ triangle_transform.setOrigin(f.m_n[0]->m_x);
+ btGjkEpaSolver2::SignedDistance(&triangle2, triangle_transform, csh, wtr, guess, results);
+ contact_point = results.witnesses[0];
+ getBarycentric(contact_point, f.m_n[0]->m_x, f.m_n[1]->m_x, f.m_n[2]->m_x, bary);
+
+ for (int i = 0; i < 3; ++i)
+ f.m_pcontact[i] = bary[i];
+
+ dst = results.distance - csh->getMargin() - margin;
+ cti.m_colObj = colObjWrap->getCollisionObject();
+ cti.m_normal = results.normal;
+ cti.m_offset = dst;
+ return true;
}
-//
void btSoftBody::updateNormals()
{
const btVector3 zv(0, 0, 0);
@@ -2979,63 +2959,63 @@ void btSoftBody::updateBounds()
m_bounds[1] = btVector3(1000, 1000, 1000);
} else {*/
-// if (m_ndbvt.m_root)
-// {
-// const btVector3& mins = m_ndbvt.m_root->volume.Mins();
-// const btVector3& maxs = m_ndbvt.m_root->volume.Maxs();
-// const btScalar csm = getCollisionShape()->getMargin();
-// const btVector3 mrg = btVector3(csm,
-// csm,
-// csm) *
-// 1; // ??? to investigate...
-// m_bounds[0] = mins - mrg;
-// m_bounds[1] = maxs + mrg;
-// if (0 != getBroadphaseHandle())
-// {
-// m_worldInfo->m_broadphase->setAabb(getBroadphaseHandle(),
-// m_bounds[0],
-// m_bounds[1],
-// m_worldInfo->m_dispatcher);
-// }
-// }
-// else
-// {
-// m_bounds[0] =
-// m_bounds[1] = btVector3(0, 0, 0);
-// }
- if (m_nodes.size())
- {
- btVector3 mins = m_nodes[0].m_x;
- btVector3 maxs = m_nodes[0].m_x;
- for (int i = 1; i < m_nodes.size(); ++i)
- {
- for (int d = 0; d < 3; ++d)
- {
- if (m_nodes[i].m_x[d] > maxs[d])
- maxs[d] = m_nodes[i].m_x[d];
- if (m_nodes[i].m_x[d] < mins[d])
- mins[d] = m_nodes[i].m_x[d];
- }
- }
- const btScalar csm = getCollisionShape()->getMargin();
- const btVector3 mrg = btVector3(csm,
- csm,
- csm);
- m_bounds[0] = mins - mrg;
- m_bounds[1] = maxs + mrg;
- if (0 != getBroadphaseHandle())
- {
- m_worldInfo->m_broadphase->setAabb(getBroadphaseHandle(),
- m_bounds[0],
- m_bounds[1],
- m_worldInfo->m_dispatcher);
- }
- }
- else
- {
- m_bounds[0] =
- m_bounds[1] = btVector3(0, 0, 0);
- }
+ // if (m_ndbvt.m_root)
+ // {
+ // const btVector3& mins = m_ndbvt.m_root->volume.Mins();
+ // const btVector3& maxs = m_ndbvt.m_root->volume.Maxs();
+ // const btScalar csm = getCollisionShape()->getMargin();
+ // const btVector3 mrg = btVector3(csm,
+ // csm,
+ // csm) *
+ // 1; // ??? to investigate...
+ // m_bounds[0] = mins - mrg;
+ // m_bounds[1] = maxs + mrg;
+ // if (0 != getBroadphaseHandle())
+ // {
+ // m_worldInfo->m_broadphase->setAabb(getBroadphaseHandle(),
+ // m_bounds[0],
+ // m_bounds[1],
+ // m_worldInfo->m_dispatcher);
+ // }
+ // }
+ // else
+ // {
+ // m_bounds[0] =
+ // m_bounds[1] = btVector3(0, 0, 0);
+ // }
+ if (m_nodes.size())
+ {
+ btVector3 mins = m_nodes[0].m_x;
+ btVector3 maxs = m_nodes[0].m_x;
+ for (int i = 1; i < m_nodes.size(); ++i)
+ {
+ for (int d = 0; d < 3; ++d)
+ {
+ if (m_nodes[i].m_x[d] > maxs[d])
+ maxs[d] = m_nodes[i].m_x[d];
+ if (m_nodes[i].m_x[d] < mins[d])
+ mins[d] = m_nodes[i].m_x[d];
+ }
+ }
+ const btScalar csm = getCollisionShape()->getMargin();
+ const btVector3 mrg = btVector3(csm,
+ csm,
+ csm);
+ m_bounds[0] = mins - mrg;
+ m_bounds[1] = maxs + mrg;
+ if (0 != getBroadphaseHandle())
+ {
+ m_worldInfo->m_broadphase->setAabb(getBroadphaseHandle(),
+ m_bounds[0],
+ m_bounds[1],
+ m_worldInfo->m_dispatcher);
+ }
+ }
+ else
+ {
+ m_bounds[0] =
+ m_bounds[1] = btVector3(0, 0, 0);
+ }
}
//
@@ -3454,60 +3434,120 @@ void btSoftBody::dampClusters()
void btSoftBody::setSpringStiffness(btScalar k)
{
- for (int i = 0; i < m_links.size(); ++i)
- {
- m_links[i].Feature::m_material->m_kLST = k;
- }
- m_repulsionStiffness = k;
+ for (int i = 0; i < m_links.size(); ++i)
+ {
+ m_links[i].Feature::m_material->m_kLST = k;
+ }
+ m_repulsionStiffness = k;
+}
+
+void btSoftBody::setGravityFactor(btScalar gravFactor)
+{
+ m_gravityFactor = gravFactor;
+}
+
+void btSoftBody::setCacheBarycenter(bool cacheBarycenter)
+{
+ m_cacheBarycenter = cacheBarycenter;
}
void btSoftBody::initializeDmInverse()
{
- btScalar unit_simplex_measure = 1./6.;
-
- for (int i = 0; i < m_tetras.size(); ++i)
- {
- Tetra &t = m_tetras[i];
- btVector3 c1 = t.m_n[1]->m_x - t.m_n[0]->m_x;
- btVector3 c2 = t.m_n[2]->m_x - t.m_n[0]->m_x;
- btVector3 c3 = t.m_n[3]->m_x - t.m_n[0]->m_x;
- btMatrix3x3 Dm(c1.getX(), c2.getX(), c3.getX(),
- c1.getY(), c2.getY(), c3.getY(),
- c1.getZ(), c2.getZ(), c3.getZ());
- t.m_element_measure = Dm.determinant() * unit_simplex_measure;
- t.m_Dm_inverse = Dm.inverse();
- }
+ btScalar unit_simplex_measure = 1. / 6.;
+
+ for (int i = 0; i < m_tetras.size(); ++i)
+ {
+ Tetra& t = m_tetras[i];
+ btVector3 c1 = t.m_n[1]->m_x - t.m_n[0]->m_x;
+ btVector3 c2 = t.m_n[2]->m_x - t.m_n[0]->m_x;
+ btVector3 c3 = t.m_n[3]->m_x - t.m_n[0]->m_x;
+ btMatrix3x3 Dm(c1.getX(), c2.getX(), c3.getX(),
+ c1.getY(), c2.getY(), c3.getY(),
+ c1.getZ(), c2.getZ(), c3.getZ());
+ t.m_element_measure = Dm.determinant() * unit_simplex_measure;
+ t.m_Dm_inverse = Dm.inverse();
+
+ // calculate the first three columns of P^{-1}
+ btVector3 a = t.m_n[0]->m_x;
+ btVector3 b = t.m_n[1]->m_x;
+ btVector3 c = t.m_n[2]->m_x;
+ btVector3 d = t.m_n[3]->m_x;
+
+ btScalar det = 1 / (a[0] * b[1] * c[2] - a[0] * b[1] * d[2] - a[0] * b[2] * c[1] + a[0] * b[2] * d[1] + a[0] * c[1] * d[2] - a[0] * c[2] * d[1] + a[1] * (-b[0] * c[2] + b[0] * d[2] + b[2] * c[0] - b[2] * d[0] - c[0] * d[2] + c[2] * d[0]) + a[2] * (b[0] * c[1] - b[0] * d[1] + b[1] * (d[0] - c[0]) + c[0] * d[1] - c[1] * d[0]) - b[0] * c[1] * d[2] + b[0] * c[2] * d[1] + b[1] * c[0] * d[2] - b[1] * c[2] * d[0] - b[2] * c[0] * d[1] + b[2] * c[1] * d[0]);
+
+ btScalar P11 = -b[2] * c[1] + d[2] * c[1] + b[1] * c[2] + b[2] * d[1] - c[2] * d[1] - b[1] * d[2];
+ btScalar P12 = b[2] * c[0] - d[2] * c[0] - b[0] * c[2] - b[2] * d[0] + c[2] * d[0] + b[0] * d[2];
+ btScalar P13 = -b[1] * c[0] + d[1] * c[0] + b[0] * c[1] + b[1] * d[0] - c[1] * d[0] - b[0] * d[1];
+ btScalar P21 = a[2] * c[1] - d[2] * c[1] - a[1] * c[2] - a[2] * d[1] + c[2] * d[1] + a[1] * d[2];
+ btScalar P22 = -a[2] * c[0] + d[2] * c[0] + a[0] * c[2] + a[2] * d[0] - c[2] * d[0] - a[0] * d[2];
+ btScalar P23 = a[1] * c[0] - d[1] * c[0] - a[0] * c[1] - a[1] * d[0] + c[1] * d[0] + a[0] * d[1];
+ btScalar P31 = -a[2] * b[1] + d[2] * b[1] + a[1] * b[2] + a[2] * d[1] - b[2] * d[1] - a[1] * d[2];
+ btScalar P32 = a[2] * b[0] - d[2] * b[0] - a[0] * b[2] - a[2] * d[0] + b[2] * d[0] + a[0] * d[2];
+ btScalar P33 = -a[1] * b[0] + d[1] * b[0] + a[0] * b[1] + a[1] * d[0] - b[1] * d[0] - a[0] * d[1];
+ btScalar P41 = a[2] * b[1] - c[2] * b[1] - a[1] * b[2] - a[2] * c[1] + b[2] * c[1] + a[1] * c[2];
+ btScalar P42 = -a[2] * b[0] + c[2] * b[0] + a[0] * b[2] + a[2] * c[0] - b[2] * c[0] - a[0] * c[2];
+ btScalar P43 = a[1] * b[0] - c[1] * b[0] - a[0] * b[1] - a[1] * c[0] + b[1] * c[0] + a[0] * c[1];
+
+ btVector4 p1(P11 * det, P21 * det, P31 * det, P41 * det);
+ btVector4 p2(P12 * det, P22 * det, P32 * det, P42 * det);
+ btVector4 p3(P13 * det, P23 * det, P33 * det, P43 * det);
+
+ t.m_P_inv[0] = p1;
+ t.m_P_inv[1] = p2;
+ t.m_P_inv[2] = p3;
+ }
+}
+
+static btScalar Dot4(const btVector4& a, const btVector4& b)
+{
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
}
void btSoftBody::updateDeformation()
{
- for (int i = 0; i < m_tetras.size(); ++i)
- {
- btSoftBody::Tetra& t = m_tetras[i];
- btVector3 c1 = t.m_n[1]->m_q - t.m_n[0]->m_q;
- btVector3 c2 = t.m_n[2]->m_q - t.m_n[0]->m_q;
- btVector3 c3 = t.m_n[3]->m_q - t.m_n[0]->m_q;
- btMatrix3x3 Ds(c1.getX(), c2.getX(), c3.getX(),
- c1.getY(), c2.getY(), c3.getY(),
- c1.getZ(), c2.getZ(), c3.getZ());
- t.m_F = Ds * t.m_Dm_inverse;
-
- btSoftBody::TetraScratch& s = m_tetraScratches[i];
- s.m_F = t.m_F;
- s.m_J = t.m_F.determinant();
- btMatrix3x3 C = t.m_F.transpose()*t.m_F;
- s.m_trace = C[0].getX() + C[1].getY() + C[2].getZ();
- s.m_cofF = t.m_F.adjoint().transpose();
- }
+ btQuaternion q;
+ for (int i = 0; i < m_tetras.size(); ++i)
+ {
+ btSoftBody::Tetra& t = m_tetras[i];
+ btVector3 c1 = t.m_n[1]->m_q - t.m_n[0]->m_q;
+ btVector3 c2 = t.m_n[2]->m_q - t.m_n[0]->m_q;
+ btVector3 c3 = t.m_n[3]->m_q - t.m_n[0]->m_q;
+ btMatrix3x3 Ds(c1.getX(), c2.getX(), c3.getX(),
+ c1.getY(), c2.getY(), c3.getY(),
+ c1.getZ(), c2.getZ(), c3.getZ());
+ t.m_F = Ds * t.m_Dm_inverse;
+
+ btSoftBody::TetraScratch& s = m_tetraScratches[i];
+ s.m_F = t.m_F;
+ s.m_J = t.m_F.determinant();
+ btMatrix3x3 C = t.m_F.transpose() * t.m_F;
+ s.m_trace = C[0].getX() + C[1].getY() + C[2].getZ();
+ s.m_cofF = t.m_F.adjoint().transpose();
+
+ btVector3 a = t.m_n[0]->m_q;
+ btVector3 b = t.m_n[1]->m_q;
+ btVector3 c = t.m_n[2]->m_q;
+ btVector3 d = t.m_n[3]->m_q;
+ btVector4 q1(a[0], b[0], c[0], d[0]);
+ btVector4 q2(a[1], b[1], c[1], d[1]);
+ btVector4 q3(a[2], b[2], c[2], d[2]);
+ btMatrix3x3 B(Dot4(q1, t.m_P_inv[0]), Dot4(q1, t.m_P_inv[1]), Dot4(q1, t.m_P_inv[2]),
+ Dot4(q2, t.m_P_inv[0]), Dot4(q2, t.m_P_inv[1]), Dot4(q2, t.m_P_inv[2]),
+ Dot4(q3, t.m_P_inv[0]), Dot4(q3, t.m_P_inv[1]), Dot4(q3, t.m_P_inv[2]));
+ q.setRotation(btVector3(0, 0, 1), 0);
+ B.extractRotation(q, 0.01); // precision of the rotation is not very important for visual correctness.
+ btMatrix3x3 Q(q);
+ s.m_corotation = Q;
+ }
}
void btSoftBody::advanceDeformation()
{
- updateDeformation();
- for (int i = 0; i < m_tetras.size(); ++i)
- {
- m_tetraScratchesTn[i] = m_tetraScratches[i];
- }
+ updateDeformation();
+ for (int i = 0; i < m_tetras.size(); ++i)
+ {
+ m_tetraScratchesTn[i] = m_tetraScratches[i];
+ }
}
//
void btSoftBody::Joint::Prepare(btScalar dt, int)
@@ -3750,7 +3790,7 @@ void btSoftBody::applyForces()
//
void btSoftBody::setMaxStress(btScalar maxStress)
{
- m_cfg.m_maxStress = maxStress;
+ m_cfg.m_maxStress = maxStress;
}
//
@@ -3765,7 +3805,7 @@ void btSoftBody::interpolateRenderMesh()
const Node* p2 = m_renderNodesParents[i][2];
btVector3 normal = btCross(p1->m_x - p0->m_x, p2->m_x - p0->m_x);
btVector3 unit_normal = normal.normalized();
- Node& n = m_renderNodes[i];
+ RenderNode& n = m_renderNodes[i];
n.m_x.setZero();
for (int j = 0; j < 3; ++j)
{
@@ -3778,7 +3818,7 @@ void btSoftBody::interpolateRenderMesh()
{
for (int i = 0; i < m_renderNodes.size(); ++i)
{
- Node& n = m_renderNodes[i];
+ RenderNode& n = m_renderNodes[i];
n.m_x.setZero();
for (int j = 0; j < 4; ++j)
{
@@ -3793,13 +3833,13 @@ void btSoftBody::interpolateRenderMesh()
void btSoftBody::setCollisionQuadrature(int N)
{
- for (int i = 0; i <= N; ++i)
- {
- for (int j = 0; i+j <= N; ++j)
- {
- m_quads.push_back(btVector3(btScalar(i)/btScalar(N), btScalar(j)/btScalar(N), btScalar(N-i-j)/btScalar(N)));
- }
- }
+ for (int i = 0; i <= N; ++i)
+ {
+ for (int j = 0; i + j <= N; ++j)
+ {
+ m_quads.push_back(btVector3(btScalar(i) / btScalar(N), btScalar(j) / btScalar(N), btScalar(N - i - j) / btScalar(N)));
+ }
+ }
}
//
@@ -4006,12 +4046,12 @@ btSoftBody::vsolver_t btSoftBody::getSolver(eVSolver::_ solver)
void btSoftBody::setSelfCollision(bool useSelfCollision)
{
- m_useSelfCollision = useSelfCollision;
+ m_useSelfCollision = useSelfCollision;
}
bool btSoftBody::useSelfCollision()
{
- return m_useSelfCollision;
+ return m_useSelfCollision;
}
//
@@ -4052,23 +4092,23 @@ void btSoftBody::defaultCollisionHandler(const btCollisionObjectWrapper* pcoWrap
collider.ProcessColObj(this, pcoWrap);
}
break;
- case fCollision::SDF_RD:
- {
- btRigidBody* prb1 = (btRigidBody*)btRigidBody::upcast(pcoWrap->getCollisionObject());
- if (pcoWrap->getCollisionObject()->isActive() || this->isActive())
- {
- const btTransform wtr = pcoWrap->getWorldTransform();
- const btScalar timemargin = 0;
- const btScalar basemargin = getCollisionShape()->getMargin();
- btVector3 mins;
- btVector3 maxs;
- ATTRIBUTE_ALIGNED16(btDbvtVolume)
- volume;
- pcoWrap->getCollisionShape()->getAabb(wtr,
- mins,
- maxs);
- volume = btDbvtVolume::FromMM(mins, maxs);
- volume.Expand(btVector3(basemargin, basemargin, basemargin));
+ case fCollision::SDF_RD:
+ {
+ btRigidBody* prb1 = (btRigidBody*)btRigidBody::upcast(pcoWrap->getCollisionObject());
+ if (pcoWrap->getCollisionObject()->isActive() || this->isActive())
+ {
+ const btTransform wtr = pcoWrap->getWorldTransform();
+ const btScalar timemargin = 0;
+ const btScalar basemargin = getCollisionShape()->getMargin();
+ btVector3 mins;
+ btVector3 maxs;
+ ATTRIBUTE_ALIGNED16(btDbvtVolume)
+ volume;
+ pcoWrap->getCollisionShape()->getAabb(wtr,
+ mins,
+ maxs);
+ volume = btDbvtVolume::FromMM(mins, maxs);
+ volume.Expand(btVector3(basemargin, basemargin, basemargin));
if (m_cfg.collisions & fCollision::SDF_RDN)
{
btSoftColliders::CollideSDF_RD docollideNode;
@@ -4080,26 +4120,26 @@ void btSoftBody::defaultCollisionHandler(const btCollisionObjectWrapper* pcoWrap
m_ndbvt.collideTV(m_ndbvt.m_root, volume, docollideNode);
}
- if (((pcoWrap->getCollisionObject()->getInternalType() == CO_RIGID_BODY) && (m_cfg.collisions & fCollision::SDF_RDF)) || ((pcoWrap->getCollisionObject()->getInternalType() == CO_FEATHERSTONE_LINK) && (m_cfg.collisions & fCollision::SDF_MDF)))
- {
- btSoftColliders::CollideSDF_RDF docollideFace;
- docollideFace.psb = this;
- docollideFace.m_colObj1Wrap = pcoWrap;
- docollideFace.m_rigidBody = prb1;
+ if (((pcoWrap->getCollisionObject()->getInternalType() == CO_RIGID_BODY) && (m_cfg.collisions & fCollision::SDF_RDF)) || ((pcoWrap->getCollisionObject()->getInternalType() == CO_FEATHERSTONE_LINK) && (m_cfg.collisions & fCollision::SDF_MDF)))
+ {
+ btSoftColliders::CollideSDF_RDF docollideFace;
+ docollideFace.psb = this;
+ docollideFace.m_colObj1Wrap = pcoWrap;
+ docollideFace.m_rigidBody = prb1;
docollideFace.dynmargin = basemargin + timemargin;
docollideFace.stamargin = basemargin;
- m_fdbvt.collideTV(m_fdbvt.m_root, volume, docollideFace);
- }
- }
- }
- break;
+ m_fdbvt.collideTV(m_fdbvt.m_root, volume, docollideFace);
+ }
+ }
+ }
+ break;
}
}
//
void btSoftBody::defaultCollisionHandler(btSoftBody* psb)
{
- BT_PROFILE("Deformable Collision");
+ BT_PROFILE("Deformable Collision");
const int cf = m_cfg.collisions & psb->m_cfg.collisions;
switch (cf & fCollision::SVSmask)
{
@@ -4137,60 +4177,60 @@ void btSoftBody::defaultCollisionHandler(btSoftBody* psb)
}
}
break;
- case fCollision::VF_DD:
- {
- if (!psb->m_softSoftCollision)
- return;
- if (psb->isActive() || this->isActive())
- {
- if (this != psb)
- {
- btSoftColliders::CollideVF_DD docollide;
- /* common */
- docollide.mrg = getCollisionShape()->getMargin() +
- psb->getCollisionShape()->getMargin();
- /* psb0 nodes vs psb1 faces */
- if (psb->m_tetras.size() > 0)
- docollide.useFaceNormal = true;
- else
- docollide.useFaceNormal = false;
- docollide.psb[0] = this;
- docollide.psb[1] = psb;
- docollide.psb[0]->m_ndbvt.collideTT(docollide.psb[0]->m_ndbvt.m_root,
- docollide.psb[1]->m_fdbvt.m_root,
- docollide);
-
- /* psb1 nodes vs psb0 faces */
- if (this->m_tetras.size() > 0)
- docollide.useFaceNormal = true;
- else
- docollide.useFaceNormal = false;
- docollide.psb[0] = psb;
- docollide.psb[1] = this;
- docollide.psb[0]->m_ndbvt.collideTT(docollide.psb[0]->m_ndbvt.m_root,
- docollide.psb[1]->m_fdbvt.m_root,
- docollide);
- }
- else
- {
- if (psb->useSelfCollision())
- {
- btSoftColliders::CollideFF_DD docollide;
- docollide.mrg = 2*getCollisionShape()->getMargin();
- docollide.psb[0] = this;
- docollide.psb[1] = psb;
- if (this->m_tetras.size() > 0)
- docollide.useFaceNormal = true;
- else
- docollide.useFaceNormal = false;
- /* psb0 faces vs psb0 faces */
- calculateNormalCone(this->m_fdbvnt);
- this->m_fdbvt.selfCollideT(m_fdbvnt,docollide);
- }
- }
- }
- }
- break;
+ case fCollision::VF_DD:
+ {
+ if (!psb->m_softSoftCollision)
+ return;
+ if (psb->isActive() || this->isActive())
+ {
+ if (this != psb)
+ {
+ btSoftColliders::CollideVF_DD docollide;
+ /* common */
+ docollide.mrg = getCollisionShape()->getMargin() +
+ psb->getCollisionShape()->getMargin();
+ /* psb0 nodes vs psb1 faces */
+ if (psb->m_tetras.size() > 0)
+ docollide.useFaceNormal = true;
+ else
+ docollide.useFaceNormal = false;
+ docollide.psb[0] = this;
+ docollide.psb[1] = psb;
+ docollide.psb[0]->m_ndbvt.collideTT(docollide.psb[0]->m_ndbvt.m_root,
+ docollide.psb[1]->m_fdbvt.m_root,
+ docollide);
+
+ /* psb1 nodes vs psb0 faces */
+ if (this->m_tetras.size() > 0)
+ docollide.useFaceNormal = true;
+ else
+ docollide.useFaceNormal = false;
+ docollide.psb[0] = psb;
+ docollide.psb[1] = this;
+ docollide.psb[0]->m_ndbvt.collideTT(docollide.psb[0]->m_ndbvt.m_root,
+ docollide.psb[1]->m_fdbvt.m_root,
+ docollide);
+ }
+ else
+ {
+ if (psb->useSelfCollision())
+ {
+ btSoftColliders::CollideFF_DD docollide;
+ docollide.mrg = 2 * getCollisionShape()->getMargin();
+ docollide.psb[0] = this;
+ docollide.psb[1] = psb;
+ if (this->m_tetras.size() > 0)
+ docollide.useFaceNormal = true;
+ else
+ docollide.useFaceNormal = false;
+ /* psb0 faces vs psb0 faces */
+ calculateNormalCone(this->m_fdbvnt);
+ this->m_fdbvt.selfCollideT(m_fdbvnt, docollide);
+ }
+ }
+ }
+ }
+ break;
default:
{
}
@@ -4205,7 +4245,7 @@ void btSoftBody::geometricCollisionHandler(btSoftBody* psb)
{
btSoftColliders::CollideCCD docollide;
/* common */
- docollide.mrg = SAFE_EPSILON; // for rounding error instead of actual margin
+ docollide.mrg = SAFE_EPSILON; // for rounding error instead of actual margin
docollide.dt = psb->m_sst.sdt;
/* psb0 nodes vs psb1 faces */
if (psb->m_tetras.size() > 0)
@@ -4215,8 +4255,8 @@ void btSoftBody::geometricCollisionHandler(btSoftBody* psb)
docollide.psb[0] = this;
docollide.psb[1] = psb;
docollide.psb[0]->m_ndbvt.collideTT(docollide.psb[0]->m_ndbvt.m_root,
- docollide.psb[1]->m_fdbvt.m_root,
- docollide);
+ docollide.psb[1]->m_fdbvt.m_root,
+ docollide);
/* psb1 nodes vs psb0 faces */
if (this->m_tetras.size() > 0)
docollide.useFaceNormal = true;
@@ -4225,8 +4265,8 @@ void btSoftBody::geometricCollisionHandler(btSoftBody* psb)
docollide.psb[0] = psb;
docollide.psb[1] = this;
docollide.psb[0]->m_ndbvt.collideTT(docollide.psb[0]->m_ndbvt.m_root,
- docollide.psb[1]->m_fdbvt.m_root,
- docollide);
+ docollide.psb[1]->m_fdbvt.m_root,
+ docollide);
}
else
{
@@ -4236,14 +4276,14 @@ void btSoftBody::geometricCollisionHandler(btSoftBody* psb)
docollide.mrg = SAFE_EPSILON;
docollide.psb[0] = this;
docollide.psb[1] = psb;
- docollide.dt = psb->m_sst.sdt;
+ docollide.dt = psb->m_sst.sdt;
if (this->m_tetras.size() > 0)
docollide.useFaceNormal = true;
else
docollide.useFaceNormal = false;
/* psb0 faces vs psb0 faces */
calculateNormalCone(this->m_fdbvnt); // should compute this outside of this scope
- this->m_fdbvt.selfCollideT(m_fdbvnt,docollide);
+ this->m_fdbvt.selfCollideT(m_fdbvnt, docollide);
}
}
}
@@ -4648,44 +4688,43 @@ const char* btSoftBody::serialize(void* dataBuffer, class btSerializer* serializ
void btSoftBody::updateDeactivation(btScalar timeStep)
{
- if ((getActivationState() == ISLAND_SLEEPING) || (getActivationState() == DISABLE_DEACTIVATION))
- return;
+ if ((getActivationState() == ISLAND_SLEEPING) || (getActivationState() == DISABLE_DEACTIVATION))
+ return;
- if (m_maxSpeedSquared < m_sleepingThreshold * m_sleepingThreshold)
- {
- m_deactivationTime += timeStep;
- }
- else
- {
- m_deactivationTime = btScalar(0.);
- setActivationState(0);
- }
+ if (m_maxSpeedSquared < m_sleepingThreshold * m_sleepingThreshold)
+ {
+ m_deactivationTime += timeStep;
+ }
+ else
+ {
+ m_deactivationTime = btScalar(0.);
+ setActivationState(0);
+ }
}
-
void btSoftBody::setZeroVelocity()
{
- for (int i = 0; i < m_nodes.size(); ++i)
- {
- m_nodes[i].m_v.setZero();
- }
+ for (int i = 0; i < m_nodes.size(); ++i)
+ {
+ m_nodes[i].m_v.setZero();
+ }
}
bool btSoftBody::wantsSleeping()
{
- if (getActivationState() == DISABLE_DEACTIVATION)
- return false;
+ if (getActivationState() == DISABLE_DEACTIVATION)
+ return false;
- //disable deactivation
- if (gDisableDeactivation || (gDeactivationTime == btScalar(0.)))
- return false;
+ //disable deactivation
+ if (gDisableDeactivation || (gDeactivationTime == btScalar(0.)))
+ return false;
- if ((getActivationState() == ISLAND_SLEEPING) || (getActivationState() == WANTS_DEACTIVATION))
- return true;
+ if ((getActivationState() == ISLAND_SLEEPING) || (getActivationState() == WANTS_DEACTIVATION))
+ return true;
- if (m_deactivationTime > gDeactivationTime)
- {
- return true;
- }
- return false;
+ if (m_deactivationTime > gDeactivationTime)
+ {
+ return true;
+ }
+ return false;
}
diff --git a/thirdparty/bullet/BulletSoftBody/btSoftBody.h b/thirdparty/bullet/BulletSoftBody/btSoftBody.h
index 6a55eccbd2..f578487b8c 100644
--- a/thirdparty/bullet/BulletSoftBody/btSoftBody.h
+++ b/thirdparty/bullet/BulletSoftBody/btSoftBody.h
@@ -35,7 +35,7 @@ subject to the following restrictions:
//#else
#define btSoftBodyData btSoftBodyFloatData
#define btSoftBodyDataName "btSoftBodyFloatData"
-static const btScalar OVERLAP_REDUCTION_FACTOR = 0.1;
+static const btScalar OVERLAP_REDUCTION_FACTOR = 0.1;
static unsigned long seed = 243703;
//#endif //BT_USE_DOUBLE_PRECISION
@@ -171,10 +171,10 @@ public:
CL_SELF = 0x0040, ///Cluster soft body self collision
VF_DD = 0x0080, ///Vertex vs face soft vs soft handling
- RVDFmask = 0x0f00, /// Rigid versus deformable face mask
- SDF_RDF = 0x0100, /// GJK based Rigid vs. deformable face
- SDF_MDF = 0x0200, /// GJK based Multibody vs. deformable face
- SDF_RDN = 0x0400, /// SDF based Rigid vs. deformable node
+ RVDFmask = 0x0f00, /// Rigid versus deformable face mask
+ SDF_RDF = 0x0100, /// GJK based Rigid vs. deformable face
+ SDF_MDF = 0x0200, /// GJK based Multibody vs. deformable face
+ SDF_RDN = 0x0400, /// SDF based Rigid vs. deformable node
/* presets */
Default = SDF_RS,
END
@@ -226,7 +226,7 @@ public:
const btCollisionObject* m_colObj; /* Rigid body */
btVector3 m_normal; /* Outward normal */
btScalar m_offset; /* Offset from origin */
- btVector3 m_bary; /* Barycentric weights for faces */
+ btVector3 m_bary; /* Barycentric weights for faces */
};
/* sMedium */
@@ -258,20 +258,29 @@ public:
Material* m_material; // Material
};
/* Node */
+ struct RenderNode
+ {
+ btVector3 m_x;
+ btVector3 m_uv1;
+ btVector3 m_normal;
+ };
struct Node : Feature
{
btVector3 m_x; // Position
btVector3 m_q; // Previous step position/Test position
btVector3 m_v; // Velocity
- btVector3 m_vn; // Previous step velocity
+ btVector3 m_vn; // Previous step velocity
btVector3 m_f; // Force accumulator
btVector3 m_n; // Normal
btScalar m_im; // 1/mass
btScalar m_area; // Area
btDbvtNode* m_leaf; // Leaf data
- btScalar m_penetration; // depth of penetration
+ int m_constrained; // depth of penetration
int m_battach : 1; // Attached
- int index;
+ int index;
+ btVector3 m_splitv; // velocity associated with split impulse
+ btMatrix3x3 m_effectiveMass; // effective mass in contact
+ btMatrix3x3 m_effectiveMass_inv; // inverse of effective mass
};
/* Link */
ATTRIBUTE_ALIGNED16(struct)
@@ -287,40 +296,47 @@ public:
BT_DECLARE_ALIGNED_ALLOCATOR();
};
+ struct RenderFace
+ {
+ RenderNode* m_n[3]; // Node pointers
+ };
+
/* Face */
struct Face : Feature
{
- Node* m_n[3]; // Node pointers
- btVector3 m_normal; // Normal
- btScalar m_ra; // Rest area
- btDbvtNode* m_leaf; // Leaf data
- btVector4 m_pcontact; // barycentric weights of the persistent contact
- btVector3 m_n0, m_n1, m_vn;
- int m_index;
+ Node* m_n[3]; // Node pointers
+ btVector3 m_normal; // Normal
+ btScalar m_ra; // Rest area
+ btDbvtNode* m_leaf; // Leaf data
+ btVector4 m_pcontact; // barycentric weights of the persistent contact
+ btVector3 m_n0, m_n1, m_vn;
+ int m_index;
};
/* Tetra */
struct Tetra : Feature
{
- Node* m_n[4]; // Node pointers
- btScalar m_rv; // Rest volume
- btDbvtNode* m_leaf; // Leaf data
- btVector3 m_c0[4]; // gradients
- btScalar m_c1; // (4*kVST)/(im0+im1+im2+im3)
- btScalar m_c2; // m_c1/sum(|g0..3|^2)
- btMatrix3x3 m_Dm_inverse; // rest Dm^-1
- btMatrix3x3 m_F;
- btScalar m_element_measure;
+ Node* m_n[4]; // Node pointers
+ btScalar m_rv; // Rest volume
+ btDbvtNode* m_leaf; // Leaf data
+ btVector3 m_c0[4]; // gradients
+ btScalar m_c1; // (4*kVST)/(im0+im1+im2+im3)
+ btScalar m_c2; // m_c1/sum(|g0..3|^2)
+ btMatrix3x3 m_Dm_inverse; // rest Dm^-1
+ btMatrix3x3 m_F;
+ btScalar m_element_measure;
+ btVector4 m_P_inv[3]; // first three columns of P_inv matrix
+ };
+
+ /* TetraScratch */
+ struct TetraScratch
+ {
+ btMatrix3x3 m_F; // deformation gradient F
+ btScalar m_trace; // trace of F^T * F
+ btScalar m_J; // det(F)
+ btMatrix3x3 m_cofF; // cofactor of F
+ btMatrix3x3 m_corotation; // corotatio of the tetra
};
-
- /* TetraScratch */
- struct TetraScratch
- {
- btMatrix3x3 m_F; // deformation gradient F
- btScalar m_trace; // trace of F^T * F
- btScalar m_J; // det(F)
- btMatrix3x3 m_cofF; // cofactor of F
- };
-
+
/* RContact */
struct RContact
{
@@ -331,67 +347,68 @@ public:
btScalar m_c2; // ima*dt
btScalar m_c3; // Friction
btScalar m_c4; // Hardness
-
- // jacobians and unit impulse responses for multibody
- btMultiBodyJacobianData jacobianData_normal;
- btMultiBodyJacobianData jacobianData_t1;
- btMultiBodyJacobianData jacobianData_t2;
- btVector3 t1;
- btVector3 t2;
+
+ // jacobians and unit impulse responses for multibody
+ btMultiBodyJacobianData jacobianData_normal;
+ btMultiBodyJacobianData jacobianData_t1;
+ btMultiBodyJacobianData jacobianData_t2;
+ btVector3 t1;
+ btVector3 t2;
};
-
- class DeformableRigidContact
- {
- public:
- sCti m_cti; // Contact infos
- btMatrix3x3 m_c0; // Impulse matrix
- btVector3 m_c1; // Relative anchor
- btScalar m_c2; // inverse mass of node/face
- btScalar m_c3; // Friction
- btScalar m_c4; // Hardness
-
- // jacobians and unit impulse responses for multibody
- btMultiBodyJacobianData jacobianData_normal;
- btMultiBodyJacobianData jacobianData_t1;
- btMultiBodyJacobianData jacobianData_t2;
- btVector3 t1;
- btVector3 t2;
- };
-
- class DeformableNodeRigidContact : public DeformableRigidContact
- {
- public:
- Node* m_node; // Owner node
- };
-
- class DeformableNodeRigidAnchor : public DeformableNodeRigidContact
- {
- public:
- btVector3 m_local; // Anchor position in body space
- };
-
- class DeformableFaceRigidContact : public DeformableRigidContact
- {
- public:
- Face* m_face; // Owner face
- btVector3 m_contactPoint; // Contact point
- btVector3 m_bary; // Barycentric weights
- btVector3 m_weights; // v_contactPoint * m_weights[i] = m_face->m_node[i]->m_v;
- };
-
- struct DeformableFaceNodeContact
- {
- Node* m_node; // Node
- Face* m_face; // Face
- btVector3 m_bary; // Barycentric weights
- btVector3 m_weights; // v_contactPoint * m_weights[i] = m_face->m_node[i]->m_v;
- btVector3 m_normal; // Normal
- btScalar m_margin; // Margin
- btScalar m_friction; // Friction
- btScalar m_imf; // inverse mass of the face at contact point
- btScalar m_c0; // scale of the impulse matrix;
- };
-
+
+ class DeformableRigidContact
+ {
+ public:
+ sCti m_cti; // Contact infos
+ btMatrix3x3 m_c0; // Impulse matrix
+ btVector3 m_c1; // Relative anchor
+ btScalar m_c2; // inverse mass of node/face
+ btScalar m_c3; // Friction
+ btScalar m_c4; // Hardness
+ btMatrix3x3 m_c5; // inverse effective mass
+
+ // jacobians and unit impulse responses for multibody
+ btMultiBodyJacobianData jacobianData_normal;
+ btMultiBodyJacobianData jacobianData_t1;
+ btMultiBodyJacobianData jacobianData_t2;
+ btVector3 t1;
+ btVector3 t2;
+ };
+
+ class DeformableNodeRigidContact : public DeformableRigidContact
+ {
+ public:
+ Node* m_node; // Owner node
+ };
+
+ class DeformableNodeRigidAnchor : public DeformableNodeRigidContact
+ {
+ public:
+ btVector3 m_local; // Anchor position in body space
+ };
+
+ class DeformableFaceRigidContact : public DeformableRigidContact
+ {
+ public:
+ Face* m_face; // Owner face
+ btVector3 m_contactPoint; // Contact point
+ btVector3 m_bary; // Barycentric weights
+ btVector3 m_weights; // v_contactPoint * m_weights[i] = m_face->m_node[i]->m_v;
+ };
+
+ struct DeformableFaceNodeContact
+ {
+ Node* m_node; // Node
+ Face* m_face; // Face
+ btVector3 m_bary; // Barycentric weights
+ btVector3 m_weights; // v_contactPoint * m_weights[i] = m_face->m_node[i]->m_v;
+ btVector3 m_normal; // Normal
+ btScalar m_margin; // Margin
+ btScalar m_friction; // Friction
+ btScalar m_imf; // inverse mass of the face at contact point
+ btScalar m_c0; // scale of the impulse matrix;
+ };
+
/* SContact */
struct SContact
{
@@ -718,19 +735,19 @@ public:
tVSolverArray m_vsequence; // Velocity solvers sequence
tPSolverArray m_psequence; // Position solvers sequence
tPSolverArray m_dsequence; // Drift solvers sequence
- btScalar drag; // deformable air drag
- btScalar m_maxStress; // Maximum principle first Piola stress
+ btScalar drag; // deformable air drag
+ btScalar m_maxStress; // Maximum principle first Piola stress
};
/* SolverState */
struct SolverState
{
//if you add new variables, always initialize them!
SolverState()
- :sdt(0),
- isdt(0),
- velmrg(0),
- radmrg(0),
- updmrg(0)
+ : sdt(0),
+ isdt(0),
+ velmrg(0),
+ radmrg(0),
+ updmrg(0)
{
}
btScalar sdt; // dt*timescale
@@ -769,9 +786,11 @@ public:
typedef btAlignedObjectArray<Cluster*> tClusterArray;
typedef btAlignedObjectArray<Note> tNoteArray;
typedef btAlignedObjectArray<Node> tNodeArray;
+ typedef btAlignedObjectArray< RenderNode> tRenderNodeArray;
typedef btAlignedObjectArray<btDbvtNode*> tLeafArray;
typedef btAlignedObjectArray<Link> tLinkArray;
typedef btAlignedObjectArray<Face> tFaceArray;
+ typedef btAlignedObjectArray<RenderFace> tRenderFaceArray;
typedef btAlignedObjectArray<Tetra> tTetraArray;
typedef btAlignedObjectArray<Anchor> tAnchorArray;
typedef btAlignedObjectArray<RContact> tRContactArray;
@@ -791,40 +810,42 @@ public:
btSoftBodyWorldInfo* m_worldInfo; // World info
tNoteArray m_notes; // Notes
tNodeArray m_nodes; // Nodes
- tNodeArray m_renderNodes; // Nodes
+ tRenderNodeArray m_renderNodes; // Render Nodes
tLinkArray m_links; // Links
tFaceArray m_faces; // Faces
- tFaceArray m_renderFaces; // Faces
+ tRenderFaceArray m_renderFaces; // Faces
tTetraArray m_tetras; // Tetras
- btAlignedObjectArray<TetraScratch> m_tetraScratches;
- btAlignedObjectArray<TetraScratch> m_tetraScratchesTn;
- tAnchorArray m_anchors; // Anchors
- btAlignedObjectArray<DeformableNodeRigidAnchor> m_deformableAnchors;
- tRContactArray m_rcontacts; // Rigid contacts
- btAlignedObjectArray<DeformableNodeRigidContact> m_nodeRigidContacts;
- btAlignedObjectArray<DeformableFaceNodeContact> m_faceNodeContacts;
- btAlignedObjectArray<DeformableFaceRigidContact> m_faceRigidContacts;
- tSContactArray m_scontacts; // Soft contacts
- tJointArray m_joints; // Joints
- tMaterialArray m_materials; // Materials
- btScalar m_timeacc; // Time accumulator
- btVector3 m_bounds[2]; // Spatial bounds
- bool m_bUpdateRtCst; // Update runtime constants
- btDbvt m_ndbvt; // Nodes tree
- btDbvt m_fdbvt; // Faces tree
- btDbvntNode* m_fdbvnt; // Faces tree with normals
- btDbvt m_cdbvt; // Clusters tree
- tClusterArray m_clusters; // Clusters
- btScalar m_dampingCoefficient; // Damping Coefficient
+ btAlignedObjectArray<TetraScratch> m_tetraScratches;
+ btAlignedObjectArray<TetraScratch> m_tetraScratchesTn;
+ tAnchorArray m_anchors; // Anchors
+ btAlignedObjectArray<DeformableNodeRigidAnchor> m_deformableAnchors;
+ tRContactArray m_rcontacts; // Rigid contacts
+ btAlignedObjectArray<DeformableNodeRigidContact> m_nodeRigidContacts;
+ btAlignedObjectArray<DeformableFaceNodeContact> m_faceNodeContacts;
+ btAlignedObjectArray<DeformableFaceRigidContact> m_faceRigidContacts;
+ tSContactArray m_scontacts; // Soft contacts
+ tJointArray m_joints; // Joints
+ tMaterialArray m_materials; // Materials
+ btScalar m_timeacc; // Time accumulator
+ btVector3 m_bounds[2]; // Spatial bounds
+ bool m_bUpdateRtCst; // Update runtime constants
+ btDbvt m_ndbvt; // Nodes tree
+ btDbvt m_fdbvt; // Faces tree
+ btDbvntNode* m_fdbvnt; // Faces tree with normals
+ btDbvt m_cdbvt; // Clusters tree
+ tClusterArray m_clusters; // Clusters
+ btScalar m_dampingCoefficient; // Damping Coefficient
btScalar m_sleepingThreshold;
btScalar m_maxSpeedSquared;
- btAlignedObjectArray<btVector3> m_quads; // quadrature points for collision detection
+ btAlignedObjectArray<btVector3> m_quads; // quadrature points for collision detection
btScalar m_repulsionStiffness;
- btAlignedObjectArray<btVector3> m_X; // initial positions
+ btScalar m_gravityFactor;
+ bool m_cacheBarycenter;
+ btAlignedObjectArray<btVector3> m_X; // initial positions
btAlignedObjectArray<btVector4> m_renderNodesInterpolationWeights;
btAlignedObjectArray<btAlignedObjectArray<const btSoftBody::Node*> > m_renderNodesParents;
- btAlignedObjectArray<btScalar> m_z; // vertical distance used in extrapolation
+ btAlignedObjectArray<btScalar> m_z; // vertical distance used in extrapolation
bool m_useSelfCollision;
bool m_softSoftCollision;
@@ -856,11 +877,11 @@ public:
{
return m_worldInfo;
}
-
- void setDampingCoefficient(btScalar damping_coeff)
- {
- m_dampingCoefficient = damping_coeff;
- }
+
+ void setDampingCoefficient(btScalar damping_coeff)
+ {
+ m_dampingCoefficient = damping_coeff;
+ }
///@todo: avoid internal softbody shape hack and move collision code to collision library
virtual void setCollisionShape(btCollisionShape* collisionShape)
@@ -921,11 +942,12 @@ public:
Material* mat = 0);
/* Append anchor */
- void appendDeformableAnchor(int node, btRigidBody* body);
- void appendDeformableAnchor(int node, btMultiBodyLinkCollider* link);
- void appendAnchor(int node,
+ void appendDeformableAnchor(int node, btRigidBody* body);
+ void appendDeformableAnchor(int node, btMultiBodyLinkCollider* link);
+ void appendAnchor(int node,
btRigidBody* body, bool disableCollisionBetweenLinkedBodies = false, btScalar influence = 1);
void appendAnchor(int node, btRigidBody* body, const btVector3& localPivot, bool disableCollisionBetweenLinkedBodies = false, btScalar influence = 1);
+ void removeAnchor(int node);
/* Append linear joint */
void appendLinearJoint(const LJoint::Specs& specs, Cluster* body0, Body body1);
void appendLinearJoint(const LJoint::Specs& specs, Body body = Body());
@@ -976,10 +998,10 @@ public:
void setLinearVelocity(const btVector3& linVel);
/* Set the angular velocity of the center of mass */
void setAngularVelocity(const btVector3& angVel);
- /* Get best fit rigid transform */
- btTransform getRigidTransform();
- /* Transform to given pose */
- void transformTo(const btTransform& trs);
+ /* Get best fit rigid transform */
+ btTransform getRigidTransform();
+ /* Transform to given pose */
+ void transformTo(const btTransform& trs);
/* Transform */
void transform(const btTransform& trs);
/* Translate */
@@ -1068,11 +1090,11 @@ public:
/* defaultCollisionHandlers */
void defaultCollisionHandler(const btCollisionObjectWrapper* pcoWrap);
void defaultCollisionHandler(btSoftBody* psb);
- void setSelfCollision(bool useSelfCollision);
- bool useSelfCollision();
- void updateDeactivation(btScalar timeStep);
- void setZeroVelocity();
- bool wantsSleeping();
+ void setSelfCollision(bool useSelfCollision);
+ bool useSelfCollision();
+ void updateDeactivation(btScalar timeStep);
+ void setZeroVelocity();
+ bool wantsSleeping();
//
// Functionality to deal with new accelerated solvers.
@@ -1151,8 +1173,8 @@ public:
void rebuildNodeTree();
btVector3 evaluateCom() const;
bool checkDeformableContact(const btCollisionObjectWrapper* colObjWrap, const btVector3& x, btScalar margin, btSoftBody::sCti& cti, bool predict = false) const;
- bool checkDeformableFaceContact(const btCollisionObjectWrapper* colObjWrap, Face& f, btVector3& contact_point, btVector3& bary, btScalar margin, btSoftBody::sCti& cti, bool predict = false) const;
- bool checkContact(const btCollisionObjectWrapper* colObjWrap, const btVector3& x, btScalar margin, btSoftBody::sCti& cti) const;
+ bool checkDeformableFaceContact(const btCollisionObjectWrapper* colObjWrap, Face& f, btVector3& contact_point, btVector3& bary, btScalar margin, btSoftBody::sCti& cti, bool predict = false) const;
+ bool checkContact(const btCollisionObjectWrapper* colObjWrap, const btVector3& x, btScalar margin, btSoftBody::sCti& cti) const;
void updateNormals();
void updateBounds();
void updatePose();
@@ -1166,14 +1188,16 @@ public:
void solveClusters(btScalar sor);
void applyClusters(bool drift);
void dampClusters();
- void setSpringStiffness(btScalar k);
- void initializeDmInverse();
- void updateDeformation();
- void advanceDeformation();
+ void setSpringStiffness(btScalar k);
+ void setGravityFactor(btScalar gravFactor);
+ void setCacheBarycenter(bool cacheBarycenter);
+ void initializeDmInverse();
+ void updateDeformation();
+ void advanceDeformation();
void applyForces();
- void setMaxStress(btScalar maxStress);
- void interpolateRenderMesh();
- void setCollisionQuadrature(int N);
+ void setMaxStress(btScalar maxStress);
+ void interpolateRenderMesh();
+ void setCollisionQuadrature(int N);
static void PSolve_Anchors(btSoftBody* psb, btScalar kst, btScalar ti);
static void PSolve_RContacts(btSoftBody* psb, btScalar kst, btScalar ti);
static void PSolve_SContacts(btSoftBody* psb, btScalar, btScalar ti);
@@ -1182,14 +1206,15 @@ public:
static psolver_t getSolver(ePSolver::_ solver);
static vsolver_t getSolver(eVSolver::_ solver);
void geometricCollisionHandler(btSoftBody* psb);
-#define SAFE_EPSILON SIMD_EPSILON*100.0
+#define SAFE_EPSILON SIMD_EPSILON * 100.0
void updateNode(btDbvtNode* node, bool use_velocity, bool margin)
{
if (node->isleaf())
{
btSoftBody::Node* n = (btSoftBody::Node*)(node->data);
- ATTRIBUTE_ALIGNED16(btDbvtVolume) vol;
- btScalar pad = margin ? m_sst.radmrg : SAFE_EPSILON; // use user defined margin or margin for floating point precision
+ ATTRIBUTE_ALIGNED16(btDbvtVolume)
+ vol;
+ btScalar pad = margin ? m_sst.radmrg : SAFE_EPSILON; // use user defined margin or margin for floating point precision
if (use_velocity)
{
btVector3 points[2] = {n->m_x, n->m_x + m_sst.sdt * n->m_v};
@@ -1207,38 +1232,40 @@ public:
{
updateNode(node->childs[0], use_velocity, margin);
updateNode(node->childs[1], use_velocity, margin);
- ATTRIBUTE_ALIGNED16(btDbvtVolume) vol;
+ ATTRIBUTE_ALIGNED16(btDbvtVolume)
+ vol;
Merge(node->childs[0]->volume, node->childs[1]->volume, vol);
node->volume = vol;
}
}
-
- void updateNodeTree(bool use_velocity, bool margin)
+
+ void updateNodeTree(bool use_velocity, bool margin)
{
if (m_ndbvt.m_root)
updateNode(m_ndbvt.m_root, use_velocity, margin);
}
- template <class DBVTNODE> // btDbvtNode or btDbvntNode
+ template <class DBVTNODE> // btDbvtNode or btDbvntNode
void updateFace(DBVTNODE* node, bool use_velocity, bool margin)
{
if (node->isleaf())
{
btSoftBody::Face* f = (btSoftBody::Face*)(node->data);
- btScalar pad = margin ? m_sst.radmrg : SAFE_EPSILON; // use user defined margin or margin for floating point precision
- ATTRIBUTE_ALIGNED16(btDbvtVolume) vol;
+ btScalar pad = margin ? m_sst.radmrg : SAFE_EPSILON; // use user defined margin or margin for floating point precision
+ ATTRIBUTE_ALIGNED16(btDbvtVolume)
+ vol;
if (use_velocity)
{
btVector3 points[6] = {f->m_n[0]->m_x, f->m_n[0]->m_x + m_sst.sdt * f->m_n[0]->m_v,
- f->m_n[1]->m_x, f->m_n[1]->m_x + m_sst.sdt * f->m_n[1]->m_v,
- f->m_n[2]->m_x, f->m_n[2]->m_x + m_sst.sdt * f->m_n[2]->m_v};
+ f->m_n[1]->m_x, f->m_n[1]->m_x + m_sst.sdt * f->m_n[1]->m_v,
+ f->m_n[2]->m_x, f->m_n[2]->m_x + m_sst.sdt * f->m_n[2]->m_v};
vol = btDbvtVolume::FromPoints(points, 6);
}
else
{
btVector3 points[3] = {f->m_n[0]->m_x,
- f->m_n[1]->m_x,
- f->m_n[2]->m_x};
+ f->m_n[1]->m_x,
+ f->m_n[2]->m_x};
vol = btDbvtVolume::FromPoints(points, 3);
}
vol.Expand(btVector3(pad, pad, pad));
@@ -1249,7 +1276,8 @@ public:
{
updateFace(node->childs[0], use_velocity, margin);
updateFace(node->childs[1], use_velocity, margin);
- ATTRIBUTE_ALIGNED16(btDbvtVolume) vol;
+ ATTRIBUTE_ALIGNED16(btDbvtVolume)
+ vol;
Merge(node->childs[0]->volume, node->childs[1]->volume, vol);
node->volume = vol;
}
@@ -1271,7 +1299,7 @@ public:
return (a * coord.x() + b * coord.y() + c * coord.z());
}
- void applyRepulsionForce(btScalar timeStep, bool applySpringForce)
+ void applyRepulsionForce(btScalar timeStep, bool applySpringForce)
{
btAlignedObjectArray<int> indices;
{
@@ -1297,58 +1325,60 @@ public:
const btVector3& n = c.m_normal;
btVector3 l = node->m_x - BaryEval(face->m_n[0]->m_x, face->m_n[1]->m_x, face->m_n[2]->m_x, w);
btScalar d = c.m_margin - n.dot(l);
- d = btMax(btScalar(0),d);
-
+ d = btMax(btScalar(0), d);
+
const btVector3& va = node->m_v;
btVector3 vb = BaryEval(face->m_n[0]->m_v, face->m_n[1]->m_v, face->m_n[2]->m_v, w);
btVector3 vr = va - vb;
- const btScalar vn = btDot(vr, n); // dn < 0 <==> opposing
+ const btScalar vn = btDot(vr, n); // dn < 0 <==> opposing
if (vn > OVERLAP_REDUCTION_FACTOR * d / timeStep)
continue;
- btVector3 vt = vr - vn*n;
+ btVector3 vt = vr - vn * n;
btScalar I = 0;
- btScalar mass = node->m_im == 0 ? 0 : btScalar(1)/node->m_im;
+ btScalar mass = node->m_im == 0 ? 0 : btScalar(1) / node->m_im;
if (applySpringForce)
I = -btMin(m_repulsionStiffness * timeStep * d, mass * (OVERLAP_REDUCTION_FACTOR * d / timeStep - vn));
if (vn < 0)
I += 0.5 * mass * vn;
- btScalar face_penetration = 0, node_penetration = node->m_penetration;
+ int face_penetration = 0, node_penetration = node->m_constrained;
for (int i = 0; i < 3; ++i)
- face_penetration = btMax(face_penetration, face->m_n[i]->m_penetration);
- btScalar I_tilde = .5 *I /(1.0+w.length2());
-
-// double the impulse if node or face is constrained.
- if (face_penetration > 0 || node_penetration > 0)
- I_tilde *= 2.0;
- if (face_penetration <= node_penetration)
+ face_penetration |= face->m_n[i]->m_constrained;
+ btScalar I_tilde = 2.0 * I / (1.0 + w.length2());
+
+ // double the impulse if node or face is constrained.
+ if (face_penetration > 0 || node_penetration > 0)
+ {
+ I_tilde *= 2.0;
+ }
+ if (face_penetration <= 0)
{
for (int j = 0; j < 3; ++j)
- face->m_n[j]->m_v += w[j]*n*I_tilde*node->m_im;
+ face->m_n[j]->m_v += w[j] * n * I_tilde * node->m_im;
}
- if (face_penetration >= node_penetration)
+ if (node_penetration <= 0)
{
- node->m_v -= I_tilde*node->m_im*n;
+ node->m_v -= I_tilde * node->m_im * n;
}
-
+
// apply frictional impulse
btScalar vt_norm = vt.safeNorm();
if (vt_norm > SIMD_EPSILON)
{
btScalar delta_vn = -2 * I * node->m_im;
btScalar mu = c.m_friction;
- btScalar vt_new = btMax(btScalar(1) - mu * delta_vn / (vt_norm + SIMD_EPSILON), btScalar(0))*vt_norm;
- I = 0.5 * mass * (vt_norm-vt_new);
+ btScalar vt_new = btMax(btScalar(1) - mu * delta_vn / (vt_norm + SIMD_EPSILON), btScalar(0)) * vt_norm;
+ I = 0.5 * mass * (vt_norm - vt_new);
vt.safeNormalize();
- I_tilde = .5 *I /(1.0+w.length2());
-// double the impulse if node or face is constrained.
-// if (face_penetration > 0 || node_penetration > 0)
-// I_tilde *= 2.0;
- if (face_penetration <= node_penetration)
+ I_tilde = 2.0 * I / (1.0 + w.length2());
+ // double the impulse if node or face is constrained.
+ if (face_penetration > 0 || node_penetration > 0)
+ I_tilde *= 2.0;
+ if (face_penetration <= 0)
{
for (int j = 0; j < 3; ++j)
face->m_n[j]->m_v += w[j] * vt * I_tilde * (face->m_n[j])->m_im;
}
- if (face_penetration >= node_penetration)
+ if (node_penetration <= 0)
{
node->m_v -= I_tilde * node->m_im * vt;
}
@@ -1356,7 +1386,7 @@ public:
}
}
virtual int calculateSerializeBufferSize() const;
-
+
///fills the dataBuffer and returns the struct name (and 0 on failure)
virtual const char* serialize(void* dataBuffer, class btSerializer* serializer) const;
};
diff --git a/thirdparty/bullet/BulletSoftBody/btSoftBodyHelpers.cpp b/thirdparty/bullet/BulletSoftBody/btSoftBodyHelpers.cpp
index c1a87c7d57..f63e48f9a5 100644
--- a/thirdparty/bullet/BulletSoftBody/btSoftBodyHelpers.cpp
+++ b/thirdparty/bullet/BulletSoftBody/btSoftBodyHelpers.cpp
@@ -727,7 +727,7 @@ btSoftBody* btSoftBodyHelpers::CreatePatch(btSoftBodyWorldInfo& worldInfo, const
int resy,
int fixeds,
bool gendiags,
- btScalar perturbation)
+ btScalar perturbation)
{
#define IDX(_x_, _y_) ((_y_)*rx + (_x_))
/* Create nodes */
@@ -747,12 +747,12 @@ btSoftBody* btSoftBodyHelpers::CreatePatch(btSoftBodyWorldInfo& worldInfo, const
for (int ix = 0; ix < rx; ++ix)
{
const btScalar tx = ix / (btScalar)(rx - 1);
- btScalar pert = perturbation * btScalar(rand())/RAND_MAX;
- btVector3 temp1 = py1;
- temp1.setY(py1.getY() + pert);
- btVector3 temp = py0;
- pert = perturbation * btScalar(rand())/RAND_MAX;
- temp.setY(py0.getY() + pert);
+ btScalar pert = perturbation * btScalar(rand()) / RAND_MAX;
+ btVector3 temp1 = py1;
+ temp1.setY(py1.getY() + pert);
+ btVector3 temp = py0;
+ pert = perturbation * btScalar(rand()) / RAND_MAX;
+ temp.setY(py0.getY() + pert);
x[IDX(ix, iy)] = lerp(temp, temp1, tx);
m[IDX(ix, iy)] = 1;
}
@@ -1233,9 +1233,9 @@ if(face&&face[0])
}
}
}
- psb->initializeDmInverse();
- psb->m_tetraScratches.resize(psb->m_tetras.size());
- psb->m_tetraScratchesTn.resize(psb->m_tetras.size());
+ psb->initializeDmInverse();
+ psb->m_tetraScratches.resize(psb->m_tetras.size());
+ psb->m_tetraScratchesTn.resize(psb->m_tetras.size());
printf("Nodes: %u\r\n", psb->m_nodes.size());
printf("Links: %u\r\n", psb->m_links.size());
printf("Faces: %u\r\n", psb->m_faces.size());
@@ -1245,61 +1245,62 @@ if(face&&face[0])
btSoftBody* btSoftBodyHelpers::CreateFromVtkFile(btSoftBodyWorldInfo& worldInfo, const char* vtk_file)
{
- std::ifstream fs;
- fs.open(vtk_file);
- btAssert(fs);
-
- typedef btAlignedObjectArray<int> Index;
- std::string line;
- btAlignedObjectArray<btVector3> X;
- btVector3 position;
- btAlignedObjectArray<Index> indices;
- bool reading_points = false;
- bool reading_tets = false;
- size_t n_points = 0;
- size_t n_tets = 0;
- size_t x_count = 0;
- size_t indices_count = 0;
- while (std::getline(fs, line))
- {
- std::stringstream ss(line);
- if (line.size() == (size_t)(0))
- {
- }
- else if (line.substr(0, 6) == "POINTS")
- {
- reading_points = true;
- reading_tets = false;
- ss.ignore(128, ' '); // ignore "POINTS"
- ss >> n_points;
- X.resize(n_points);
- }
- else if (line.substr(0, 5) == "CELLS")
- {
- reading_points = false;
- reading_tets = true;
- ss.ignore(128, ' '); // ignore "CELLS"
- ss >> n_tets;
- indices.resize(n_tets);
- }
- else if (line.substr(0, 10) == "CELL_TYPES")
- {
- reading_points = false;
- reading_tets = false;
- }
- else if (reading_points)
- {
- btScalar p;
- ss >> p;
- position.setX(p);
- ss >> p;
- position.setY(p);
- ss >> p;
- position.setZ(p);
- X[x_count++] = position;
- }
- else if (reading_tets)
- {
+ std::ifstream fs;
+ fs.open(vtk_file);
+ btAssert(fs);
+
+ typedef btAlignedObjectArray<int> Index;
+ std::string line;
+ btAlignedObjectArray<btVector3> X;
+ btVector3 position;
+ btAlignedObjectArray<Index> indices;
+ bool reading_points = false;
+ bool reading_tets = false;
+ size_t n_points = 0;
+ size_t n_tets = 0;
+ size_t x_count = 0;
+ size_t indices_count = 0;
+ while (std::getline(fs, line))
+ {
+ std::stringstream ss(line);
+ if (line.size() == (size_t)(0))
+ {
+ }
+ else if (line.substr(0, 6) == "POINTS")
+ {
+ reading_points = true;
+ reading_tets = false;
+ ss.ignore(128, ' '); // ignore "POINTS"
+ ss >> n_points;
+ X.resize(n_points);
+ }
+ else if (line.substr(0, 5) == "CELLS")
+ {
+ reading_points = false;
+ reading_tets = true;
+ ss.ignore(128, ' '); // ignore "CELLS"
+ ss >> n_tets;
+ indices.resize(n_tets);
+ }
+ else if (line.substr(0, 10) == "CELL_TYPES")
+ {
+ reading_points = false;
+ reading_tets = false;
+ }
+ else if (reading_points)
+ {
+ btScalar p;
+ ss >> p;
+ position.setX(p);
+ ss >> p;
+ position.setY(p);
+ ss >> p;
+ position.setZ(p);
+ //printf("v %f %f %f\n", position.getX(), position.getY(), position.getZ());
+ X[x_count++] = position;
+ }
+ else if (reading_tets)
+ {
int d;
ss >> d;
if (d != 4)
@@ -1308,317 +1309,355 @@ btSoftBody* btSoftBodyHelpers::CreateFromVtkFile(btSoftBodyWorldInfo& worldInfo,
fs.close();
return 0;
}
- ss.ignore(128, ' '); // ignore "4"
- Index tet;
- tet.resize(4);
- for (size_t i = 0; i < 4; i++)
- {
- ss >> tet[i];
- printf("%d ", tet[i]);
- }
- printf("\n");
- indices[indices_count++] = tet;
- }
- }
- btSoftBody* psb = new btSoftBody(&worldInfo, n_points, &X[0], 0);
-
- for (int i = 0; i < n_tets; ++i)
- {
- const Index& ni = indices[i];
- psb->appendTetra(ni[0], ni[1], ni[2], ni[3]);
- {
- psb->appendLink(ni[0], ni[1], 0, true);
- psb->appendLink(ni[1], ni[2], 0, true);
- psb->appendLink(ni[2], ni[0], 0, true);
- psb->appendLink(ni[0], ni[3], 0, true);
- psb->appendLink(ni[1], ni[3], 0, true);
- psb->appendLink(ni[2], ni[3], 0, true);
- }
- }
-
-
- generateBoundaryFaces(psb);
- psb->initializeDmInverse();
- psb->m_tetraScratches.resize(psb->m_tetras.size());
- psb->m_tetraScratchesTn.resize(psb->m_tetras.size());
- printf("Nodes: %u\r\n", psb->m_nodes.size());
- printf("Links: %u\r\n", psb->m_links.size());
- printf("Faces: %u\r\n", psb->m_faces.size());
- printf("Tetras: %u\r\n", psb->m_tetras.size());
-
- fs.close();
- return psb;
+ ss.ignore(128, ' '); // ignore "4"
+ Index tet;
+ tet.resize(4);
+ for (size_t i = 0; i < 4; i++)
+ {
+ ss >> tet[i];
+ //printf("%d ", tet[i]);
+ }
+ //printf("\n");
+ indices[indices_count++] = tet;
+ }
+ }
+ btSoftBody* psb = new btSoftBody(&worldInfo, n_points, &X[0], 0);
+
+ for (int i = 0; i < n_tets; ++i)
+ {
+ const Index& ni = indices[i];
+ psb->appendTetra(ni[0], ni[1], ni[2], ni[3]);
+ {
+ psb->appendLink(ni[0], ni[1], 0, true);
+ psb->appendLink(ni[1], ni[2], 0, true);
+ psb->appendLink(ni[2], ni[0], 0, true);
+ psb->appendLink(ni[0], ni[3], 0, true);
+ psb->appendLink(ni[1], ni[3], 0, true);
+ psb->appendLink(ni[2], ni[3], 0, true);
+ }
+ }
+
+ generateBoundaryFaces(psb);
+ psb->initializeDmInverse();
+ psb->m_tetraScratches.resize(psb->m_tetras.size());
+ psb->m_tetraScratchesTn.resize(psb->m_tetras.size());
+ printf("Nodes: %u\r\n", psb->m_nodes.size());
+ printf("Links: %u\r\n", psb->m_links.size());
+ printf("Faces: %u\r\n", psb->m_faces.size());
+ printf("Tetras: %u\r\n", psb->m_tetras.size());
+
+ fs.close();
+ return psb;
}
void btSoftBodyHelpers::generateBoundaryFaces(btSoftBody* psb)
{
- int counter = 0;
- for (int i = 0; i < psb->m_nodes.size(); ++i)
- {
- psb->m_nodes[i].index = counter++;
- }
- typedef btAlignedObjectArray<int> Index;
- btAlignedObjectArray<Index> indices;
- indices.resize(psb->m_tetras.size());
- for (int i = 0; i < indices.size(); ++i)
- {
- Index index;
- index.push_back(psb->m_tetras[i].m_n[0]->index);
- index.push_back(psb->m_tetras[i].m_n[1]->index);
- index.push_back(psb->m_tetras[i].m_n[2]->index);
- index.push_back(psb->m_tetras[i].m_n[3]->index);
- indices[i] = index;
- }
-
- std::map<std::vector<int>, std::vector<int> > dict;
- for (int i = 0; i < indices.size(); ++i)
- {
- for (int j = 0; j < 4; ++j)
- {
- std::vector<int> f;
- if (j == 0)
- {
- f.push_back(indices[i][1]);
- f.push_back(indices[i][0]);
- f.push_back(indices[i][2]);
- }
- if (j == 1)
- {
- f.push_back(indices[i][3]);
- f.push_back(indices[i][0]);
- f.push_back(indices[i][1]);
- }
- if (j == 2)
- {
- f.push_back(indices[i][3]);
- f.push_back(indices[i][1]);
- f.push_back(indices[i][2]);
- }
- if (j == 3)
- {
- f.push_back(indices[i][2]);
- f.push_back(indices[i][0]);
- f.push_back(indices[i][3]);
- }
- std::vector<int> f_sorted = f;
- std::sort(f_sorted.begin(), f_sorted.end());
- if (dict.find(f_sorted) != dict.end())
- {
- dict.erase(f_sorted);
- }
- else
- {
- dict.insert(std::make_pair(f_sorted, f));
- }
- }
- }
-
- for (std::map<std::vector<int>, std::vector<int> >::iterator it = dict.begin(); it != dict.end(); ++it)
- {
- std::vector<int> f = it->second;
- psb->appendFace(f[0], f[1], f[2]);
- }
+ int counter = 0;
+ for (int i = 0; i < psb->m_nodes.size(); ++i)
+ {
+ psb->m_nodes[i].index = counter++;
+ }
+ typedef btAlignedObjectArray<int> Index;
+ btAlignedObjectArray<Index> indices;
+ indices.resize(psb->m_tetras.size());
+ for (int i = 0; i < indices.size(); ++i)
+ {
+ Index index;
+ index.push_back(psb->m_tetras[i].m_n[0]->index);
+ index.push_back(psb->m_tetras[i].m_n[1]->index);
+ index.push_back(psb->m_tetras[i].m_n[2]->index);
+ index.push_back(psb->m_tetras[i].m_n[3]->index);
+ indices[i] = index;
+ }
+
+ std::map<std::vector<int>, std::vector<int> > dict;
+ for (int i = 0; i < indices.size(); ++i)
+ {
+ for (int j = 0; j < 4; ++j)
+ {
+ std::vector<int> f;
+ if (j == 0)
+ {
+ f.push_back(indices[i][1]);
+ f.push_back(indices[i][0]);
+ f.push_back(indices[i][2]);
+ }
+ if (j == 1)
+ {
+ f.push_back(indices[i][3]);
+ f.push_back(indices[i][0]);
+ f.push_back(indices[i][1]);
+ }
+ if (j == 2)
+ {
+ f.push_back(indices[i][3]);
+ f.push_back(indices[i][1]);
+ f.push_back(indices[i][2]);
+ }
+ if (j == 3)
+ {
+ f.push_back(indices[i][2]);
+ f.push_back(indices[i][0]);
+ f.push_back(indices[i][3]);
+ }
+ std::vector<int> f_sorted = f;
+ std::sort(f_sorted.begin(), f_sorted.end());
+ if (dict.find(f_sorted) != dict.end())
+ {
+ dict.erase(f_sorted);
+ }
+ else
+ {
+ dict.insert(std::make_pair(f_sorted, f));
+ }
+ }
+ }
+
+ for (std::map<std::vector<int>, std::vector<int> >::iterator it = dict.begin(); it != dict.end(); ++it)
+ {
+ std::vector<int> f = it->second;
+ psb->appendFace(f[0], f[1], f[2]);
+ //printf("f %d %d %d\n", f[0] + 1, f[1] + 1, f[2] + 1);
+ }
}
+//Write the surface mesh to an obj file.
void btSoftBodyHelpers::writeObj(const char* filename, const btSoftBody* psb)
{
- std::ofstream fs;
- fs.open(filename);
- btAssert(fs);
- for (int i = 0; i < psb->m_nodes.size(); ++i)
- {
- fs << "v";
- for (int d = 0; d < 3; d++)
- {
- fs << " " << psb->m_nodes[i].m_x[d];
- }
- fs << "\n";
- }
-
- for (int i = 0; i < psb->m_faces.size(); ++i)
- {
- fs << "f";
- for (int n = 0; n < 3; n++)
- {
- fs << " " << psb->m_faces[i].m_n[n]->index + 1;
- }
- fs << "\n";
- }
- fs.close();
+ std::ofstream fs;
+ fs.open(filename);
+ btAssert(fs);
+
+ if (psb->m_tetras.size() > 0)
+ {
+ // For tetrahedron mesh, we need to re-index the surface mesh for it to be in obj file/
+ std::map<int, int> dict;
+ for (int i = 0; i < psb->m_faces.size(); i++)
+ {
+ for (int d = 0; d < 3; d++)
+ {
+ int index = psb->m_faces[i].m_n[d]->index;
+ if (dict.find(index) == dict.end())
+ {
+ int dict_size = dict.size();
+ dict[index] = dict_size;
+ fs << "v";
+ for (int k = 0; k < 3; k++)
+ {
+ fs << " " << psb->m_nodes[index].m_x[k];
+ }
+ fs << "\n";
+ }
+ }
+ }
+ // Write surface mesh.
+ for (int i = 0; i < psb->m_faces.size(); ++i)
+ {
+ fs << "f";
+ for (int n = 0; n < 3; n++)
+ {
+ fs << " " << dict[psb->m_faces[i].m_n[n]->index] + 1;
+ }
+ fs << "\n";
+ }
+ }
+ else
+ {
+ // For trimesh, directly write out all the nodes and faces.xs
+ for (int i = 0; i < psb->m_nodes.size(); ++i)
+ {
+ fs << "v";
+ for (int d = 0; d < 3; d++)
+ {
+ fs << " " << psb->m_nodes[i].m_x[d];
+ }
+ fs << "\n";
+ }
+
+ for (int i = 0; i < psb->m_faces.size(); ++i)
+ {
+ fs << "f";
+ for (int n = 0; n < 3; n++)
+ {
+ fs << " " << psb->m_faces[i].m_n[n]->index + 1;
+ }
+ fs << "\n";
+ }
+ }
+ fs.close();
}
void btSoftBodyHelpers::duplicateFaces(const char* filename, const btSoftBody* psb)
{
- std::ifstream fs_read;
- fs_read.open(filename);
- std::string line;
- btVector3 pos;
- btAlignedObjectArray<btAlignedObjectArray<int> > additional_faces;
- while (std::getline(fs_read, line))
- {
- std::stringstream ss(line);
- if (line[0] == 'v')
- {
- }
- else if (line[0] == 'f')
- {
- ss.ignore();
- int id0, id1, id2;
- ss >> id0;
- ss >> id1;
- ss >> id2;
- btAlignedObjectArray<int> new_face;
- new_face.push_back(id1);
- new_face.push_back(id0);
- new_face.push_back(id2);
- additional_faces.push_back(new_face);
- }
- }
- fs_read.close();
-
- std::ofstream fs_write;
- fs_write.open(filename, std::ios_base::app);
- for (int i = 0; i < additional_faces.size(); ++i)
- {
- fs_write << "f";
- for (int n = 0; n < 3; n++)
- {
- fs_write << " " << additional_faces[i][n];
- }
- fs_write << "\n";
- }
- fs_write.close();
+ std::ifstream fs_read;
+ fs_read.open(filename);
+ std::string line;
+ btVector3 pos;
+ btAlignedObjectArray<btAlignedObjectArray<int> > additional_faces;
+ while (std::getline(fs_read, line))
+ {
+ std::stringstream ss(line);
+ if (line[0] == 'v')
+ {
+ }
+ else if (line[0] == 'f')
+ {
+ ss.ignore();
+ int id0, id1, id2;
+ ss >> id0;
+ ss >> id1;
+ ss >> id2;
+ btAlignedObjectArray<int> new_face;
+ new_face.push_back(id1);
+ new_face.push_back(id0);
+ new_face.push_back(id2);
+ additional_faces.push_back(new_face);
+ }
+ }
+ fs_read.close();
+
+ std::ofstream fs_write;
+ fs_write.open(filename, std::ios_base::app);
+ for (int i = 0; i < additional_faces.size(); ++i)
+ {
+ fs_write << "f";
+ for (int n = 0; n < 3; n++)
+ {
+ fs_write << " " << additional_faces[i][n];
+ }
+ fs_write << "\n";
+ }
+ fs_write.close();
}
// Given a simplex with vertices a,b,c,d, find the barycentric weights of p in this simplex
void btSoftBodyHelpers::getBarycentricWeights(const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& d, const btVector3& p, btVector4& bary)
{
- btVector3 vap = p - a;
- btVector3 vbp = p - b;
-
- btVector3 vab = b - a;
- btVector3 vac = c - a;
- btVector3 vad = d - a;
-
- btVector3 vbc = c - b;
- btVector3 vbd = d - b;
- btScalar va6 = (vbp.cross(vbd)).dot(vbc);
- btScalar vb6 = (vap.cross(vac)).dot(vad);
- btScalar vc6 = (vap.cross(vad)).dot(vab);
- btScalar vd6 = (vap.cross(vab)).dot(vac);
- btScalar v6 = btScalar(1) / (vab.cross(vac).dot(vad));
- bary = btVector4(va6*v6, vb6*v6, vc6*v6, vd6*v6);
+ btVector3 vap = p - a;
+ btVector3 vbp = p - b;
+
+ btVector3 vab = b - a;
+ btVector3 vac = c - a;
+ btVector3 vad = d - a;
+
+ btVector3 vbc = c - b;
+ btVector3 vbd = d - b;
+ btScalar va6 = (vbp.cross(vbd)).dot(vbc);
+ btScalar vb6 = (vap.cross(vac)).dot(vad);
+ btScalar vc6 = (vap.cross(vad)).dot(vab);
+ btScalar vd6 = (vap.cross(vab)).dot(vac);
+ btScalar v6 = btScalar(1) / (vab.cross(vac).dot(vad));
+ bary = btVector4(va6 * v6, vb6 * v6, vc6 * v6, vd6 * v6);
}
// Given a simplex with vertices a,b,c, find the barycentric weights of p in this simplex. bary[3] = 0.
void btSoftBodyHelpers::getBarycentricWeights(const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& p, btVector4& bary)
{
- btVector3 v0 = b - a, v1 = c - a, v2 = p - a;
- btScalar d00 = btDot(v0, v0);
- btScalar d01 = btDot(v0, v1);
- btScalar d11 = btDot(v1, v1);
- btScalar d20 = btDot(v2, v0);
- btScalar d21 = btDot(v2, v1);
- btScalar invDenom = 1.0 / (d00 * d11 - d01 * d01);
- bary[1] = (d11 * d20 - d01 * d21) * invDenom;
- bary[2] = (d00 * d21 - d01 * d20) * invDenom;
- bary[0] = 1.0 - bary[1] - bary[2];
- bary[3] = 0;
+ btVector3 v0 = b - a, v1 = c - a, v2 = p - a;
+ btScalar d00 = btDot(v0, v0);
+ btScalar d01 = btDot(v0, v1);
+ btScalar d11 = btDot(v1, v1);
+ btScalar d20 = btDot(v2, v0);
+ btScalar d21 = btDot(v2, v1);
+ btScalar invDenom = 1.0 / (d00 * d11 - d01 * d01);
+ bary[1] = (d11 * d20 - d01 * d21) * invDenom;
+ bary[2] = (d00 * d21 - d01 * d20) * invDenom;
+ bary[0] = 1.0 - bary[1] - bary[2];
+ bary[3] = 0;
}
// Iterate through all render nodes to find the simulation tetrahedron that contains the render node and record the barycentric weights
// If the node is not inside any tetrahedron, assign it to the tetrahedron in which the node has the least negative barycentric weight
void btSoftBodyHelpers::interpolateBarycentricWeights(btSoftBody* psb)
{
- psb->m_z.resize(0);
- psb->m_renderNodesInterpolationWeights.resize(psb->m_renderNodes.size());
- psb->m_renderNodesParents.resize(psb->m_renderNodes.size());
- for (int i = 0; i < psb->m_renderNodes.size(); ++i)
- {
- const btVector3& p = psb->m_renderNodes[i].m_x;
- btVector4 bary;
- btVector4 optimal_bary;
- btScalar min_bary_weight = -1e3;
- btAlignedObjectArray<const btSoftBody::Node*> optimal_parents;
- for (int j = 0; j < psb->m_tetras.size(); ++j)
- {
- const btSoftBody::Tetra& t = psb->m_tetras[j];
- getBarycentricWeights(t.m_n[0]->m_x, t.m_n[1]->m_x, t.m_n[2]->m_x, t.m_n[3]->m_x, p, bary);
- btScalar new_min_bary_weight = bary[0];
- for (int k = 1; k < 4; ++k)
- {
- new_min_bary_weight = btMin(new_min_bary_weight, bary[k]);
- }
- if (new_min_bary_weight > min_bary_weight)
- {
- btAlignedObjectArray<const btSoftBody::Node*> parents;
- parents.push_back(t.m_n[0]);
- parents.push_back(t.m_n[1]);
- parents.push_back(t.m_n[2]);
- parents.push_back(t.m_n[3]);
- optimal_parents = parents;
- optimal_bary = bary;
- min_bary_weight = new_min_bary_weight;
- // stop searching if p is inside the tetrahedron at hand
- if (bary[0]>=0. && bary[1]>=0. && bary[2]>=0. && bary[3]>=0.)
- {
- break;
- }
- }
- }
- psb->m_renderNodesInterpolationWeights[i] = optimal_bary;
- psb->m_renderNodesParents[i] = optimal_parents;
- }
+ psb->m_z.resize(0);
+ psb->m_renderNodesInterpolationWeights.resize(psb->m_renderNodes.size());
+ psb->m_renderNodesParents.resize(psb->m_renderNodes.size());
+ for (int i = 0; i < psb->m_renderNodes.size(); ++i)
+ {
+ const btVector3& p = psb->m_renderNodes[i].m_x;
+ btVector4 bary;
+ btVector4 optimal_bary;
+ btScalar min_bary_weight = -1e3;
+ btAlignedObjectArray<const btSoftBody::Node*> optimal_parents;
+ for (int j = 0; j < psb->m_tetras.size(); ++j)
+ {
+ const btSoftBody::Tetra& t = psb->m_tetras[j];
+ getBarycentricWeights(t.m_n[0]->m_x, t.m_n[1]->m_x, t.m_n[2]->m_x, t.m_n[3]->m_x, p, bary);
+ btScalar new_min_bary_weight = bary[0];
+ for (int k = 1; k < 4; ++k)
+ {
+ new_min_bary_weight = btMin(new_min_bary_weight, bary[k]);
+ }
+ if (new_min_bary_weight > min_bary_weight)
+ {
+ btAlignedObjectArray<const btSoftBody::Node*> parents;
+ parents.push_back(t.m_n[0]);
+ parents.push_back(t.m_n[1]);
+ parents.push_back(t.m_n[2]);
+ parents.push_back(t.m_n[3]);
+ optimal_parents = parents;
+ optimal_bary = bary;
+ min_bary_weight = new_min_bary_weight;
+ // stop searching if p is inside the tetrahedron at hand
+ if (bary[0] >= 0. && bary[1] >= 0. && bary[2] >= 0. && bary[3] >= 0.)
+ {
+ break;
+ }
+ }
+ }
+ psb->m_renderNodesInterpolationWeights[i] = optimal_bary;
+ psb->m_renderNodesParents[i] = optimal_parents;
+ }
}
-
// Iterate through all render nodes to find the simulation triangle that's closest to the node in the barycentric sense.
void btSoftBodyHelpers::extrapolateBarycentricWeights(btSoftBody* psb)
{
- psb->m_renderNodesInterpolationWeights.resize(psb->m_renderNodes.size());
- psb->m_renderNodesParents.resize(psb->m_renderNodes.size());
- psb->m_z.resize(psb->m_renderNodes.size());
- for (int i = 0; i < psb->m_renderNodes.size(); ++i)
- {
- const btVector3& p = psb->m_renderNodes[i].m_x;
- btVector4 bary;
- btVector4 optimal_bary;
- btScalar min_bary_weight = -SIMD_INFINITY;
- btAlignedObjectArray<const btSoftBody::Node*> optimal_parents;
- btScalar dist = 0, optimal_dist = 0;
- for (int j = 0; j < psb->m_faces.size(); ++j)
- {
- const btSoftBody::Face& f = psb->m_faces[j];
- btVector3 n = btCross(f.m_n[1]->m_x - f.m_n[0]->m_x, f.m_n[2]->m_x - f.m_n[0]->m_x);
- btVector3 unit_n = n.normalized();
- dist = (p-f.m_n[0]->m_x).dot(unit_n);
- btVector3 proj_p = p - dist*unit_n;
- getBarycentricWeights(f.m_n[0]->m_x, f.m_n[1]->m_x, f.m_n[2]->m_x, proj_p, bary);
- btScalar new_min_bary_weight = bary[0];
- for (int k = 1; k < 3; ++k)
- {
- new_min_bary_weight = btMin(new_min_bary_weight, bary[k]);
- }
-
- // p is out of the current best triangle, we found a traingle that's better
- bool better_than_closest_outisde = (new_min_bary_weight > min_bary_weight && min_bary_weight<0.);
- // p is inside of the current best triangle, we found a triangle that's better
- bool better_than_best_inside = (new_min_bary_weight>=0 && min_bary_weight>=0 && btFabs(dist)<btFabs(optimal_dist));
-
- if (better_than_closest_outisde || better_than_best_inside)
- {
- btAlignedObjectArray<const btSoftBody::Node*> parents;
- parents.push_back(f.m_n[0]);
- parents.push_back(f.m_n[1]);
- parents.push_back(f.m_n[2]);
- optimal_parents = parents;
- optimal_bary = bary;
- optimal_dist = dist;
- min_bary_weight = new_min_bary_weight;
- }
- }
- psb->m_renderNodesInterpolationWeights[i] = optimal_bary;
- psb->m_renderNodesParents[i] = optimal_parents;
- psb->m_z[i] = optimal_dist;
- }
+ psb->m_renderNodesInterpolationWeights.resize(psb->m_renderNodes.size());
+ psb->m_renderNodesParents.resize(psb->m_renderNodes.size());
+ psb->m_z.resize(psb->m_renderNodes.size());
+ for (int i = 0; i < psb->m_renderNodes.size(); ++i)
+ {
+ const btVector3& p = psb->m_renderNodes[i].m_x;
+ btVector4 bary;
+ btVector4 optimal_bary;
+ btScalar min_bary_weight = -SIMD_INFINITY;
+ btAlignedObjectArray<const btSoftBody::Node*> optimal_parents;
+ btScalar dist = 0, optimal_dist = 0;
+ for (int j = 0; j < psb->m_faces.size(); ++j)
+ {
+ const btSoftBody::Face& f = psb->m_faces[j];
+ btVector3 n = btCross(f.m_n[1]->m_x - f.m_n[0]->m_x, f.m_n[2]->m_x - f.m_n[0]->m_x);
+ btVector3 unit_n = n.normalized();
+ dist = (p - f.m_n[0]->m_x).dot(unit_n);
+ btVector3 proj_p = p - dist * unit_n;
+ getBarycentricWeights(f.m_n[0]->m_x, f.m_n[1]->m_x, f.m_n[2]->m_x, proj_p, bary);
+ btScalar new_min_bary_weight = bary[0];
+ for (int k = 1; k < 3; ++k)
+ {
+ new_min_bary_weight = btMin(new_min_bary_weight, bary[k]);
+ }
+
+ // p is out of the current best triangle, we found a traingle that's better
+ bool better_than_closest_outisde = (new_min_bary_weight > min_bary_weight && min_bary_weight < 0.);
+ // p is inside of the current best triangle, we found a triangle that's better
+ bool better_than_best_inside = (new_min_bary_weight >= 0 && min_bary_weight >= 0 && btFabs(dist) < btFabs(optimal_dist));
+
+ if (better_than_closest_outisde || better_than_best_inside)
+ {
+ btAlignedObjectArray<const btSoftBody::Node*> parents;
+ parents.push_back(f.m_n[0]);
+ parents.push_back(f.m_n[1]);
+ parents.push_back(f.m_n[2]);
+ optimal_parents = parents;
+ optimal_bary = bary;
+ optimal_dist = dist;
+ min_bary_weight = new_min_bary_weight;
+ }
+ }
+ psb->m_renderNodesInterpolationWeights[i] = optimal_bary;
+ psb->m_renderNodesParents[i] = optimal_parents;
+ psb->m_z[i] = optimal_dist;
+ }
}
diff --git a/thirdparty/bullet/BulletSoftBody/btSoftBodyHelpers.h b/thirdparty/bullet/BulletSoftBody/btSoftBodyHelpers.h
index abe1870890..237d29761d 100644
--- a/thirdparty/bullet/BulletSoftBody/btSoftBodyHelpers.h
+++ b/thirdparty/bullet/BulletSoftBody/btSoftBodyHelpers.h
@@ -93,7 +93,7 @@ struct btSoftBodyHelpers
int resy,
int fixeds,
bool gendiags,
- btScalar perturbation = 0.);
+ btScalar perturbation = 0.);
/* Create a patch with UV Texture Coordinates */
static btSoftBody* CreatePatchUV(btSoftBodyWorldInfo& worldInfo,
const btVector3& corner00,
@@ -142,21 +142,21 @@ struct btSoftBodyHelpers
bool bfacelinks,
bool btetralinks,
bool bfacesfromtetras);
- static btSoftBody* CreateFromVtkFile(btSoftBodyWorldInfo& worldInfo, const char* vtk_file);
+ static btSoftBody* CreateFromVtkFile(btSoftBodyWorldInfo& worldInfo, const char* vtk_file);
- static void writeObj(const char* file, const btSoftBody* psb);
-
- static void getBarycentricWeights(const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& d, const btVector3& p, btVector4& bary);
-
- static void getBarycentricWeights(const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& p, btVector4& bary);
-
- static void interpolateBarycentricWeights(btSoftBody* psb);
-
- static void extrapolateBarycentricWeights(btSoftBody* psb);
-
- static void generateBoundaryFaces(btSoftBody* psb);
-
- static void duplicateFaces(const char* filename, const btSoftBody* psb);
+ static void writeObj(const char* file, const btSoftBody* psb);
+
+ static void getBarycentricWeights(const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& d, const btVector3& p, btVector4& bary);
+
+ static void getBarycentricWeights(const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& p, btVector4& bary);
+
+ static void interpolateBarycentricWeights(btSoftBody* psb);
+
+ static void extrapolateBarycentricWeights(btSoftBody* psb);
+
+ static void generateBoundaryFaces(btSoftBody* psb);
+
+ static void duplicateFaces(const char* filename, const btSoftBody* psb);
/// Sort the list of links to move link calculations that are dependent upon earlier
/// ones as far as possible away from the calculation of those values
/// This tends to make adjacent loop iterations not dependent upon one another,
diff --git a/thirdparty/bullet/BulletSoftBody/btSoftBodyInternals.h b/thirdparty/bullet/BulletSoftBody/btSoftBodyInternals.h
index b9ebc95b6b..c17bbb5cd4 100644
--- a/thirdparty/bullet/BulletSoftBody/btSoftBodyInternals.h
+++ b/thirdparty/bullet/BulletSoftBody/btSoftBodyInternals.h
@@ -32,86 +32,85 @@ subject to the following restrictions:
// Given a multibody link, a contact point and a contact direction, fill in the jacobian data needed to calculate the velocity change given an impulse in the contact direction
static SIMD_FORCE_INLINE void findJacobian(const btMultiBodyLinkCollider* multibodyLinkCol,
- btMultiBodyJacobianData& jacobianData,
- const btVector3& contact_point,
- const btVector3& dir)
-{
- const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6;
- jacobianData.m_jacobians.resize(ndof);
- jacobianData.m_deltaVelocitiesUnitImpulse.resize(ndof);
- btScalar* jac = &jacobianData.m_jacobians[0];
-
- multibodyLinkCol->m_multiBody->fillContactJacobianMultiDof(multibodyLinkCol->m_link, contact_point, dir, jac, jacobianData.scratch_r, jacobianData.scratch_v, jacobianData.scratch_m);
- multibodyLinkCol->m_multiBody->calcAccelerationDeltasMultiDof(&jacobianData.m_jacobians[0], &jacobianData.m_deltaVelocitiesUnitImpulse[0], jacobianData.scratch_r, jacobianData.scratch_v);
+ btMultiBodyJacobianData& jacobianData,
+ const btVector3& contact_point,
+ const btVector3& dir)
+{
+ const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6;
+ jacobianData.m_jacobians.resize(ndof);
+ jacobianData.m_deltaVelocitiesUnitImpulse.resize(ndof);
+ btScalar* jac = &jacobianData.m_jacobians[0];
+
+ multibodyLinkCol->m_multiBody->fillContactJacobianMultiDof(multibodyLinkCol->m_link, contact_point, dir, jac, jacobianData.scratch_r, jacobianData.scratch_v, jacobianData.scratch_m);
+ multibodyLinkCol->m_multiBody->calcAccelerationDeltasMultiDof(&jacobianData.m_jacobians[0], &jacobianData.m_deltaVelocitiesUnitImpulse[0], jacobianData.scratch_r, jacobianData.scratch_v);
}
static SIMD_FORCE_INLINE btVector3 generateUnitOrthogonalVector(const btVector3& u)
{
- btScalar ux = u.getX();
- btScalar uy = u.getY();
- btScalar uz = u.getZ();
- btScalar ax = std::abs(ux);
- btScalar ay = std::abs(uy);
- btScalar az = std::abs(uz);
- btVector3 v;
- if (ax <= ay && ax <= az)
- v = btVector3(0, -uz, uy);
- else if (ay <= ax && ay <= az)
- v = btVector3(-uz, 0, ux);
- else
- v = btVector3(-uy, ux, 0);
- v.normalize();
- return v;
+ btScalar ux = u.getX();
+ btScalar uy = u.getY();
+ btScalar uz = u.getZ();
+ btScalar ax = std::abs(ux);
+ btScalar ay = std::abs(uy);
+ btScalar az = std::abs(uz);
+ btVector3 v;
+ if (ax <= ay && ax <= az)
+ v = btVector3(0, -uz, uy);
+ else if (ay <= ax && ay <= az)
+ v = btVector3(-uz, 0, ux);
+ else
+ v = btVector3(-uy, ux, 0);
+ v.normalize();
+ return v;
}
static SIMD_FORCE_INLINE bool proximityTest(const btVector3& x1, const btVector3& x2, const btVector3& x3, const btVector3& x4, const btVector3& normal, const btScalar& mrg, btVector3& bary)
{
- btVector3 x43 = x4-x3;
- if (std::abs(x43.dot(normal)) > mrg)
- return false;
- btVector3 x13 = x1-x3;
- btVector3 x23 = x2-x3;
- btScalar a11 = x13.length2();
- btScalar a22 = x23.length2();
- btScalar a12 = x13.dot(x23);
- btScalar b1 = x13.dot(x43);
- btScalar b2 = x23.dot(x43);
- btScalar det = a11*a22 - a12*a12;
- if (det < SIMD_EPSILON)
- return false;
- btScalar w1 = (b1*a22-b2*a12)/det;
- btScalar w2 = (b2*a11-b1*a12)/det;
- btScalar w3 = 1-w1-w2;
- btScalar delta = mrg / std::sqrt(0.5*std::abs(x13.cross(x23).safeNorm()));
- bary = btVector3(w1,w2,w3);
- for (int i = 0; i < 3; ++i)
- {
- if (bary[i] < -delta || bary[i] > 1+delta)
- return false;
- }
- return true;
+ btVector3 x43 = x4 - x3;
+ if (std::abs(x43.dot(normal)) > mrg)
+ return false;
+ btVector3 x13 = x1 - x3;
+ btVector3 x23 = x2 - x3;
+ btScalar a11 = x13.length2();
+ btScalar a22 = x23.length2();
+ btScalar a12 = x13.dot(x23);
+ btScalar b1 = x13.dot(x43);
+ btScalar b2 = x23.dot(x43);
+ btScalar det = a11 * a22 - a12 * a12;
+ if (det < SIMD_EPSILON)
+ return false;
+ btScalar w1 = (b1 * a22 - b2 * a12) / det;
+ btScalar w2 = (b2 * a11 - b1 * a12) / det;
+ btScalar w3 = 1 - w1 - w2;
+ btScalar delta = mrg / std::sqrt(0.5 * std::abs(x13.cross(x23).safeNorm()));
+ bary = btVector3(w1, w2, w3);
+ for (int i = 0; i < 3; ++i)
+ {
+ if (bary[i] < -delta || bary[i] > 1 + delta)
+ return false;
+ }
+ return true;
}
static const int KDOP_COUNT = 13;
-static btVector3 dop[KDOP_COUNT]={btVector3(1,0,0),
- btVector3(0,1,0),
- btVector3(0,0,1),
- btVector3(1,1,0),
- btVector3(1,0,1),
- btVector3(0,1,1),
- btVector3(1,-1,0),
- btVector3(1,0,-1),
- btVector3(0,1,-1),
- btVector3(1,1,1),
- btVector3(1,-1,1),
- btVector3(1,1,-1),
- btVector3(1,-1,-1)
-};
+static btVector3 dop[KDOP_COUNT] = {btVector3(1, 0, 0),
+ btVector3(0, 1, 0),
+ btVector3(0, 0, 1),
+ btVector3(1, 1, 0),
+ btVector3(1, 0, 1),
+ btVector3(0, 1, 1),
+ btVector3(1, -1, 0),
+ btVector3(1, 0, -1),
+ btVector3(0, 1, -1),
+ btVector3(1, 1, 1),
+ btVector3(1, -1, 1),
+ btVector3(1, 1, -1),
+ btVector3(1, -1, -1)};
static inline int getSign(const btVector3& n, const btVector3& x)
{
btScalar d = n.dot(x);
- if (d>SIMD_EPSILON)
+ if (d > SIMD_EPSILON)
return 1;
- if (d<-SIMD_EPSILON)
+ if (d < -SIMD_EPSILON)
return -1;
return 0;
}
@@ -119,13 +118,12 @@ static inline int getSign(const btVector3& n, const btVector3& x)
static SIMD_FORCE_INLINE bool hasSeparatingPlane(const btSoftBody::Face* face, const btSoftBody::Node* node, const btScalar& dt)
{
btVector3 hex[6] = {face->m_n[0]->m_x - node->m_x,
- face->m_n[1]->m_x - node->m_x,
- face->m_n[2]->m_x - node->m_x,
- face->m_n[0]->m_x + dt*face->m_n[0]->m_v - node->m_x,
- face->m_n[1]->m_x + dt*face->m_n[1]->m_v - node->m_x,
- face->m_n[2]->m_x + dt*face->m_n[2]->m_v - node->m_x
- };
- btVector3 segment = dt*node->m_v;
+ face->m_n[1]->m_x - node->m_x,
+ face->m_n[2]->m_x - node->m_x,
+ face->m_n[0]->m_x + dt * face->m_n[0]->m_v - node->m_x,
+ face->m_n[1]->m_x + dt * face->m_n[1]->m_v - node->m_x,
+ face->m_n[2]->m_x + dt * face->m_n[2]->m_v - node->m_x};
+ btVector3 segment = dt * node->m_v;
for (int i = 0; i < KDOP_COUNT; ++i)
{
int s = getSign(dop[i], segment);
@@ -143,488 +141,494 @@ static SIMD_FORCE_INLINE bool hasSeparatingPlane(const btSoftBody::Face* face, c
static SIMD_FORCE_INLINE bool nearZero(const btScalar& a)
{
- return (a>-SAFE_EPSILON && a<SAFE_EPSILON);
+ return (a > -SAFE_EPSILON && a < SAFE_EPSILON);
}
static SIMD_FORCE_INLINE bool sameSign(const btScalar& a, const btScalar& b)
{
- return (nearZero(a) || nearZero(b) || (a>SAFE_EPSILON && b>SAFE_EPSILON) || (a<-SAFE_EPSILON && b<-SAFE_EPSILON));
+ return (nearZero(a) || nearZero(b) || (a > SAFE_EPSILON && b > SAFE_EPSILON) || (a < -SAFE_EPSILON && b < -SAFE_EPSILON));
}
static SIMD_FORCE_INLINE bool diffSign(const btScalar& a, const btScalar& b)
{
- return !sameSign(a, b);
-}
-inline btScalar evaluateBezier2(const btScalar &p0, const btScalar &p1, const btScalar &p2, const btScalar &t, const btScalar &s)
-{
- btScalar s2 = s*s;
- btScalar t2 = t*t;
-
- return p0*s2+p1*btScalar(2.0)*s*t+p2*t2;
-}
-inline btScalar evaluateBezier(const btScalar &p0, const btScalar &p1, const btScalar &p2, const btScalar &p3, const btScalar &t, const btScalar &s)
-{
- btScalar s2 = s*s;
- btScalar s3 = s2*s;
- btScalar t2 = t*t;
- btScalar t3 = t2*t;
-
- return p0*s3+p1*btScalar(3.0)*s2*t+p2*btScalar(3.0)*s*t2+p3*t3;
-}
-static SIMD_FORCE_INLINE bool getSigns(bool type_c, const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3, const btScalar& t0, const btScalar& t1, btScalar &lt0, btScalar &lt1)
-{
- if (sameSign(t0, t1)) {
- lt0 = t0;
- lt1 = t0;
- return true;
- }
-
- if (type_c || diffSign(k0, k3)) {
- btScalar ft = evaluateBezier(k0, k1, k2, k3, t0, -t1);
- if (t0<-0)
- ft = -ft;
-
- if (sameSign(ft, k0)) {
- lt0 = t1;
- lt1 = t1;
- }
- else {
- lt0 = t0;
- lt1 = t0;
- }
- return true;
- }
-
- if (!type_c) {
- btScalar ft = evaluateBezier(k0, k1, k2, k3, t0, -t1);
- if (t0<-0)
- ft = -ft;
-
- if (diffSign(ft, k0)) {
- lt0 = t0;
- lt1 = t1;
- return true;
- }
-
- btScalar fk = evaluateBezier2(k1-k0, k2-k1, k3-k2, t0, -t1);
-
- if (sameSign(fk, k1-k0))
- lt0 = lt1 = t1;
- else
- lt0 = lt1 = t0;
-
- return true;
- }
- return false;
+ return !sameSign(a, b);
+}
+inline btScalar evaluateBezier2(const btScalar& p0, const btScalar& p1, const btScalar& p2, const btScalar& t, const btScalar& s)
+{
+ btScalar s2 = s * s;
+ btScalar t2 = t * t;
+
+ return p0 * s2 + p1 * btScalar(2.0) * s * t + p2 * t2;
+}
+inline btScalar evaluateBezier(const btScalar& p0, const btScalar& p1, const btScalar& p2, const btScalar& p3, const btScalar& t, const btScalar& s)
+{
+ btScalar s2 = s * s;
+ btScalar s3 = s2 * s;
+ btScalar t2 = t * t;
+ btScalar t3 = t2 * t;
+
+ return p0 * s3 + p1 * btScalar(3.0) * s2 * t + p2 * btScalar(3.0) * s * t2 + p3 * t3;
+}
+static SIMD_FORCE_INLINE bool getSigns(bool type_c, const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3, const btScalar& t0, const btScalar& t1, btScalar& lt0, btScalar& lt1)
+{
+ if (sameSign(t0, t1))
+ {
+ lt0 = t0;
+ lt1 = t0;
+ return true;
+ }
+
+ if (type_c || diffSign(k0, k3))
+ {
+ btScalar ft = evaluateBezier(k0, k1, k2, k3, t0, -t1);
+ if (t0 < -0)
+ ft = -ft;
+
+ if (sameSign(ft, k0))
+ {
+ lt0 = t1;
+ lt1 = t1;
+ }
+ else
+ {
+ lt0 = t0;
+ lt1 = t0;
+ }
+ return true;
+ }
+
+ if (!type_c)
+ {
+ btScalar ft = evaluateBezier(k0, k1, k2, k3, t0, -t1);
+ if (t0 < -0)
+ ft = -ft;
+
+ if (diffSign(ft, k0))
+ {
+ lt0 = t0;
+ lt1 = t1;
+ return true;
+ }
+
+ btScalar fk = evaluateBezier2(k1 - k0, k2 - k1, k3 - k2, t0, -t1);
+
+ if (sameSign(fk, k1 - k0))
+ lt0 = lt1 = t1;
+ else
+ lt0 = lt1 = t0;
+
+ return true;
+ }
+ return false;
}
static SIMD_FORCE_INLINE void getBernsteinCoeff(const btSoftBody::Face* face, const btSoftBody::Node* node, const btScalar& dt, btScalar& k0, btScalar& k1, btScalar& k2, btScalar& k3)
{
- const btVector3& n0 = face->m_n0;
- const btVector3& n1 = face->m_n1;
- btVector3 n_hat = n0 + n1 - face->m_vn;
- btVector3 p0ma0 = node->m_x - face->m_n[0]->m_x;
- btVector3 p1ma1 = node->m_q - face->m_n[0]->m_q;
- k0 = (p0ma0).dot(n0) * 3.0;
- k1 = (p0ma0).dot(n_hat) + (p1ma1).dot(n0);
- k2 = (p1ma1).dot(n_hat) + (p0ma0).dot(n1);
- k3 = (p1ma1).dot(n1) * 3.0;
+ const btVector3& n0 = face->m_n0;
+ const btVector3& n1 = face->m_n1;
+ btVector3 n_hat = n0 + n1 - face->m_vn;
+ btVector3 p0ma0 = node->m_x - face->m_n[0]->m_x;
+ btVector3 p1ma1 = node->m_q - face->m_n[0]->m_q;
+ k0 = (p0ma0).dot(n0) * 3.0;
+ k1 = (p0ma0).dot(n_hat) + (p1ma1).dot(n0);
+ k2 = (p1ma1).dot(n_hat) + (p0ma0).dot(n1);
+ k3 = (p1ma1).dot(n1) * 3.0;
}
static SIMD_FORCE_INLINE void polyDecomposition(const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3, const btScalar& j0, const btScalar& j1, const btScalar& j2, btScalar& u0, btScalar& u1, btScalar& v0, btScalar& v1)
{
- btScalar denom = 4.0 * (j1-j2) * (j1-j0) + (j2-j0) * (j2-j0);
- u0 = (2.0*(j1-j2)*(3.0*k1-2.0*k0-k3) - (j0-j2)*(3.0*k2-2.0*k3-k0)) / denom;
- u1 = (2.0*(j1-j0)*(3.0*k2-2.0*k3-k0) - (j2-j0)*(3.0*k1-2.0*k0-k3)) / denom;
- v0 = k0-u0*j0;
- v1 = k3-u1*j2;
+ btScalar denom = 4.0 * (j1 - j2) * (j1 - j0) + (j2 - j0) * (j2 - j0);
+ u0 = (2.0 * (j1 - j2) * (3.0 * k1 - 2.0 * k0 - k3) - (j0 - j2) * (3.0 * k2 - 2.0 * k3 - k0)) / denom;
+ u1 = (2.0 * (j1 - j0) * (3.0 * k2 - 2.0 * k3 - k0) - (j2 - j0) * (3.0 * k1 - 2.0 * k0 - k3)) / denom;
+ v0 = k0 - u0 * j0;
+ v1 = k3 - u1 * j2;
}
static SIMD_FORCE_INLINE bool rootFindingLemma(const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3)
{
- btScalar u0, u1, v0, v1;
- btScalar j0 = 3.0*(k1-k0);
- btScalar j1 = 3.0*(k2-k1);
- btScalar j2 = 3.0*(k3-k2);
- polyDecomposition(k0,k1,k2,k3,j0,j1,j2,u0,u1,v0,v1);
- if (sameSign(v0, v1))
- {
- btScalar Ypa = j0*(1.0-v0)*(1.0-v0) + 2.0*j1*v0*(1.0-v0) + j2*v0*v0; // Y'(v0)
- if (sameSign(Ypa, j0))
- {
- return (diffSign(k0,v1));
- }
- }
- return diffSign(k0,v0);
-}
-
-static SIMD_FORCE_INLINE void getJs(const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3, const btSoftBody::Node* a, const btSoftBody::Node* b, const btSoftBody::Node* c, const btSoftBody::Node* p, const btScalar& dt, btScalar& j0, btScalar& j1, btScalar& j2)
-{
- const btVector3& a0 = a->m_x;
- const btVector3& b0 = b->m_x;
- const btVector3& c0 = c->m_x;
- const btVector3& va = a->m_v;
- const btVector3& vb = b->m_v;
- const btVector3& vc = c->m_v;
- const btVector3 a1 = a0 + dt*va;
- const btVector3 b1 = b0 + dt*vb;
- const btVector3 c1 = c0 + dt*vc;
- btVector3 n0 = (b0-a0).cross(c0-a0);
- btVector3 n1 = (b1-a1).cross(c1-a1);
- btVector3 n_hat = n0+n1 - dt*dt*(vb-va).cross(vc-va);
- const btVector3& p0 = p->m_x;
- const btVector3& vp = p->m_v;
- btVector3 p1 = p0 + dt*vp;
- btVector3 m0 = (b0-p0).cross(c0-p0);
- btVector3 m1 = (b1-p1).cross(c1-p1);
- btVector3 m_hat = m0+m1 - dt*dt*(vb-vp).cross(vc-vp);
- btScalar l0 = m0.dot(n0);
- btScalar l1 = 0.25 * (m0.dot(n_hat) + m_hat.dot(n0));
- btScalar l2 = btScalar(1)/btScalar(6)*(m0.dot(n1) + m_hat.dot(n_hat) + m1.dot(n0));
- btScalar l3 = 0.25 * (m_hat.dot(n1) + m1.dot(n_hat));
- btScalar l4 = m1.dot(n1);
-
- btScalar k1p = 0.25 * k0 + 0.75 * k1;
- btScalar k2p = 0.5 * k1 + 0.5 * k2;
- btScalar k3p = 0.75 * k2 + 0.25 * k3;
-
- btScalar s0 = (l1 * k0 - l0 * k1p)*4.0;
- btScalar s1 = (l2 * k0 - l0 * k2p)*2.0;
- btScalar s2 = (l3 * k0 - l0 * k3p)*btScalar(4)/btScalar(3);
- btScalar s3 = l4 * k0 - l0 * k3;
-
- j0 = (s1*k0 - s0*k1) * 3.0;
- j1 = (s2*k0 - s0*k2) * 1.5;
- j2 = (s3*k0 - s0*k3);
+ btScalar u0, u1, v0, v1;
+ btScalar j0 = 3.0 * (k1 - k0);
+ btScalar j1 = 3.0 * (k2 - k1);
+ btScalar j2 = 3.0 * (k3 - k2);
+ polyDecomposition(k0, k1, k2, k3, j0, j1, j2, u0, u1, v0, v1);
+ if (sameSign(v0, v1))
+ {
+ btScalar Ypa = j0 * (1.0 - v0) * (1.0 - v0) + 2.0 * j1 * v0 * (1.0 - v0) + j2 * v0 * v0; // Y'(v0)
+ if (sameSign(Ypa, j0))
+ {
+ return (diffSign(k0, v1));
+ }
+ }
+ return diffSign(k0, v0);
+}
+
+static SIMD_FORCE_INLINE void getJs(const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3, const btSoftBody::Node* a, const btSoftBody::Node* b, const btSoftBody::Node* c, const btSoftBody::Node* p, const btScalar& dt, btScalar& j0, btScalar& j1, btScalar& j2)
+{
+ const btVector3& a0 = a->m_x;
+ const btVector3& b0 = b->m_x;
+ const btVector3& c0 = c->m_x;
+ const btVector3& va = a->m_v;
+ const btVector3& vb = b->m_v;
+ const btVector3& vc = c->m_v;
+ const btVector3 a1 = a0 + dt * va;
+ const btVector3 b1 = b0 + dt * vb;
+ const btVector3 c1 = c0 + dt * vc;
+ btVector3 n0 = (b0 - a0).cross(c0 - a0);
+ btVector3 n1 = (b1 - a1).cross(c1 - a1);
+ btVector3 n_hat = n0 + n1 - dt * dt * (vb - va).cross(vc - va);
+ const btVector3& p0 = p->m_x;
+ const btVector3& vp = p->m_v;
+ btVector3 p1 = p0 + dt * vp;
+ btVector3 m0 = (b0 - p0).cross(c0 - p0);
+ btVector3 m1 = (b1 - p1).cross(c1 - p1);
+ btVector3 m_hat = m0 + m1 - dt * dt * (vb - vp).cross(vc - vp);
+ btScalar l0 = m0.dot(n0);
+ btScalar l1 = 0.25 * (m0.dot(n_hat) + m_hat.dot(n0));
+ btScalar l2 = btScalar(1) / btScalar(6) * (m0.dot(n1) + m_hat.dot(n_hat) + m1.dot(n0));
+ btScalar l3 = 0.25 * (m_hat.dot(n1) + m1.dot(n_hat));
+ btScalar l4 = m1.dot(n1);
+
+ btScalar k1p = 0.25 * k0 + 0.75 * k1;
+ btScalar k2p = 0.5 * k1 + 0.5 * k2;
+ btScalar k3p = 0.75 * k2 + 0.25 * k3;
+
+ btScalar s0 = (l1 * k0 - l0 * k1p) * 4.0;
+ btScalar s1 = (l2 * k0 - l0 * k2p) * 2.0;
+ btScalar s2 = (l3 * k0 - l0 * k3p) * btScalar(4) / btScalar(3);
+ btScalar s3 = l4 * k0 - l0 * k3;
+
+ j0 = (s1 * k0 - s0 * k1) * 3.0;
+ j1 = (s2 * k0 - s0 * k2) * 1.5;
+ j2 = (s3 * k0 - s0 * k3);
}
static SIMD_FORCE_INLINE bool signDetermination1Internal(const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3, const btScalar& u0, const btScalar& u1, const btScalar& v0, const btScalar& v1)
{
- btScalar Yu0 = k0*(1.0-u0)*(1.0-u0)*(1.0-u0) + 3.0*k1*u0*(1.0-u0)*(1.0-u0) + 3.0*k2*u0*u0*(1.0-u0) + k3*u0*u0*u0; // Y(u0)
- btScalar Yv0 = k0*(1.0-v0)*(1.0-v0)*(1.0-v0) + 3.0*k1*v0*(1.0-v0)*(1.0-v0) + 3.0*k2*v0*v0*(1.0-v0) + k3*v0*v0*v0; // Y(v0)
+ btScalar Yu0 = k0 * (1.0 - u0) * (1.0 - u0) * (1.0 - u0) + 3.0 * k1 * u0 * (1.0 - u0) * (1.0 - u0) + 3.0 * k2 * u0 * u0 * (1.0 - u0) + k3 * u0 * u0 * u0; // Y(u0)
+ btScalar Yv0 = k0 * (1.0 - v0) * (1.0 - v0) * (1.0 - v0) + 3.0 * k1 * v0 * (1.0 - v0) * (1.0 - v0) + 3.0 * k2 * v0 * v0 * (1.0 - v0) + k3 * v0 * v0 * v0; // Y(v0)
- btScalar sign_Ytp = (u0 > u1) ? Yu0 : -Yu0;
- btScalar L = sameSign(sign_Ytp, k0) ? u1 : u0;
- sign_Ytp = (v0 > v1) ? Yv0 : -Yv0;
- btScalar K = (sameSign(sign_Ytp,k0)) ? v1 : v0;
- return diffSign(L,K);
+ btScalar sign_Ytp = (u0 > u1) ? Yu0 : -Yu0;
+ btScalar L = sameSign(sign_Ytp, k0) ? u1 : u0;
+ sign_Ytp = (v0 > v1) ? Yv0 : -Yv0;
+ btScalar K = (sameSign(sign_Ytp, k0)) ? v1 : v0;
+ return diffSign(L, K);
}
static SIMD_FORCE_INLINE bool signDetermination2Internal(const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3, const btScalar& j0, const btScalar& j1, const btScalar& j2, const btScalar& u0, const btScalar& u1, const btScalar& v0, const btScalar& v1)
{
- btScalar Yu0 = k0*(1.0-u0)*(1.0-u0)*(1.0-u0) + 3.0*k1*u0*(1.0-u0)*(1.0-u0) + 3.0*k2*u0*u0*(1.0-u0) + k3*u0*u0*u0; // Y(u0)
- btScalar sign_Ytp = (u0 > u1) ? Yu0 : -Yu0, L1, L2;
- if (diffSign(sign_Ytp,k0))
- {
- L1 = u0;
- L2 = u1;
- }
- else
- {
- btScalar Yp_u0 = j0*(1.0-u0)*(1.0-u0) + 2.0*j1*(1.0-u0)*u0 + j2*u0*u0;
- if (sameSign(Yp_u0,j0))
- {
- L1 = u1;
- L2 = u1;
- }
- else
- {
- L1 = u0;
- L2 = u0;
- }
- }
- btScalar Yv0 = k0*(1.0-v0)*(1.0-v0)*(1.0-v0) + 3.0*k1*v0*(1.0-v0)*(1.0-v0) + 3.0*k2*v0*v0*(1.0-v0) + k3*v0*v0*v0; // Y(uv0)
- sign_Ytp = (v0 > v1) ? Yv0 : -Yv0;
- btScalar K1, K2;
- if (diffSign(sign_Ytp,k0))
- {
- K1 = v0;
- K2 = v1;
- }
- else
- {
- btScalar Yp_v0 = j0*(1.0-v0)*(1.0-v0) + 2.0*j1*(1.0-v0)*v0 + j2*v0*v0;
- if (sameSign(Yp_v0,j0))
- {
- K1 = v1;
- K2 = v1;
- }
- else
- {
- K1 = v0;
- K2 = v0;
- }
- }
- return (diffSign(K1, L1) || diffSign(L2, K2));
+ btScalar Yu0 = k0 * (1.0 - u0) * (1.0 - u0) * (1.0 - u0) + 3.0 * k1 * u0 * (1.0 - u0) * (1.0 - u0) + 3.0 * k2 * u0 * u0 * (1.0 - u0) + k3 * u0 * u0 * u0; // Y(u0)
+ btScalar sign_Ytp = (u0 > u1) ? Yu0 : -Yu0, L1, L2;
+ if (diffSign(sign_Ytp, k0))
+ {
+ L1 = u0;
+ L2 = u1;
+ }
+ else
+ {
+ btScalar Yp_u0 = j0 * (1.0 - u0) * (1.0 - u0) + 2.0 * j1 * (1.0 - u0) * u0 + j2 * u0 * u0;
+ if (sameSign(Yp_u0, j0))
+ {
+ L1 = u1;
+ L2 = u1;
+ }
+ else
+ {
+ L1 = u0;
+ L2 = u0;
+ }
+ }
+ btScalar Yv0 = k0 * (1.0 - v0) * (1.0 - v0) * (1.0 - v0) + 3.0 * k1 * v0 * (1.0 - v0) * (1.0 - v0) + 3.0 * k2 * v0 * v0 * (1.0 - v0) + k3 * v0 * v0 * v0; // Y(uv0)
+ sign_Ytp = (v0 > v1) ? Yv0 : -Yv0;
+ btScalar K1, K2;
+ if (diffSign(sign_Ytp, k0))
+ {
+ K1 = v0;
+ K2 = v1;
+ }
+ else
+ {
+ btScalar Yp_v0 = j0 * (1.0 - v0) * (1.0 - v0) + 2.0 * j1 * (1.0 - v0) * v0 + j2 * v0 * v0;
+ if (sameSign(Yp_v0, j0))
+ {
+ K1 = v1;
+ K2 = v1;
+ }
+ else
+ {
+ K1 = v0;
+ K2 = v0;
+ }
+ }
+ return (diffSign(K1, L1) || diffSign(L2, K2));
}
static SIMD_FORCE_INLINE bool signDetermination1(const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3, const btSoftBody::Face* face, const btSoftBody::Node* node, const btScalar& dt)
{
- btScalar j0, j1, j2, u0, u1, v0, v1;
- // p1
- getJs(k0,k1,k2,k3,face->m_n[0], face->m_n[1], face->m_n[2], node, dt, j0, j1, j2);
- if (nearZero(j0+j2-j1*2.0))
- {
- btScalar lt0, lt1;
- getSigns(true, k0, k1, k2, k3, j0, j2, lt0, lt1);
- if (lt0 < -SAFE_EPSILON)
- return false;
- }
- else
- {
- polyDecomposition(k0,k1,k2,k3,j0,j1,j2,u0,u1,v0,v1);
- if (!signDetermination1Internal(k0,k1,k2,k3,u0,u1,v0,v1))
- return false;
- }
- // p2
- getJs(k0,k1,k2,k3,face->m_n[1], face->m_n[2], face->m_n[0], node, dt, j0, j1, j2);
- if (nearZero(j0+j2-j1*2.0))
- {
- btScalar lt0, lt1;
- getSigns(true, k0, k1, k2, k3, j0, j2, lt0, lt1);
- if (lt0 < -SAFE_EPSILON)
- return false;
- }
- else
- {
- polyDecomposition(k0,k1,k2,k3,j0,j1,j2,u0,u1,v0,v1);
- if (!signDetermination1Internal(k0,k1,k2,k3,u0,u1,v0,v1))
- return false;
- }
- // p3
- getJs(k0,k1,k2,k3,face->m_n[2], face->m_n[0], face->m_n[1], node, dt, j0, j1, j2);
- if (nearZero(j0+j2-j1*2.0))
- {
- btScalar lt0, lt1;
- getSigns(true, k0, k1, k2, k3, j0, j2, lt0, lt1);
- if (lt0 < -SAFE_EPSILON)
- return false;
- }
- else
- {
- polyDecomposition(k0,k1,k2,k3,j0,j1,j2,u0,u1,v0,v1);
- if (!signDetermination1Internal(k0,k1,k2,k3,u0,u1,v0,v1))
- return false;
- }
- return true;
+ btScalar j0, j1, j2, u0, u1, v0, v1;
+ // p1
+ getJs(k0, k1, k2, k3, face->m_n[0], face->m_n[1], face->m_n[2], node, dt, j0, j1, j2);
+ if (nearZero(j0 + j2 - j1 * 2.0))
+ {
+ btScalar lt0, lt1;
+ getSigns(true, k0, k1, k2, k3, j0, j2, lt0, lt1);
+ if (lt0 < -SAFE_EPSILON)
+ return false;
+ }
+ else
+ {
+ polyDecomposition(k0, k1, k2, k3, j0, j1, j2, u0, u1, v0, v1);
+ if (!signDetermination1Internal(k0, k1, k2, k3, u0, u1, v0, v1))
+ return false;
+ }
+ // p2
+ getJs(k0, k1, k2, k3, face->m_n[1], face->m_n[2], face->m_n[0], node, dt, j0, j1, j2);
+ if (nearZero(j0 + j2 - j1 * 2.0))
+ {
+ btScalar lt0, lt1;
+ getSigns(true, k0, k1, k2, k3, j0, j2, lt0, lt1);
+ if (lt0 < -SAFE_EPSILON)
+ return false;
+ }
+ else
+ {
+ polyDecomposition(k0, k1, k2, k3, j0, j1, j2, u0, u1, v0, v1);
+ if (!signDetermination1Internal(k0, k1, k2, k3, u0, u1, v0, v1))
+ return false;
+ }
+ // p3
+ getJs(k0, k1, k2, k3, face->m_n[2], face->m_n[0], face->m_n[1], node, dt, j0, j1, j2);
+ if (nearZero(j0 + j2 - j1 * 2.0))
+ {
+ btScalar lt0, lt1;
+ getSigns(true, k0, k1, k2, k3, j0, j2, lt0, lt1);
+ if (lt0 < -SAFE_EPSILON)
+ return false;
+ }
+ else
+ {
+ polyDecomposition(k0, k1, k2, k3, j0, j1, j2, u0, u1, v0, v1);
+ if (!signDetermination1Internal(k0, k1, k2, k3, u0, u1, v0, v1))
+ return false;
+ }
+ return true;
}
static SIMD_FORCE_INLINE bool signDetermination2(const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3, const btSoftBody::Face* face, const btSoftBody::Node* node, const btScalar& dt)
{
- btScalar j0, j1, j2, u0, u1, v0, v1;
- // p1
- getJs(k0,k1,k2,k3,face->m_n[0], face->m_n[1], face->m_n[2], node, dt, j0, j1, j2);
- if (nearZero(j0+j2-j1*2.0))
- {
- btScalar lt0, lt1;
- bool bt0 = true, bt1=true;
- getSigns(false, k0, k1, k2, k3, j0, j2, lt0, lt1);
- if (lt0 < -SAFE_EPSILON)
- bt0 = false;
- if (lt1 < -SAFE_EPSILON)
- bt1 = false;
- if (!bt0 && !bt1)
- return false;
- }
- else
- {
- polyDecomposition(k0,k1,k2,k3,j0,j1,j2,u0,u1,v0,v1);
- if (!signDetermination2Internal(k0,k1,k2,k3,j0,j1,j2,u0,u1,v0,v1))
- return false;
- }
- // p2
- getJs(k0,k1,k2,k3,face->m_n[1], face->m_n[2], face->m_n[0], node, dt, j0, j1, j2);
- if (nearZero(j0+j2-j1*2.0))
- {
- btScalar lt0, lt1;
- bool bt0=true, bt1=true;
- getSigns(false, k0, k1, k2, k3, j0, j2, lt0, lt1);
- if (lt0 < -SAFE_EPSILON)
- bt0 = false;
- if (lt1 < -SAFE_EPSILON)
- bt1 = false;
- if (!bt0 && !bt1)
- return false;
- }
- else
- {
- polyDecomposition(k0,k1,k2,k3,j0,j1,j2,u0,u1,v0,v1);
- if (!signDetermination2Internal(k0,k1,k2,k3,j0,j1,j2,u0,u1,v0,v1))
- return false;
- }
- // p3
- getJs(k0,k1,k2,k3,face->m_n[2], face->m_n[0], face->m_n[1], node, dt, j0, j1, j2);
- if (nearZero(j0+j2-j1*2.0))
- {
- btScalar lt0, lt1;
- bool bt0=true, bt1=true;
- getSigns(false, k0, k1, k2, k3, j0, j2, lt0, lt1);
- if (lt0 < -SAFE_EPSILON)
- bt0 = false;
- if (lt1 < -SAFE_EPSILON)
- bt1 = false;
- if (!bt0 && !bt1)
- return false;
- }
- else
- {
- polyDecomposition(k0,k1,k2,k3,j0,j1,j2,u0,u1,v0,v1);
- if (!signDetermination2Internal(k0,k1,k2,k3,j0,j1,j2,u0,u1,v0,v1))
- return false;
- }
- return true;
+ btScalar j0, j1, j2, u0, u1, v0, v1;
+ // p1
+ getJs(k0, k1, k2, k3, face->m_n[0], face->m_n[1], face->m_n[2], node, dt, j0, j1, j2);
+ if (nearZero(j0 + j2 - j1 * 2.0))
+ {
+ btScalar lt0, lt1;
+ bool bt0 = true, bt1 = true;
+ getSigns(false, k0, k1, k2, k3, j0, j2, lt0, lt1);
+ if (lt0 < -SAFE_EPSILON)
+ bt0 = false;
+ if (lt1 < -SAFE_EPSILON)
+ bt1 = false;
+ if (!bt0 && !bt1)
+ return false;
+ }
+ else
+ {
+ polyDecomposition(k0, k1, k2, k3, j0, j1, j2, u0, u1, v0, v1);
+ if (!signDetermination2Internal(k0, k1, k2, k3, j0, j1, j2, u0, u1, v0, v1))
+ return false;
+ }
+ // p2
+ getJs(k0, k1, k2, k3, face->m_n[1], face->m_n[2], face->m_n[0], node, dt, j0, j1, j2);
+ if (nearZero(j0 + j2 - j1 * 2.0))
+ {
+ btScalar lt0, lt1;
+ bool bt0 = true, bt1 = true;
+ getSigns(false, k0, k1, k2, k3, j0, j2, lt0, lt1);
+ if (lt0 < -SAFE_EPSILON)
+ bt0 = false;
+ if (lt1 < -SAFE_EPSILON)
+ bt1 = false;
+ if (!bt0 && !bt1)
+ return false;
+ }
+ else
+ {
+ polyDecomposition(k0, k1, k2, k3, j0, j1, j2, u0, u1, v0, v1);
+ if (!signDetermination2Internal(k0, k1, k2, k3, j0, j1, j2, u0, u1, v0, v1))
+ return false;
+ }
+ // p3
+ getJs(k0, k1, k2, k3, face->m_n[2], face->m_n[0], face->m_n[1], node, dt, j0, j1, j2);
+ if (nearZero(j0 + j2 - j1 * 2.0))
+ {
+ btScalar lt0, lt1;
+ bool bt0 = true, bt1 = true;
+ getSigns(false, k0, k1, k2, k3, j0, j2, lt0, lt1);
+ if (lt0 < -SAFE_EPSILON)
+ bt0 = false;
+ if (lt1 < -SAFE_EPSILON)
+ bt1 = false;
+ if (!bt0 && !bt1)
+ return false;
+ }
+ else
+ {
+ polyDecomposition(k0, k1, k2, k3, j0, j1, j2, u0, u1, v0, v1);
+ if (!signDetermination2Internal(k0, k1, k2, k3, j0, j1, j2, u0, u1, v0, v1))
+ return false;
+ }
+ return true;
}
static SIMD_FORCE_INLINE bool coplanarAndInsideTest(const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3, const btSoftBody::Face* face, const btSoftBody::Node* node, const btScalar& dt)
{
- // Coplanar test
- if (diffSign(k1-k0, k3-k2))
- {
- // Case b:
- if (sameSign(k0, k3) && !rootFindingLemma(k0,k1,k2,k3))
- return false;
- // inside test
- return signDetermination2(k0, k1, k2, k3, face, node, dt);
- }
- else
- {
- // Case c:
- if (sameSign(k0, k3))
- return false;
- // inside test
- return signDetermination1(k0, k1, k2, k3, face, node, dt);
- }
- return false;
+ // Coplanar test
+ if (diffSign(k1 - k0, k3 - k2))
+ {
+ // Case b:
+ if (sameSign(k0, k3) && !rootFindingLemma(k0, k1, k2, k3))
+ return false;
+ // inside test
+ return signDetermination2(k0, k1, k2, k3, face, node, dt);
+ }
+ else
+ {
+ // Case c:
+ if (sameSign(k0, k3))
+ return false;
+ // inside test
+ return signDetermination1(k0, k1, k2, k3, face, node, dt);
+ }
+ return false;
}
static SIMD_FORCE_INLINE bool conservativeCulling(const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3, const btScalar& mrg)
{
- if (k0 > mrg && k1 > mrg && k2 > mrg && k3 > mrg)
- return true;
- if (k0 < -mrg && k1 < -mrg && k2 < -mrg && k3 < -mrg)
- return true;
- return false;
+ if (k0 > mrg && k1 > mrg && k2 > mrg && k3 > mrg)
+ return true;
+ if (k0 < -mrg && k1 < -mrg && k2 < -mrg && k3 < -mrg)
+ return true;
+ return false;
}
static SIMD_FORCE_INLINE bool bernsteinVFTest(const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3, const btScalar& mrg, const btSoftBody::Face* face, const btSoftBody::Node* node, const btScalar& dt)
{
- if (conservativeCulling(k0, k1, k2, k3, mrg))
- return false;
- return coplanarAndInsideTest(k0, k1, k2, k3, face, node, dt);
+ if (conservativeCulling(k0, k1, k2, k3, mrg))
+ return false;
+ return coplanarAndInsideTest(k0, k1, k2, k3, face, node, dt);
}
static SIMD_FORCE_INLINE void deCasteljau(const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3, const btScalar& t0, btScalar& k10, btScalar& k20, btScalar& k30, btScalar& k21, btScalar& k12)
{
- k10 = k0*(1.0-t0) + k1*t0;
- btScalar k11 = k1*(1.0-t0) + k2*t0;
- k12 = k2*(1.0-t0) + k3*t0;
- k20 = k10*(1.0-t0) + k11*t0;
- k21 = k11*(1.0-t0) + k12*t0;
- k30 = k20*(1.0-t0) + k21*t0;
+ k10 = k0 * (1.0 - t0) + k1 * t0;
+ btScalar k11 = k1 * (1.0 - t0) + k2 * t0;
+ k12 = k2 * (1.0 - t0) + k3 * t0;
+ k20 = k10 * (1.0 - t0) + k11 * t0;
+ k21 = k11 * (1.0 - t0) + k12 * t0;
+ k30 = k20 * (1.0 - t0) + k21 * t0;
}
static SIMD_FORCE_INLINE bool bernsteinVFTest(const btSoftBody::Face* face, const btSoftBody::Node* node, const btScalar& dt, const btScalar& mrg)
{
- btScalar k0, k1, k2, k3;
- getBernsteinCoeff(face, node, dt, k0, k1, k2, k3);
- if (conservativeCulling(k0, k1, k2, k3, mrg))
- return false;
- return true;
- if (diffSign(k2-2.0*k1+k0, k3-2.0*k2+k1))
- {
- btScalar k10, k20, k30, k21, k12;
- btScalar t0 = (k2-2.0*k1+k0)/(k0-3.0*k1+3.0*k2-k3);
- deCasteljau(k0, k1, k2, k3, t0, k10, k20, k30, k21, k12);
- return bernsteinVFTest(k0, k10, k20, k30, mrg, face, node, dt) || bernsteinVFTest(k30, k21, k12, k3, mrg, face, node, dt);
- }
- return coplanarAndInsideTest(k0, k1, k2, k3, face, node, dt);
+ btScalar k0, k1, k2, k3;
+ getBernsteinCoeff(face, node, dt, k0, k1, k2, k3);
+ if (conservativeCulling(k0, k1, k2, k3, mrg))
+ return false;
+ return true;
+ if (diffSign(k2 - 2.0 * k1 + k0, k3 - 2.0 * k2 + k1))
+ {
+ btScalar k10, k20, k30, k21, k12;
+ btScalar t0 = (k2 - 2.0 * k1 + k0) / (k0 - 3.0 * k1 + 3.0 * k2 - k3);
+ deCasteljau(k0, k1, k2, k3, t0, k10, k20, k30, k21, k12);
+ return bernsteinVFTest(k0, k10, k20, k30, mrg, face, node, dt) || bernsteinVFTest(k30, k21, k12, k3, mrg, face, node, dt);
+ }
+ return coplanarAndInsideTest(k0, k1, k2, k3, face, node, dt);
}
static SIMD_FORCE_INLINE bool continuousCollisionDetection(const btSoftBody::Face* face, const btSoftBody::Node* node, const btScalar& dt, const btScalar& mrg, btVector3& bary)
{
- if (hasSeparatingPlane(face, node, dt))
- return false;
- btVector3 x21 = face->m_n[1]->m_x - face->m_n[0]->m_x;
- btVector3 x31 = face->m_n[2]->m_x - face->m_n[0]->m_x;
- btVector3 x41 = node->m_x - face->m_n[0]->m_x;
- btVector3 v21 = face->m_n[1]->m_v - face->m_n[0]->m_v;
- btVector3 v31 = face->m_n[2]->m_v - face->m_n[0]->m_v;
- btVector3 v41 = node->m_v - face->m_n[0]->m_v;
- btVector3 a = x21.cross(x31);
- btVector3 b = x21.cross(v31) + v21.cross(x31);
- btVector3 c = v21.cross(v31);
- btVector3 d = x41;
- btVector3 e = v41;
- btScalar a0 = a.dot(d);
- btScalar a1 = a.dot(e) + b.dot(d);
- btScalar a2 = c.dot(d) + b.dot(e);
- btScalar a3 = c.dot(e);
- btScalar eps = SAFE_EPSILON;
- int num_roots = 0;
- btScalar roots[3];
- if (std::abs(a3) < eps)
- {
- // cubic term is zero
- if (std::abs(a2) < eps)
- {
- if (std::abs(a1) < eps)
- {
- if (std::abs(a0) < eps)
- {
- num_roots = 2;
- roots[0] = 0;
- roots[1] = dt;
- }
- }
- else
- {
- num_roots = 1;
- roots[0] = -a0/a1;
- }
- }
- else
- {
- num_roots = SolveP2(roots, a1/a2, a0/a2);
- }
- }
- else
- {
- num_roots = SolveP3(roots, a2/a3, a1/a3, a0/a3);
- }
-// std::sort(roots, roots+num_roots);
- if (num_roots > 1)
- {
- if (roots[0] > roots[1])
- btSwap(roots[0], roots[1]);
- }
- if (num_roots > 2)
- {
- if (roots[0] > roots[2])
- btSwap(roots[0], roots[2]);
- if (roots[1] > roots[2])
- btSwap(roots[1], roots[2]);
- }
- for (int r = 0; r < num_roots; ++r)
- {
- double root = roots[r];
- if (root <= 0)
- continue;
- if (root > dt + SIMD_EPSILON)
- return false;
- btVector3 x1 = face->m_n[0]->m_x + root * face->m_n[0]->m_v;
- btVector3 x2 = face->m_n[1]->m_x + root * face->m_n[1]->m_v;
- btVector3 x3 = face->m_n[2]->m_x + root * face->m_n[2]->m_v;
- btVector3 x4 = node->m_x + root * node->m_v;
- btVector3 normal = (x2-x1).cross(x3-x1);
- normal.safeNormalize();
- if (proximityTest(x1, x2, x3, x4, normal, mrg, bary))
- return true;
- }
- return false;
+ if (hasSeparatingPlane(face, node, dt))
+ return false;
+ btVector3 x21 = face->m_n[1]->m_x - face->m_n[0]->m_x;
+ btVector3 x31 = face->m_n[2]->m_x - face->m_n[0]->m_x;
+ btVector3 x41 = node->m_x - face->m_n[0]->m_x;
+ btVector3 v21 = face->m_n[1]->m_v - face->m_n[0]->m_v;
+ btVector3 v31 = face->m_n[2]->m_v - face->m_n[0]->m_v;
+ btVector3 v41 = node->m_v - face->m_n[0]->m_v;
+ btVector3 a = x21.cross(x31);
+ btVector3 b = x21.cross(v31) + v21.cross(x31);
+ btVector3 c = v21.cross(v31);
+ btVector3 d = x41;
+ btVector3 e = v41;
+ btScalar a0 = a.dot(d);
+ btScalar a1 = a.dot(e) + b.dot(d);
+ btScalar a2 = c.dot(d) + b.dot(e);
+ btScalar a3 = c.dot(e);
+ btScalar eps = SAFE_EPSILON;
+ int num_roots = 0;
+ btScalar roots[3];
+ if (std::abs(a3) < eps)
+ {
+ // cubic term is zero
+ if (std::abs(a2) < eps)
+ {
+ if (std::abs(a1) < eps)
+ {
+ if (std::abs(a0) < eps)
+ {
+ num_roots = 2;
+ roots[0] = 0;
+ roots[1] = dt;
+ }
+ }
+ else
+ {
+ num_roots = 1;
+ roots[0] = -a0 / a1;
+ }
+ }
+ else
+ {
+ num_roots = SolveP2(roots, a1 / a2, a0 / a2);
+ }
+ }
+ else
+ {
+ num_roots = SolveP3(roots, a2 / a3, a1 / a3, a0 / a3);
+ }
+ // std::sort(roots, roots+num_roots);
+ if (num_roots > 1)
+ {
+ if (roots[0] > roots[1])
+ btSwap(roots[0], roots[1]);
+ }
+ if (num_roots > 2)
+ {
+ if (roots[0] > roots[2])
+ btSwap(roots[0], roots[2]);
+ if (roots[1] > roots[2])
+ btSwap(roots[1], roots[2]);
+ }
+ for (int r = 0; r < num_roots; ++r)
+ {
+ double root = roots[r];
+ if (root <= 0)
+ continue;
+ if (root > dt + SIMD_EPSILON)
+ return false;
+ btVector3 x1 = face->m_n[0]->m_x + root * face->m_n[0]->m_v;
+ btVector3 x2 = face->m_n[1]->m_x + root * face->m_n[1]->m_v;
+ btVector3 x3 = face->m_n[2]->m_x + root * face->m_n[2]->m_v;
+ btVector3 x4 = node->m_x + root * node->m_v;
+ btVector3 normal = (x2 - x1).cross(x3 - x1);
+ normal.safeNormalize();
+ if (proximityTest(x1, x2, x3, x4, normal, mrg, bary))
+ return true;
+ }
+ return false;
}
static SIMD_FORCE_INLINE bool bernsteinCCD(const btSoftBody::Face* face, const btSoftBody::Node* node, const btScalar& dt, const btScalar& mrg, btVector3& bary)
{
- if (!bernsteinVFTest(face, node, dt, mrg))
- return false;
- if (!continuousCollisionDetection(face, node, dt, 1e-6, bary))
- return false;
- return true;
+ if (!bernsteinVFTest(face, node, dt, mrg))
+ return false;
+ if (!continuousCollisionDetection(face, node, dt, 1e-6, bary))
+ return false;
+ return true;
}
//
@@ -902,62 +906,61 @@ static inline btMatrix3x3 Diagonal(btScalar x)
static inline btMatrix3x3 Diagonal(const btVector3& v)
{
- btMatrix3x3 m;
- m[0] = btVector3(v.getX(), 0, 0);
- m[1] = btVector3(0, v.getY(), 0);
- m[2] = btVector3(0, 0, v.getZ());
- return (m);
-}
-
-static inline btScalar Dot(const btScalar* a,const btScalar* b, int ndof)
-{
- btScalar result = 0;
- for (int i = 0; i < ndof; ++i)
- result += a[i] * b[i];
- return result;
-}
-
-static inline btMatrix3x3 OuterProduct(const btScalar* v1,const btScalar* v2,const btScalar* v3,
- const btScalar* u1, const btScalar* u2, const btScalar* u3, int ndof)
-{
- btMatrix3x3 m;
- btScalar a11 = Dot(v1,u1,ndof);
- btScalar a12 = Dot(v1,u2,ndof);
- btScalar a13 = Dot(v1,u3,ndof);
-
- btScalar a21 = Dot(v2,u1,ndof);
- btScalar a22 = Dot(v2,u2,ndof);
- btScalar a23 = Dot(v2,u3,ndof);
-
- btScalar a31 = Dot(v3,u1,ndof);
- btScalar a32 = Dot(v3,u2,ndof);
- btScalar a33 = Dot(v3,u3,ndof);
- m[0] = btVector3(a11, a12, a13);
- m[1] = btVector3(a21, a22, a23);
- m[2] = btVector3(a31, a32, a33);
- return (m);
-}
-
-static inline btMatrix3x3 OuterProduct(const btVector3& v1,const btVector3& v2)
-{
- btMatrix3x3 m;
- btScalar a11 = v1[0] * v2[0];
- btScalar a12 = v1[0] * v2[1];
- btScalar a13 = v1[0] * v2[2];
-
- btScalar a21 = v1[1] * v2[0];
- btScalar a22 = v1[1] * v2[1];
- btScalar a23 = v1[1] * v2[2];
-
- btScalar a31 = v1[2] * v2[0];
- btScalar a32 = v1[2] * v2[1];
- btScalar a33 = v1[2] * v2[2];
- m[0] = btVector3(a11, a12, a13);
- m[1] = btVector3(a21, a22, a23);
- m[2] = btVector3(a31, a32, a33);
- return (m);
+ btMatrix3x3 m;
+ m[0] = btVector3(v.getX(), 0, 0);
+ m[1] = btVector3(0, v.getY(), 0);
+ m[2] = btVector3(0, 0, v.getZ());
+ return (m);
+}
+
+static inline btScalar Dot(const btScalar* a, const btScalar* b, int ndof)
+{
+ btScalar result = 0;
+ for (int i = 0; i < ndof; ++i)
+ result += a[i] * b[i];
+ return result;
}
+static inline btMatrix3x3 OuterProduct(const btScalar* v1, const btScalar* v2, const btScalar* v3,
+ const btScalar* u1, const btScalar* u2, const btScalar* u3, int ndof)
+{
+ btMatrix3x3 m;
+ btScalar a11 = Dot(v1, u1, ndof);
+ btScalar a12 = Dot(v1, u2, ndof);
+ btScalar a13 = Dot(v1, u3, ndof);
+
+ btScalar a21 = Dot(v2, u1, ndof);
+ btScalar a22 = Dot(v2, u2, ndof);
+ btScalar a23 = Dot(v2, u3, ndof);
+
+ btScalar a31 = Dot(v3, u1, ndof);
+ btScalar a32 = Dot(v3, u2, ndof);
+ btScalar a33 = Dot(v3, u3, ndof);
+ m[0] = btVector3(a11, a12, a13);
+ m[1] = btVector3(a21, a22, a23);
+ m[2] = btVector3(a31, a32, a33);
+ return (m);
+}
+
+static inline btMatrix3x3 OuterProduct(const btVector3& v1, const btVector3& v2)
+{
+ btMatrix3x3 m;
+ btScalar a11 = v1[0] * v2[0];
+ btScalar a12 = v1[0] * v2[1];
+ btScalar a13 = v1[0] * v2[2];
+
+ btScalar a21 = v1[1] * v2[0];
+ btScalar a22 = v1[1] * v2[1];
+ btScalar a23 = v1[1] * v2[2];
+
+ btScalar a31 = v1[2] * v2[0];
+ btScalar a32 = v1[2] * v2[1];
+ btScalar a33 = v1[2] * v2[2];
+ m[0] = btVector3(a11, a12, a13);
+ m[1] = btVector3(a21, a22, a23);
+ m[2] = btVector3(a31, a32, a33);
+ return (m);
+}
//
static inline btMatrix3x3 Add(const btMatrix3x3& a,
@@ -1008,6 +1011,20 @@ static inline btMatrix3x3 ImpulseMatrix(btScalar dt,
}
//
+static inline btMatrix3x3 ImpulseMatrix(btScalar dt,
+ const btMatrix3x3& effective_mass_inv,
+ btScalar imb,
+ const btMatrix3x3& iwi,
+ const btVector3& r)
+{
+ return (Diagonal(1 / dt) * Add(effective_mass_inv, MassMatrix(imb, iwi, r)).inverse());
+ // btMatrix3x3 iimb = MassMatrix(imb, iwi, r);
+ // if (iimb.determinant() == 0)
+ // return effective_mass_inv.inverse();
+ // return effective_mass_inv.inverse() * Add(effective_mass_inv.inverse(), iimb.inverse()).inverse() * iimb.inverse();
+}
+
+//
static inline btMatrix3x3 ImpulseMatrix(btScalar ima, const btMatrix3x3& iia, const btVector3& ra,
btScalar imb, const btMatrix3x3& iib, const btVector3& rb)
{
@@ -1091,73 +1108,70 @@ static inline void ProjectOrigin(const btVector3& a,
//
static inline bool rayIntersectsTriangle(const btVector3& origin, const btVector3& dir, const btVector3& v0, const btVector3& v1, const btVector3& v2, btScalar& t)
{
- btScalar a, f, u, v;
-
- btVector3 e1 = v1 - v0;
- btVector3 e2 = v2 - v0;
- btVector3 h = dir.cross(e2);
- a = e1.dot(h);
-
- if (a > -0.00001 && a < 0.00001)
- return (false);
-
- f = btScalar(1) / a;
- btVector3 s = origin - v0;
- u = f * s.dot(h);
-
- if (u < 0.0 || u > 1.0)
- return (false);
-
- btVector3 q = s.cross(e1);
- v = f * dir.dot(q);
- if (v < 0.0 || u + v > 1.0)
- return (false);
- // at this stage we can compute t to find out where
- // the intersection point is on the line
- t = f * e2.dot(q);
- if (t > 0) // ray intersection
- return (true);
- else // this means that there is a line intersection
- // but not a ray intersection
- return (false);
+ btScalar a, f, u, v;
+
+ btVector3 e1 = v1 - v0;
+ btVector3 e2 = v2 - v0;
+ btVector3 h = dir.cross(e2);
+ a = e1.dot(h);
+
+ if (a > -0.00001 && a < 0.00001)
+ return (false);
+
+ f = btScalar(1) / a;
+ btVector3 s = origin - v0;
+ u = f * s.dot(h);
+
+ if (u < 0.0 || u > 1.0)
+ return (false);
+
+ btVector3 q = s.cross(e1);
+ v = f * dir.dot(q);
+ if (v < 0.0 || u + v > 1.0)
+ return (false);
+ // at this stage we can compute t to find out where
+ // the intersection point is on the line
+ t = f * e2.dot(q);
+ if (t > 0) // ray intersection
+ return (true);
+ else // this means that there is a line intersection
+ // but not a ray intersection
+ return (false);
}
static inline bool lineIntersectsTriangle(const btVector3& rayStart, const btVector3& rayEnd, const btVector3& p1, const btVector3& p2, const btVector3& p3, btVector3& sect, btVector3& normal)
{
- btVector3 dir = rayEnd - rayStart;
- btScalar dir_norm = dir.norm();
- if (dir_norm < SIMD_EPSILON)
- return false;
- dir.normalize();
-
- btScalar t;
-
- bool ret = rayIntersectsTriangle(rayStart, dir, p1, p2, p3, t);
-
- if (ret)
- {
- if (t <= dir_norm)
- {
- sect = rayStart + dir * t;
- }
- else
- {
- ret = false;
- }
- }
-
- if (ret)
- {
- btVector3 n = (p3-p1).cross(p2-p1);
- n.safeNormalize();
- if (n.dot(dir) < 0)
- normal = n;
- else
- normal = -n;
- }
- return ret;
-}
+ btVector3 dir = rayEnd - rayStart;
+ btScalar dir_norm = dir.norm();
+ if (dir_norm < SIMD_EPSILON)
+ return false;
+ dir.normalize();
+ btScalar t;
+ bool ret = rayIntersectsTriangle(rayStart, dir, p1, p2, p3, t);
+
+ if (ret)
+ {
+ if (t <= dir_norm)
+ {
+ sect = rayStart + dir * t;
+ }
+ else
+ {
+ ret = false;
+ }
+ }
+ if (ret)
+ {
+ btVector3 n = (p3 - p1).cross(p2 - p1);
+ n.safeNormalize();
+ if (n.dot(dir) < 0)
+ normal = n;
+ else
+ normal = -n;
+ }
+ return ret;
+}
//
template <typename T>
@@ -1586,57 +1600,57 @@ struct btSoftColliders
psa->m_cdbvt.collideTT(psa->m_cdbvt.m_root, psb->m_cdbvt.m_root, *this);
}
};
- //
- // CollideSDF_RS
- //
- struct CollideSDF_RS : btDbvt::ICollide
- {
- void Process(const btDbvtNode* leaf)
- {
- btSoftBody::Node* node = (btSoftBody::Node*)leaf->data;
- DoNode(*node);
- }
- void DoNode(btSoftBody::Node& n) const
- {
- const btScalar m = n.m_im > 0 ? dynmargin : stamargin;
- btSoftBody::RContact c;
-
- if ((!n.m_battach) &&
- psb->checkContact(m_colObj1Wrap, n.m_x, m, c.m_cti))
- {
- const btScalar ima = n.m_im;
- const btScalar imb = m_rigidBody ? m_rigidBody->getInvMass() : 0.f;
- const btScalar ms = ima + imb;
- if (ms > 0)
- {
- const btTransform& wtr = m_rigidBody ? m_rigidBody->getWorldTransform() : m_colObj1Wrap->getCollisionObject()->getWorldTransform();
- static const btMatrix3x3 iwiStatic(0, 0, 0, 0, 0, 0, 0, 0, 0);
- const btMatrix3x3& iwi = m_rigidBody ? m_rigidBody->getInvInertiaTensorWorld() : iwiStatic;
- const btVector3 ra = n.m_x - wtr.getOrigin();
- const btVector3 va = m_rigidBody ? m_rigidBody->getVelocityInLocalPoint(ra) * psb->m_sst.sdt : btVector3(0, 0, 0);
- const btVector3 vb = n.m_x - n.m_q;
- const btVector3 vr = vb - va;
- const btScalar dn = btDot(vr, c.m_cti.m_normal);
- const btVector3 fv = vr - c.m_cti.m_normal * dn;
- const btScalar fc = psb->m_cfg.kDF * m_colObj1Wrap->getCollisionObject()->getFriction();
- c.m_node = &n;
- c.m_c0 = ImpulseMatrix(psb->m_sst.sdt, ima, imb, iwi, ra);
- c.m_c1 = ra;
- c.m_c2 = ima * psb->m_sst.sdt;
- c.m_c3 = fv.length2() < (dn * fc * dn * fc) ? 0 : 1 - fc;
- c.m_c4 = m_colObj1Wrap->getCollisionObject()->isStaticOrKinematicObject() ? psb->m_cfg.kKHR : psb->m_cfg.kCHR;
- psb->m_rcontacts.push_back(c);
- if (m_rigidBody)
- m_rigidBody->activate();
- }
- }
- }
- btSoftBody* psb;
- const btCollisionObjectWrapper* m_colObj1Wrap;
- btRigidBody* m_rigidBody;
- btScalar dynmargin;
- btScalar stamargin;
- };
+ //
+ // CollideSDF_RS
+ //
+ struct CollideSDF_RS : btDbvt::ICollide
+ {
+ void Process(const btDbvtNode* leaf)
+ {
+ btSoftBody::Node* node = (btSoftBody::Node*)leaf->data;
+ DoNode(*node);
+ }
+ void DoNode(btSoftBody::Node& n) const
+ {
+ const btScalar m = n.m_im > 0 ? dynmargin : stamargin;
+ btSoftBody::RContact c;
+
+ if ((!n.m_battach) &&
+ psb->checkContact(m_colObj1Wrap, n.m_x, m, c.m_cti))
+ {
+ const btScalar ima = n.m_im;
+ const btScalar imb = m_rigidBody ? m_rigidBody->getInvMass() : 0.f;
+ const btScalar ms = ima + imb;
+ if (ms > 0)
+ {
+ const btTransform& wtr = m_rigidBody ? m_rigidBody->getWorldTransform() : m_colObj1Wrap->getCollisionObject()->getWorldTransform();
+ static const btMatrix3x3 iwiStatic(0, 0, 0, 0, 0, 0, 0, 0, 0);
+ const btMatrix3x3& iwi = m_rigidBody ? m_rigidBody->getInvInertiaTensorWorld() : iwiStatic;
+ const btVector3 ra = n.m_x - wtr.getOrigin();
+ const btVector3 va = m_rigidBody ? m_rigidBody->getVelocityInLocalPoint(ra) * psb->m_sst.sdt : btVector3(0, 0, 0);
+ const btVector3 vb = n.m_x - n.m_q;
+ const btVector3 vr = vb - va;
+ const btScalar dn = btDot(vr, c.m_cti.m_normal);
+ const btVector3 fv = vr - c.m_cti.m_normal * dn;
+ const btScalar fc = psb->m_cfg.kDF * m_colObj1Wrap->getCollisionObject()->getFriction();
+ c.m_node = &n;
+ c.m_c0 = ImpulseMatrix(psb->m_sst.sdt, ima, imb, iwi, ra);
+ c.m_c1 = ra;
+ c.m_c2 = ima * psb->m_sst.sdt;
+ c.m_c3 = fv.length2() < (dn * fc * dn * fc) ? 0 : 1 - fc;
+ c.m_c4 = m_colObj1Wrap->getCollisionObject()->isStaticOrKinematicObject() ? psb->m_cfg.kKHR : psb->m_cfg.kCHR;
+ psb->m_rcontacts.push_back(c);
+ if (m_rigidBody)
+ m_rigidBody->activate();
+ }
+ }
+ }
+ btSoftBody* psb;
+ const btCollisionObjectWrapper* m_colObj1Wrap;
+ btRigidBody* m_rigidBody;
+ btScalar dynmargin;
+ btScalar stamargin;
+ };
//
// CollideSDF_RD
@@ -1654,72 +1668,74 @@ struct btSoftColliders
btSoftBody::DeformableNodeRigidContact c;
if (!n.m_battach)
- {
+ {
// check for collision at x_{n+1}^*
if (psb->checkDeformableContact(m_colObj1Wrap, n.m_q, m, c.m_cti, /*predict = */ true))
- {
- const btScalar ima = n.m_im;
- // todo: collision between multibody and fixed deformable node will be missed.
- const btScalar imb = m_rigidBody ? m_rigidBody->getInvMass() : 0.f;
- const btScalar ms = ima + imb;
- if (ms > 0)
- {
- // resolve contact at x_n
- psb->checkDeformableContact(m_colObj1Wrap, n.m_x, m, c.m_cti, /*predict = */ false);
- btSoftBody::sCti& cti = c.m_cti;
- c.m_node = &n;
- const btScalar fc = psb->m_cfg.kDF * m_colObj1Wrap->getCollisionObject()->getFriction();
- c.m_c2 = ima;
- c.m_c3 = fc;
- c.m_c4 = m_colObj1Wrap->getCollisionObject()->isStaticOrKinematicObject() ? psb->m_cfg.kKHR : psb->m_cfg.kCHR;
-
- if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
- {
- const btTransform& wtr = m_rigidBody ? m_rigidBody->getWorldTransform() : m_colObj1Wrap->getCollisionObject()->getWorldTransform();
- static const btMatrix3x3 iwiStatic(0, 0, 0, 0, 0, 0, 0, 0, 0);
- const btMatrix3x3& iwi = m_rigidBody ? m_rigidBody->getInvInertiaTensorWorld() : iwiStatic;
- const btVector3 ra = n.m_x - wtr.getOrigin();
-
- c.m_c0 = ImpulseMatrix(1, ima, imb, iwi, ra);
- c.m_c1 = ra;
- }
- else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
- {
- btMultiBodyLinkCollider* multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(cti.m_colObj);
- if (multibodyLinkCol)
- {
- btVector3 normal = cti.m_normal;
- btVector3 t1 = generateUnitOrthogonalVector(normal);
- btVector3 t2 = btCross(normal, t1);
- btMultiBodyJacobianData jacobianData_normal, jacobianData_t1, jacobianData_t2;
- findJacobian(multibodyLinkCol, jacobianData_normal, c.m_node->m_x, normal);
- findJacobian(multibodyLinkCol, jacobianData_t1, c.m_node->m_x, t1);
- findJacobian(multibodyLinkCol, jacobianData_t2, c.m_node->m_x, t2);
-
- btScalar* J_n = &jacobianData_normal.m_jacobians[0];
- btScalar* J_t1 = &jacobianData_t1.m_jacobians[0];
- btScalar* J_t2 = &jacobianData_t2.m_jacobians[0];
-
- btScalar* u_n = &jacobianData_normal.m_deltaVelocitiesUnitImpulse[0];
- btScalar* u_t1 = &jacobianData_t1.m_deltaVelocitiesUnitImpulse[0];
- btScalar* u_t2 = &jacobianData_t2.m_deltaVelocitiesUnitImpulse[0];
-
- btMatrix3x3 rot(normal.getX(), normal.getY(), normal.getZ(),
- t1.getX(), t1.getY(), t1.getZ(),
- t2.getX(), t2.getY(), t2.getZ()); // world frame to local frame
- const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6;
- btMatrix3x3 local_impulse_matrix = (Diagonal(n.m_im) + OuterProduct(J_n, J_t1, J_t2, u_n, u_t1, u_t2, ndof)).inverse();
- c.m_c0 = rot.transpose() * local_impulse_matrix * rot;
- c.jacobianData_normal = jacobianData_normal;
- c.jacobianData_t1 = jacobianData_t1;
- c.jacobianData_t2 = jacobianData_t2;
- c.t1 = t1;
- c.t2 = t2;
- }
- }
- psb->m_nodeRigidContacts.push_back(c);
- }
- }
+ {
+ const btScalar ima = n.m_im;
+ // todo: collision between multibody and fixed deformable node will be missed.
+ const btScalar imb = m_rigidBody ? m_rigidBody->getInvMass() : 0.f;
+ const btScalar ms = ima + imb;
+ if (ms > 0)
+ {
+ // resolve contact at x_n
+ psb->checkDeformableContact(m_colObj1Wrap, n.m_x, m, c.m_cti, /*predict = */ false);
+ btSoftBody::sCti& cti = c.m_cti;
+ c.m_node = &n;
+ const btScalar fc = psb->m_cfg.kDF * m_colObj1Wrap->getCollisionObject()->getFriction();
+ c.m_c2 = ima;
+ c.m_c3 = fc;
+ c.m_c4 = m_colObj1Wrap->getCollisionObject()->isStaticOrKinematicObject() ? psb->m_cfg.kKHR : psb->m_cfg.kCHR;
+ c.m_c5 = n.m_effectiveMass_inv;
+
+ if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
+ {
+ const btTransform& wtr = m_rigidBody ? m_rigidBody->getWorldTransform() : m_colObj1Wrap->getCollisionObject()->getWorldTransform();
+ static const btMatrix3x3 iwiStatic(0, 0, 0, 0, 0, 0, 0, 0, 0);
+ const btMatrix3x3& iwi = m_rigidBody ? m_rigidBody->getInvInertiaTensorWorld() : iwiStatic;
+ const btVector3 ra = n.m_x - wtr.getOrigin();
+
+ c.m_c0 = ImpulseMatrix(1, n.m_effectiveMass_inv, imb, iwi, ra);
+ // c.m_c0 = ImpulseMatrix(1, ima, imb, iwi, ra);
+ c.m_c1 = ra;
+ }
+ else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
+ {
+ btMultiBodyLinkCollider* multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(cti.m_colObj);
+ if (multibodyLinkCol)
+ {
+ btVector3 normal = cti.m_normal;
+ btVector3 t1 = generateUnitOrthogonalVector(normal);
+ btVector3 t2 = btCross(normal, t1);
+ btMultiBodyJacobianData jacobianData_normal, jacobianData_t1, jacobianData_t2;
+ findJacobian(multibodyLinkCol, jacobianData_normal, c.m_node->m_x, normal);
+ findJacobian(multibodyLinkCol, jacobianData_t1, c.m_node->m_x, t1);
+ findJacobian(multibodyLinkCol, jacobianData_t2, c.m_node->m_x, t2);
+
+ btScalar* J_n = &jacobianData_normal.m_jacobians[0];
+ btScalar* J_t1 = &jacobianData_t1.m_jacobians[0];
+ btScalar* J_t2 = &jacobianData_t2.m_jacobians[0];
+
+ btScalar* u_n = &jacobianData_normal.m_deltaVelocitiesUnitImpulse[0];
+ btScalar* u_t1 = &jacobianData_t1.m_deltaVelocitiesUnitImpulse[0];
+ btScalar* u_t2 = &jacobianData_t2.m_deltaVelocitiesUnitImpulse[0];
+
+ btMatrix3x3 rot(normal.getX(), normal.getY(), normal.getZ(),
+ t1.getX(), t1.getY(), t1.getZ(),
+ t2.getX(), t2.getY(), t2.getZ()); // world frame to local frame
+ const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6;
+ btMatrix3x3 local_impulse_matrix = (n.m_effectiveMass_inv + OuterProduct(J_n, J_t1, J_t2, u_n, u_t1, u_t2, ndof)).inverse();
+ c.m_c0 = rot.transpose() * local_impulse_matrix * rot;
+ c.jacobianData_normal = jacobianData_normal;
+ c.jacobianData_t1 = jacobianData_t1;
+ c.jacobianData_t2 = jacobianData_t2;
+ c.t1 = t1;
+ c.t2 = t2;
+ }
+ }
+ psb->m_nodeRigidContacts.push_back(c);
+ }
+ }
}
}
btSoftBody* psb;
@@ -1728,112 +1744,111 @@ struct btSoftColliders
btScalar dynmargin;
btScalar stamargin;
};
-
- //
- // CollideSDF_RDF
- //
- struct CollideSDF_RDF : btDbvt::ICollide
- {
- void Process(const btDbvtNode* leaf)
- {
- btSoftBody::Face* face = (btSoftBody::Face*)leaf->data;
- DoNode(*face);
- }
- void DoNode(btSoftBody::Face& f) const
- {
- btSoftBody::Node* n0 = f.m_n[0];
- btSoftBody::Node* n1 = f.m_n[1];
- btSoftBody::Node* n2 = f.m_n[2];
- const btScalar m = (n0->m_im > 0 && n1->m_im > 0 && n2->m_im > 0 )? dynmargin : stamargin;
- btSoftBody::DeformableFaceRigidContact c;
- btVector3 contact_point;
- btVector3 bary;
- if (psb->checkDeformableFaceContact(m_colObj1Wrap, f, contact_point, bary, m, c.m_cti, true))
- {
- f.m_pcontact[3] = 1;
- btScalar ima = n0->m_im + n1->m_im + n2->m_im;
- const btScalar imb = m_rigidBody ? m_rigidBody->getInvMass() : 0.f;
- // todo: collision between multibody and fixed deformable face will be missed.
- const btScalar ms = ima + imb;
- if (ms > 0)
- {
- // resolve contact at x_n
-// psb->checkDeformableFaceContact(m_colObj1Wrap, f, contact_point, bary, m, c.m_cti, /*predict = */ false);
- btSoftBody::sCti& cti = c.m_cti;
- c.m_contactPoint = contact_point;
- c.m_bary = bary;
- // todo xuchenhan@: this is assuming mass of all vertices are the same. Need to modify if mass are different for distinct vertices
- c.m_weights = btScalar(2)/(btScalar(1) + bary.length2()) * bary;
- c.m_face = &f;
+
+ //
+ // CollideSDF_RDF
+ //
+ struct CollideSDF_RDF : btDbvt::ICollide
+ {
+ void Process(const btDbvtNode* leaf)
+ {
+ btSoftBody::Face* face = (btSoftBody::Face*)leaf->data;
+ DoNode(*face);
+ }
+ void DoNode(btSoftBody::Face& f) const
+ {
+ btSoftBody::Node* n0 = f.m_n[0];
+ btSoftBody::Node* n1 = f.m_n[1];
+ btSoftBody::Node* n2 = f.m_n[2];
+ const btScalar m = (n0->m_im > 0 && n1->m_im > 0 && n2->m_im > 0) ? dynmargin : stamargin;
+ btSoftBody::DeformableFaceRigidContact c;
+ btVector3 contact_point;
+ btVector3 bary;
+ if (psb->checkDeformableFaceContact(m_colObj1Wrap, f, contact_point, bary, m, c.m_cti, true))
+ {
+ btScalar ima = n0->m_im + n1->m_im + n2->m_im;
+ const btScalar imb = m_rigidBody ? m_rigidBody->getInvMass() : 0.f;
+ // todo: collision between multibody and fixed deformable face will be missed.
+ const btScalar ms = ima + imb;
+ if (ms > 0)
+ {
+ // resolve contact at x_n
+ // psb->checkDeformableFaceContact(m_colObj1Wrap, f, contact_point, bary, m, c.m_cti, /*predict = */ false);
+ btSoftBody::sCti& cti = c.m_cti;
+ c.m_contactPoint = contact_point;
+ c.m_bary = bary;
+ // todo xuchenhan@: this is assuming mass of all vertices are the same. Need to modify if mass are different for distinct vertices
+ c.m_weights = btScalar(2) / (btScalar(1) + bary.length2()) * bary;
+ c.m_face = &f;
// friction is handled by the nodes to prevent sticking
-// const btScalar fc = 0;
- const btScalar fc = psb->m_cfg.kDF * m_colObj1Wrap->getCollisionObject()->getFriction();
-
- // the effective inverse mass of the face as in https://graphics.stanford.edu/papers/cloth-sig02/cloth.pdf
- ima = bary.getX()*c.m_weights.getX() * n0->m_im + bary.getY()*c.m_weights.getY() * n1->m_im + bary.getZ()*c.m_weights.getZ() * n2->m_im;
- c.m_c2 = ima;
- c.m_c3 = fc;
- c.m_c4 = m_colObj1Wrap->getCollisionObject()->isStaticOrKinematicObject() ? psb->m_cfg.kKHR : psb->m_cfg.kCHR;
- if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
- {
- const btTransform& wtr = m_rigidBody ? m_rigidBody->getWorldTransform() : m_colObj1Wrap->getCollisionObject()->getWorldTransform();
- static const btMatrix3x3 iwiStatic(0, 0, 0, 0, 0, 0, 0, 0, 0);
- const btMatrix3x3& iwi = m_rigidBody ? m_rigidBody->getInvInertiaTensorWorld() : iwiStatic;
- const btVector3 ra = contact_point - wtr.getOrigin();
-
- // we do not scale the impulse matrix by dt
- c.m_c0 = ImpulseMatrix(1, ima, imb, iwi, ra);
- c.m_c1 = ra;
- }
- else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
- {
- btMultiBodyLinkCollider* multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(cti.m_colObj);
- if (multibodyLinkCol)
- {
- btVector3 normal = cti.m_normal;
- btVector3 t1 = generateUnitOrthogonalVector(normal);
- btVector3 t2 = btCross(normal, t1);
- btMultiBodyJacobianData jacobianData_normal, jacobianData_t1, jacobianData_t2;
- findJacobian(multibodyLinkCol, jacobianData_normal, contact_point, normal);
- findJacobian(multibodyLinkCol, jacobianData_t1, contact_point, t1);
- findJacobian(multibodyLinkCol, jacobianData_t2, contact_point, t2);
-
- btScalar* J_n = &jacobianData_normal.m_jacobians[0];
- btScalar* J_t1 = &jacobianData_t1.m_jacobians[0];
- btScalar* J_t2 = &jacobianData_t2.m_jacobians[0];
-
- btScalar* u_n = &jacobianData_normal.m_deltaVelocitiesUnitImpulse[0];
- btScalar* u_t1 = &jacobianData_t1.m_deltaVelocitiesUnitImpulse[0];
- btScalar* u_t2 = &jacobianData_t2.m_deltaVelocitiesUnitImpulse[0];
-
- btMatrix3x3 rot(normal.getX(), normal.getY(), normal.getZ(),
- t1.getX(), t1.getY(), t1.getZ(),
- t2.getX(), t2.getY(), t2.getZ()); // world frame to local frame
- const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6;
- btMatrix3x3 local_impulse_matrix = (Diagonal(ima) + OuterProduct(J_n, J_t1, J_t2, u_n, u_t1, u_t2, ndof)).inverse();
- c.m_c0 = rot.transpose() * local_impulse_matrix * rot;
- c.jacobianData_normal = jacobianData_normal;
- c.jacobianData_t1 = jacobianData_t1;
- c.jacobianData_t2 = jacobianData_t2;
- c.t1 = t1;
- c.t2 = t2;
- }
- }
- psb->m_faceRigidContacts.push_back(c);
- }
- }
- else
- {
- f.m_pcontact[3] = 0;
- }
- }
- btSoftBody* psb;
- const btCollisionObjectWrapper* m_colObj1Wrap;
- btRigidBody* m_rigidBody;
- btScalar dynmargin;
- btScalar stamargin;
- };
-
+ // const btScalar fc = 0;
+ const btScalar fc = psb->m_cfg.kDF * m_colObj1Wrap->getCollisionObject()->getFriction();
+
+ // the effective inverse mass of the face as in https://graphics.stanford.edu/papers/cloth-sig02/cloth.pdf
+ ima = bary.getX() * c.m_weights.getX() * n0->m_im + bary.getY() * c.m_weights.getY() * n1->m_im + bary.getZ() * c.m_weights.getZ() * n2->m_im;
+ c.m_c2 = ima;
+ c.m_c3 = fc;
+ c.m_c4 = m_colObj1Wrap->getCollisionObject()->isStaticOrKinematicObject() ? psb->m_cfg.kKHR : psb->m_cfg.kCHR;
+ c.m_c5 = Diagonal(ima);
+ if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
+ {
+ const btTransform& wtr = m_rigidBody ? m_rigidBody->getWorldTransform() : m_colObj1Wrap->getCollisionObject()->getWorldTransform();
+ static const btMatrix3x3 iwiStatic(0, 0, 0, 0, 0, 0, 0, 0, 0);
+ const btMatrix3x3& iwi = m_rigidBody ? m_rigidBody->getInvInertiaTensorWorld() : iwiStatic;
+ const btVector3 ra = contact_point - wtr.getOrigin();
+
+ // we do not scale the impulse matrix by dt
+ c.m_c0 = ImpulseMatrix(1, ima, imb, iwi, ra);
+ c.m_c1 = ra;
+ }
+ else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
+ {
+ btMultiBodyLinkCollider* multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(cti.m_colObj);
+ if (multibodyLinkCol)
+ {
+ btVector3 normal = cti.m_normal;
+ btVector3 t1 = generateUnitOrthogonalVector(normal);
+ btVector3 t2 = btCross(normal, t1);
+ btMultiBodyJacobianData jacobianData_normal, jacobianData_t1, jacobianData_t2;
+ findJacobian(multibodyLinkCol, jacobianData_normal, contact_point, normal);
+ findJacobian(multibodyLinkCol, jacobianData_t1, contact_point, t1);
+ findJacobian(multibodyLinkCol, jacobianData_t2, contact_point, t2);
+
+ btScalar* J_n = &jacobianData_normal.m_jacobians[0];
+ btScalar* J_t1 = &jacobianData_t1.m_jacobians[0];
+ btScalar* J_t2 = &jacobianData_t2.m_jacobians[0];
+
+ btScalar* u_n = &jacobianData_normal.m_deltaVelocitiesUnitImpulse[0];
+ btScalar* u_t1 = &jacobianData_t1.m_deltaVelocitiesUnitImpulse[0];
+ btScalar* u_t2 = &jacobianData_t2.m_deltaVelocitiesUnitImpulse[0];
+
+ btMatrix3x3 rot(normal.getX(), normal.getY(), normal.getZ(),
+ t1.getX(), t1.getY(), t1.getZ(),
+ t2.getX(), t2.getY(), t2.getZ()); // world frame to local frame
+ const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6;
+ btMatrix3x3 local_impulse_matrix = (Diagonal(ima) + OuterProduct(J_n, J_t1, J_t2, u_n, u_t1, u_t2, ndof)).inverse();
+ c.m_c0 = rot.transpose() * local_impulse_matrix * rot;
+ c.jacobianData_normal = jacobianData_normal;
+ c.jacobianData_t1 = jacobianData_t1;
+ c.jacobianData_t2 = jacobianData_t2;
+ c.t1 = t1;
+ c.t2 = t2;
+ }
+ }
+ psb->m_faceRigidContacts.push_back(c);
+ }
+ }
+ // Set caching barycenters to be false after collision detection.
+ // Only turn on when contact is static.
+ f.m_pcontact[3] = 0;
+ }
+ btSoftBody* psb;
+ const btCollisionObjectWrapper* m_colObj1Wrap;
+ btRigidBody* m_rigidBody;
+ btScalar dynmargin;
+ btScalar stamargin;
+ };
+
//
// CollideVF_SS
//
@@ -1844,12 +1859,12 @@ struct btSoftColliders
{
btSoftBody::Node* node = (btSoftBody::Node*)lnode->data;
btSoftBody::Face* face = (btSoftBody::Face*)lface->data;
- for (int i = 0; i < 3; ++i)
- {
- if (face->m_n[i] == node)
- continue;
- }
-
+ for (int i = 0; i < 3; ++i)
+ {
+ if (face->m_n[i] == node)
+ continue;
+ }
+
btVector3 o = node->m_x;
btVector3 p;
btScalar d = SIMD_INFINITY;
@@ -1879,7 +1894,7 @@ struct btSoftColliders
c.m_node = node;
c.m_face = face;
c.m_weights = w;
- c.m_friction = btMax (psb[0]->m_cfg.kDF, psb[1]->m_cfg.kDF);
+ c.m_friction = btMax(psb[0]->m_cfg.kDF, psb[1]->m_cfg.kDF);
c.m_cfm[0] = ma / ms * psb[0]->m_cfg.kSHR;
c.m_cfm[1] = mb / ms * psb[1]->m_cfg.kSHR;
psb[0]->m_scontacts.push_back(c);
@@ -1889,206 +1904,205 @@ struct btSoftColliders
btSoftBody* psb[2];
btScalar mrg;
};
-
-
- //
- // CollideVF_DD
- //
- struct CollideVF_DD : btDbvt::ICollide
- {
- void Process(const btDbvtNode* lnode,
- const btDbvtNode* lface)
- {
- btSoftBody::Node* node = (btSoftBody::Node*)lnode->data;
- btSoftBody::Face* face = (btSoftBody::Face*)lface->data;
- btVector3 bary;
- if (proximityTest(face->m_n[0]->m_x, face->m_n[1]->m_x, face->m_n[2]->m_x, node->m_x, face->m_normal, mrg, bary))
- {
- const btSoftBody::Node* n[] = {face->m_n[0], face->m_n[1], face->m_n[2]};
- const btVector3 w = bary;
- const btScalar ma = node->m_im;
- btScalar mb = BaryEval(n[0]->m_im, n[1]->m_im, n[2]->m_im, w);
- if ((n[0]->m_im <= 0) ||
- (n[1]->m_im <= 0) ||
- (n[2]->m_im <= 0))
- {
- mb = 0;
- }
- const btScalar ms = ma + mb;
- if (ms > 0)
- {
- btSoftBody::DeformableFaceNodeContact c;
- c.m_normal = face->m_normal;
- if (!useFaceNormal && c.m_normal.dot(node->m_x - face->m_n[2]->m_x) < 0)
- c.m_normal = -face->m_normal;
- c.m_margin = mrg;
- c.m_node = node;
- c.m_face = face;
- c.m_bary = w;
- c.m_friction = psb[0]->m_cfg.kDF * psb[1]->m_cfg.kDF;
- psb[0]->m_faceNodeContacts.push_back(c);
- }
- }
- }
- btSoftBody* psb[2];
- btScalar mrg;
- bool useFaceNormal;
- };
-
- //
- // CollideFF_DD
- //
- struct CollideFF_DD : btDbvt::ICollide
- {
- void Process(const btDbvntNode* lface1,
- const btDbvntNode* lface2)
- {
- btSoftBody::Face* f1 = (btSoftBody::Face*)lface1->data;
- btSoftBody::Face* f2 = (btSoftBody::Face*)lface2->data;
- if (f1 != f2)
- {
- Repel(f1, f2);
- Repel(f2, f1);
- }
- }
- void Repel(btSoftBody::Face* f1, btSoftBody::Face* f2)
- {
- //#define REPEL_NEIGHBOR 1
+
+ //
+ // CollideVF_DD
+ //
+ struct CollideVF_DD : btDbvt::ICollide
+ {
+ void Process(const btDbvtNode* lnode,
+ const btDbvtNode* lface)
+ {
+ btSoftBody::Node* node = (btSoftBody::Node*)lnode->data;
+ btSoftBody::Face* face = (btSoftBody::Face*)lface->data;
+ btVector3 bary;
+ if (proximityTest(face->m_n[0]->m_x, face->m_n[1]->m_x, face->m_n[2]->m_x, node->m_x, face->m_normal, mrg, bary))
+ {
+ const btSoftBody::Node* n[] = {face->m_n[0], face->m_n[1], face->m_n[2]};
+ const btVector3 w = bary;
+ const btScalar ma = node->m_im;
+ btScalar mb = BaryEval(n[0]->m_im, n[1]->m_im, n[2]->m_im, w);
+ if ((n[0]->m_im <= 0) ||
+ (n[1]->m_im <= 0) ||
+ (n[2]->m_im <= 0))
+ {
+ mb = 0;
+ }
+ const btScalar ms = ma + mb;
+ if (ms > 0)
+ {
+ btSoftBody::DeformableFaceNodeContact c;
+ c.m_normal = face->m_normal;
+ if (!useFaceNormal && c.m_normal.dot(node->m_x - face->m_n[2]->m_x) < 0)
+ c.m_normal = -face->m_normal;
+ c.m_margin = mrg;
+ c.m_node = node;
+ c.m_face = face;
+ c.m_bary = w;
+ c.m_friction = psb[0]->m_cfg.kDF * psb[1]->m_cfg.kDF;
+ psb[0]->m_faceNodeContacts.push_back(c);
+ }
+ }
+ }
+ btSoftBody* psb[2];
+ btScalar mrg;
+ bool useFaceNormal;
+ };
+
+ //
+ // CollideFF_DD
+ //
+ struct CollideFF_DD : btDbvt::ICollide
+ {
+ void Process(const btDbvntNode* lface1,
+ const btDbvntNode* lface2)
+ {
+ btSoftBody::Face* f1 = (btSoftBody::Face*)lface1->data;
+ btSoftBody::Face* f2 = (btSoftBody::Face*)lface2->data;
+ if (f1 != f2)
+ {
+ Repel(f1, f2);
+ Repel(f2, f1);
+ }
+ }
+ void Repel(btSoftBody::Face* f1, btSoftBody::Face* f2)
+ {
+ //#define REPEL_NEIGHBOR 1
#ifndef REPEL_NEIGHBOR
- for (int node_id = 0; node_id < 3; ++node_id)
- {
- btSoftBody::Node* node = f1->m_n[node_id];
- for (int i = 0; i < 3; ++i)
- {
- if (f2->m_n[i] == node)
- return;
- }
- }
+ for (int node_id = 0; node_id < 3; ++node_id)
+ {
+ btSoftBody::Node* node = f1->m_n[node_id];
+ for (int i = 0; i < 3; ++i)
+ {
+ if (f2->m_n[i] == node)
+ return;
+ }
+ }
#endif
- bool skip = false;
- for (int node_id = 0; node_id < 3; ++node_id)
- {
- btSoftBody::Node* node = f1->m_n[node_id];
+ bool skip = false;
+ for (int node_id = 0; node_id < 3; ++node_id)
+ {
+ btSoftBody::Node* node = f1->m_n[node_id];
#ifdef REPEL_NEIGHBOR
- for (int i = 0; i < 3; ++i)
- {
- if (f2->m_n[i] == node)
- {
- skip = true;
- break;
- }
- }
- if (skip)
- {
- skip = false;
- continue;
- }
+ for (int i = 0; i < 3; ++i)
+ {
+ if (f2->m_n[i] == node)
+ {
+ skip = true;
+ break;
+ }
+ }
+ if (skip)
+ {
+ skip = false;
+ continue;
+ }
#endif
- btSoftBody::Face* face = f2;
- btVector3 bary;
- if (!proximityTest(face->m_n[0]->m_x, face->m_n[1]->m_x, face->m_n[2]->m_x, node->m_x, face->m_normal, mrg, bary))
- continue;
- btSoftBody::DeformableFaceNodeContact c;
- c.m_normal = face->m_normal;
- if (!useFaceNormal && c.m_normal.dot(node->m_x - face->m_n[2]->m_x) < 0)
- c.m_normal = -face->m_normal;
- c.m_margin = mrg;
- c.m_node = node;
- c.m_face = face;
- c.m_bary = bary;
- c.m_friction = psb[0]->m_cfg.kDF * psb[1]->m_cfg.kDF;
- psb[0]->m_faceNodeContacts.push_back(c);
- }
- }
- btSoftBody* psb[2];
- btScalar mrg;
- bool useFaceNormal;
- };
-
- struct CollideCCD : btDbvt::ICollide
- {
- void Process(const btDbvtNode* lnode,
- const btDbvtNode* lface)
- {
- btSoftBody::Node* node = (btSoftBody::Node*)lnode->data;
- btSoftBody::Face* face = (btSoftBody::Face*)lface->data;
- btVector3 bary;
- if (bernsteinCCD(face, node, dt, SAFE_EPSILON, bary))
- {
- btSoftBody::DeformableFaceNodeContact c;
- c.m_normal = face->m_normal;
- if (!useFaceNormal && c.m_normal.dot(node->m_x - face->m_n[2]->m_x) < 0)
- c.m_normal = -face->m_normal;
- c.m_node = node;
- c.m_face = face;
- c.m_bary = bary;
- c.m_friction = psb[0]->m_cfg.kDF * psb[1]->m_cfg.kDF;
- psb[0]->m_faceNodeContacts.push_back(c);
- }
- }
- void Process(const btDbvntNode* lface1,
- const btDbvntNode* lface2)
- {
- btSoftBody::Face* f1 = (btSoftBody::Face*)lface1->data;
- btSoftBody::Face* f2 = (btSoftBody::Face*)lface2->data;
- if (f1 != f2)
- {
- Repel(f1, f2);
- Repel(f2, f1);
- }
- }
- void Repel(btSoftBody::Face* f1, btSoftBody::Face* f2)
- {
- //#define REPEL_NEIGHBOR 1
+ btSoftBody::Face* face = f2;
+ btVector3 bary;
+ if (!proximityTest(face->m_n[0]->m_x, face->m_n[1]->m_x, face->m_n[2]->m_x, node->m_x, face->m_normal, mrg, bary))
+ continue;
+ btSoftBody::DeformableFaceNodeContact c;
+ c.m_normal = face->m_normal;
+ if (!useFaceNormal && c.m_normal.dot(node->m_x - face->m_n[2]->m_x) < 0)
+ c.m_normal = -face->m_normal;
+ c.m_margin = mrg;
+ c.m_node = node;
+ c.m_face = face;
+ c.m_bary = bary;
+ c.m_friction = psb[0]->m_cfg.kDF * psb[1]->m_cfg.kDF;
+ psb[0]->m_faceNodeContacts.push_back(c);
+ }
+ }
+ btSoftBody* psb[2];
+ btScalar mrg;
+ bool useFaceNormal;
+ };
+
+ struct CollideCCD : btDbvt::ICollide
+ {
+ void Process(const btDbvtNode* lnode,
+ const btDbvtNode* lface)
+ {
+ btSoftBody::Node* node = (btSoftBody::Node*)lnode->data;
+ btSoftBody::Face* face = (btSoftBody::Face*)lface->data;
+ btVector3 bary;
+ if (bernsteinCCD(face, node, dt, SAFE_EPSILON, bary))
+ {
+ btSoftBody::DeformableFaceNodeContact c;
+ c.m_normal = face->m_normal;
+ if (!useFaceNormal && c.m_normal.dot(node->m_x - face->m_n[2]->m_x) < 0)
+ c.m_normal = -face->m_normal;
+ c.m_node = node;
+ c.m_face = face;
+ c.m_bary = bary;
+ c.m_friction = psb[0]->m_cfg.kDF * psb[1]->m_cfg.kDF;
+ psb[0]->m_faceNodeContacts.push_back(c);
+ }
+ }
+ void Process(const btDbvntNode* lface1,
+ const btDbvntNode* lface2)
+ {
+ btSoftBody::Face* f1 = (btSoftBody::Face*)lface1->data;
+ btSoftBody::Face* f2 = (btSoftBody::Face*)lface2->data;
+ if (f1 != f2)
+ {
+ Repel(f1, f2);
+ Repel(f2, f1);
+ }
+ }
+ void Repel(btSoftBody::Face* f1, btSoftBody::Face* f2)
+ {
+ //#define REPEL_NEIGHBOR 1
#ifndef REPEL_NEIGHBOR
- for (int node_id = 0; node_id < 3; ++node_id)
- {
- btSoftBody::Node* node = f1->m_n[node_id];
- for (int i = 0; i < 3; ++i)
- {
- if (f2->m_n[i] == node)
- return;
- }
- }
+ for (int node_id = 0; node_id < 3; ++node_id)
+ {
+ btSoftBody::Node* node = f1->m_n[node_id];
+ for (int i = 0; i < 3; ++i)
+ {
+ if (f2->m_n[i] == node)
+ return;
+ }
+ }
#endif
- bool skip = false;
- for (int node_id = 0; node_id < 3; ++node_id)
- {
- btSoftBody::Node* node = f1->m_n[node_id];
+ bool skip = false;
+ for (int node_id = 0; node_id < 3; ++node_id)
+ {
+ btSoftBody::Node* node = f1->m_n[node_id];
#ifdef REPEL_NEIGHBOR
- for (int i = 0; i < 3; ++i)
- {
- if (f2->m_n[i] == node)
- {
- skip = true;
- break;
- }
- }
- if (skip)
- {
- skip = false;
- continue;
- }
+ for (int i = 0; i < 3; ++i)
+ {
+ if (f2->m_n[i] == node)
+ {
+ skip = true;
+ break;
+ }
+ }
+ if (skip)
+ {
+ skip = false;
+ continue;
+ }
#endif
- btSoftBody::Face* face = f2;
- btVector3 bary;
+ btSoftBody::Face* face = f2;
+ btVector3 bary;
if (bernsteinCCD(face, node, dt, SAFE_EPSILON, bary))
- {
- btSoftBody::DeformableFaceNodeContact c;
- c.m_normal = face->m_normal;
- if (!useFaceNormal && c.m_normal.dot(node->m_x - face->m_n[2]->m_x) < 0)
- c.m_normal = -face->m_normal;
- c.m_node = node;
- c.m_face = face;
- c.m_bary = bary;
- c.m_friction = psb[0]->m_cfg.kDF * psb[1]->m_cfg.kDF;
- psb[0]->m_faceNodeContacts.push_back(c);
- }
- }
- }
- btSoftBody* psb[2];
- btScalar dt, mrg;
- bool useFaceNormal;
- };
+ {
+ btSoftBody::DeformableFaceNodeContact c;
+ c.m_normal = face->m_normal;
+ if (!useFaceNormal && c.m_normal.dot(node->m_x - face->m_n[2]->m_x) < 0)
+ c.m_normal = -face->m_normal;
+ c.m_node = node;
+ c.m_face = face;
+ c.m_bary = bary;
+ c.m_friction = psb[0]->m_cfg.kDF * psb[1]->m_cfg.kDF;
+ psb[0]->m_faceNodeContacts.push_back(c);
+ }
+ }
+ }
+ btSoftBody* psb[2];
+ btScalar dt, mrg;
+ bool useFaceNormal;
+ };
};
#endif //_BT_SOFT_BODY_INTERNALS_H
diff --git a/thirdparty/bullet/BulletSoftBody/btSoftBodySolvers.h b/thirdparty/bullet/BulletSoftBody/btSoftBodySolvers.h
index c4ac4141aa..dbb2624eee 100644
--- a/thirdparty/bullet/BulletSoftBody/btSoftBodySolvers.h
+++ b/thirdparty/bullet/BulletSoftBody/btSoftBodySolvers.h
@@ -36,7 +36,7 @@ public:
CL_SIMD_SOLVER,
DX_SOLVER,
DX_SIMD_SOLVER,
- DEFORMABLE_SOLVER
+ DEFORMABLE_SOLVER
};
protected:
diff --git a/thirdparty/bullet/BulletSoftBody/btSoftMultiBodyDynamicsWorld.cpp b/thirdparty/bullet/BulletSoftBody/btSoftMultiBodyDynamicsWorld.cpp
index 282dbf75f0..329bd19d71 100644
--- a/thirdparty/bullet/BulletSoftBody/btSoftMultiBodyDynamicsWorld.cpp
+++ b/thirdparty/bullet/BulletSoftBody/btSoftMultiBodyDynamicsWorld.cpp
@@ -100,6 +100,11 @@ void btSoftMultiBodyDynamicsWorld::internalSingleStepSimulation(btScalar timeSte
///update soft bodies
m_softBodySolver->updateSoftBodies();
+ for (int i = 0; i < m_softBodies.size(); i++)
+ {
+ btSoftBody* psb = (btSoftBody*)m_softBodies[i];
+ psb->interpolateRenderMesh();
+ }
// End solver-wise simulation step
// ///////////////////////////////
}
diff --git a/thirdparty/bullet/BulletSoftBody/btSparseSDF.h b/thirdparty/bullet/BulletSoftBody/btSparseSDF.h
index eb290a1dbd..d611726bcd 100644
--- a/thirdparty/bullet/BulletSoftBody/btSparseSDF.h
+++ b/thirdparty/bullet/BulletSoftBody/btSparseSDF.h
@@ -22,36 +22,36 @@ subject to the following restrictions:
// Fast Hash
-#if !defined (get16bits)
-#define get16bits(d) ((((unsigned int)(((const unsigned char *)(d))[1])) << 8)\
-+(unsigned int)(((const unsigned char *)(d))[0]) )
+#if !defined(get16bits)
+#define get16bits(d) ((((unsigned int)(((const unsigned char*)(d))[1])) << 8) + (unsigned int)(((const unsigned char*)(d))[0]))
#endif
//
// super hash function by Paul Hsieh
//
-inline unsigned int HsiehHash (const char * data, int len) {
- unsigned int hash = len, tmp;
- len>>=2;
-
- /* Main loop */
- for (;len > 0; len--) {
- hash += get16bits (data);
- tmp = (get16bits (data+2) << 11) ^ hash;
- hash = (hash << 16) ^ tmp;
- data += 2*sizeof (unsigned short);
- hash += hash >> 11;
- }
+inline unsigned int HsiehHash(const char* data, int len)
+{
+ unsigned int hash = len, tmp;
+ len >>= 2;
+ /* Main loop */
+ for (; len > 0; len--)
+ {
+ hash += get16bits(data);
+ tmp = (get16bits(data + 2) << 11) ^ hash;
+ hash = (hash << 16) ^ tmp;
+ data += 2 * sizeof(unsigned short);
+ hash += hash >> 11;
+ }
- /* Force "avalanching" of final 127 bits */
- hash ^= hash << 3;
- hash += hash >> 5;
- hash ^= hash << 4;
- hash += hash >> 17;
- hash ^= hash << 25;
- hash += hash >> 6;
+ /* Force "avalanching" of final 127 bits */
+ hash ^= hash << 3;
+ hash += hash >> 5;
+ hash ^= hash << 4;
+ hash += hash >> 17;
+ hash ^= hash << 25;
+ hash += hash >> 6;
- return hash;
+ return hash;
}
template <const int CELLSIZE>
@@ -81,7 +81,7 @@ struct btSparseSdf
btAlignedObjectArray<Cell*> cells;
btScalar voxelsz;
- btScalar m_defaultVoxelsz;
+ btScalar m_defaultVoxelsz;
int puid;
int ncells;
int m_clampCells;
@@ -103,16 +103,16 @@ struct btSparseSdf
//if this limit is reached, the SDF is reset (at the cost of some performance during the reset)
m_clampCells = clampCells;
cells.resize(hashsize, 0);
- m_defaultVoxelsz = 0.25;
+ m_defaultVoxelsz = 0.25;
Reset();
}
//
-
- void setDefaultVoxelsz(btScalar sz)
- {
- m_defaultVoxelsz = sz;
- }
-
+
+ void setDefaultVoxelsz(btScalar sz)
+ {
+ m_defaultVoxelsz = sz;
+ }
+
void Reset()
{
for (int i = 0, ni = cells.size(); i < ni; ++i)
@@ -162,7 +162,7 @@ struct btSparseSdf
nqueries = 1;
nprobes = 1;
++puid; ///@todo: Reset puid's when int range limit is reached */
- /* else setup a priority list... */
+ /* else setup a priority list... */
}
//
int RemoveReferences(btCollisionShape* pcs)
@@ -221,7 +221,7 @@ struct btSparseSdf
else
{
// printf("c->hash/c[0][1][2]=%d,%d,%d,%d\n", c->hash, c->c[0], c->c[1],c->c[2]);
- //printf("h,ixb,iyb,izb=%d,%d,%d,%d\n", h,ix.b, iy.b, iz.b);
+ //printf("h,ixb,iyb,izb=%d,%d,%d,%d\n", h,ix.b, iy.b, iz.b);
c = c->next;
}
@@ -363,7 +363,7 @@ struct btSparseSdf
myset.p = (void*)shape;
const char* ptr = (const char*)&myset;
- unsigned int result = HsiehHash(ptr, sizeof(btS) );
+ unsigned int result = HsiehHash(ptr, sizeof(btS));
return result;
}
diff --git a/thirdparty/bullet/BulletSoftBody/poly34.cpp b/thirdparty/bullet/BulletSoftBody/poly34.cpp
index 819d0c79f7..ec7549c8e8 100644
--- a/thirdparty/bullet/BulletSoftBody/poly34.cpp
+++ b/thirdparty/bullet/BulletSoftBody/poly34.cpp
@@ -6,7 +6,7 @@
//
#include <math.h>
-#include "poly34.h" // solution of cubic and quartic equation
+#include "poly34.h" // solution of cubic and quartic equation
#define TwoPi 6.28318530717958648
const btScalar eps = SIMD_EPSILON;
@@ -15,50 +15,53 @@ const btScalar eps = SIMD_EPSILON;
//=============================================================================
static SIMD_FORCE_INLINE btScalar _root3(btScalar x)
{
- btScalar s = 1.;
- while (x < 1.) {
- x *= 8.;
- s *= 0.5;
- }
- while (x > 8.) {
- x *= 0.125;
- s *= 2.;
- }
- btScalar r = 1.5;
- r -= 1. / 3. * (r - x / (r * r));
- r -= 1. / 3. * (r - x / (r * r));
- r -= 1. / 3. * (r - x / (r * r));
- r -= 1. / 3. * (r - x / (r * r));
- r -= 1. / 3. * (r - x / (r * r));
- r -= 1. / 3. * (r - x / (r * r));
- return r * s;
+ btScalar s = 1.;
+ while (x < 1.)
+ {
+ x *= 8.;
+ s *= 0.5;
+ }
+ while (x > 8.)
+ {
+ x *= 0.125;
+ s *= 2.;
+ }
+ btScalar r = 1.5;
+ r -= 1. / 3. * (r - x / (r * r));
+ r -= 1. / 3. * (r - x / (r * r));
+ r -= 1. / 3. * (r - x / (r * r));
+ r -= 1. / 3. * (r - x / (r * r));
+ r -= 1. / 3. * (r - x / (r * r));
+ r -= 1. / 3. * (r - x / (r * r));
+ return r * s;
}
btScalar SIMD_FORCE_INLINE root3(btScalar x)
{
- if (x > 0)
- return _root3(x);
- else if (x < 0)
- return -_root3(-x);
- else
- return 0.;
+ if (x > 0)
+ return _root3(x);
+ else if (x < 0)
+ return -_root3(-x);
+ else
+ return 0.;
}
// x - array of size 2
// return 2: 2 real roots x[0], x[1]
// return 0: pair of complex roots: x[0]i*x[1]
int SolveP2(btScalar* x, btScalar a, btScalar b)
-{ // solve equation x^2 + a*x + b = 0
- btScalar D = 0.25 * a * a - b;
- if (D >= 0) {
- D = sqrt(D);
- x[0] = -0.5 * a + D;
- x[1] = -0.5 * a - D;
- return 2;
- }
- x[0] = -0.5 * a;
- x[1] = sqrt(-D);
- return 0;
+{ // solve equation x^2 + a*x + b = 0
+ btScalar D = 0.25 * a * a - b;
+ if (D >= 0)
+ {
+ D = sqrt(D);
+ x[0] = -0.5 * a + D;
+ x[1] = -0.5 * a - D;
+ return 2;
+ }
+ x[0] = -0.5 * a;
+ x[1] = sqrt(-D);
+ return 0;
}
//---------------------------------------------------------------------------
// x - array of size 3
@@ -66,217 +69,228 @@ int SolveP2(btScalar* x, btScalar a, btScalar b)
// 2 real roots: x[0], x[1], return 2
// 1 real root : x[0], x[1] i*x[2], return 1
int SolveP3(btScalar* x, btScalar a, btScalar b, btScalar c)
-{ // solve cubic equation x^3 + a*x^2 + b*x + c = 0
- btScalar a2 = a * a;
- btScalar q = (a2 - 3 * b) / 9;
- if (q < 0)
- q = eps;
- btScalar r = (a * (2 * a2 - 9 * b) + 27 * c) / 54;
- // equation x^3 + q*x + r = 0
- btScalar r2 = r * r;
- btScalar q3 = q * q * q;
- btScalar A, B;
- if (r2 <= (q3 + eps)) { //<<-- FIXED!
- btScalar t = r / sqrt(q3);
- if (t < -1)
- t = -1;
- if (t > 1)
- t = 1;
- t = acos(t);
- a /= 3;
- q = -2 * sqrt(q);
- x[0] = q * cos(t / 3) - a;
- x[1] = q * cos((t + TwoPi) / 3) - a;
- x[2] = q * cos((t - TwoPi) / 3) - a;
- return (3);
- }
- else {
- //A =-pow(fabs(r)+sqrt(r2-q3),1./3);
- A = -root3(fabs(r) + sqrt(r2 - q3));
- if (r < 0)
- A = -A;
- B = (A == 0 ? 0 : q / A);
-
- a /= 3;
- x[0] = (A + B) - a;
- x[1] = -0.5 * (A + B) - a;
- x[2] = 0.5 * sqrt(3.) * (A - B);
- if (fabs(x[2]) < eps) {
- x[2] = x[1];
- return (2);
- }
- return (1);
- }
-} // SolveP3(btScalar *x,btScalar a,btScalar b,btScalar c) {
+{ // solve cubic equation x^3 + a*x^2 + b*x + c = 0
+ btScalar a2 = a * a;
+ btScalar q = (a2 - 3 * b) / 9;
+ if (q < 0)
+ q = eps;
+ btScalar r = (a * (2 * a2 - 9 * b) + 27 * c) / 54;
+ // equation x^3 + q*x + r = 0
+ btScalar r2 = r * r;
+ btScalar q3 = q * q * q;
+ btScalar A, B;
+ if (r2 <= (q3 + eps))
+ { //<<-- FIXED!
+ btScalar t = r / sqrt(q3);
+ if (t < -1)
+ t = -1;
+ if (t > 1)
+ t = 1;
+ t = acos(t);
+ a /= 3;
+ q = -2 * sqrt(q);
+ x[0] = q * cos(t / 3) - a;
+ x[1] = q * cos((t + TwoPi) / 3) - a;
+ x[2] = q * cos((t - TwoPi) / 3) - a;
+ return (3);
+ }
+ else
+ {
+ //A =-pow(fabs(r)+sqrt(r2-q3),1./3);
+ A = -root3(fabs(r) + sqrt(r2 - q3));
+ if (r < 0)
+ A = -A;
+ B = (A == 0 ? 0 : q / A);
+
+ a /= 3;
+ x[0] = (A + B) - a;
+ x[1] = -0.5 * (A + B) - a;
+ x[2] = 0.5 * sqrt(3.) * (A - B);
+ if (fabs(x[2]) < eps)
+ {
+ x[2] = x[1];
+ return (2);
+ }
+ return (1);
+ }
+} // SolveP3(btScalar *x,btScalar a,btScalar b,btScalar c) {
//---------------------------------------------------------------------------
// a>=0!
-void CSqrt(btScalar x, btScalar y, btScalar& a, btScalar& b) // returns: a+i*s = sqrt(x+i*y)
+void CSqrt(btScalar x, btScalar y, btScalar& a, btScalar& b) // returns: a+i*s = sqrt(x+i*y)
{
- btScalar r = sqrt(x * x + y * y);
- if (y == 0) {
- r = sqrt(r);
- if (x >= 0) {
- a = r;
- b = 0;
- }
- else {
- a = 0;
- b = r;
- }
- }
- else { // y != 0
- a = sqrt(0.5 * (x + r));
- b = 0.5 * y / a;
- }
+ btScalar r = sqrt(x * x + y * y);
+ if (y == 0)
+ {
+ r = sqrt(r);
+ if (x >= 0)
+ {
+ a = r;
+ b = 0;
+ }
+ else
+ {
+ a = 0;
+ b = r;
+ }
+ }
+ else
+ { // y != 0
+ a = sqrt(0.5 * (x + r));
+ b = 0.5 * y / a;
+ }
}
//---------------------------------------------------------------------------
-int SolveP4Bi(btScalar* x, btScalar b, btScalar d) // solve equation x^4 + b*x^2 + d = 0
+int SolveP4Bi(btScalar* x, btScalar b, btScalar d) // solve equation x^4 + b*x^2 + d = 0
{
- btScalar D = b * b - 4 * d;
- if (D >= 0) {
- btScalar sD = sqrt(D);
- btScalar x1 = (-b + sD) / 2;
- btScalar x2 = (-b - sD) / 2; // x2 <= x1
- if (x2 >= 0) // 0 <= x2 <= x1, 4 real roots
- {
- btScalar sx1 = sqrt(x1);
- btScalar sx2 = sqrt(x2);
- x[0] = -sx1;
- x[1] = sx1;
- x[2] = -sx2;
- x[3] = sx2;
- return 4;
- }
- if (x1 < 0) // x2 <= x1 < 0, two pair of imaginary roots
- {
- btScalar sx1 = sqrt(-x1);
- btScalar sx2 = sqrt(-x2);
- x[0] = 0;
- x[1] = sx1;
- x[2] = 0;
- x[3] = sx2;
- return 0;
- }
- // now x2 < 0 <= x1 , two real roots and one pair of imginary root
- btScalar sx1 = sqrt(x1);
- btScalar sx2 = sqrt(-x2);
- x[0] = -sx1;
- x[1] = sx1;
- x[2] = 0;
- x[3] = sx2;
- return 2;
- }
- else { // if( D < 0 ), two pair of compex roots
- btScalar sD2 = 0.5 * sqrt(-D);
- CSqrt(-0.5 * b, sD2, x[0], x[1]);
- CSqrt(-0.5 * b, -sD2, x[2], x[3]);
- return 0;
- } // if( D>=0 )
-} // SolveP4Bi(btScalar *x, btScalar b, btScalar d) // solve equation x^4 + b*x^2 d
+ btScalar D = b * b - 4 * d;
+ if (D >= 0)
+ {
+ btScalar sD = sqrt(D);
+ btScalar x1 = (-b + sD) / 2;
+ btScalar x2 = (-b - sD) / 2; // x2 <= x1
+ if (x2 >= 0) // 0 <= x2 <= x1, 4 real roots
+ {
+ btScalar sx1 = sqrt(x1);
+ btScalar sx2 = sqrt(x2);
+ x[0] = -sx1;
+ x[1] = sx1;
+ x[2] = -sx2;
+ x[3] = sx2;
+ return 4;
+ }
+ if (x1 < 0) // x2 <= x1 < 0, two pair of imaginary roots
+ {
+ btScalar sx1 = sqrt(-x1);
+ btScalar sx2 = sqrt(-x2);
+ x[0] = 0;
+ x[1] = sx1;
+ x[2] = 0;
+ x[3] = sx2;
+ return 0;
+ }
+ // now x2 < 0 <= x1 , two real roots and one pair of imginary root
+ btScalar sx1 = sqrt(x1);
+ btScalar sx2 = sqrt(-x2);
+ x[0] = -sx1;
+ x[1] = sx1;
+ x[2] = 0;
+ x[3] = sx2;
+ return 2;
+ }
+ else
+ { // if( D < 0 ), two pair of compex roots
+ btScalar sD2 = 0.5 * sqrt(-D);
+ CSqrt(-0.5 * b, sD2, x[0], x[1]);
+ CSqrt(-0.5 * b, -sD2, x[2], x[3]);
+ return 0;
+ } // if( D>=0 )
+} // SolveP4Bi(btScalar *x, btScalar b, btScalar d) // solve equation x^4 + b*x^2 d
//---------------------------------------------------------------------------
#define SWAP(a, b) \
-{ \
-t = b; \
-b = a; \
-a = t; \
-}
-static void dblSort3(btScalar& a, btScalar& b, btScalar& c) // make: a <= b <= c
+ { \
+ t = b; \
+ b = a; \
+ a = t; \
+ }
+static void dblSort3(btScalar& a, btScalar& b, btScalar& c) // make: a <= b <= c
{
- btScalar t;
- if (a > b)
- SWAP(a, b); // now a<=b
- if (c < b) {
- SWAP(b, c); // now a<=b, b<=c
- if (a > b)
- SWAP(a, b); // now a<=b
- }
+ btScalar t;
+ if (a > b)
+ SWAP(a, b); // now a<=b
+ if (c < b)
+ {
+ SWAP(b, c); // now a<=b, b<=c
+ if (a > b)
+ SWAP(a, b); // now a<=b
+ }
}
//---------------------------------------------------------------------------
-int SolveP4De(btScalar* x, btScalar b, btScalar c, btScalar d) // solve equation x^4 + b*x^2 + c*x + d
+int SolveP4De(btScalar* x, btScalar b, btScalar c, btScalar d) // solve equation x^4 + b*x^2 + c*x + d
{
- //if( c==0 ) return SolveP4Bi(x,b,d); // After that, c!=0
- if (fabs(c) < 1e-14 * (fabs(b) + fabs(d)))
- return SolveP4Bi(x, b, d); // After that, c!=0
-
- int res3 = SolveP3(x, 2 * b, b * b - 4 * d, -c * c); // solve resolvent
- // by Viet theorem: x1*x2*x3=-c*c not equals to 0, so x1!=0, x2!=0, x3!=0
- if (res3 > 1) // 3 real roots,
- {
- dblSort3(x[0], x[1], x[2]); // sort roots to x[0] <= x[1] <= x[2]
- // Note: x[0]*x[1]*x[2]= c*c > 0
- if (x[0] > 0) // all roots are positive
- {
- btScalar sz1 = sqrt(x[0]);
- btScalar sz2 = sqrt(x[1]);
- btScalar sz3 = sqrt(x[2]);
- // Note: sz1*sz2*sz3= -c (and not equal to 0)
- if (c > 0) {
- x[0] = (-sz1 - sz2 - sz3) / 2;
- x[1] = (-sz1 + sz2 + sz3) / 2;
- x[2] = (+sz1 - sz2 + sz3) / 2;
- x[3] = (+sz1 + sz2 - sz3) / 2;
- return 4;
- }
- // now: c<0
- x[0] = (-sz1 - sz2 + sz3) / 2;
- x[1] = (-sz1 + sz2 - sz3) / 2;
- x[2] = (+sz1 - sz2 - sz3) / 2;
- x[3] = (+sz1 + sz2 + sz3) / 2;
- return 4;
- } // if( x[0] > 0) // all roots are positive
- // now x[0] <= x[1] < 0, x[2] > 0
- // two pair of comlex roots
- btScalar sz1 = sqrt(-x[0]);
- btScalar sz2 = sqrt(-x[1]);
- btScalar sz3 = sqrt(x[2]);
-
- if (c > 0) // sign = -1
- {
- x[0] = -sz3 / 2;
- x[1] = (sz1 - sz2) / 2; // x[0]i*x[1]
- x[2] = sz3 / 2;
- x[3] = (-sz1 - sz2) / 2; // x[2]i*x[3]
- return 0;
- }
- // now: c<0 , sign = +1
- x[0] = sz3 / 2;
- x[1] = (-sz1 + sz2) / 2;
- x[2] = -sz3 / 2;
- x[3] = (sz1 + sz2) / 2;
- return 0;
- } // if( res3>1 ) // 3 real roots,
- // now resoventa have 1 real and pair of compex roots
- // x[0] - real root, and x[0]>0,
- // x[1]i*x[2] - complex roots,
- // x[0] must be >=0. But one times x[0]=~ 1e-17, so:
- if (x[0] < 0)
- x[0] = 0;
- btScalar sz1 = sqrt(x[0]);
- btScalar szr, szi;
- CSqrt(x[1], x[2], szr, szi); // (szr+i*szi)^2 = x[1]+i*x[2]
- if (c > 0) // sign = -1
- {
- x[0] = -sz1 / 2 - szr; // 1st real root
- x[1] = -sz1 / 2 + szr; // 2nd real root
- x[2] = sz1 / 2;
- x[3] = szi;
- return 2;
- }
- // now: c<0 , sign = +1
- x[0] = sz1 / 2 - szr; // 1st real root
- x[1] = sz1 / 2 + szr; // 2nd real root
- x[2] = -sz1 / 2;
- x[3] = szi;
- return 2;
-} // SolveP4De(btScalar *x, btScalar b, btScalar c, btScalar d) // solve equation x^4 + b*x^2 + c*x + d
+ //if( c==0 ) return SolveP4Bi(x,b,d); // After that, c!=0
+ if (fabs(c) < 1e-14 * (fabs(b) + fabs(d)))
+ return SolveP4Bi(x, b, d); // After that, c!=0
+
+ int res3 = SolveP3(x, 2 * b, b * b - 4 * d, -c * c); // solve resolvent
+ // by Viet theorem: x1*x2*x3=-c*c not equals to 0, so x1!=0, x2!=0, x3!=0
+ if (res3 > 1) // 3 real roots,
+ {
+ dblSort3(x[0], x[1], x[2]); // sort roots to x[0] <= x[1] <= x[2]
+ // Note: x[0]*x[1]*x[2]= c*c > 0
+ if (x[0] > 0) // all roots are positive
+ {
+ btScalar sz1 = sqrt(x[0]);
+ btScalar sz2 = sqrt(x[1]);
+ btScalar sz3 = sqrt(x[2]);
+ // Note: sz1*sz2*sz3= -c (and not equal to 0)
+ if (c > 0)
+ {
+ x[0] = (-sz1 - sz2 - sz3) / 2;
+ x[1] = (-sz1 + sz2 + sz3) / 2;
+ x[2] = (+sz1 - sz2 + sz3) / 2;
+ x[3] = (+sz1 + sz2 - sz3) / 2;
+ return 4;
+ }
+ // now: c<0
+ x[0] = (-sz1 - sz2 + sz3) / 2;
+ x[1] = (-sz1 + sz2 - sz3) / 2;
+ x[2] = (+sz1 - sz2 - sz3) / 2;
+ x[3] = (+sz1 + sz2 + sz3) / 2;
+ return 4;
+ } // if( x[0] > 0) // all roots are positive
+ // now x[0] <= x[1] < 0, x[2] > 0
+ // two pair of comlex roots
+ btScalar sz1 = sqrt(-x[0]);
+ btScalar sz2 = sqrt(-x[1]);
+ btScalar sz3 = sqrt(x[2]);
+
+ if (c > 0) // sign = -1
+ {
+ x[0] = -sz3 / 2;
+ x[1] = (sz1 - sz2) / 2; // x[0]i*x[1]
+ x[2] = sz3 / 2;
+ x[3] = (-sz1 - sz2) / 2; // x[2]i*x[3]
+ return 0;
+ }
+ // now: c<0 , sign = +1
+ x[0] = sz3 / 2;
+ x[1] = (-sz1 + sz2) / 2;
+ x[2] = -sz3 / 2;
+ x[3] = (sz1 + sz2) / 2;
+ return 0;
+ } // if( res3>1 ) // 3 real roots,
+ // now resoventa have 1 real and pair of compex roots
+ // x[0] - real root, and x[0]>0,
+ // x[1]i*x[2] - complex roots,
+ // x[0] must be >=0. But one times x[0]=~ 1e-17, so:
+ if (x[0] < 0)
+ x[0] = 0;
+ btScalar sz1 = sqrt(x[0]);
+ btScalar szr, szi;
+ CSqrt(x[1], x[2], szr, szi); // (szr+i*szi)^2 = x[1]+i*x[2]
+ if (c > 0) // sign = -1
+ {
+ x[0] = -sz1 / 2 - szr; // 1st real root
+ x[1] = -sz1 / 2 + szr; // 2nd real root
+ x[2] = sz1 / 2;
+ x[3] = szi;
+ return 2;
+ }
+ // now: c<0 , sign = +1
+ x[0] = sz1 / 2 - szr; // 1st real root
+ x[1] = sz1 / 2 + szr; // 2nd real root
+ x[2] = -sz1 / 2;
+ x[3] = szi;
+ return 2;
+} // SolveP4De(btScalar *x, btScalar b, btScalar c, btScalar d) // solve equation x^4 + b*x^2 + c*x + d
//-----------------------------------------------------------------------------
-btScalar N4Step(btScalar x, btScalar a, btScalar b, btScalar c, btScalar d) // one Newton step for x^4 + a*x^3 + b*x^2 + c*x + d
+btScalar N4Step(btScalar x, btScalar a, btScalar b, btScalar c, btScalar d) // one Newton step for x^4 + a*x^3 + b*x^2 + c*x + d
{
- btScalar fxs = ((4 * x + 3 * a) * x + 2 * b) * x + c; // f'(x)
- if (fxs == 0)
- return x; //return 1e99; <<-- FIXED!
- btScalar fx = (((x + a) * x + b) * x + c) * x + d; // f(x)
- return x - fx / fxs;
+ btScalar fxs = ((4 * x + 3 * a) * x + 2 * b) * x + c; // f'(x)
+ if (fxs == 0)
+ return x; //return 1e99; <<-- FIXED!
+ btScalar fx = (((x + a) * x + b) * x + c) * x + d; // f(x)
+ return x - fx / fxs;
}
//-----------------------------------------------------------------------------
// x - array of size 4
@@ -284,136 +298,150 @@ btScalar N4Step(btScalar x, btScalar a, btScalar b, btScalar c, btScalar d) // o
// return 2: 2 real roots x[0], x[1] and complex x[2]i*x[3],
// return 0: two pair of complex roots: x[0]i*x[1], x[2]i*x[3],
int SolveP4(btScalar* x, btScalar a, btScalar b, btScalar c, btScalar d)
-{ // solve equation x^4 + a*x^3 + b*x^2 + c*x + d by Dekart-Euler method
- // move to a=0:
- btScalar d1 = d + 0.25 * a * (0.25 * b * a - 3. / 64 * a * a * a - c);
- btScalar c1 = c + 0.5 * a * (0.25 * a * a - b);
- btScalar b1 = b - 0.375 * a * a;
- int res = SolveP4De(x, b1, c1, d1);
- if (res == 4) {
- x[0] -= a / 4;
- x[1] -= a / 4;
- x[2] -= a / 4;
- x[3] -= a / 4;
- }
- else if (res == 2) {
- x[0] -= a / 4;
- x[1] -= a / 4;
- x[2] -= a / 4;
- }
- else {
- x[0] -= a / 4;
- x[2] -= a / 4;
- }
- // one Newton step for each real root:
- if (res > 0) {
- x[0] = N4Step(x[0], a, b, c, d);
- x[1] = N4Step(x[1], a, b, c, d);
- }
- if (res > 2) {
- x[2] = N4Step(x[2], a, b, c, d);
- x[3] = N4Step(x[3], a, b, c, d);
- }
- return res;
+{ // solve equation x^4 + a*x^3 + b*x^2 + c*x + d by Dekart-Euler method
+ // move to a=0:
+ btScalar d1 = d + 0.25 * a * (0.25 * b * a - 3. / 64 * a * a * a - c);
+ btScalar c1 = c + 0.5 * a * (0.25 * a * a - b);
+ btScalar b1 = b - 0.375 * a * a;
+ int res = SolveP4De(x, b1, c1, d1);
+ if (res == 4)
+ {
+ x[0] -= a / 4;
+ x[1] -= a / 4;
+ x[2] -= a / 4;
+ x[3] -= a / 4;
+ }
+ else if (res == 2)
+ {
+ x[0] -= a / 4;
+ x[1] -= a / 4;
+ x[2] -= a / 4;
+ }
+ else
+ {
+ x[0] -= a / 4;
+ x[2] -= a / 4;
+ }
+ // one Newton step for each real root:
+ if (res > 0)
+ {
+ x[0] = N4Step(x[0], a, b, c, d);
+ x[1] = N4Step(x[1], a, b, c, d);
+ }
+ if (res > 2)
+ {
+ x[2] = N4Step(x[2], a, b, c, d);
+ x[3] = N4Step(x[3], a, b, c, d);
+ }
+ return res;
}
//-----------------------------------------------------------------------------
#define F5(t) (((((t + a) * t + b) * t + c) * t + d) * t + e)
//-----------------------------------------------------------------------------
-btScalar SolveP5_1(btScalar a, btScalar b, btScalar c, btScalar d, btScalar e) // return real root of x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
+btScalar SolveP5_1(btScalar a, btScalar b, btScalar c, btScalar d, btScalar e) // return real root of x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
{
- int cnt;
- if (fabs(e) < eps)
- return 0;
-
- btScalar brd = fabs(a); // brd - border of real roots
- if (fabs(b) > brd)
- brd = fabs(b);
- if (fabs(c) > brd)
- brd = fabs(c);
- if (fabs(d) > brd)
- brd = fabs(d);
- if (fabs(e) > brd)
- brd = fabs(e);
- brd++; // brd - border of real roots
-
- btScalar x0, f0; // less than root
- btScalar x1, f1; // greater than root
- btScalar x2, f2, f2s; // next values, f(x2), f'(x2)
- btScalar dx = 0;
-
- if (e < 0) {
- x0 = 0;
- x1 = brd;
- f0 = e;
- f1 = F5(x1);
- x2 = 0.01 * brd;
- } // positive root
- else {
- x0 = -brd;
- x1 = 0;
- f0 = F5(x0);
- f1 = e;
- x2 = -0.01 * brd;
- } // negative root
-
- if (fabs(f0) < eps)
- return x0;
- if (fabs(f1) < eps)
- return x1;
-
- // now x0<x1, f(x0)<0, f(x1)>0
- // Firstly 10 bisections
- for (cnt = 0; cnt < 10; cnt++) {
- x2 = (x0 + x1) / 2; // next point
- //x2 = x0 - f0*(x1 - x0) / (f1 - f0); // next point
- f2 = F5(x2); // f(x2)
- if (fabs(f2) < eps)
- return x2;
- if (f2 > 0) {
- x1 = x2;
- f1 = f2;
- }
- else {
- x0 = x2;
- f0 = f2;
- }
- }
-
- // At each step:
- // x0<x1, f(x0)<0, f(x1)>0.
- // x2 - next value
- // we hope that x0 < x2 < x1, but not necessarily
- do {
- if (cnt++ > 50)
- break;
- if (x2 <= x0 || x2 >= x1)
- x2 = (x0 + x1) / 2; // now x0 < x2 < x1
- f2 = F5(x2); // f(x2)
- if (fabs(f2) < eps)
- return x2;
- if (f2 > 0) {
- x1 = x2;
- f1 = f2;
- }
- else {
- x0 = x2;
- f0 = f2;
- }
- f2s = (((5 * x2 + 4 * a) * x2 + 3 * b) * x2 + 2 * c) * x2 + d; // f'(x2)
- if (fabs(f2s) < eps) {
- x2 = 1e99;
- continue;
- }
- dx = f2 / f2s;
- x2 -= dx;
- } while (fabs(dx) > eps);
- return x2;
-} // SolveP5_1(btScalar a,btScalar b,btScalar c,btScalar d,btScalar e) // return real root of x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
+ int cnt;
+ if (fabs(e) < eps)
+ return 0;
+
+ btScalar brd = fabs(a); // brd - border of real roots
+ if (fabs(b) > brd)
+ brd = fabs(b);
+ if (fabs(c) > brd)
+ brd = fabs(c);
+ if (fabs(d) > brd)
+ brd = fabs(d);
+ if (fabs(e) > brd)
+ brd = fabs(e);
+ brd++; // brd - border of real roots
+
+ btScalar x0, f0; // less than root
+ btScalar x1, f1; // greater than root
+ btScalar x2, f2, f2s; // next values, f(x2), f'(x2)
+ btScalar dx = 0;
+
+ if (e < 0)
+ {
+ x0 = 0;
+ x1 = brd;
+ f0 = e;
+ f1 = F5(x1);
+ x2 = 0.01 * brd;
+ } // positive root
+ else
+ {
+ x0 = -brd;
+ x1 = 0;
+ f0 = F5(x0);
+ f1 = e;
+ x2 = -0.01 * brd;
+ } // negative root
+
+ if (fabs(f0) < eps)
+ return x0;
+ if (fabs(f1) < eps)
+ return x1;
+
+ // now x0<x1, f(x0)<0, f(x1)>0
+ // Firstly 10 bisections
+ for (cnt = 0; cnt < 10; cnt++)
+ {
+ x2 = (x0 + x1) / 2; // next point
+ //x2 = x0 - f0*(x1 - x0) / (f1 - f0); // next point
+ f2 = F5(x2); // f(x2)
+ if (fabs(f2) < eps)
+ return x2;
+ if (f2 > 0)
+ {
+ x1 = x2;
+ f1 = f2;
+ }
+ else
+ {
+ x0 = x2;
+ f0 = f2;
+ }
+ }
+
+ // At each step:
+ // x0<x1, f(x0)<0, f(x1)>0.
+ // x2 - next value
+ // we hope that x0 < x2 < x1, but not necessarily
+ do
+ {
+ if (cnt++ > 50)
+ break;
+ if (x2 <= x0 || x2 >= x1)
+ x2 = (x0 + x1) / 2; // now x0 < x2 < x1
+ f2 = F5(x2); // f(x2)
+ if (fabs(f2) < eps)
+ return x2;
+ if (f2 > 0)
+ {
+ x1 = x2;
+ f1 = f2;
+ }
+ else
+ {
+ x0 = x2;
+ f0 = f2;
+ }
+ f2s = (((5 * x2 + 4 * a) * x2 + 3 * b) * x2 + 2 * c) * x2 + d; // f'(x2)
+ if (fabs(f2s) < eps)
+ {
+ x2 = 1e99;
+ continue;
+ }
+ dx = f2 / f2s;
+ x2 -= dx;
+ } while (fabs(dx) > eps);
+ return x2;
+} // SolveP5_1(btScalar a,btScalar b,btScalar c,btScalar d,btScalar e) // return real root of x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
//-----------------------------------------------------------------------------
-int SolveP5(btScalar* x, btScalar a, btScalar b, btScalar c, btScalar d, btScalar e) // solve equation x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
+int SolveP5(btScalar* x, btScalar a, btScalar b, btScalar c, btScalar d, btScalar e) // solve equation x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
{
- btScalar r = x[0] = SolveP5_1(a, b, c, d, e);
- btScalar a1 = a + r, b1 = b + r * a1, c1 = c + r * b1, d1 = d + r * c1;
- return 1 + SolveP4(x + 1, a1, b1, c1, d1);
-} // SolveP5(btScalar *x,btScalar a,btScalar b,btScalar c,btScalar d,btScalar e) // solve equation x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
+ btScalar r = x[0] = SolveP5_1(a, b, c, d, e);
+ btScalar a1 = a + r, b1 = b + r * a1, c1 = c + r * b1, d1 = d + r * c1;
+ return 1 + SolveP4(x + 1, a1, b1, c1, d1);
+} // SolveP5(btScalar *x,btScalar a,btScalar b,btScalar c,btScalar d,btScalar e) // solve equation x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
//-----------------------------------------------------------------------------
diff --git a/thirdparty/bullet/BulletSoftBody/poly34.h b/thirdparty/bullet/BulletSoftBody/poly34.h
index 32ad5d7da5..35a52c5fec 100644
--- a/thirdparty/bullet/BulletSoftBody/poly34.h
+++ b/thirdparty/bullet/BulletSoftBody/poly34.h
@@ -8,31 +8,31 @@
// x - array of size 2
// return 2: 2 real roots x[0], x[1]
// return 0: pair of complex roots: x[0]i*x[1]
-int SolveP2(btScalar* x, btScalar a, btScalar b); // solve equation x^2 + a*x + b = 0
+int SolveP2(btScalar* x, btScalar a, btScalar b); // solve equation x^2 + a*x + b = 0
// x - array of size 3
// return 3: 3 real roots x[0], x[1], x[2]
// return 1: 1 real root x[0] and pair of complex roots: x[1]i*x[2]
-int SolveP3(btScalar* x, btScalar a, btScalar b, btScalar c); // solve cubic equation x^3 + a*x^2 + b*x + c = 0
+int SolveP3(btScalar* x, btScalar a, btScalar b, btScalar c); // solve cubic equation x^3 + a*x^2 + b*x + c = 0
// x - array of size 4
// return 4: 4 real roots x[0], x[1], x[2], x[3], possible multiple roots
// return 2: 2 real roots x[0], x[1] and complex x[2]i*x[3],
// return 0: two pair of complex roots: x[0]i*x[1], x[2]i*x[3],
-int SolveP4(btScalar* x, btScalar a, btScalar b, btScalar c, btScalar d); // solve equation x^4 + a*x^3 + b*x^2 + c*x + d = 0 by Dekart-Euler method
+int SolveP4(btScalar* x, btScalar a, btScalar b, btScalar c, btScalar d); // solve equation x^4 + a*x^3 + b*x^2 + c*x + d = 0 by Dekart-Euler method
// x - array of size 5
// return 5: 5 real roots x[0], x[1], x[2], x[3], x[4], possible multiple roots
// return 3: 3 real roots x[0], x[1], x[2] and complex x[3]i*x[4],
// return 1: 1 real root x[0] and two pair of complex roots: x[1]i*x[2], x[3]i*x[4],
-int SolveP5(btScalar* x, btScalar a, btScalar b, btScalar c, btScalar d, btScalar e); // solve equation x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
+int SolveP5(btScalar* x, btScalar a, btScalar b, btScalar c, btScalar d, btScalar e); // solve equation x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
//-----------------------------------------------------------------------------
// And some additional functions for internal use.
// Your may remove this definitions from here
-int SolveP4Bi(btScalar* x, btScalar b, btScalar d); // solve equation x^4 + b*x^2 + d = 0
-int SolveP4De(btScalar* x, btScalar b, btScalar c, btScalar d); // solve equation x^4 + b*x^2 + c*x + d = 0
-void CSqrt(btScalar x, btScalar y, btScalar& a, btScalar& b); // returns as a+i*s, sqrt(x+i*y)
-btScalar N4Step(btScalar x, btScalar a, btScalar b, btScalar c, btScalar d); // one Newton step for x^4 + a*x^3 + b*x^2 + c*x + d
-btScalar SolveP5_1(btScalar a, btScalar b, btScalar c, btScalar d, btScalar e); // return real root of x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
+int SolveP4Bi(btScalar* x, btScalar b, btScalar d); // solve equation x^4 + b*x^2 + d = 0
+int SolveP4De(btScalar* x, btScalar b, btScalar c, btScalar d); // solve equation x^4 + b*x^2 + c*x + d = 0
+void CSqrt(btScalar x, btScalar y, btScalar& a, btScalar& b); // returns as a+i*s, sqrt(x+i*y)
+btScalar N4Step(btScalar x, btScalar a, btScalar b, btScalar c, btScalar d); // one Newton step for x^4 + a*x^3 + b*x^2 + c*x + d
+btScalar SolveP5_1(btScalar a, btScalar b, btScalar c, btScalar d, btScalar e); // return real root of x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
#endif
diff --git a/thirdparty/bullet/LinearMath/btAlignedAllocator.cpp b/thirdparty/bullet/LinearMath/btAlignedAllocator.cpp
index 39b302b600..be8f8aa6d0 100644
--- a/thirdparty/bullet/LinearMath/btAlignedAllocator.cpp
+++ b/thirdparty/bullet/LinearMath/btAlignedAllocator.cpp
@@ -138,7 +138,7 @@ struct btDebugPtrMagic
};
};
-void *btAlignedAllocInternal(size_t size, int alignment, int line, char *filename)
+void *btAlignedAllocInternal(size_t size, int alignment, int line, const char *filename)
{
if (size == 0)
{
@@ -195,7 +195,7 @@ void *btAlignedAllocInternal(size_t size, int alignment, int line, char *filenam
return (ret);
}
-void btAlignedFreeInternal(void *ptr, int line, char *filename)
+void btAlignedFreeInternal(void *ptr, int line, const char *filename)
{
void *real;
diff --git a/thirdparty/bullet/LinearMath/btAlignedAllocator.h b/thirdparty/bullet/LinearMath/btAlignedAllocator.h
index ce4d3585f1..971f62bfb0 100644
--- a/thirdparty/bullet/LinearMath/btAlignedAllocator.h
+++ b/thirdparty/bullet/LinearMath/btAlignedAllocator.h
@@ -35,9 +35,9 @@ int btDumpMemoryLeaks();
#define btAlignedFree(ptr) \
btAlignedFreeInternal(ptr, __LINE__, __FILE__)
-void* btAlignedAllocInternal(size_t size, int alignment, int line, char* filename);
+void* btAlignedAllocInternal(size_t size, int alignment, int line, const char* filename);
-void btAlignedFreeInternal(void* ptr, int line, char* filename);
+void btAlignedFreeInternal(void* ptr, int line, const char* filename);
#else
void* btAlignedAllocInternal(size_t size, int alignment);
diff --git a/thirdparty/bullet/LinearMath/btConvexHullComputer.cpp b/thirdparty/bullet/LinearMath/btConvexHullComputer.cpp
index 8bbfdc5f25..12125fd2de 100644
--- a/thirdparty/bullet/LinearMath/btConvexHullComputer.cpp
+++ b/thirdparty/bullet/LinearMath/btConvexHullComputer.cpp
@@ -105,7 +105,7 @@ public:
Point64 cross(const Point32& b) const
{
- return Point64(y * b.z - z * b.y, z * b.x - x * b.z, x * b.y - y * b.x);
+ 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
@@ -115,7 +115,7 @@ public:
int64_t dot(const Point32& b) const
{
- return x * b.x + y * b.y + z * b.z;
+ return ((int64_t)x) * b.x + ((int64_t)y) * b.y + ((int64_t)z) * b.z;
}
int64_t dot(const Point64& b) const
@@ -2673,6 +2673,7 @@ btScalar btConvexHullComputer::compute(const void* coords, bool doubleCoords, in
}
vertices.resize(0);
+ original_vertex_index.resize(0);
edges.resize(0);
faces.resize(0);
@@ -2683,6 +2684,7 @@ btScalar btConvexHullComputer::compute(const void* coords, bool doubleCoords, in
{
btConvexHullInternal::Vertex* v = oldVertices[copied];
vertices.push_back(hull.getCoordinates(v));
+ original_vertex_index.push_back(v->point.index);
btConvexHullInternal::Edge* firstEdge = v->edges;
if (firstEdge)
{
diff --git a/thirdparty/bullet/LinearMath/btConvexHullComputer.h b/thirdparty/bullet/LinearMath/btConvexHullComputer.h
index cba684f2dc..18b26eea9a 100644
--- a/thirdparty/bullet/LinearMath/btConvexHullComputer.h
+++ b/thirdparty/bullet/LinearMath/btConvexHullComputer.h
@@ -66,6 +66,9 @@ public:
// Vertices of the output hull
btAlignedObjectArray<btVector3> vertices;
+ // The original vertex index in the input coords array
+ btAlignedObjectArray<int> original_vertex_index;
+
// Edges of the output hull
btAlignedObjectArray<Edge> edges;
diff --git a/thirdparty/bullet/LinearMath/btReducedVector.h b/thirdparty/bullet/LinearMath/btReducedVector.h
index 83b5e581e5..313a4271f0 100644
--- a/thirdparty/bullet/LinearMath/btReducedVector.h
+++ b/thirdparty/bullet/LinearMath/btReducedVector.h
@@ -267,7 +267,7 @@ public:
std::sort(tuples.begin(), tuples.end());
btAlignedObjectArray<int> new_indices;
btAlignedObjectArray<btVector3> new_vecs;
- for (int i = 0; i < tuples.size(); ++i)
+ for (size_t i = 0; i < tuples.size(); ++i)
{
new_indices.push_back(tuples[i].b);
new_vecs.push_back(m_vecs[tuples[i].a]);
diff --git a/thirdparty/bullet/LinearMath/btScalar.h b/thirdparty/bullet/LinearMath/btScalar.h
index 86d94e8974..36b90cc944 100644
--- a/thirdparty/bullet/LinearMath/btScalar.h
+++ b/thirdparty/bullet/LinearMath/btScalar.h
@@ -25,7 +25,7 @@ subject to the following restrictions:
#include <float.h>
/* SVN $Revision$ on $Date$ from http://bullet.googlecode.com*/
-#define BT_BULLET_VERSION 289
+#define BT_BULLET_VERSION 307
inline int btGetVersion()
{
diff --git a/thirdparty/bullet/LinearMath/btSerializer.h b/thirdparty/bullet/LinearMath/btSerializer.h
index 2ee712047f..9abcf031d0 100644
--- a/thirdparty/bullet/LinearMath/btSerializer.h
+++ b/thirdparty/bullet/LinearMath/btSerializer.h
@@ -479,9 +479,9 @@ public:
buffer[8] = 'V';
}
- buffer[9] = '2';
- buffer[10] = '8';
- buffer[11] = '9';
+ buffer[9] = '3';
+ buffer[10] = '0';
+ buffer[11] = '7';
}
virtual void startSerialization()
diff --git a/thirdparty/mbedtls/include/mbedtls/bignum.h b/thirdparty/mbedtls/include/mbedtls/bignum.h
index 4bb9fa3d43..4d04b336e7 100644
--- a/thirdparty/mbedtls/include/mbedtls/bignum.h
+++ b/thirdparty/mbedtls/include/mbedtls/bignum.h
@@ -88,12 +88,12 @@
* Maximum window size used for modular exponentiation. Default: 6
* Minimum value: 1. Maximum value: 6.
*
- * Result is an array of ( 2 << MBEDTLS_MPI_WINDOW_SIZE ) MPIs used
+ * Result is an array of ( 2 ** MBEDTLS_MPI_WINDOW_SIZE ) MPIs used
* for the sliding window calculation. (So 64 by default)
*
* Reduction in size, reduces speed.
*/
-#define MBEDTLS_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */
+#define MBEDTLS_MPI_WINDOW_SIZE 6 /**< Maximum window size used. */
#endif /* !MBEDTLS_MPI_WINDOW_SIZE */
#if !defined(MBEDTLS_MPI_MAX_SIZE)
diff --git a/thirdparty/mbedtls/include/mbedtls/ccm.h b/thirdparty/mbedtls/include/mbedtls/ccm.h
index 3dcdc91894..d50c6ec993 100644
--- a/thirdparty/mbedtls/include/mbedtls/ccm.h
+++ b/thirdparty/mbedtls/include/mbedtls/ccm.h
@@ -175,7 +175,7 @@ void mbedtls_ccm_free( mbedtls_ccm_context *ctx );
* than zero, \p output must be a writable buffer of at least
* that length.
* \param tag The buffer holding the authentication field. This must be a
- * readable buffer of at least \p tag_len Bytes.
+ * writable buffer of at least \p tag_len Bytes.
* \param tag_len The length of the authentication field to generate in Bytes:
* 4, 6, 8, 10, 12, 14 or 16.
*
@@ -220,7 +220,7 @@ int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length,
* than zero, \p output must be a writable buffer of at least
* that length.
* \param tag The buffer holding the authentication field. This must be a
- * readable buffer of at least \p tag_len Bytes.
+ * writable buffer of at least \p tag_len Bytes.
* \param tag_len The length of the authentication field to generate in Bytes:
* 0, 4, 6, 8, 10, 12, 14 or 16.
*
diff --git a/thirdparty/mbedtls/include/mbedtls/config.h b/thirdparty/mbedtls/include/mbedtls/config.h
index 217998a5eb..e17bc7e306 100644
--- a/thirdparty/mbedtls/include/mbedtls/config.h
+++ b/thirdparty/mbedtls/include/mbedtls/config.h
@@ -3128,7 +3128,7 @@
*/
/* MPI / BIGNUM options */
-//#define MBEDTLS_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */
+//#define MBEDTLS_MPI_WINDOW_SIZE 6 /**< Maximum window size used. */
//#define MBEDTLS_MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */
/* CTR_DRBG options */
diff --git a/thirdparty/mbedtls/include/mbedtls/ctr_drbg.h b/thirdparty/mbedtls/include/mbedtls/ctr_drbg.h
index 7e5f2e5769..278fbbbb7a 100644
--- a/thirdparty/mbedtls/include/mbedtls/ctr_drbg.h
+++ b/thirdparty/mbedtls/include/mbedtls/ctr_drbg.h
@@ -224,6 +224,11 @@ mbedtls_ctr_drbg_context;
* and prepares it for mbedtls_ctr_drbg_seed()
* or mbedtls_ctr_drbg_free().
*
+ * \note The reseed interval is
+ * #MBEDTLS_CTR_DRBG_RESEED_INTERVAL by default.
+ * You can override it by calling
+ * mbedtls_ctr_drbg_set_reseed_interval().
+ *
* \param ctx The CTR_DRBG context to initialize.
*/
void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx );
@@ -305,7 +310,8 @@ int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx,
size_t len );
/**
- * \brief This function clears CTR_CRBG context data.
+ * \brief This function resets CTR_DRBG context to the state immediately
+ * after initial call of mbedtls_ctr_drbg_init().
*
* \param ctx The CTR_DRBG context to clear.
*/
diff --git a/thirdparty/mbedtls/include/mbedtls/gcm.h b/thirdparty/mbedtls/include/mbedtls/gcm.h
index 4e4434ed4d..1201fbd4f1 100644
--- a/thirdparty/mbedtls/include/mbedtls/gcm.h
+++ b/thirdparty/mbedtls/include/mbedtls/gcm.h
@@ -182,7 +182,7 @@ int mbedtls_gcm_setkey( mbedtls_gcm_context *ctx,
* than zero, this must be a writable buffer of at least that
* size in Bytes.
* \param tag_len The length of the tag to generate.
- * \param tag The buffer for holding the tag. This must be a readable
+ * \param tag The buffer for holding the tag. This must be a writable
* buffer of at least \p tag_len Bytes.
*
* \return \c 0 if the encryption or decryption was performed
@@ -310,7 +310,7 @@ int mbedtls_gcm_update( mbedtls_gcm_context *ctx,
* tag. The tag can have a maximum length of 16 Bytes.
*
* \param ctx The GCM context. This must be initialized.
- * \param tag The buffer for holding the tag. This must be a readable
+ * \param tag The buffer for holding the tag. This must be a writable
* buffer of at least \p tag_len Bytes.
* \param tag_len The length of the tag to generate. This must be at least
* four.
diff --git a/thirdparty/mbedtls/include/mbedtls/hmac_drbg.h b/thirdparty/mbedtls/include/mbedtls/hmac_drbg.h
index 6883678204..970c033c15 100644
--- a/thirdparty/mbedtls/include/mbedtls/hmac_drbg.h
+++ b/thirdparty/mbedtls/include/mbedtls/hmac_drbg.h
@@ -138,6 +138,10 @@ typedef struct mbedtls_hmac_drbg_context
* This function makes the context ready for mbedtls_hmac_drbg_seed(),
* mbedtls_hmac_drbg_seed_buf() or mbedtls_hmac_drbg_free().
*
+ * \note The reseed interval is #MBEDTLS_HMAC_DRBG_RESEED_INTERVAL
+ * by default. Override this value by calling
+ * mbedtls_hmac_drbg_set_reseed_interval().
+ *
* \param ctx HMAC_DRBG context to be initialized.
*/
void mbedtls_hmac_drbg_init( mbedtls_hmac_drbg_context *ctx );
@@ -361,7 +365,8 @@ int mbedtls_hmac_drbg_random_with_add( void *p_rng,
int mbedtls_hmac_drbg_random( void *p_rng, unsigned char *output, size_t out_len );
/**
- * \brief Free an HMAC_DRBG context
+ * \brief This function resets HMAC_DRBG context to the state immediately
+ * after initial call of mbedtls_hmac_drbg_init().
*
* \param ctx The HMAC_DRBG context to free.
*/
diff --git a/thirdparty/mbedtls/include/mbedtls/sha512.h b/thirdparty/mbedtls/include/mbedtls/sha512.h
index 9ff78ecf41..5e5a15e000 100644
--- a/thirdparty/mbedtls/include/mbedtls/sha512.h
+++ b/thirdparty/mbedtls/include/mbedtls/sha512.h
@@ -152,8 +152,7 @@ int mbedtls_sha512_update_ret( mbedtls_sha512_context *ctx,
/**
* \brief This function finishes the SHA-512 operation, and writes
- * the result to the output buffer. This function is for
- * internal use only.
+ * the result to the output buffer.
*
* \param ctx The SHA-512 context. This must be initialized
* and have a hash operation started.
@@ -169,6 +168,7 @@ int mbedtls_sha512_finish_ret( mbedtls_sha512_context *ctx,
/**
* \brief This function processes a single data block within
* the ongoing SHA-512 computation.
+ * This function is for internal use only.
*
* \param ctx The SHA-512 context. This must be initialized.
* \param data The buffer holding one block of data. This
diff --git a/thirdparty/mbedtls/include/mbedtls/ssl.h b/thirdparty/mbedtls/include/mbedtls/ssl.h
index d3ee3c4e6f..fe33ac8d57 100644
--- a/thirdparty/mbedtls/include/mbedtls/ssl.h
+++ b/thirdparty/mbedtls/include/mbedtls/ssl.h
@@ -1409,7 +1409,7 @@ void mbedtls_ssl_conf_dbg( mbedtls_ssl_config *conf,
* \note For DTLS, you need to provide either a non-NULL
* f_recv_timeout callback, or a f_recv that doesn't block.
*
- * \note See the documentations of \c mbedtls_ssl_sent_t,
+ * \note See the documentations of \c mbedtls_ssl_send_t,
* \c mbedtls_ssl_recv_t and \c mbedtls_ssl_recv_timeout_t for
* the conventions those callbacks must follow.
*
diff --git a/thirdparty/mbedtls/include/mbedtls/version.h b/thirdparty/mbedtls/include/mbedtls/version.h
index d09b45002d..5f0a8f114c 100644
--- a/thirdparty/mbedtls/include/mbedtls/version.h
+++ b/thirdparty/mbedtls/include/mbedtls/version.h
@@ -65,16 +65,16 @@
*/
#define MBEDTLS_VERSION_MAJOR 2
#define MBEDTLS_VERSION_MINOR 16
-#define MBEDTLS_VERSION_PATCH 8
+#define MBEDTLS_VERSION_PATCH 9
/**
* The single version number has the following structure:
* MMNNPP00
* Major version | Minor version | Patch version
*/
-#define MBEDTLS_VERSION_NUMBER 0x02100800
-#define MBEDTLS_VERSION_STRING "2.16.8"
-#define MBEDTLS_VERSION_STRING_FULL "mbed TLS 2.16.8"
+#define MBEDTLS_VERSION_NUMBER 0x02100900
+#define MBEDTLS_VERSION_STRING "2.16.9"
+#define MBEDTLS_VERSION_STRING_FULL "mbed TLS 2.16.9"
#if defined(MBEDTLS_VERSION_C)
diff --git a/thirdparty/mbedtls/library/aes.c b/thirdparty/mbedtls/library/aes.c
index 9b337505fd..da0e5b6bdc 100644
--- a/thirdparty/mbedtls/library/aes.c
+++ b/thirdparty/mbedtls/library/aes.c
@@ -760,6 +760,7 @@ exit:
return( ret );
}
+#endif /* !MBEDTLS_AES_SETKEY_DEC_ALT */
#if defined(MBEDTLS_CIPHER_MODE_XTS)
static int mbedtls_aes_xts_decode_keys( const unsigned char *key,
@@ -838,8 +839,6 @@ int mbedtls_aes_xts_setkey_dec( mbedtls_aes_xts_context *ctx,
}
#endif /* MBEDTLS_CIPHER_MODE_XTS */
-#endif /* !MBEDTLS_AES_SETKEY_DEC_ALT */
-
#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \
do \
{ \
@@ -897,63 +896,56 @@ int mbedtls_internal_aes_encrypt( mbedtls_aes_context *ctx,
unsigned char output[16] )
{
int i;
- uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3;
-
- RK = ctx->rk;
+ uint32_t *RK = ctx->rk;
+ struct
+ {
+ uint32_t X[4];
+ uint32_t Y[4];
+ } t;
- GET_UINT32_LE( X0, input, 0 ); X0 ^= *RK++;
- GET_UINT32_LE( X1, input, 4 ); X1 ^= *RK++;
- GET_UINT32_LE( X2, input, 8 ); X2 ^= *RK++;
- GET_UINT32_LE( X3, input, 12 ); X3 ^= *RK++;
+ GET_UINT32_LE( t.X[0], input, 0 ); t.X[0] ^= *RK++;
+ GET_UINT32_LE( t.X[1], input, 4 ); t.X[1] ^= *RK++;
+ GET_UINT32_LE( t.X[2], input, 8 ); t.X[2] ^= *RK++;
+ GET_UINT32_LE( t.X[3], input, 12 ); t.X[3] ^= *RK++;
for( i = ( ctx->nr >> 1 ) - 1; i > 0; i-- )
{
- AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );
- AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 );
+ AES_FROUND( t.Y[0], t.Y[1], t.Y[2], t.Y[3], t.X[0], t.X[1], t.X[2], t.X[3] );
+ AES_FROUND( t.X[0], t.X[1], t.X[2], t.X[3], t.Y[0], t.Y[1], t.Y[2], t.Y[3] );
}
- AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );
-
- X0 = *RK++ ^ \
- ( (uint32_t) FSb[ ( Y0 ) & 0xFF ] ) ^
- ( (uint32_t) FSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^
- ( (uint32_t) FSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^
- ( (uint32_t) FSb[ ( Y3 >> 24 ) & 0xFF ] << 24 );
-
- X1 = *RK++ ^ \
- ( (uint32_t) FSb[ ( Y1 ) & 0xFF ] ) ^
- ( (uint32_t) FSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^
- ( (uint32_t) FSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^
- ( (uint32_t) FSb[ ( Y0 >> 24 ) & 0xFF ] << 24 );
-
- X2 = *RK++ ^ \
- ( (uint32_t) FSb[ ( Y2 ) & 0xFF ] ) ^
- ( (uint32_t) FSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^
- ( (uint32_t) FSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^
- ( (uint32_t) FSb[ ( Y1 >> 24 ) & 0xFF ] << 24 );
-
- X3 = *RK++ ^ \
- ( (uint32_t) FSb[ ( Y3 ) & 0xFF ] ) ^
- ( (uint32_t) FSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^
- ( (uint32_t) FSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^
- ( (uint32_t) FSb[ ( Y2 >> 24 ) & 0xFF ] << 24 );
-
- PUT_UINT32_LE( X0, output, 0 );
- PUT_UINT32_LE( X1, output, 4 );
- PUT_UINT32_LE( X2, output, 8 );
- PUT_UINT32_LE( X3, output, 12 );
-
- mbedtls_platform_zeroize( &X0, sizeof( X0 ) );
- mbedtls_platform_zeroize( &X1, sizeof( X1 ) );
- mbedtls_platform_zeroize( &X2, sizeof( X2 ) );
- mbedtls_platform_zeroize( &X3, sizeof( X3 ) );
-
- mbedtls_platform_zeroize( &Y0, sizeof( Y0 ) );
- mbedtls_platform_zeroize( &Y1, sizeof( Y1 ) );
- mbedtls_platform_zeroize( &Y2, sizeof( Y2 ) );
- mbedtls_platform_zeroize( &Y3, sizeof( Y3 ) );
-
- mbedtls_platform_zeroize( &RK, sizeof( RK ) );
+ AES_FROUND( t.Y[0], t.Y[1], t.Y[2], t.Y[3], t.X[0], t.X[1], t.X[2], t.X[3] );
+
+ t.X[0] = *RK++ ^ \
+ ( (uint32_t) FSb[ ( t.Y[0] ) & 0xFF ] ) ^
+ ( (uint32_t) FSb[ ( t.Y[1] >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) FSb[ ( t.Y[2] >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) FSb[ ( t.Y[3] >> 24 ) & 0xFF ] << 24 );
+
+ t.X[1] = *RK++ ^ \
+ ( (uint32_t) FSb[ ( t.Y[1] ) & 0xFF ] ) ^
+ ( (uint32_t) FSb[ ( t.Y[2] >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) FSb[ ( t.Y[3] >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) FSb[ ( t.Y[0] >> 24 ) & 0xFF ] << 24 );
+
+ t.X[2] = *RK++ ^ \
+ ( (uint32_t) FSb[ ( t.Y[2] ) & 0xFF ] ) ^
+ ( (uint32_t) FSb[ ( t.Y[3] >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) FSb[ ( t.Y[0] >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) FSb[ ( t.Y[1] >> 24 ) & 0xFF ] << 24 );
+
+ t.X[3] = *RK++ ^ \
+ ( (uint32_t) FSb[ ( t.Y[3] ) & 0xFF ] ) ^
+ ( (uint32_t) FSb[ ( t.Y[0] >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) FSb[ ( t.Y[1] >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) FSb[ ( t.Y[2] >> 24 ) & 0xFF ] << 24 );
+
+ PUT_UINT32_LE( t.X[0], output, 0 );
+ PUT_UINT32_LE( t.X[1], output, 4 );
+ PUT_UINT32_LE( t.X[2], output, 8 );
+ PUT_UINT32_LE( t.X[3], output, 12 );
+
+ mbedtls_platform_zeroize( &t, sizeof( t ) );
return( 0 );
}
@@ -977,63 +969,56 @@ int mbedtls_internal_aes_decrypt( mbedtls_aes_context *ctx,
unsigned char output[16] )
{
int i;
- uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3;
-
- RK = ctx->rk;
+ uint32_t *RK = ctx->rk;
+ struct
+ {
+ uint32_t X[4];
+ uint32_t Y[4];
+ } t;
- GET_UINT32_LE( X0, input, 0 ); X0 ^= *RK++;
- GET_UINT32_LE( X1, input, 4 ); X1 ^= *RK++;
- GET_UINT32_LE( X2, input, 8 ); X2 ^= *RK++;
- GET_UINT32_LE( X3, input, 12 ); X3 ^= *RK++;
+ GET_UINT32_LE( t.X[0], input, 0 ); t.X[0] ^= *RK++;
+ GET_UINT32_LE( t.X[1], input, 4 ); t.X[1] ^= *RK++;
+ GET_UINT32_LE( t.X[2], input, 8 ); t.X[2] ^= *RK++;
+ GET_UINT32_LE( t.X[3], input, 12 ); t.X[3] ^= *RK++;
for( i = ( ctx->nr >> 1 ) - 1; i > 0; i-- )
{
- AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );
- AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 );
+ AES_RROUND( t.Y[0], t.Y[1], t.Y[2], t.Y[3], t.X[0], t.X[1], t.X[2], t.X[3] );
+ AES_RROUND( t.X[0], t.X[1], t.X[2], t.X[3], t.Y[0], t.Y[1], t.Y[2], t.Y[3] );
}
- AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );
-
- X0 = *RK++ ^ \
- ( (uint32_t) RSb[ ( Y0 ) & 0xFF ] ) ^
- ( (uint32_t) RSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^
- ( (uint32_t) RSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^
- ( (uint32_t) RSb[ ( Y1 >> 24 ) & 0xFF ] << 24 );
-
- X1 = *RK++ ^ \
- ( (uint32_t) RSb[ ( Y1 ) & 0xFF ] ) ^
- ( (uint32_t) RSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^
- ( (uint32_t) RSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^
- ( (uint32_t) RSb[ ( Y2 >> 24 ) & 0xFF ] << 24 );
-
- X2 = *RK++ ^ \
- ( (uint32_t) RSb[ ( Y2 ) & 0xFF ] ) ^
- ( (uint32_t) RSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^
- ( (uint32_t) RSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^
- ( (uint32_t) RSb[ ( Y3 >> 24 ) & 0xFF ] << 24 );
-
- X3 = *RK++ ^ \
- ( (uint32_t) RSb[ ( Y3 ) & 0xFF ] ) ^
- ( (uint32_t) RSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^
- ( (uint32_t) RSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^
- ( (uint32_t) RSb[ ( Y0 >> 24 ) & 0xFF ] << 24 );
-
- PUT_UINT32_LE( X0, output, 0 );
- PUT_UINT32_LE( X1, output, 4 );
- PUT_UINT32_LE( X2, output, 8 );
- PUT_UINT32_LE( X3, output, 12 );
-
- mbedtls_platform_zeroize( &X0, sizeof( X0 ) );
- mbedtls_platform_zeroize( &X1, sizeof( X1 ) );
- mbedtls_platform_zeroize( &X2, sizeof( X2 ) );
- mbedtls_platform_zeroize( &X3, sizeof( X3 ) );
-
- mbedtls_platform_zeroize( &Y0, sizeof( Y0 ) );
- mbedtls_platform_zeroize( &Y1, sizeof( Y1 ) );
- mbedtls_platform_zeroize( &Y2, sizeof( Y2 ) );
- mbedtls_platform_zeroize( &Y3, sizeof( Y3 ) );
-
- mbedtls_platform_zeroize( &RK, sizeof( RK ) );
+ AES_RROUND( t.Y[0], t.Y[1], t.Y[2], t.Y[3], t.X[0], t.X[1], t.X[2], t.X[3] );
+
+ t.X[0] = *RK++ ^ \
+ ( (uint32_t) RSb[ ( t.Y[0] ) & 0xFF ] ) ^
+ ( (uint32_t) RSb[ ( t.Y[3] >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) RSb[ ( t.Y[2] >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) RSb[ ( t.Y[1] >> 24 ) & 0xFF ] << 24 );
+
+ t.X[1] = *RK++ ^ \
+ ( (uint32_t) RSb[ ( t.Y[1] ) & 0xFF ] ) ^
+ ( (uint32_t) RSb[ ( t.Y[0] >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) RSb[ ( t.Y[3] >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) RSb[ ( t.Y[2] >> 24 ) & 0xFF ] << 24 );
+
+ t.X[2] = *RK++ ^ \
+ ( (uint32_t) RSb[ ( t.Y[2] ) & 0xFF ] ) ^
+ ( (uint32_t) RSb[ ( t.Y[1] >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) RSb[ ( t.Y[0] >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) RSb[ ( t.Y[3] >> 24 ) & 0xFF ] << 24 );
+
+ t.X[3] = *RK++ ^ \
+ ( (uint32_t) RSb[ ( t.Y[3] ) & 0xFF ] ) ^
+ ( (uint32_t) RSb[ ( t.Y[2] >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) RSb[ ( t.Y[1] >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) RSb[ ( t.Y[0] >> 24 ) & 0xFF ] << 24 );
+
+ PUT_UINT32_LE( t.X[0], output, 0 );
+ PUT_UINT32_LE( t.X[1], output, 4 );
+ PUT_UINT32_LE( t.X[2], output, 8 );
+ PUT_UINT32_LE( t.X[3], output, 12 );
+
+ mbedtls_platform_zeroize( &t, sizeof( t ) );
return( 0 );
}
diff --git a/thirdparty/mbedtls/library/bignum.c b/thirdparty/mbedtls/library/bignum.c
index dfe976d648..2feb727d89 100644
--- a/thirdparty/mbedtls/library/bignum.c
+++ b/thirdparty/mbedtls/library/bignum.c
@@ -1364,7 +1364,10 @@ int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi
/* If we ran out of space for the carry, it means that the result
* is negative. */
if( n == X->n )
- return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
+ {
+ ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
+ goto cleanup;
+ }
--X->p[n];
}
@@ -2044,7 +2047,7 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A,
size_t i, j, nblimbs;
size_t bufsize, nbits;
mbedtls_mpi_uint ei, mm, state;
- mbedtls_mpi RR, T, W[ 2 << MBEDTLS_MPI_WINDOW_SIZE ], Apos;
+ mbedtls_mpi RR, T, W[ 1 << MBEDTLS_MPI_WINDOW_SIZE ], Apos;
int neg;
MPI_VALIDATE_RET( X != NULL );
@@ -2058,6 +2061,10 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A,
if( mbedtls_mpi_cmp_int( E, 0 ) < 0 )
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+ if( mbedtls_mpi_bitlen( E ) > MBEDTLS_MPI_MAX_BITS ||
+ mbedtls_mpi_bitlen( N ) > MBEDTLS_MPI_MAX_BITS )
+ return ( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+
/*
* Init temps and window size
*/
@@ -2334,7 +2341,7 @@ int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size,
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
Xp = (unsigned char*) X->p;
- f_rng( p_rng, Xp + overhead, size );
+ MBEDTLS_MPI_CHK( f_rng( p_rng, Xp + overhead, size ) );
mpi_bigendian_to_host( X->p, limbs );
diff --git a/thirdparty/mbedtls/library/cipher_wrap.c b/thirdparty/mbedtls/library/cipher_wrap.c
index 1dcac21be1..5973ca6ba2 100644
--- a/thirdparty/mbedtls/library/cipher_wrap.c
+++ b/thirdparty/mbedtls/library/cipher_wrap.c
@@ -779,7 +779,7 @@ static const mbedtls_cipher_info_t camellia_128_ecb_info = {
MBEDTLS_MODE_ECB,
128,
"CAMELLIA-128-ECB",
- 16,
+ 0,
0,
16,
&camellia_info
@@ -790,7 +790,7 @@ static const mbedtls_cipher_info_t camellia_192_ecb_info = {
MBEDTLS_MODE_ECB,
192,
"CAMELLIA-192-ECB",
- 16,
+ 0,
0,
16,
&camellia_info
@@ -801,7 +801,7 @@ static const mbedtls_cipher_info_t camellia_256_ecb_info = {
MBEDTLS_MODE_ECB,
256,
"CAMELLIA-256-ECB",
- 16,
+ 0,
0,
16,
&camellia_info
@@ -1155,7 +1155,7 @@ static const mbedtls_cipher_info_t aria_128_ecb_info = {
MBEDTLS_MODE_ECB,
128,
"ARIA-128-ECB",
- 16,
+ 0,
0,
16,
&aria_info
@@ -1166,7 +1166,7 @@ static const mbedtls_cipher_info_t aria_192_ecb_info = {
MBEDTLS_MODE_ECB,
192,
"ARIA-192-ECB",
- 16,
+ 0,
0,
16,
&aria_info
@@ -1177,7 +1177,7 @@ static const mbedtls_cipher_info_t aria_256_ecb_info = {
MBEDTLS_MODE_ECB,
256,
"ARIA-256-ECB",
- 16,
+ 0,
0,
16,
&aria_info
@@ -1579,7 +1579,7 @@ static const mbedtls_cipher_info_t des_ecb_info = {
MBEDTLS_MODE_ECB,
MBEDTLS_KEY_LENGTH_DES,
"DES-ECB",
- 8,
+ 0,
0,
8,
&des_info
@@ -1630,7 +1630,7 @@ static const mbedtls_cipher_info_t des_ede_ecb_info = {
MBEDTLS_MODE_ECB,
MBEDTLS_KEY_LENGTH_DES_EDE,
"DES-EDE-ECB",
- 8,
+ 0,
0,
8,
&des_ede_info
@@ -1681,7 +1681,7 @@ static const mbedtls_cipher_info_t des_ede3_ecb_info = {
MBEDTLS_MODE_ECB,
MBEDTLS_KEY_LENGTH_DES_EDE3,
"DES-EDE3-ECB",
- 8,
+ 0,
0,
8,
&des_ede3_info
@@ -1796,7 +1796,7 @@ static const mbedtls_cipher_info_t blowfish_ecb_info = {
MBEDTLS_MODE_ECB,
128,
"BLOWFISH-ECB",
- 8,
+ 0,
MBEDTLS_CIPHER_VARIABLE_KEY_LEN,
8,
&blowfish_info
diff --git a/thirdparty/mbedtls/library/cmac.c b/thirdparty/mbedtls/library/cmac.c
index 1a1200b52b..409f67958e 100644
--- a/thirdparty/mbedtls/library/cmac.c
+++ b/thirdparty/mbedtls/library/cmac.c
@@ -450,7 +450,7 @@ exit:
*/
int mbedtls_aes_cmac_prf_128( const unsigned char *key, size_t key_length,
const unsigned char *input, size_t in_len,
- unsigned char *output )
+ unsigned char output[16] )
{
int ret;
const mbedtls_cipher_info_t *cipher_info;
diff --git a/thirdparty/mbedtls/library/ctr_drbg.c b/thirdparty/mbedtls/library/ctr_drbg.c
index b98df29a9b..e92008bbe8 100644
--- a/thirdparty/mbedtls/library/ctr_drbg.c
+++ b/thirdparty/mbedtls/library/ctr_drbg.c
@@ -82,11 +82,17 @@ void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_ctr_drbg_context ) );
+ ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
+
#if defined(MBEDTLS_THREADING_C)
mbedtls_mutex_init( &ctx->mutex );
#endif
}
+/*
+ * This function resets CTR_DRBG context to the state immediately
+ * after initial call of mbedtls_ctr_drbg_init().
+ */
void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx )
{
if( ctx == NULL )
@@ -97,6 +103,10 @@ void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx )
#endif
mbedtls_aes_free( &ctx->aes_ctx );
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ctr_drbg_context ) );
+ ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_init( &ctx->mutex );
+#endif
}
void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx, int resistance )
@@ -419,7 +429,6 @@ int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx,
if( ctx->entropy_len == 0 )
ctx->entropy_len = MBEDTLS_CTR_DRBG_ENTROPY_LEN;
- ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
/*
* Initialize with an empty key
diff --git a/thirdparty/mbedtls/library/ecp_curves.c b/thirdparty/mbedtls/library/ecp_curves.c
index cc4c5b71c0..b04596b561 100644
--- a/thirdparty/mbedtls/library/ecp_curves.c
+++ b/thirdparty/mbedtls/library/ecp_curves.c
@@ -1044,7 +1044,7 @@ static inline void sub32( uint32_t *dst, uint32_t src, signed char *carry )
STORE32; i++; \
cur = c > 0 ? c : 0; STORE32; \
cur = 0; while( ++i < MAX32 ) { STORE32; } \
- if( c < 0 ) fix_negative( N, c, &C, bits );
+ if( c < 0 ) MBEDTLS_MPI_CHK( fix_negative( N, c, &C, bits ) );
/*
* If the result is negative, we get it in the form
diff --git a/thirdparty/mbedtls/library/entropy_poll.c b/thirdparty/mbedtls/library/entropy_poll.c
index 26b7e4e2b9..2095a7dd34 100644
--- a/thirdparty/mbedtls/library/entropy_poll.c
+++ b/thirdparty/mbedtls/library/entropy_poll.c
@@ -44,7 +44,7 @@
* **********
*/
-#if defined(__linux__)
+#if defined(__linux__) && !defined(_GNU_SOURCE)
/* Ensure that syscall() is available even when compiling with -std=c99 */
#define _GNU_SOURCE
#endif
diff --git a/thirdparty/mbedtls/library/error.c b/thirdparty/mbedtls/library/error.c
index eb52052b51..b83b8d1f1b 100644
--- a/thirdparty/mbedtls/library/error.c
+++ b/thirdparty/mbedtls/library/error.c
@@ -51,20 +51,19 @@
#endif
#if defined(MBEDTLS_ERROR_C) || defined(MBEDTLS_ERROR_STRERROR_DUMMY)
+
#include "mbedtls/error.h"
-#include <string.h>
-#endif
+
+#if defined(MBEDTLS_ERROR_C)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#define mbedtls_snprintf snprintf
-#define mbedtls_time_t time_t
#endif
-#if defined(MBEDTLS_ERROR_C)
-
#include <stdio.h>
+#include <string.h>
#if defined(MBEDTLS_AES_C)
#include "mbedtls/aes.h"
@@ -929,8 +928,6 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
#else /* MBEDTLS_ERROR_C */
-#if defined(MBEDTLS_ERROR_STRERROR_DUMMY)
-
/*
* Provide an non-function in case MBEDTLS_ERROR_C is not defined
*/
@@ -942,6 +939,6 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
buf[0] = '\0';
}
-#endif /* MBEDTLS_ERROR_STRERROR_DUMMY */
-
#endif /* MBEDTLS_ERROR_C */
+
+#endif /* MBEDTLS_ERROR_C || MBEDTLS_ERROR_STRERROR_DUMMY */
diff --git a/thirdparty/mbedtls/library/hmac_drbg.c b/thirdparty/mbedtls/library/hmac_drbg.c
index 9fbfc30660..10cbd462ba 100644
--- a/thirdparty/mbedtls/library/hmac_drbg.c
+++ b/thirdparty/mbedtls/library/hmac_drbg.c
@@ -83,6 +83,8 @@ void mbedtls_hmac_drbg_init( mbedtls_hmac_drbg_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_hmac_drbg_context ) );
+ ctx->reseed_interval = MBEDTLS_HMAC_DRBG_RESEED_INTERVAL;
+
#if defined(MBEDTLS_THREADING_C)
mbedtls_mutex_init( &ctx->mutex );
#endif
@@ -296,8 +298,6 @@ int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx,
ctx->f_entropy = f_entropy;
ctx->p_entropy = p_entropy;
- ctx->reseed_interval = MBEDTLS_HMAC_DRBG_RESEED_INTERVAL;
-
if( ctx->entropy_len == 0 )
{
/*
@@ -442,7 +442,8 @@ int mbedtls_hmac_drbg_random( void *p_rng, unsigned char *output, size_t out_len
}
/*
- * Free an HMAC_DRBG context
+ * This function resets HMAC_DRBG context to the state immediately
+ * after initial call of mbedtls_hmac_drbg_init().
*/
void mbedtls_hmac_drbg_free( mbedtls_hmac_drbg_context *ctx )
{
@@ -454,6 +455,10 @@ void mbedtls_hmac_drbg_free( mbedtls_hmac_drbg_context *ctx )
#endif
mbedtls_md_free( &ctx->md_ctx );
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_hmac_drbg_context ) );
+ ctx->reseed_interval = MBEDTLS_HMAC_DRBG_RESEED_INTERVAL;
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_init( &ctx->mutex );
+#endif
}
#if defined(MBEDTLS_FS_IO)
diff --git a/thirdparty/mbedtls/library/md2.c b/thirdparty/mbedtls/library/md2.c
index cbdaaabdc7..fdcb630a1f 100644
--- a/thirdparty/mbedtls/library/md2.c
+++ b/thirdparty/mbedtls/library/md2.c
@@ -177,6 +177,9 @@ int mbedtls_internal_md2_process( mbedtls_md2_context *ctx )
t = ctx->cksum[i];
}
+ /* Zeroise variables to clear sensitive data from memory. */
+ mbedtls_platform_zeroize( &t, sizeof( t ) );
+
return( 0 );
}
diff --git a/thirdparty/mbedtls/library/md4.c b/thirdparty/mbedtls/library/md4.c
index cb16dce54a..95e893e654 100644
--- a/thirdparty/mbedtls/library/md4.c
+++ b/thirdparty/mbedtls/library/md4.c
@@ -143,31 +143,34 @@ void mbedtls_md4_starts( mbedtls_md4_context *ctx )
int mbedtls_internal_md4_process( mbedtls_md4_context *ctx,
const unsigned char data[64] )
{
- uint32_t X[16], A, B, C, D;
-
- GET_UINT32_LE( X[ 0], data, 0 );
- GET_UINT32_LE( X[ 1], data, 4 );
- GET_UINT32_LE( X[ 2], data, 8 );
- GET_UINT32_LE( X[ 3], data, 12 );
- GET_UINT32_LE( X[ 4], data, 16 );
- GET_UINT32_LE( X[ 5], data, 20 );
- GET_UINT32_LE( X[ 6], data, 24 );
- GET_UINT32_LE( X[ 7], data, 28 );
- GET_UINT32_LE( X[ 8], data, 32 );
- GET_UINT32_LE( X[ 9], data, 36 );
- GET_UINT32_LE( X[10], data, 40 );
- GET_UINT32_LE( X[11], data, 44 );
- GET_UINT32_LE( X[12], data, 48 );
- GET_UINT32_LE( X[13], data, 52 );
- GET_UINT32_LE( X[14], data, 56 );
- GET_UINT32_LE( X[15], data, 60 );
+ struct
+ {
+ uint32_t X[16], A, B, C, D;
+ } local;
+
+ GET_UINT32_LE( local.X[ 0], data, 0 );
+ GET_UINT32_LE( local.X[ 1], data, 4 );
+ GET_UINT32_LE( local.X[ 2], data, 8 );
+ GET_UINT32_LE( local.X[ 3], data, 12 );
+ GET_UINT32_LE( local.X[ 4], data, 16 );
+ GET_UINT32_LE( local.X[ 5], data, 20 );
+ GET_UINT32_LE( local.X[ 6], data, 24 );
+ GET_UINT32_LE( local.X[ 7], data, 28 );
+ GET_UINT32_LE( local.X[ 8], data, 32 );
+ GET_UINT32_LE( local.X[ 9], data, 36 );
+ GET_UINT32_LE( local.X[10], data, 40 );
+ GET_UINT32_LE( local.X[11], data, 44 );
+ GET_UINT32_LE( local.X[12], data, 48 );
+ GET_UINT32_LE( local.X[13], data, 52 );
+ GET_UINT32_LE( local.X[14], data, 56 );
+ GET_UINT32_LE( local.X[15], data, 60 );
#define S(x,n) (((x) << (n)) | (((x) & 0xFFFFFFFF) >> (32 - (n))))
- A = ctx->state[0];
- B = ctx->state[1];
- C = ctx->state[2];
- D = ctx->state[3];
+ local.A = ctx->state[0];
+ local.B = ctx->state[1];
+ local.C = ctx->state[2];
+ local.D = ctx->state[3];
#define F(x, y, z) (((x) & (y)) | ((~(x)) & (z)))
#define P(a,b,c,d,x,s) \
@@ -178,22 +181,22 @@ int mbedtls_internal_md4_process( mbedtls_md4_context *ctx,
} while( 0 )
- P( A, B, C, D, X[ 0], 3 );
- P( D, A, B, C, X[ 1], 7 );
- P( C, D, A, B, X[ 2], 11 );
- P( B, C, D, A, X[ 3], 19 );
- P( A, B, C, D, X[ 4], 3 );
- P( D, A, B, C, X[ 5], 7 );
- P( C, D, A, B, X[ 6], 11 );
- P( B, C, D, A, X[ 7], 19 );
- P( A, B, C, D, X[ 8], 3 );
- P( D, A, B, C, X[ 9], 7 );
- P( C, D, A, B, X[10], 11 );
- P( B, C, D, A, X[11], 19 );
- P( A, B, C, D, X[12], 3 );
- P( D, A, B, C, X[13], 7 );
- P( C, D, A, B, X[14], 11 );
- P( B, C, D, A, X[15], 19 );
+ P( local.A, local.B, local.C, local.D, local.X[ 0], 3 );
+ P( local.D, local.A, local.B, local.C, local.X[ 1], 7 );
+ P( local.C, local.D, local.A, local.B, local.X[ 2], 11 );
+ P( local.B, local.C, local.D, local.A, local.X[ 3], 19 );
+ P( local.A, local.B, local.C, local.D, local.X[ 4], 3 );
+ P( local.D, local.A, local.B, local.C, local.X[ 5], 7 );
+ P( local.C, local.D, local.A, local.B, local.X[ 6], 11 );
+ P( local.B, local.C, local.D, local.A, local.X[ 7], 19 );
+ P( local.A, local.B, local.C, local.D, local.X[ 8], 3 );
+ P( local.D, local.A, local.B, local.C, local.X[ 9], 7 );
+ P( local.C, local.D, local.A, local.B, local.X[10], 11 );
+ P( local.B, local.C, local.D, local.A, local.X[11], 19 );
+ P( local.A, local.B, local.C, local.D, local.X[12], 3 );
+ P( local.D, local.A, local.B, local.C, local.X[13], 7 );
+ P( local.C, local.D, local.A, local.B, local.X[14], 11 );
+ P( local.B, local.C, local.D, local.A, local.X[15], 19 );
#undef P
#undef F
@@ -206,22 +209,22 @@ int mbedtls_internal_md4_process( mbedtls_md4_context *ctx,
(a) = S((a),(s)); \
} while( 0 )
- P( A, B, C, D, X[ 0], 3 );
- P( D, A, B, C, X[ 4], 5 );
- P( C, D, A, B, X[ 8], 9 );
- P( B, C, D, A, X[12], 13 );
- P( A, B, C, D, X[ 1], 3 );
- P( D, A, B, C, X[ 5], 5 );
- P( C, D, A, B, X[ 9], 9 );
- P( B, C, D, A, X[13], 13 );
- P( A, B, C, D, X[ 2], 3 );
- P( D, A, B, C, X[ 6], 5 );
- P( C, D, A, B, X[10], 9 );
- P( B, C, D, A, X[14], 13 );
- P( A, B, C, D, X[ 3], 3 );
- P( D, A, B, C, X[ 7], 5 );
- P( C, D, A, B, X[11], 9 );
- P( B, C, D, A, X[15], 13 );
+ P( local.A, local.B, local.C, local.D, local.X[ 0], 3 );
+ P( local.D, local.A, local.B, local.C, local.X[ 4], 5 );
+ P( local.C, local.D, local.A, local.B, local.X[ 8], 9 );
+ P( local.B, local.C, local.D, local.A, local.X[12], 13 );
+ P( local.A, local.B, local.C, local.D, local.X[ 1], 3 );
+ P( local.D, local.A, local.B, local.C, local.X[ 5], 5 );
+ P( local.C, local.D, local.A, local.B, local.X[ 9], 9 );
+ P( local.B, local.C, local.D, local.A, local.X[13], 13 );
+ P( local.A, local.B, local.C, local.D, local.X[ 2], 3 );
+ P( local.D, local.A, local.B, local.C, local.X[ 6], 5 );
+ P( local.C, local.D, local.A, local.B, local.X[10], 9 );
+ P( local.B, local.C, local.D, local.A, local.X[14], 13 );
+ P( local.A, local.B, local.C, local.D, local.X[ 3], 3 );
+ P( local.D, local.A, local.B, local.C, local.X[ 7], 5 );
+ P( local.C, local.D, local.A, local.B, local.X[11], 9 );
+ P( local.B, local.C, local.D, local.A, local.X[15], 13 );
#undef P
#undef F
@@ -234,30 +237,33 @@ int mbedtls_internal_md4_process( mbedtls_md4_context *ctx,
(a) = S((a),(s)); \
} while( 0 )
- P( A, B, C, D, X[ 0], 3 );
- P( D, A, B, C, X[ 8], 9 );
- P( C, D, A, B, X[ 4], 11 );
- P( B, C, D, A, X[12], 15 );
- P( A, B, C, D, X[ 2], 3 );
- P( D, A, B, C, X[10], 9 );
- P( C, D, A, B, X[ 6], 11 );
- P( B, C, D, A, X[14], 15 );
- P( A, B, C, D, X[ 1], 3 );
- P( D, A, B, C, X[ 9], 9 );
- P( C, D, A, B, X[ 5], 11 );
- P( B, C, D, A, X[13], 15 );
- P( A, B, C, D, X[ 3], 3 );
- P( D, A, B, C, X[11], 9 );
- P( C, D, A, B, X[ 7], 11 );
- P( B, C, D, A, X[15], 15 );
+ P( local.A, local.B, local.C, local.D, local.X[ 0], 3 );
+ P( local.D, local.A, local.B, local.C, local.X[ 8], 9 );
+ P( local.C, local.D, local.A, local.B, local.X[ 4], 11 );
+ P( local.B, local.C, local.D, local.A, local.X[12], 15 );
+ P( local.A, local.B, local.C, local.D, local.X[ 2], 3 );
+ P( local.D, local.A, local.B, local.C, local.X[10], 9 );
+ P( local.C, local.D, local.A, local.B, local.X[ 6], 11 );
+ P( local.B, local.C, local.D, local.A, local.X[14], 15 );
+ P( local.A, local.B, local.C, local.D, local.X[ 1], 3 );
+ P( local.D, local.A, local.B, local.C, local.X[ 9], 9 );
+ P( local.C, local.D, local.A, local.B, local.X[ 5], 11 );
+ P( local.B, local.C, local.D, local.A, local.X[13], 15 );
+ P( local.A, local.B, local.C, local.D, local.X[ 3], 3 );
+ P( local.D, local.A, local.B, local.C, local.X[11], 9 );
+ P( local.C, local.D, local.A, local.B, local.X[ 7], 11 );
+ P( local.B, local.C, local.D, local.A, local.X[15], 15 );
#undef F
#undef P
- ctx->state[0] += A;
- ctx->state[1] += B;
- ctx->state[2] += C;
- ctx->state[3] += D;
+ ctx->state[0] += local.A;
+ ctx->state[1] += local.B;
+ ctx->state[2] += local.C;
+ ctx->state[3] += local.D;
+
+ /* Zeroise variables to clear sensitive data from memory. */
+ mbedtls_platform_zeroize( &local, sizeof( local ) );
return( 0 );
}
diff --git a/thirdparty/mbedtls/library/md5.c b/thirdparty/mbedtls/library/md5.c
index fe25925214..d2b634fbb1 100644
--- a/thirdparty/mbedtls/library/md5.c
+++ b/thirdparty/mbedtls/library/md5.c
@@ -142,128 +142,134 @@ void mbedtls_md5_starts( mbedtls_md5_context *ctx )
int mbedtls_internal_md5_process( mbedtls_md5_context *ctx,
const unsigned char data[64] )
{
- uint32_t X[16], A, B, C, D;
-
- GET_UINT32_LE( X[ 0], data, 0 );
- GET_UINT32_LE( X[ 1], data, 4 );
- GET_UINT32_LE( X[ 2], data, 8 );
- GET_UINT32_LE( X[ 3], data, 12 );
- GET_UINT32_LE( X[ 4], data, 16 );
- GET_UINT32_LE( X[ 5], data, 20 );
- GET_UINT32_LE( X[ 6], data, 24 );
- GET_UINT32_LE( X[ 7], data, 28 );
- GET_UINT32_LE( X[ 8], data, 32 );
- GET_UINT32_LE( X[ 9], data, 36 );
- GET_UINT32_LE( X[10], data, 40 );
- GET_UINT32_LE( X[11], data, 44 );
- GET_UINT32_LE( X[12], data, 48 );
- GET_UINT32_LE( X[13], data, 52 );
- GET_UINT32_LE( X[14], data, 56 );
- GET_UINT32_LE( X[15], data, 60 );
+ struct
+ {
+ uint32_t X[16], A, B, C, D;
+ } local;
+
+ GET_UINT32_LE( local.X[ 0], data, 0 );
+ GET_UINT32_LE( local.X[ 1], data, 4 );
+ GET_UINT32_LE( local.X[ 2], data, 8 );
+ GET_UINT32_LE( local.X[ 3], data, 12 );
+ GET_UINT32_LE( local.X[ 4], data, 16 );
+ GET_UINT32_LE( local.X[ 5], data, 20 );
+ GET_UINT32_LE( local.X[ 6], data, 24 );
+ GET_UINT32_LE( local.X[ 7], data, 28 );
+ GET_UINT32_LE( local.X[ 8], data, 32 );
+ GET_UINT32_LE( local.X[ 9], data, 36 );
+ GET_UINT32_LE( local.X[10], data, 40 );
+ GET_UINT32_LE( local.X[11], data, 44 );
+ GET_UINT32_LE( local.X[12], data, 48 );
+ GET_UINT32_LE( local.X[13], data, 52 );
+ GET_UINT32_LE( local.X[14], data, 56 );
+ GET_UINT32_LE( local.X[15], data, 60 );
#define S(x,n) \
( ( (x) << (n) ) | ( ( (x) & 0xFFFFFFFF) >> ( 32 - (n) ) ) )
-#define P(a,b,c,d,k,s,t) \
- do \
- { \
- (a) += F((b),(c),(d)) + X[(k)] + (t); \
- (a) = S((a),(s)) + (b); \
+#define P(a,b,c,d,k,s,t) \
+ do \
+ { \
+ (a) += F((b),(c),(d)) + local.X[(k)] + (t); \
+ (a) = S((a),(s)) + (b); \
} while( 0 )
- A = ctx->state[0];
- B = ctx->state[1];
- C = ctx->state[2];
- D = ctx->state[3];
+ local.A = ctx->state[0];
+ local.B = ctx->state[1];
+ local.C = ctx->state[2];
+ local.D = ctx->state[3];
#define F(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
- P( A, B, C, D, 0, 7, 0xD76AA478 );
- P( D, A, B, C, 1, 12, 0xE8C7B756 );
- P( C, D, A, B, 2, 17, 0x242070DB );
- P( B, C, D, A, 3, 22, 0xC1BDCEEE );
- P( A, B, C, D, 4, 7, 0xF57C0FAF );
- P( D, A, B, C, 5, 12, 0x4787C62A );
- P( C, D, A, B, 6, 17, 0xA8304613 );
- P( B, C, D, A, 7, 22, 0xFD469501 );
- P( A, B, C, D, 8, 7, 0x698098D8 );
- P( D, A, B, C, 9, 12, 0x8B44F7AF );
- P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
- P( B, C, D, A, 11, 22, 0x895CD7BE );
- P( A, B, C, D, 12, 7, 0x6B901122 );
- P( D, A, B, C, 13, 12, 0xFD987193 );
- P( C, D, A, B, 14, 17, 0xA679438E );
- P( B, C, D, A, 15, 22, 0x49B40821 );
+ P( local.A, local.B, local.C, local.D, 0, 7, 0xD76AA478 );
+ P( local.D, local.A, local.B, local.C, 1, 12, 0xE8C7B756 );
+ P( local.C, local.D, local.A, local.B, 2, 17, 0x242070DB );
+ P( local.B, local.C, local.D, local.A, 3, 22, 0xC1BDCEEE );
+ P( local.A, local.B, local.C, local.D, 4, 7, 0xF57C0FAF );
+ P( local.D, local.A, local.B, local.C, 5, 12, 0x4787C62A );
+ P( local.C, local.D, local.A, local.B, 6, 17, 0xA8304613 );
+ P( local.B, local.C, local.D, local.A, 7, 22, 0xFD469501 );
+ P( local.A, local.B, local.C, local.D, 8, 7, 0x698098D8 );
+ P( local.D, local.A, local.B, local.C, 9, 12, 0x8B44F7AF );
+ P( local.C, local.D, local.A, local.B, 10, 17, 0xFFFF5BB1 );
+ P( local.B, local.C, local.D, local.A, 11, 22, 0x895CD7BE );
+ P( local.A, local.B, local.C, local.D, 12, 7, 0x6B901122 );
+ P( local.D, local.A, local.B, local.C, 13, 12, 0xFD987193 );
+ P( local.C, local.D, local.A, local.B, 14, 17, 0xA679438E );
+ P( local.B, local.C, local.D, local.A, 15, 22, 0x49B40821 );
#undef F
#define F(x,y,z) ((y) ^ ((z) & ((x) ^ (y))))
- P( A, B, C, D, 1, 5, 0xF61E2562 );
- P( D, A, B, C, 6, 9, 0xC040B340 );
- P( C, D, A, B, 11, 14, 0x265E5A51 );
- P( B, C, D, A, 0, 20, 0xE9B6C7AA );
- P( A, B, C, D, 5, 5, 0xD62F105D );
- P( D, A, B, C, 10, 9, 0x02441453 );
- P( C, D, A, B, 15, 14, 0xD8A1E681 );
- P( B, C, D, A, 4, 20, 0xE7D3FBC8 );
- P( A, B, C, D, 9, 5, 0x21E1CDE6 );
- P( D, A, B, C, 14, 9, 0xC33707D6 );
- P( C, D, A, B, 3, 14, 0xF4D50D87 );
- P( B, C, D, A, 8, 20, 0x455A14ED );
- P( A, B, C, D, 13, 5, 0xA9E3E905 );
- P( D, A, B, C, 2, 9, 0xFCEFA3F8 );
- P( C, D, A, B, 7, 14, 0x676F02D9 );
- P( B, C, D, A, 12, 20, 0x8D2A4C8A );
+ P( local.A, local.B, local.C, local.D, 1, 5, 0xF61E2562 );
+ P( local.D, local.A, local.B, local.C, 6, 9, 0xC040B340 );
+ P( local.C, local.D, local.A, local.B, 11, 14, 0x265E5A51 );
+ P( local.B, local.C, local.D, local.A, 0, 20, 0xE9B6C7AA );
+ P( local.A, local.B, local.C, local.D, 5, 5, 0xD62F105D );
+ P( local.D, local.A, local.B, local.C, 10, 9, 0x02441453 );
+ P( local.C, local.D, local.A, local.B, 15, 14, 0xD8A1E681 );
+ P( local.B, local.C, local.D, local.A, 4, 20, 0xE7D3FBC8 );
+ P( local.A, local.B, local.C, local.D, 9, 5, 0x21E1CDE6 );
+ P( local.D, local.A, local.B, local.C, 14, 9, 0xC33707D6 );
+ P( local.C, local.D, local.A, local.B, 3, 14, 0xF4D50D87 );
+ P( local.B, local.C, local.D, local.A, 8, 20, 0x455A14ED );
+ P( local.A, local.B, local.C, local.D, 13, 5, 0xA9E3E905 );
+ P( local.D, local.A, local.B, local.C, 2, 9, 0xFCEFA3F8 );
+ P( local.C, local.D, local.A, local.B, 7, 14, 0x676F02D9 );
+ P( local.B, local.C, local.D, local.A, 12, 20, 0x8D2A4C8A );
#undef F
#define F(x,y,z) ((x) ^ (y) ^ (z))
- P( A, B, C, D, 5, 4, 0xFFFA3942 );
- P( D, A, B, C, 8, 11, 0x8771F681 );
- P( C, D, A, B, 11, 16, 0x6D9D6122 );
- P( B, C, D, A, 14, 23, 0xFDE5380C );
- P( A, B, C, D, 1, 4, 0xA4BEEA44 );
- P( D, A, B, C, 4, 11, 0x4BDECFA9 );
- P( C, D, A, B, 7, 16, 0xF6BB4B60 );
- P( B, C, D, A, 10, 23, 0xBEBFBC70 );
- P( A, B, C, D, 13, 4, 0x289B7EC6 );
- P( D, A, B, C, 0, 11, 0xEAA127FA );
- P( C, D, A, B, 3, 16, 0xD4EF3085 );
- P( B, C, D, A, 6, 23, 0x04881D05 );
- P( A, B, C, D, 9, 4, 0xD9D4D039 );
- P( D, A, B, C, 12, 11, 0xE6DB99E5 );
- P( C, D, A, B, 15, 16, 0x1FA27CF8 );
- P( B, C, D, A, 2, 23, 0xC4AC5665 );
+ P( local.A, local.B, local.C, local.D, 5, 4, 0xFFFA3942 );
+ P( local.D, local.A, local.B, local.C, 8, 11, 0x8771F681 );
+ P( local.C, local.D, local.A, local.B, 11, 16, 0x6D9D6122 );
+ P( local.B, local.C, local.D, local.A, 14, 23, 0xFDE5380C );
+ P( local.A, local.B, local.C, local.D, 1, 4, 0xA4BEEA44 );
+ P( local.D, local.A, local.B, local.C, 4, 11, 0x4BDECFA9 );
+ P( local.C, local.D, local.A, local.B, 7, 16, 0xF6BB4B60 );
+ P( local.B, local.C, local.D, local.A, 10, 23, 0xBEBFBC70 );
+ P( local.A, local.B, local.C, local.D, 13, 4, 0x289B7EC6 );
+ P( local.D, local.A, local.B, local.C, 0, 11, 0xEAA127FA );
+ P( local.C, local.D, local.A, local.B, 3, 16, 0xD4EF3085 );
+ P( local.B, local.C, local.D, local.A, 6, 23, 0x04881D05 );
+ P( local.A, local.B, local.C, local.D, 9, 4, 0xD9D4D039 );
+ P( local.D, local.A, local.B, local.C, 12, 11, 0xE6DB99E5 );
+ P( local.C, local.D, local.A, local.B, 15, 16, 0x1FA27CF8 );
+ P( local.B, local.C, local.D, local.A, 2, 23, 0xC4AC5665 );
#undef F
#define F(x,y,z) ((y) ^ ((x) | ~(z)))
- P( A, B, C, D, 0, 6, 0xF4292244 );
- P( D, A, B, C, 7, 10, 0x432AFF97 );
- P( C, D, A, B, 14, 15, 0xAB9423A7 );
- P( B, C, D, A, 5, 21, 0xFC93A039 );
- P( A, B, C, D, 12, 6, 0x655B59C3 );
- P( D, A, B, C, 3, 10, 0x8F0CCC92 );
- P( C, D, A, B, 10, 15, 0xFFEFF47D );
- P( B, C, D, A, 1, 21, 0x85845DD1 );
- P( A, B, C, D, 8, 6, 0x6FA87E4F );
- P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
- P( C, D, A, B, 6, 15, 0xA3014314 );
- P( B, C, D, A, 13, 21, 0x4E0811A1 );
- P( A, B, C, D, 4, 6, 0xF7537E82 );
- P( D, A, B, C, 11, 10, 0xBD3AF235 );
- P( C, D, A, B, 2, 15, 0x2AD7D2BB );
- P( B, C, D, A, 9, 21, 0xEB86D391 );
+ P( local.A, local.B, local.C, local.D, 0, 6, 0xF4292244 );
+ P( local.D, local.A, local.B, local.C, 7, 10, 0x432AFF97 );
+ P( local.C, local.D, local.A, local.B, 14, 15, 0xAB9423A7 );
+ P( local.B, local.C, local.D, local.A, 5, 21, 0xFC93A039 );
+ P( local.A, local.B, local.C, local.D, 12, 6, 0x655B59C3 );
+ P( local.D, local.A, local.B, local.C, 3, 10, 0x8F0CCC92 );
+ P( local.C, local.D, local.A, local.B, 10, 15, 0xFFEFF47D );
+ P( local.B, local.C, local.D, local.A, 1, 21, 0x85845DD1 );
+ P( local.A, local.B, local.C, local.D, 8, 6, 0x6FA87E4F );
+ P( local.D, local.A, local.B, local.C, 15, 10, 0xFE2CE6E0 );
+ P( local.C, local.D, local.A, local.B, 6, 15, 0xA3014314 );
+ P( local.B, local.C, local.D, local.A, 13, 21, 0x4E0811A1 );
+ P( local.A, local.B, local.C, local.D, 4, 6, 0xF7537E82 );
+ P( local.D, local.A, local.B, local.C, 11, 10, 0xBD3AF235 );
+ P( local.C, local.D, local.A, local.B, 2, 15, 0x2AD7D2BB );
+ P( local.B, local.C, local.D, local.A, 9, 21, 0xEB86D391 );
#undef F
- ctx->state[0] += A;
- ctx->state[1] += B;
- ctx->state[2] += C;
- ctx->state[3] += D;
+ ctx->state[0] += local.A;
+ ctx->state[1] += local.B;
+ ctx->state[2] += local.C;
+ ctx->state[3] += local.D;
+
+ /* Zeroise variables to clear sensitive data from memory. */
+ mbedtls_platform_zeroize( &local, sizeof( local ) );
return( 0 );
}
diff --git a/thirdparty/mbedtls/library/pem.c b/thirdparty/mbedtls/library/pem.c
index a7a2f7f5cf..50e663ccdb 100644
--- a/thirdparty/mbedtls/library/pem.c
+++ b/thirdparty/mbedtls/library/pem.c
@@ -508,8 +508,12 @@ int mbedtls_pem_write_buffer( const char *header, const char *footer,
*p++ = '\0';
*olen = p - buf;
+ /* Clean any remaining data previously written to the buffer */
+ memset( buf + *olen, 0, buf_len - *olen );
+
mbedtls_free( encode_buf );
return( 0 );
}
#endif /* MBEDTLS_PEM_WRITE_C */
#endif /* MBEDTLS_PEM_PARSE_C || MBEDTLS_PEM_WRITE_C */
+
diff --git a/thirdparty/mbedtls/library/pkcs5.c b/thirdparty/mbedtls/library/pkcs5.c
index 8a80aa5d05..c4447f1546 100644
--- a/thirdparty/mbedtls/library/pkcs5.c
+++ b/thirdparty/mbedtls/library/pkcs5.c
@@ -247,7 +247,7 @@ int mbedtls_pkcs5_pbkdf2_hmac( mbedtls_md_context_t *ctx, const unsigned char *p
unsigned int iteration_count,
uint32_t key_length, unsigned char *output )
{
- int ret, j;
+ int ret = 0, j;
unsigned int i;
unsigned char md1[MBEDTLS_MD_MAX_SIZE];
unsigned char work[MBEDTLS_MD_MAX_SIZE];
@@ -269,16 +269,16 @@ int mbedtls_pkcs5_pbkdf2_hmac( mbedtls_md_context_t *ctx, const unsigned char *p
// U1 ends up in work
//
if( ( ret = mbedtls_md_hmac_starts( ctx, password, plen ) ) != 0 )
- return( ret );
+ goto cleanup;
if( ( ret = mbedtls_md_hmac_update( ctx, salt, slen ) ) != 0 )
- return( ret );
+ goto cleanup;
if( ( ret = mbedtls_md_hmac_update( ctx, counter, 4 ) ) != 0 )
- return( ret );
+ goto cleanup;
if( ( ret = mbedtls_md_hmac_finish( ctx, work ) ) != 0 )
- return( ret );
+ goto cleanup;
memcpy( md1, work, md_size );
@@ -287,13 +287,13 @@ int mbedtls_pkcs5_pbkdf2_hmac( mbedtls_md_context_t *ctx, const unsigned char *p
// U2 ends up in md1
//
if( ( ret = mbedtls_md_hmac_starts( ctx, password, plen ) ) != 0 )
- return( ret );
+ goto cleanup;
if( ( ret = mbedtls_md_hmac_update( ctx, md1, md_size ) ) != 0 )
- return( ret );
+ goto cleanup;
if( ( ret = mbedtls_md_hmac_finish( ctx, md1 ) ) != 0 )
- return( ret );
+ goto cleanup;
// U1 xor U2
//
@@ -312,7 +312,12 @@ int mbedtls_pkcs5_pbkdf2_hmac( mbedtls_md_context_t *ctx, const unsigned char *p
break;
}
- return( 0 );
+cleanup:
+ /* Zeroise buffers to clear sensitive data from memory. */
+ mbedtls_platform_zeroize( work, MBEDTLS_MD_MAX_SIZE );
+ mbedtls_platform_zeroize( md1, MBEDTLS_MD_MAX_SIZE );
+
+ return( ret );
}
#if defined(MBEDTLS_SELF_TEST)
diff --git a/thirdparty/mbedtls/library/pkparse.c b/thirdparty/mbedtls/library/pkparse.c
index 086807d836..e410f3aae1 100644
--- a/thirdparty/mbedtls/library/pkparse.c
+++ b/thirdparty/mbedtls/library/pkparse.c
@@ -692,7 +692,7 @@ int mbedtls_pk_parse_subpubkey( unsigned char **p, const unsigned char *end,
ret = MBEDTLS_ERR_PK_UNKNOWN_PK_ALG;
if( ret == 0 && *p != end )
- ret = MBEDTLS_ERR_PK_INVALID_PUBKEY
+ ret = MBEDTLS_ERR_PK_INVALID_PUBKEY +
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
if( ret != 0 )
diff --git a/thirdparty/mbedtls/library/platform_util.c b/thirdparty/mbedtls/library/platform_util.c
index 3ba2aead12..c8cd52d52a 100644
--- a/thirdparty/mbedtls/library/platform_util.c
+++ b/thirdparty/mbedtls/library/platform_util.c
@@ -115,7 +115,7 @@ void mbedtls_platform_zeroize( void *buf, size_t len )
#if !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \
( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \
- _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) )
+ _POSIX_THREAD_SAFE_FUNCTIONS >= 200112L ) )
/*
* This is a convenience shorthand macro to avoid checking the long
* preprocessor conditions above. Ideally, we could expose this macro in
@@ -129,7 +129,7 @@ void mbedtls_platform_zeroize( void *buf, size_t len )
#endif /* !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \
( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \
- _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) ) */
+ _POSIX_THREAD_SAFE_FUNCTIONS >= 200112L ) ) */
struct tm *mbedtls_platform_gmtime_r( const mbedtls_time_t *tt,
struct tm *tm_buf )
diff --git a/thirdparty/mbedtls/library/ripemd160.c b/thirdparty/mbedtls/library/ripemd160.c
index 0b6efcb574..d6ee933b2e 100644
--- a/thirdparty/mbedtls/library/ripemd160.c
+++ b/thirdparty/mbedtls/library/ripemd160.c
@@ -147,30 +147,33 @@ void mbedtls_ripemd160_starts( mbedtls_ripemd160_context *ctx )
int mbedtls_internal_ripemd160_process( mbedtls_ripemd160_context *ctx,
const unsigned char data[64] )
{
- uint32_t A, B, C, D, E, Ap, Bp, Cp, Dp, Ep, X[16];
-
- GET_UINT32_LE( X[ 0], data, 0 );
- GET_UINT32_LE( X[ 1], data, 4 );
- GET_UINT32_LE( X[ 2], data, 8 );
- GET_UINT32_LE( X[ 3], data, 12 );
- GET_UINT32_LE( X[ 4], data, 16 );
- GET_UINT32_LE( X[ 5], data, 20 );
- GET_UINT32_LE( X[ 6], data, 24 );
- GET_UINT32_LE( X[ 7], data, 28 );
- GET_UINT32_LE( X[ 8], data, 32 );
- GET_UINT32_LE( X[ 9], data, 36 );
- GET_UINT32_LE( X[10], data, 40 );
- GET_UINT32_LE( X[11], data, 44 );
- GET_UINT32_LE( X[12], data, 48 );
- GET_UINT32_LE( X[13], data, 52 );
- GET_UINT32_LE( X[14], data, 56 );
- GET_UINT32_LE( X[15], data, 60 );
-
- A = Ap = ctx->state[0];
- B = Bp = ctx->state[1];
- C = Cp = ctx->state[2];
- D = Dp = ctx->state[3];
- E = Ep = ctx->state[4];
+ struct
+ {
+ uint32_t A, B, C, D, E, Ap, Bp, Cp, Dp, Ep, X[16];
+ } local;
+
+ GET_UINT32_LE( local.X[ 0], data, 0 );
+ GET_UINT32_LE( local.X[ 1], data, 4 );
+ GET_UINT32_LE( local.X[ 2], data, 8 );
+ GET_UINT32_LE( local.X[ 3], data, 12 );
+ GET_UINT32_LE( local.X[ 4], data, 16 );
+ GET_UINT32_LE( local.X[ 5], data, 20 );
+ GET_UINT32_LE( local.X[ 6], data, 24 );
+ GET_UINT32_LE( local.X[ 7], data, 28 );
+ GET_UINT32_LE( local.X[ 8], data, 32 );
+ GET_UINT32_LE( local.X[ 9], data, 36 );
+ GET_UINT32_LE( local.X[10], data, 40 );
+ GET_UINT32_LE( local.X[11], data, 44 );
+ GET_UINT32_LE( local.X[12], data, 48 );
+ GET_UINT32_LE( local.X[13], data, 52 );
+ GET_UINT32_LE( local.X[14], data, 56 );
+ GET_UINT32_LE( local.X[15], data, 60 );
+
+ local.A = local.Ap = ctx->state[0];
+ local.B = local.Bp = ctx->state[1];
+ local.C = local.Cp = ctx->state[2];
+ local.D = local.Dp = ctx->state[3];
+ local.E = local.Ep = ctx->state[4];
#define F1( x, y, z ) ( (x) ^ (y) ^ (z) )
#define F2( x, y, z ) ( ( (x) & (y) ) | ( ~(x) & (z) ) )
@@ -180,12 +183,12 @@ int mbedtls_internal_ripemd160_process( mbedtls_ripemd160_context *ctx,
#define S( x, n ) ( ( (x) << (n) ) | ( (x) >> (32 - (n)) ) )
-#define P( a, b, c, d, e, r, s, f, k ) \
- do \
- { \
- (a) += f( (b), (c), (d) ) + X[r] + (k); \
- (a) = S( (a), (s) ) + (e); \
- (c) = S( (c), 10 ); \
+#define P( a, b, c, d, e, r, s, f, k ) \
+ do \
+ { \
+ (a) += f( (b), (c), (d) ) + local.X[r] + (k); \
+ (a) = S( (a), (s) ) + (e); \
+ (c) = S( (c), 10 ); \
} while( 0 )
#define P2( a, b, c, d, e, r, s, rp, sp ) \
@@ -200,22 +203,22 @@ int mbedtls_internal_ripemd160_process( mbedtls_ripemd160_context *ctx,
#define K 0x00000000
#define Fp F5
#define Kp 0x50A28BE6
- P2( A, B, C, D, E, 0, 11, 5, 8 );
- P2( E, A, B, C, D, 1, 14, 14, 9 );
- P2( D, E, A, B, C, 2, 15, 7, 9 );
- P2( C, D, E, A, B, 3, 12, 0, 11 );
- P2( B, C, D, E, A, 4, 5, 9, 13 );
- P2( A, B, C, D, E, 5, 8, 2, 15 );
- P2( E, A, B, C, D, 6, 7, 11, 15 );
- P2( D, E, A, B, C, 7, 9, 4, 5 );
- P2( C, D, E, A, B, 8, 11, 13, 7 );
- P2( B, C, D, E, A, 9, 13, 6, 7 );
- P2( A, B, C, D, E, 10, 14, 15, 8 );
- P2( E, A, B, C, D, 11, 15, 8, 11 );
- P2( D, E, A, B, C, 12, 6, 1, 14 );
- P2( C, D, E, A, B, 13, 7, 10, 14 );
- P2( B, C, D, E, A, 14, 9, 3, 12 );
- P2( A, B, C, D, E, 15, 8, 12, 6 );
+ P2( local.A, local.B, local.C, local.D, local.E, 0, 11, 5, 8 );
+ P2( local.E, local.A, local.B, local.C, local.D, 1, 14, 14, 9 );
+ P2( local.D, local.E, local.A, local.B, local.C, 2, 15, 7, 9 );
+ P2( local.C, local.D, local.E, local.A, local.B, 3, 12, 0, 11 );
+ P2( local.B, local.C, local.D, local.E, local.A, 4, 5, 9, 13 );
+ P2( local.A, local.B, local.C, local.D, local.E, 5, 8, 2, 15 );
+ P2( local.E, local.A, local.B, local.C, local.D, 6, 7, 11, 15 );
+ P2( local.D, local.E, local.A, local.B, local.C, 7, 9, 4, 5 );
+ P2( local.C, local.D, local.E, local.A, local.B, 8, 11, 13, 7 );
+ P2( local.B, local.C, local.D, local.E, local.A, 9, 13, 6, 7 );
+ P2( local.A, local.B, local.C, local.D, local.E, 10, 14, 15, 8 );
+ P2( local.E, local.A, local.B, local.C, local.D, 11, 15, 8, 11 );
+ P2( local.D, local.E, local.A, local.B, local.C, 12, 6, 1, 14 );
+ P2( local.C, local.D, local.E, local.A, local.B, 13, 7, 10, 14 );
+ P2( local.B, local.C, local.D, local.E, local.A, 14, 9, 3, 12 );
+ P2( local.A, local.B, local.C, local.D, local.E, 15, 8, 12, 6 );
#undef F
#undef K
#undef Fp
@@ -225,22 +228,22 @@ int mbedtls_internal_ripemd160_process( mbedtls_ripemd160_context *ctx,
#define K 0x5A827999
#define Fp F4
#define Kp 0x5C4DD124
- P2( E, A, B, C, D, 7, 7, 6, 9 );
- P2( D, E, A, B, C, 4, 6, 11, 13 );
- P2( C, D, E, A, B, 13, 8, 3, 15 );
- P2( B, C, D, E, A, 1, 13, 7, 7 );
- P2( A, B, C, D, E, 10, 11, 0, 12 );
- P2( E, A, B, C, D, 6, 9, 13, 8 );
- P2( D, E, A, B, C, 15, 7, 5, 9 );
- P2( C, D, E, A, B, 3, 15, 10, 11 );
- P2( B, C, D, E, A, 12, 7, 14, 7 );
- P2( A, B, C, D, E, 0, 12, 15, 7 );
- P2( E, A, B, C, D, 9, 15, 8, 12 );
- P2( D, E, A, B, C, 5, 9, 12, 7 );
- P2( C, D, E, A, B, 2, 11, 4, 6 );
- P2( B, C, D, E, A, 14, 7, 9, 15 );
- P2( A, B, C, D, E, 11, 13, 1, 13 );
- P2( E, A, B, C, D, 8, 12, 2, 11 );
+ P2( local.E, local.A, local.B, local.C, local.D, 7, 7, 6, 9 );
+ P2( local.D, local.E, local.A, local.B, local.C, 4, 6, 11, 13 );
+ P2( local.C, local.D, local.E, local.A, local.B, 13, 8, 3, 15 );
+ P2( local.B, local.C, local.D, local.E, local.A, 1, 13, 7, 7 );
+ P2( local.A, local.B, local.C, local.D, local.E, 10, 11, 0, 12 );
+ P2( local.E, local.A, local.B, local.C, local.D, 6, 9, 13, 8 );
+ P2( local.D, local.E, local.A, local.B, local.C, 15, 7, 5, 9 );
+ P2( local.C, local.D, local.E, local.A, local.B, 3, 15, 10, 11 );
+ P2( local.B, local.C, local.D, local.E, local.A, 12, 7, 14, 7 );
+ P2( local.A, local.B, local.C, local.D, local.E, 0, 12, 15, 7 );
+ P2( local.E, local.A, local.B, local.C, local.D, 9, 15, 8, 12 );
+ P2( local.D, local.E, local.A, local.B, local.C, 5, 9, 12, 7 );
+ P2( local.C, local.D, local.E, local.A, local.B, 2, 11, 4, 6 );
+ P2( local.B, local.C, local.D, local.E, local.A, 14, 7, 9, 15 );
+ P2( local.A, local.B, local.C, local.D, local.E, 11, 13, 1, 13 );
+ P2( local.E, local.A, local.B, local.C, local.D, 8, 12, 2, 11 );
#undef F
#undef K
#undef Fp
@@ -250,22 +253,22 @@ int mbedtls_internal_ripemd160_process( mbedtls_ripemd160_context *ctx,
#define K 0x6ED9EBA1
#define Fp F3
#define Kp 0x6D703EF3
- P2( D, E, A, B, C, 3, 11, 15, 9 );
- P2( C, D, E, A, B, 10, 13, 5, 7 );
- P2( B, C, D, E, A, 14, 6, 1, 15 );
- P2( A, B, C, D, E, 4, 7, 3, 11 );
- P2( E, A, B, C, D, 9, 14, 7, 8 );
- P2( D, E, A, B, C, 15, 9, 14, 6 );
- P2( C, D, E, A, B, 8, 13, 6, 6 );
- P2( B, C, D, E, A, 1, 15, 9, 14 );
- P2( A, B, C, D, E, 2, 14, 11, 12 );
- P2( E, A, B, C, D, 7, 8, 8, 13 );
- P2( D, E, A, B, C, 0, 13, 12, 5 );
- P2( C, D, E, A, B, 6, 6, 2, 14 );
- P2( B, C, D, E, A, 13, 5, 10, 13 );
- P2( A, B, C, D, E, 11, 12, 0, 13 );
- P2( E, A, B, C, D, 5, 7, 4, 7 );
- P2( D, E, A, B, C, 12, 5, 13, 5 );
+ P2( local.D, local.E, local.A, local.B, local.C, 3, 11, 15, 9 );
+ P2( local.C, local.D, local.E, local.A, local.B, 10, 13, 5, 7 );
+ P2( local.B, local.C, local.D, local.E, local.A, 14, 6, 1, 15 );
+ P2( local.A, local.B, local.C, local.D, local.E, 4, 7, 3, 11 );
+ P2( local.E, local.A, local.B, local.C, local.D, 9, 14, 7, 8 );
+ P2( local.D, local.E, local.A, local.B, local.C, 15, 9, 14, 6 );
+ P2( local.C, local.D, local.E, local.A, local.B, 8, 13, 6, 6 );
+ P2( local.B, local.C, local.D, local.E, local.A, 1, 15, 9, 14 );
+ P2( local.A, local.B, local.C, local.D, local.E, 2, 14, 11, 12 );
+ P2( local.E, local.A, local.B, local.C, local.D, 7, 8, 8, 13 );
+ P2( local.D, local.E, local.A, local.B, local.C, 0, 13, 12, 5 );
+ P2( local.C, local.D, local.E, local.A, local.B, 6, 6, 2, 14 );
+ P2( local.B, local.C, local.D, local.E, local.A, 13, 5, 10, 13 );
+ P2( local.A, local.B, local.C, local.D, local.E, 11, 12, 0, 13 );
+ P2( local.E, local.A, local.B, local.C, local.D, 5, 7, 4, 7 );
+ P2( local.D, local.E, local.A, local.B, local.C, 12, 5, 13, 5 );
#undef F
#undef K
#undef Fp
@@ -275,22 +278,22 @@ int mbedtls_internal_ripemd160_process( mbedtls_ripemd160_context *ctx,
#define K 0x8F1BBCDC
#define Fp F2
#define Kp 0x7A6D76E9
- P2( C, D, E, A, B, 1, 11, 8, 15 );
- P2( B, C, D, E, A, 9, 12, 6, 5 );
- P2( A, B, C, D, E, 11, 14, 4, 8 );
- P2( E, A, B, C, D, 10, 15, 1, 11 );
- P2( D, E, A, B, C, 0, 14, 3, 14 );
- P2( C, D, E, A, B, 8, 15, 11, 14 );
- P2( B, C, D, E, A, 12, 9, 15, 6 );
- P2( A, B, C, D, E, 4, 8, 0, 14 );
- P2( E, A, B, C, D, 13, 9, 5, 6 );
- P2( D, E, A, B, C, 3, 14, 12, 9 );
- P2( C, D, E, A, B, 7, 5, 2, 12 );
- P2( B, C, D, E, A, 15, 6, 13, 9 );
- P2( A, B, C, D, E, 14, 8, 9, 12 );
- P2( E, A, B, C, D, 5, 6, 7, 5 );
- P2( D, E, A, B, C, 6, 5, 10, 15 );
- P2( C, D, E, A, B, 2, 12, 14, 8 );
+ P2( local.C, local.D, local.E, local.A, local.B, 1, 11, 8, 15 );
+ P2( local.B, local.C, local.D, local.E, local.A, 9, 12, 6, 5 );
+ P2( local.A, local.B, local.C, local.D, local.E, 11, 14, 4, 8 );
+ P2( local.E, local.A, local.B, local.C, local.D, 10, 15, 1, 11 );
+ P2( local.D, local.E, local.A, local.B, local.C, 0, 14, 3, 14 );
+ P2( local.C, local.D, local.E, local.A, local.B, 8, 15, 11, 14 );
+ P2( local.B, local.C, local.D, local.E, local.A, 12, 9, 15, 6 );
+ P2( local.A, local.B, local.C, local.D, local.E, 4, 8, 0, 14 );
+ P2( local.E, local.A, local.B, local.C, local.D, 13, 9, 5, 6 );
+ P2( local.D, local.E, local.A, local.B, local.C, 3, 14, 12, 9 );
+ P2( local.C, local.D, local.E, local.A, local.B, 7, 5, 2, 12 );
+ P2( local.B, local.C, local.D, local.E, local.A, 15, 6, 13, 9 );
+ P2( local.A, local.B, local.C, local.D, local.E, 14, 8, 9, 12 );
+ P2( local.E, local.A, local.B, local.C, local.D, 5, 6, 7, 5 );
+ P2( local.D, local.E, local.A, local.B, local.C, 6, 5, 10, 15 );
+ P2( local.C, local.D, local.E, local.A, local.B, 2, 12, 14, 8 );
#undef F
#undef K
#undef Fp
@@ -300,33 +303,36 @@ int mbedtls_internal_ripemd160_process( mbedtls_ripemd160_context *ctx,
#define K 0xA953FD4E
#define Fp F1
#define Kp 0x00000000
- P2( B, C, D, E, A, 4, 9, 12, 8 );
- P2( A, B, C, D, E, 0, 15, 15, 5 );
- P2( E, A, B, C, D, 5, 5, 10, 12 );
- P2( D, E, A, B, C, 9, 11, 4, 9 );
- P2( C, D, E, A, B, 7, 6, 1, 12 );
- P2( B, C, D, E, A, 12, 8, 5, 5 );
- P2( A, B, C, D, E, 2, 13, 8, 14 );
- P2( E, A, B, C, D, 10, 12, 7, 6 );
- P2( D, E, A, B, C, 14, 5, 6, 8 );
- P2( C, D, E, A, B, 1, 12, 2, 13 );
- P2( B, C, D, E, A, 3, 13, 13, 6 );
- P2( A, B, C, D, E, 8, 14, 14, 5 );
- P2( E, A, B, C, D, 11, 11, 0, 15 );
- P2( D, E, A, B, C, 6, 8, 3, 13 );
- P2( C, D, E, A, B, 15, 5, 9, 11 );
- P2( B, C, D, E, A, 13, 6, 11, 11 );
+ P2( local.B, local.C, local.D, local.E, local.A, 4, 9, 12, 8 );
+ P2( local.A, local.B, local.C, local.D, local.E, 0, 15, 15, 5 );
+ P2( local.E, local.A, local.B, local.C, local.D, 5, 5, 10, 12 );
+ P2( local.D, local.E, local.A, local.B, local.C, 9, 11, 4, 9 );
+ P2( local.C, local.D, local.E, local.A, local.B, 7, 6, 1, 12 );
+ P2( local.B, local.C, local.D, local.E, local.A, 12, 8, 5, 5 );
+ P2( local.A, local.B, local.C, local.D, local.E, 2, 13, 8, 14 );
+ P2( local.E, local.A, local.B, local.C, local.D, 10, 12, 7, 6 );
+ P2( local.D, local.E, local.A, local.B, local.C, 14, 5, 6, 8 );
+ P2( local.C, local.D, local.E, local.A, local.B, 1, 12, 2, 13 );
+ P2( local.B, local.C, local.D, local.E, local.A, 3, 13, 13, 6 );
+ P2( local.A, local.B, local.C, local.D, local.E, 8, 14, 14, 5 );
+ P2( local.E, local.A, local.B, local.C, local.D, 11, 11, 0, 15 );
+ P2( local.D, local.E, local.A, local.B, local.C, 6, 8, 3, 13 );
+ P2( local.C, local.D, local.E, local.A, local.B, 15, 5, 9, 11 );
+ P2( local.B, local.C, local.D, local.E, local.A, 13, 6, 11, 11 );
#undef F
#undef K
#undef Fp
#undef Kp
- C = ctx->state[1] + C + Dp;
- ctx->state[1] = ctx->state[2] + D + Ep;
- ctx->state[2] = ctx->state[3] + E + Ap;
- ctx->state[3] = ctx->state[4] + A + Bp;
- ctx->state[4] = ctx->state[0] + B + Cp;
- ctx->state[0] = C;
+ local.C = ctx->state[1] + local.C + local.Dp;
+ ctx->state[1] = ctx->state[2] + local.D + local.Ep;
+ ctx->state[2] = ctx->state[3] + local.E + local.Ap;
+ ctx->state[3] = ctx->state[4] + local.A + local.Bp;
+ ctx->state[4] = ctx->state[0] + local.B + local.Cp;
+ ctx->state[0] = local.C;
+
+ /* Zeroise variables to clear sensitive data from memory. */
+ mbedtls_platform_zeroize( &local, sizeof( local ) );
return( 0 );
}
diff --git a/thirdparty/mbedtls/library/rsa.c b/thirdparty/mbedtls/library/rsa.c
index 42becbf17b..a25c633bc6 100644
--- a/thirdparty/mbedtls/library/rsa.c
+++ b/thirdparty/mbedtls/library/rsa.c
@@ -841,15 +841,14 @@ static int rsa_prepare_blinding( mbedtls_rsa_context *ctx,
* which one, we just loop and choose new values for both of them.
* (Each iteration succeeds with overwhelming probability.) */
ret = mbedtls_mpi_inv_mod( &ctx->Vi, &ctx->Vi, &ctx->N );
- if( ret == MBEDTLS_ERR_MPI_NOT_ACCEPTABLE )
- continue;
- if( ret != 0 )
+ if( ret != 0 && ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE )
goto cleanup;
- /* Finish the computation of Vf^-1 = R * (R Vf)^-1 */
- MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &R ) );
- MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->N ) );
- } while( 0 );
+ } while( ret == MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
+
+ /* Finish the computation of Vf^-1 = R * (R Vf)^-1 */
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &R ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->N ) );
/* Blinding value: Vi = Vf^(-e) mod N
* (Vi already contains Vf^-1 at this point) */
diff --git a/thirdparty/mbedtls/library/sha1.c b/thirdparty/mbedtls/library/sha1.c
index 8682abd740..e99a5e8635 100644
--- a/thirdparty/mbedtls/library/sha1.c
+++ b/thirdparty/mbedtls/library/sha1.c
@@ -155,35 +155,40 @@ void mbedtls_sha1_starts( mbedtls_sha1_context *ctx )
int mbedtls_internal_sha1_process( mbedtls_sha1_context *ctx,
const unsigned char data[64] )
{
- uint32_t temp, W[16], A, B, C, D, E;
+ struct
+ {
+ uint32_t temp, W[16], A, B, C, D, E;
+ } local;
SHA1_VALIDATE_RET( ctx != NULL );
SHA1_VALIDATE_RET( (const unsigned char *)data != NULL );
- GET_UINT32_BE( W[ 0], data, 0 );
- GET_UINT32_BE( W[ 1], data, 4 );
- GET_UINT32_BE( W[ 2], data, 8 );
- GET_UINT32_BE( W[ 3], data, 12 );
- GET_UINT32_BE( W[ 4], data, 16 );
- GET_UINT32_BE( W[ 5], data, 20 );
- GET_UINT32_BE( W[ 6], data, 24 );
- GET_UINT32_BE( W[ 7], data, 28 );
- GET_UINT32_BE( W[ 8], data, 32 );
- GET_UINT32_BE( W[ 9], data, 36 );
- GET_UINT32_BE( W[10], data, 40 );
- GET_UINT32_BE( W[11], data, 44 );
- GET_UINT32_BE( W[12], data, 48 );
- GET_UINT32_BE( W[13], data, 52 );
- GET_UINT32_BE( W[14], data, 56 );
- GET_UINT32_BE( W[15], data, 60 );
+ GET_UINT32_BE( local.W[ 0], data, 0 );
+ GET_UINT32_BE( local.W[ 1], data, 4 );
+ GET_UINT32_BE( local.W[ 2], data, 8 );
+ GET_UINT32_BE( local.W[ 3], data, 12 );
+ GET_UINT32_BE( local.W[ 4], data, 16 );
+ GET_UINT32_BE( local.W[ 5], data, 20 );
+ GET_UINT32_BE( local.W[ 6], data, 24 );
+ GET_UINT32_BE( local.W[ 7], data, 28 );
+ GET_UINT32_BE( local.W[ 8], data, 32 );
+ GET_UINT32_BE( local.W[ 9], data, 36 );
+ GET_UINT32_BE( local.W[10], data, 40 );
+ GET_UINT32_BE( local.W[11], data, 44 );
+ GET_UINT32_BE( local.W[12], data, 48 );
+ GET_UINT32_BE( local.W[13], data, 52 );
+ GET_UINT32_BE( local.W[14], data, 56 );
+ GET_UINT32_BE( local.W[15], data, 60 );
#define S(x,n) (((x) << (n)) | (((x) & 0xFFFFFFFF) >> (32 - (n))))
#define R(t) \
( \
- temp = W[( (t) - 3 ) & 0x0F] ^ W[( (t) - 8 ) & 0x0F] ^ \
- W[( (t) - 14 ) & 0x0F] ^ W[ (t) & 0x0F], \
- ( W[(t) & 0x0F] = S(temp,1) ) \
+ local.temp = local.W[( (t) - 3 ) & 0x0F] ^ \
+ local.W[( (t) - 8 ) & 0x0F] ^ \
+ local.W[( (t) - 14 ) & 0x0F] ^ \
+ local.W[ (t) & 0x0F], \
+ ( local.W[(t) & 0x0F] = S(local.temp,1) ) \
)
#define P(a,b,c,d,e,x) \
@@ -193,35 +198,35 @@ int mbedtls_internal_sha1_process( mbedtls_sha1_context *ctx,
(b) = S((b),30); \
} while( 0 )
- A = ctx->state[0];
- B = ctx->state[1];
- C = ctx->state[2];
- D = ctx->state[3];
- E = ctx->state[4];
+ local.A = ctx->state[0];
+ local.B = ctx->state[1];
+ local.C = ctx->state[2];
+ local.D = ctx->state[3];
+ local.E = ctx->state[4];
#define F(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
#define K 0x5A827999
- P( A, B, C, D, E, W[0] );
- P( E, A, B, C, D, W[1] );
- P( D, E, A, B, C, W[2] );
- P( C, D, E, A, B, W[3] );
- P( B, C, D, E, A, W[4] );
- P( A, B, C, D, E, W[5] );
- P( E, A, B, C, D, W[6] );
- P( D, E, A, B, C, W[7] );
- P( C, D, E, A, B, W[8] );
- P( B, C, D, E, A, W[9] );
- P( A, B, C, D, E, W[10] );
- P( E, A, B, C, D, W[11] );
- P( D, E, A, B, C, W[12] );
- P( C, D, E, A, B, W[13] );
- P( B, C, D, E, A, W[14] );
- P( A, B, C, D, E, W[15] );
- P( E, A, B, C, D, R(16) );
- P( D, E, A, B, C, R(17) );
- P( C, D, E, A, B, R(18) );
- P( B, C, D, E, A, R(19) );
+ P( local.A, local.B, local.C, local.D, local.E, local.W[0] );
+ P( local.E, local.A, local.B, local.C, local.D, local.W[1] );
+ P( local.D, local.E, local.A, local.B, local.C, local.W[2] );
+ P( local.C, local.D, local.E, local.A, local.B, local.W[3] );
+ P( local.B, local.C, local.D, local.E, local.A, local.W[4] );
+ P( local.A, local.B, local.C, local.D, local.E, local.W[5] );
+ P( local.E, local.A, local.B, local.C, local.D, local.W[6] );
+ P( local.D, local.E, local.A, local.B, local.C, local.W[7] );
+ P( local.C, local.D, local.E, local.A, local.B, local.W[8] );
+ P( local.B, local.C, local.D, local.E, local.A, local.W[9] );
+ P( local.A, local.B, local.C, local.D, local.E, local.W[10] );
+ P( local.E, local.A, local.B, local.C, local.D, local.W[11] );
+ P( local.D, local.E, local.A, local.B, local.C, local.W[12] );
+ P( local.C, local.D, local.E, local.A, local.B, local.W[13] );
+ P( local.B, local.C, local.D, local.E, local.A, local.W[14] );
+ P( local.A, local.B, local.C, local.D, local.E, local.W[15] );
+ P( local.E, local.A, local.B, local.C, local.D, R(16) );
+ P( local.D, local.E, local.A, local.B, local.C, R(17) );
+ P( local.C, local.D, local.E, local.A, local.B, R(18) );
+ P( local.B, local.C, local.D, local.E, local.A, R(19) );
#undef K
#undef F
@@ -229,26 +234,26 @@ int mbedtls_internal_sha1_process( mbedtls_sha1_context *ctx,
#define F(x,y,z) ((x) ^ (y) ^ (z))
#define K 0x6ED9EBA1
- P( A, B, C, D, E, R(20) );
- P( E, A, B, C, D, R(21) );
- P( D, E, A, B, C, R(22) );
- P( C, D, E, A, B, R(23) );
- P( B, C, D, E, A, R(24) );
- P( A, B, C, D, E, R(25) );
- P( E, A, B, C, D, R(26) );
- P( D, E, A, B, C, R(27) );
- P( C, D, E, A, B, R(28) );
- P( B, C, D, E, A, R(29) );
- P( A, B, C, D, E, R(30) );
- P( E, A, B, C, D, R(31) );
- P( D, E, A, B, C, R(32) );
- P( C, D, E, A, B, R(33) );
- P( B, C, D, E, A, R(34) );
- P( A, B, C, D, E, R(35) );
- P( E, A, B, C, D, R(36) );
- P( D, E, A, B, C, R(37) );
- P( C, D, E, A, B, R(38) );
- P( B, C, D, E, A, R(39) );
+ P( local.A, local.B, local.C, local.D, local.E, R(20) );
+ P( local.E, local.A, local.B, local.C, local.D, R(21) );
+ P( local.D, local.E, local.A, local.B, local.C, R(22) );
+ P( local.C, local.D, local.E, local.A, local.B, R(23) );
+ P( local.B, local.C, local.D, local.E, local.A, R(24) );
+ P( local.A, local.B, local.C, local.D, local.E, R(25) );
+ P( local.E, local.A, local.B, local.C, local.D, R(26) );
+ P( local.D, local.E, local.A, local.B, local.C, R(27) );
+ P( local.C, local.D, local.E, local.A, local.B, R(28) );
+ P( local.B, local.C, local.D, local.E, local.A, R(29) );
+ P( local.A, local.B, local.C, local.D, local.E, R(30) );
+ P( local.E, local.A, local.B, local.C, local.D, R(31) );
+ P( local.D, local.E, local.A, local.B, local.C, R(32) );
+ P( local.C, local.D, local.E, local.A, local.B, R(33) );
+ P( local.B, local.C, local.D, local.E, local.A, R(34) );
+ P( local.A, local.B, local.C, local.D, local.E, R(35) );
+ P( local.E, local.A, local.B, local.C, local.D, R(36) );
+ P( local.D, local.E, local.A, local.B, local.C, R(37) );
+ P( local.C, local.D, local.E, local.A, local.B, R(38) );
+ P( local.B, local.C, local.D, local.E, local.A, R(39) );
#undef K
#undef F
@@ -256,26 +261,26 @@ int mbedtls_internal_sha1_process( mbedtls_sha1_context *ctx,
#define F(x,y,z) (((x) & (y)) | ((z) & ((x) | (y))))
#define K 0x8F1BBCDC
- P( A, B, C, D, E, R(40) );
- P( E, A, B, C, D, R(41) );
- P( D, E, A, B, C, R(42) );
- P( C, D, E, A, B, R(43) );
- P( B, C, D, E, A, R(44) );
- P( A, B, C, D, E, R(45) );
- P( E, A, B, C, D, R(46) );
- P( D, E, A, B, C, R(47) );
- P( C, D, E, A, B, R(48) );
- P( B, C, D, E, A, R(49) );
- P( A, B, C, D, E, R(50) );
- P( E, A, B, C, D, R(51) );
- P( D, E, A, B, C, R(52) );
- P( C, D, E, A, B, R(53) );
- P( B, C, D, E, A, R(54) );
- P( A, B, C, D, E, R(55) );
- P( E, A, B, C, D, R(56) );
- P( D, E, A, B, C, R(57) );
- P( C, D, E, A, B, R(58) );
- P( B, C, D, E, A, R(59) );
+ P( local.A, local.B, local.C, local.D, local.E, R(40) );
+ P( local.E, local.A, local.B, local.C, local.D, R(41) );
+ P( local.D, local.E, local.A, local.B, local.C, R(42) );
+ P( local.C, local.D, local.E, local.A, local.B, R(43) );
+ P( local.B, local.C, local.D, local.E, local.A, R(44) );
+ P( local.A, local.B, local.C, local.D, local.E, R(45) );
+ P( local.E, local.A, local.B, local.C, local.D, R(46) );
+ P( local.D, local.E, local.A, local.B, local.C, R(47) );
+ P( local.C, local.D, local.E, local.A, local.B, R(48) );
+ P( local.B, local.C, local.D, local.E, local.A, R(49) );
+ P( local.A, local.B, local.C, local.D, local.E, R(50) );
+ P( local.E, local.A, local.B, local.C, local.D, R(51) );
+ P( local.D, local.E, local.A, local.B, local.C, R(52) );
+ P( local.C, local.D, local.E, local.A, local.B, R(53) );
+ P( local.B, local.C, local.D, local.E, local.A, R(54) );
+ P( local.A, local.B, local.C, local.D, local.E, R(55) );
+ P( local.E, local.A, local.B, local.C, local.D, R(56) );
+ P( local.D, local.E, local.A, local.B, local.C, R(57) );
+ P( local.C, local.D, local.E, local.A, local.B, R(58) );
+ P( local.B, local.C, local.D, local.E, local.A, R(59) );
#undef K
#undef F
@@ -283,35 +288,38 @@ int mbedtls_internal_sha1_process( mbedtls_sha1_context *ctx,
#define F(x,y,z) ((x) ^ (y) ^ (z))
#define K 0xCA62C1D6
- P( A, B, C, D, E, R(60) );
- P( E, A, B, C, D, R(61) );
- P( D, E, A, B, C, R(62) );
- P( C, D, E, A, B, R(63) );
- P( B, C, D, E, A, R(64) );
- P( A, B, C, D, E, R(65) );
- P( E, A, B, C, D, R(66) );
- P( D, E, A, B, C, R(67) );
- P( C, D, E, A, B, R(68) );
- P( B, C, D, E, A, R(69) );
- P( A, B, C, D, E, R(70) );
- P( E, A, B, C, D, R(71) );
- P( D, E, A, B, C, R(72) );
- P( C, D, E, A, B, R(73) );
- P( B, C, D, E, A, R(74) );
- P( A, B, C, D, E, R(75) );
- P( E, A, B, C, D, R(76) );
- P( D, E, A, B, C, R(77) );
- P( C, D, E, A, B, R(78) );
- P( B, C, D, E, A, R(79) );
+ P( local.A, local.B, local.C, local.D, local.E, R(60) );
+ P( local.E, local.A, local.B, local.C, local.D, R(61) );
+ P( local.D, local.E, local.A, local.B, local.C, R(62) );
+ P( local.C, local.D, local.E, local.A, local.B, R(63) );
+ P( local.B, local.C, local.D, local.E, local.A, R(64) );
+ P( local.A, local.B, local.C, local.D, local.E, R(65) );
+ P( local.E, local.A, local.B, local.C, local.D, R(66) );
+ P( local.D, local.E, local.A, local.B, local.C, R(67) );
+ P( local.C, local.D, local.E, local.A, local.B, R(68) );
+ P( local.B, local.C, local.D, local.E, local.A, R(69) );
+ P( local.A, local.B, local.C, local.D, local.E, R(70) );
+ P( local.E, local.A, local.B, local.C, local.D, R(71) );
+ P( local.D, local.E, local.A, local.B, local.C, R(72) );
+ P( local.C, local.D, local.E, local.A, local.B, R(73) );
+ P( local.B, local.C, local.D, local.E, local.A, R(74) );
+ P( local.A, local.B, local.C, local.D, local.E, R(75) );
+ P( local.E, local.A, local.B, local.C, local.D, R(76) );
+ P( local.D, local.E, local.A, local.B, local.C, R(77) );
+ P( local.C, local.D, local.E, local.A, local.B, R(78) );
+ P( local.B, local.C, local.D, local.E, local.A, R(79) );
#undef K
#undef F
- ctx->state[0] += A;
- ctx->state[1] += B;
- ctx->state[2] += C;
- ctx->state[3] += D;
- ctx->state[4] += E;
+ ctx->state[0] += local.A;
+ ctx->state[1] += local.B;
+ ctx->state[2] += local.C;
+ ctx->state[3] += local.D;
+ ctx->state[4] += local.E;
+
+ /* Zeroise buffers and variables to clear sensitive data from memory. */
+ mbedtls_platform_zeroize( &local, sizeof( local ) );
return( 0 );
}
diff --git a/thirdparty/mbedtls/library/sha256.c b/thirdparty/mbedtls/library/sha256.c
index 5169584b68..75a8f8a2b2 100644
--- a/thirdparty/mbedtls/library/sha256.c
+++ b/thirdparty/mbedtls/library/sha256.c
@@ -209,77 +209,104 @@ static const uint32_t K[] =
#define F0(x,y,z) (((x) & (y)) | ((z) & ((x) | (y))))
#define F1(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
-#define R(t) \
- ( \
- W[t] = S1(W[(t) - 2]) + W[(t) - 7] + \
- S0(W[(t) - 15]) + W[(t) - 16] \
+#define R(t) \
+ ( \
+ local.W[t] = S1(local.W[(t) - 2]) + local.W[(t) - 7] + \
+ S0(local.W[(t) - 15]) + local.W[(t) - 16] \
)
-#define P(a,b,c,d,e,f,g,h,x,K) \
- do \
- { \
- temp1 = (h) + S3(e) + F1((e),(f),(g)) + (K) + (x); \
- temp2 = S2(a) + F0((a),(b),(c)); \
- (d) += temp1; (h) = temp1 + temp2; \
+#define P(a,b,c,d,e,f,g,h,x,K) \
+ do \
+ { \
+ local.temp1 = (h) + S3(e) + F1((e),(f),(g)) + (K) + (x); \
+ local.temp2 = S2(a) + F0((a),(b),(c)); \
+ (d) += local.temp1; (h) = local.temp1 + local.temp2; \
} while( 0 )
int mbedtls_internal_sha256_process( mbedtls_sha256_context *ctx,
const unsigned char data[64] )
{
- uint32_t temp1, temp2, W[64];
- uint32_t A[8];
+ struct
+ {
+ uint32_t temp1, temp2, W[64];
+ uint32_t A[8];
+ } local;
+
unsigned int i;
SHA256_VALIDATE_RET( ctx != NULL );
SHA256_VALIDATE_RET( (const unsigned char *)data != NULL );
for( i = 0; i < 8; i++ )
- A[i] = ctx->state[i];
+ local.A[i] = ctx->state[i];
#if defined(MBEDTLS_SHA256_SMALLER)
for( i = 0; i < 64; i++ )
{
if( i < 16 )
- GET_UINT32_BE( W[i], data, 4 * i );
+ GET_UINT32_BE( local.W[i], data, 4 * i );
else
R( i );
- P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i] );
+ P( local.A[0], local.A[1], local.A[2], local.A[3], local.A[4],
+ local.A[5], local.A[6], local.A[7], local.W[i], K[i] );
- temp1 = A[7]; A[7] = A[6]; A[6] = A[5]; A[5] = A[4]; A[4] = A[3];
- A[3] = A[2]; A[2] = A[1]; A[1] = A[0]; A[0] = temp1;
+ local.temp1 = local.A[7]; local.A[7] = local.A[6];
+ local.A[6] = local.A[5]; local.A[5] = local.A[4];
+ local.A[4] = local.A[3]; local.A[3] = local.A[2];
+ local.A[2] = local.A[1]; local.A[1] = local.A[0];
+ local.A[0] = local.temp1;
}
#else /* MBEDTLS_SHA256_SMALLER */
for( i = 0; i < 16; i++ )
- GET_UINT32_BE( W[i], data, 4 * i );
+ GET_UINT32_BE( local.W[i], data, 4 * i );
for( i = 0; i < 16; i += 8 )
{
- P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i+0], K[i+0] );
- P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[i+1], K[i+1] );
- P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[i+2], K[i+2] );
- P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[i+3], K[i+3] );
- P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[i+4], K[i+4] );
- P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[i+5], K[i+5] );
- P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[i+6], K[i+6] );
- P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[i+7], K[i+7] );
+ P( local.A[0], local.A[1], local.A[2], local.A[3], local.A[4],
+ local.A[5], local.A[6], local.A[7], local.W[i+0], K[i+0] );
+ P( local.A[7], local.A[0], local.A[1], local.A[2], local.A[3],
+ local.A[4], local.A[5], local.A[6], local.W[i+1], K[i+1] );
+ P( local.A[6], local.A[7], local.A[0], local.A[1], local.A[2],
+ local.A[3], local.A[4], local.A[5], local.W[i+2], K[i+2] );
+ P( local.A[5], local.A[6], local.A[7], local.A[0], local.A[1],
+ local.A[2], local.A[3], local.A[4], local.W[i+3], K[i+3] );
+ P( local.A[4], local.A[5], local.A[6], local.A[7], local.A[0],
+ local.A[1], local.A[2], local.A[3], local.W[i+4], K[i+4] );
+ P( local.A[3], local.A[4], local.A[5], local.A[6], local.A[7],
+ local.A[0], local.A[1], local.A[2], local.W[i+5], K[i+5] );
+ P( local.A[2], local.A[3], local.A[4], local.A[5], local.A[6],
+ local.A[7], local.A[0], local.A[1], local.W[i+6], K[i+6] );
+ P( local.A[1], local.A[2], local.A[3], local.A[4], local.A[5],
+ local.A[6], local.A[7], local.A[0], local.W[i+7], K[i+7] );
}
for( i = 16; i < 64; i += 8 )
{
- P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(i+0), K[i+0] );
- P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(i+1), K[i+1] );
- P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(i+2), K[i+2] );
- P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(i+3), K[i+3] );
- P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(i+4), K[i+4] );
- P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(i+5), K[i+5] );
- P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(i+6), K[i+6] );
- P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(i+7), K[i+7] );
+ P( local.A[0], local.A[1], local.A[2], local.A[3], local.A[4],
+ local.A[5], local.A[6], local.A[7], R(i+0), K[i+0] );
+ P( local.A[7], local.A[0], local.A[1], local.A[2], local.A[3],
+ local.A[4], local.A[5], local.A[6], R(i+1), K[i+1] );
+ P( local.A[6], local.A[7], local.A[0], local.A[1], local.A[2],
+ local.A[3], local.A[4], local.A[5], R(i+2), K[i+2] );
+ P( local.A[5], local.A[6], local.A[7], local.A[0], local.A[1],
+ local.A[2], local.A[3], local.A[4], R(i+3), K[i+3] );
+ P( local.A[4], local.A[5], local.A[6], local.A[7], local.A[0],
+ local.A[1], local.A[2], local.A[3], R(i+4), K[i+4] );
+ P( local.A[3], local.A[4], local.A[5], local.A[6], local.A[7],
+ local.A[0], local.A[1], local.A[2], R(i+5), K[i+5] );
+ P( local.A[2], local.A[3], local.A[4], local.A[5], local.A[6],
+ local.A[7], local.A[0], local.A[1], R(i+6), K[i+6] );
+ P( local.A[1], local.A[2], local.A[3], local.A[4], local.A[5],
+ local.A[6], local.A[7], local.A[0], R(i+7), K[i+7] );
}
#endif /* MBEDTLS_SHA256_SMALLER */
for( i = 0; i < 8; i++ )
- ctx->state[i] += A[i];
+ ctx->state[i] += local.A[i];
+
+ /* Zeroise buffers and variables to clear sensitive data from memory. */
+ mbedtls_platform_zeroize( &local, sizeof( local ) );
return( 0 );
}
diff --git a/thirdparty/mbedtls/library/sha512.c b/thirdparty/mbedtls/library/sha512.c
index 36d5d96146..986037ab7c 100644
--- a/thirdparty/mbedtls/library/sha512.c
+++ b/thirdparty/mbedtls/library/sha512.c
@@ -243,8 +243,11 @@ int mbedtls_internal_sha512_process( mbedtls_sha512_context *ctx,
const unsigned char data[128] )
{
int i;
- uint64_t temp1, temp2, W[80];
- uint64_t A, B, C, D, E, F, G, H;
+ struct
+ {
+ uint64_t temp1, temp2, W[80];
+ uint64_t A, B, C, D, E, F, G, H;
+ } local;
SHA512_VALIDATE_RET( ctx != NULL );
SHA512_VALIDATE_RET( (const unsigned char *)data != NULL );
@@ -261,56 +264,67 @@ int mbedtls_internal_sha512_process( mbedtls_sha512_context *ctx,
#define F0(x,y,z) (((x) & (y)) | ((z) & ((x) | (y))))
#define F1(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
-#define P(a,b,c,d,e,f,g,h,x,K) \
- do \
- { \
- temp1 = (h) + S3(e) + F1((e),(f),(g)) + (K) + (x); \
- temp2 = S2(a) + F0((a),(b),(c)); \
- (d) += temp1; (h) = temp1 + temp2; \
+#define P(a,b,c,d,e,f,g,h,x,K) \
+ do \
+ { \
+ local.temp1 = (h) + S3(e) + F1((e),(f),(g)) + (K) + (x); \
+ local.temp2 = S2(a) + F0((a),(b),(c)); \
+ (d) += local.temp1; (h) = local.temp1 + local.temp2; \
} while( 0 )
for( i = 0; i < 16; i++ )
{
- GET_UINT64_BE( W[i], data, i << 3 );
+ GET_UINT64_BE( local.W[i], data, i << 3 );
}
for( ; i < 80; i++ )
{
- W[i] = S1(W[i - 2]) + W[i - 7] +
- S0(W[i - 15]) + W[i - 16];
+ local.W[i] = S1(local.W[i - 2]) + local.W[i - 7] +
+ S0(local.W[i - 15]) + local.W[i - 16];
}
- A = ctx->state[0];
- B = ctx->state[1];
- C = ctx->state[2];
- D = ctx->state[3];
- E = ctx->state[4];
- F = ctx->state[5];
- G = ctx->state[6];
- H = ctx->state[7];
+ local.A = ctx->state[0];
+ local.B = ctx->state[1];
+ local.C = ctx->state[2];
+ local.D = ctx->state[3];
+ local.E = ctx->state[4];
+ local.F = ctx->state[5];
+ local.G = ctx->state[6];
+ local.H = ctx->state[7];
i = 0;
do
{
- P( A, B, C, D, E, F, G, H, W[i], K[i] ); i++;
- P( H, A, B, C, D, E, F, G, W[i], K[i] ); i++;
- P( G, H, A, B, C, D, E, F, W[i], K[i] ); i++;
- P( F, G, H, A, B, C, D, E, W[i], K[i] ); i++;
- P( E, F, G, H, A, B, C, D, W[i], K[i] ); i++;
- P( D, E, F, G, H, A, B, C, W[i], K[i] ); i++;
- P( C, D, E, F, G, H, A, B, W[i], K[i] ); i++;
- P( B, C, D, E, F, G, H, A, W[i], K[i] ); i++;
+ P( local.A, local.B, local.C, local.D, local.E,
+ local.F, local.G, local.H, local.W[i], K[i] ); i++;
+ P( local.H, local.A, local.B, local.C, local.D,
+ local.E, local.F, local.G, local.W[i], K[i] ); i++;
+ P( local.G, local.H, local.A, local.B, local.C,
+ local.D, local.E, local.F, local.W[i], K[i] ); i++;
+ P( local.F, local.G, local.H, local.A, local.B,
+ local.C, local.D, local.E, local.W[i], K[i] ); i++;
+ P( local.E, local.F, local.G, local.H, local.A,
+ local.B, local.C, local.D, local.W[i], K[i] ); i++;
+ P( local.D, local.E, local.F, local.G, local.H,
+ local.A, local.B, local.C, local.W[i], K[i] ); i++;
+ P( local.C, local.D, local.E, local.F, local.G,
+ local.H, local.A, local.B, local.W[i], K[i] ); i++;
+ P( local.B, local.C, local.D, local.E, local.F,
+ local.G, local.H, local.A, local.W[i], K[i] ); i++;
}
while( i < 80 );
- ctx->state[0] += A;
- ctx->state[1] += B;
- ctx->state[2] += C;
- ctx->state[3] += D;
- ctx->state[4] += E;
- ctx->state[5] += F;
- ctx->state[6] += G;
- ctx->state[7] += H;
+ ctx->state[0] += local.A;
+ ctx->state[1] += local.B;
+ ctx->state[2] += local.C;
+ ctx->state[3] += local.D;
+ ctx->state[4] += local.E;
+ ctx->state[5] += local.F;
+ ctx->state[6] += local.G;
+ ctx->state[7] += local.H;
+
+ /* Zeroise buffers and variables to clear sensitive data from memory. */
+ mbedtls_platform_zeroize( &local, sizeof( local ) );
return( 0 );
}
diff --git a/thirdparty/mbedtls/library/ssl_srv.c b/thirdparty/mbedtls/library/ssl_srv.c
index 97b778452c..cbf6142ac2 100644
--- a/thirdparty/mbedtls/library/ssl_srv.c
+++ b/thirdparty/mbedtls/library/ssl_srv.c
@@ -3587,11 +3587,12 @@ static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl,
/* In case of a failure in decryption, the decryption may write less than
* 2 bytes of output, but we always read the first two bytes. It doesn't
* matter in the end because diff will be nonzero in that case due to
- * peer_pmslen being less than 48, and we only care whether diff is 0.
- * But do initialize peer_pms for robustness anyway. This also makes
- * memory analyzers happy (don't access uninitialized memory, even
- * if it's an unsigned char). */
+ * ret being nonzero, and we only care whether diff is 0.
+ * But do initialize peer_pms and peer_pmslen for robustness anyway. This
+ * also makes memory analyzers happy (don't access uninitialized memory,
+ * even if it's an unsigned char). */
peer_pms[0] = peer_pms[1] = ~0;
+ peer_pmslen = 0;
ret = ssl_decrypt_encrypted_pms( ssl, p, end,
peer_pms,
diff --git a/thirdparty/mbedtls/library/ssl_tls.c b/thirdparty/mbedtls/library/ssl_tls.c
index 2471600c9a..c749a8611c 100644
--- a/thirdparty/mbedtls/library/ssl_tls.c
+++ b/thirdparty/mbedtls/library/ssl_tls.c
@@ -621,7 +621,7 @@ static void ssl_calc_finished_tls( mbedtls_ssl_context *, unsigned char *, int )
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
#if defined(MBEDTLS_SHA256_C)
static void ssl_update_checksum_sha256( mbedtls_ssl_context *, const unsigned char *, size_t );
-static void ssl_calc_verify_tls_sha256( mbedtls_ssl_context *,unsigned char * );
+static void ssl_calc_verify_tls_sha256( mbedtls_ssl_context *, unsigned char * );
static void ssl_calc_finished_tls_sha256( mbedtls_ssl_context *,unsigned char *, int );
#endif
@@ -1142,7 +1142,7 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl )
}
#if defined(MBEDTLS_SSL_PROTO_SSL3)
-void ssl_calc_verify_ssl( mbedtls_ssl_context *ssl, unsigned char hash[36] )
+void ssl_calc_verify_ssl( mbedtls_ssl_context *ssl, unsigned char *hash )
{
mbedtls_md5_context md5;
mbedtls_sha1_context sha1;
@@ -1191,7 +1191,7 @@ void ssl_calc_verify_ssl( mbedtls_ssl_context *ssl, unsigned char hash[36] )
#endif /* MBEDTLS_SSL_PROTO_SSL3 */
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1)
-void ssl_calc_verify_tls( mbedtls_ssl_context *ssl, unsigned char hash[36] )
+void ssl_calc_verify_tls( mbedtls_ssl_context *ssl, unsigned char *hash )
{
mbedtls_md5_context md5;
mbedtls_sha1_context sha1;
@@ -1219,7 +1219,7 @@ void ssl_calc_verify_tls( mbedtls_ssl_context *ssl, unsigned char hash[36] )
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
#if defined(MBEDTLS_SHA256_C)
-void ssl_calc_verify_tls_sha256( mbedtls_ssl_context *ssl, unsigned char hash[32] )
+void ssl_calc_verify_tls_sha256( mbedtls_ssl_context *ssl, unsigned char *hash )
{
mbedtls_sha256_context sha256;
@@ -1240,7 +1240,7 @@ void ssl_calc_verify_tls_sha256( mbedtls_ssl_context *ssl, unsigned char hash[32
#endif /* MBEDTLS_SHA256_C */
#if defined(MBEDTLS_SHA512_C)
-void ssl_calc_verify_tls_sha384( mbedtls_ssl_context *ssl, unsigned char hash[48] )
+void ssl_calc_verify_tls_sha384( mbedtls_ssl_context *ssl, unsigned char *hash )
{
mbedtls_sha512_context sha512;
@@ -6363,6 +6363,9 @@ static void ssl_calc_finished_tls_sha256(
#endif /* MBEDTLS_SHA256_C */
#if defined(MBEDTLS_SHA512_C)
+
+typedef int (*finish_sha384_t)(mbedtls_sha512_context*, unsigned char*);
+
static void ssl_calc_finished_tls_sha384(
mbedtls_ssl_context *ssl, unsigned char *buf, int from )
{
@@ -6370,6 +6373,12 @@ static void ssl_calc_finished_tls_sha384(
const char *sender;
mbedtls_sha512_context sha512;
unsigned char padbuf[48];
+ /*
+ * For SHA-384, we can save 16 bytes by keeping padbuf 48 bytes long.
+ * However, to avoid stringop-overflow warning in gcc, we have to cast
+ * mbedtls_sha512_finish_ret().
+ */
+ finish_sha384_t finish_sha384 = (finish_sha384_t)mbedtls_sha512_finish_ret;
mbedtls_ssl_session *session = ssl->session_negotiate;
if( !session )
@@ -6396,7 +6405,7 @@ static void ssl_calc_finished_tls_sha384(
? "client finished"
: "server finished";
- mbedtls_sha512_finish_ret( &sha512, padbuf );
+ finish_sha384( &sha512, padbuf );
ssl->handshake->tls_prf( session->master, 48, sender,
padbuf, 48, buf, len );
diff --git a/thirdparty/mbedtls/library/threading.c b/thirdparty/mbedtls/library/threading.c
index 61c4b94041..f4f29cff5e 100644
--- a/thirdparty/mbedtls/library/threading.c
+++ b/thirdparty/mbedtls/library/threading.c
@@ -73,7 +73,7 @@
#if !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \
( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \
- _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) )
+ _POSIX_THREAD_SAFE_FUNCTIONS >= 200112L ) )
/*
* This is a convenience shorthand macro to avoid checking the long
* preprocessor conditions above. Ideally, we could expose this macro in
@@ -88,7 +88,7 @@
#endif /* !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \
( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \
- _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) ) */
+ _POSIX_THREAD_SAFE_FUNCTIONS >= 200112L ) ) */
#endif /* MBEDTLS_HAVE_TIME_DATE && !MBEDTLS_PLATFORM_GMTIME_R_ALT */
diff --git a/thirdparty/mbedtls/library/x509_crt.c b/thirdparty/mbedtls/library/x509_crt.c
index de40eaaf58..c458c25ff4 100644
--- a/thirdparty/mbedtls/library/x509_crt.c
+++ b/thirdparty/mbedtls/library/x509_crt.c
@@ -1101,6 +1101,7 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, const unsigned char *
if( crt->sig_oid.len != sig_oid2.len ||
memcmp( crt->sig_oid.p, sig_oid2.p, crt->sig_oid.len ) != 0 ||
+ sig_params1.tag != sig_params2.tag ||
sig_params1.len != sig_params2.len ||
( sig_params1.len != 0 &&
memcmp( sig_params1.p, sig_params2.p, sig_params1.len ) != 0 ) )
diff --git a/thirdparty/meshoptimizer/LICENSE.md b/thirdparty/meshoptimizer/LICENSE.md
new file mode 100644
index 0000000000..4fcd766d22
--- /dev/null
+++ b/thirdparty/meshoptimizer/LICENSE.md
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2016-2020 Arseny Kapoulkine
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION 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/meshoptimizer/allocator.cpp b/thirdparty/meshoptimizer/allocator.cpp
new file mode 100644
index 0000000000..da7cc540b2
--- /dev/null
+++ b/thirdparty/meshoptimizer/allocator.cpp
@@ -0,0 +1,8 @@
+// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
+#include "meshoptimizer.h"
+
+void meshopt_setAllocator(void* (*allocate)(size_t), void (*deallocate)(void*))
+{
+ meshopt_Allocator::Storage::allocate = allocate;
+ meshopt_Allocator::Storage::deallocate = deallocate;
+}
diff --git a/thirdparty/meshoptimizer/clusterizer.cpp b/thirdparty/meshoptimizer/clusterizer.cpp
new file mode 100644
index 0000000000..f7d88c5136
--- /dev/null
+++ b/thirdparty/meshoptimizer/clusterizer.cpp
@@ -0,0 +1,351 @@
+// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
+#include "meshoptimizer.h"
+
+#include <assert.h>
+#include <math.h>
+#include <string.h>
+
+// This work is based on:
+// Graham Wihlidal. Optimizing the Graphics Pipeline with Compute. 2016
+// Matthaeus Chajdas. GeometryFX 1.2 - Cluster Culling. 2016
+// Jack Ritter. An Efficient Bounding Sphere. 1990
+namespace meshopt
+{
+
+static void computeBoundingSphere(float result[4], const float points[][3], size_t count)
+{
+ assert(count > 0);
+
+ // find extremum points along all 3 axes; for each axis we get a pair of points with min/max coordinates
+ size_t pmin[3] = {0, 0, 0};
+ size_t pmax[3] = {0, 0, 0};
+
+ for (size_t i = 0; i < count; ++i)
+ {
+ const float* p = points[i];
+
+ for (int axis = 0; axis < 3; ++axis)
+ {
+ pmin[axis] = (p[axis] < points[pmin[axis]][axis]) ? i : pmin[axis];
+ pmax[axis] = (p[axis] > points[pmax[axis]][axis]) ? i : pmax[axis];
+ }
+ }
+
+ // find the pair of points with largest distance
+ float paxisd2 = 0;
+ int paxis = 0;
+
+ for (int axis = 0; axis < 3; ++axis)
+ {
+ const float* p1 = points[pmin[axis]];
+ const float* p2 = points[pmax[axis]];
+
+ float d2 = (p2[0] - p1[0]) * (p2[0] - p1[0]) + (p2[1] - p1[1]) * (p2[1] - p1[1]) + (p2[2] - p1[2]) * (p2[2] - p1[2]);
+
+ if (d2 > paxisd2)
+ {
+ paxisd2 = d2;
+ paxis = axis;
+ }
+ }
+
+ // use the longest segment as the initial sphere diameter
+ const float* p1 = points[pmin[paxis]];
+ const float* p2 = points[pmax[paxis]];
+
+ float center[3] = {(p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2, (p1[2] + p2[2]) / 2};
+ float radius = sqrtf(paxisd2) / 2;
+
+ // iteratively adjust the sphere up until all points fit
+ for (size_t i = 0; i < count; ++i)
+ {
+ const float* p = points[i];
+ float d2 = (p[0] - center[0]) * (p[0] - center[0]) + (p[1] - center[1]) * (p[1] - center[1]) + (p[2] - center[2]) * (p[2] - center[2]);
+
+ if (d2 > radius * radius)
+ {
+ float d = sqrtf(d2);
+ assert(d > 0);
+
+ float k = 0.5f + (radius / d) / 2;
+
+ center[0] = center[0] * k + p[0] * (1 - k);
+ center[1] = center[1] * k + p[1] * (1 - k);
+ center[2] = center[2] * k + p[2] * (1 - k);
+ radius = (radius + d) / 2;
+ }
+ }
+
+ result[0] = center[0];
+ result[1] = center[1];
+ result[2] = center[2];
+ result[3] = radius;
+}
+
+} // namespace meshopt
+
+size_t meshopt_buildMeshletsBound(size_t index_count, size_t max_vertices, size_t max_triangles)
+{
+ assert(index_count % 3 == 0);
+ assert(max_vertices >= 3);
+ assert(max_triangles >= 1);
+
+ // meshlet construction is limited by max vertices and max triangles per meshlet
+ // the worst case is that the input is an unindexed stream since this equally stresses both limits
+ // note that we assume that in the worst case, we leave 2 vertices unpacked in each meshlet - if we have space for 3 we can pack any triangle
+ size_t max_vertices_conservative = max_vertices - 2;
+ size_t meshlet_limit_vertices = (index_count + max_vertices_conservative - 1) / max_vertices_conservative;
+ size_t meshlet_limit_triangles = (index_count / 3 + max_triangles - 1) / max_triangles;
+
+ return meshlet_limit_vertices > meshlet_limit_triangles ? meshlet_limit_vertices : meshlet_limit_triangles;
+}
+
+size_t meshopt_buildMeshlets(meshopt_Meshlet* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles)
+{
+ assert(index_count % 3 == 0);
+ assert(max_vertices >= 3);
+ assert(max_triangles >= 1);
+
+ meshopt_Allocator allocator;
+
+ meshopt_Meshlet meshlet;
+ memset(&meshlet, 0, sizeof(meshlet));
+
+ assert(max_vertices <= sizeof(meshlet.vertices) / sizeof(meshlet.vertices[0]));
+ assert(max_triangles <= sizeof(meshlet.indices) / 3);
+
+ // index of the vertex in the meshlet, 0xff if the vertex isn't used
+ unsigned char* used = allocator.allocate<unsigned char>(vertex_count);
+ memset(used, -1, vertex_count);
+
+ size_t offset = 0;
+
+ for (size_t i = 0; i < index_count; i += 3)
+ {
+ unsigned int a = indices[i + 0], b = indices[i + 1], c = indices[i + 2];
+ assert(a < vertex_count && b < vertex_count && c < vertex_count);
+
+ unsigned char& av = used[a];
+ unsigned char& bv = used[b];
+ unsigned char& cv = used[c];
+
+ unsigned int used_extra = (av == 0xff) + (bv == 0xff) + (cv == 0xff);
+
+ if (meshlet.vertex_count + used_extra > max_vertices || meshlet.triangle_count >= max_triangles)
+ {
+ destination[offset++] = meshlet;
+
+ for (size_t j = 0; j < meshlet.vertex_count; ++j)
+ used[meshlet.vertices[j]] = 0xff;
+
+ memset(&meshlet, 0, sizeof(meshlet));
+ }
+
+ if (av == 0xff)
+ {
+ av = meshlet.vertex_count;
+ meshlet.vertices[meshlet.vertex_count++] = a;
+ }
+
+ if (bv == 0xff)
+ {
+ bv = meshlet.vertex_count;
+ meshlet.vertices[meshlet.vertex_count++] = b;
+ }
+
+ if (cv == 0xff)
+ {
+ cv = meshlet.vertex_count;
+ meshlet.vertices[meshlet.vertex_count++] = c;
+ }
+
+ meshlet.indices[meshlet.triangle_count][0] = av;
+ meshlet.indices[meshlet.triangle_count][1] = bv;
+ meshlet.indices[meshlet.triangle_count][2] = cv;
+ meshlet.triangle_count++;
+ }
+
+ if (meshlet.triangle_count)
+ destination[offset++] = meshlet;
+
+ assert(offset <= meshopt_buildMeshletsBound(index_count, max_vertices, max_triangles));
+
+ return offset;
+}
+
+meshopt_Bounds meshopt_computeClusterBounds(const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
+{
+ 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(index_count / 3 <= 256);
+
+ (void)vertex_count;
+
+ size_t vertex_stride_float = vertex_positions_stride / sizeof(float);
+
+ // compute triangle normals and gather triangle corners
+ float normals[256][3];
+ float corners[256][3][3];
+ size_t triangles = 0;
+
+ for (size_t i = 0; i < index_count; i += 3)
+ {
+ unsigned int a = indices[i + 0], b = indices[i + 1], c = indices[i + 2];
+ assert(a < vertex_count && b < vertex_count && c < vertex_count);
+
+ const float* p0 = vertex_positions + vertex_stride_float * a;
+ const float* p1 = vertex_positions + vertex_stride_float * b;
+ const float* p2 = vertex_positions + vertex_stride_float * c;
+
+ float p10[3] = {p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2]};
+ float p20[3] = {p2[0] - p0[0], p2[1] - p0[1], p2[2] - p0[2]};
+
+ float normalx = p10[1] * p20[2] - p10[2] * p20[1];
+ float normaly = p10[2] * p20[0] - p10[0] * p20[2];
+ float normalz = p10[0] * p20[1] - p10[1] * p20[0];
+
+ float area = sqrtf(normalx * normalx + normaly * normaly + normalz * normalz);
+
+ // no need to include degenerate triangles - they will be invisible anyway
+ if (area == 0.f)
+ continue;
+
+ // record triangle normals & corners for future use; normal and corner 0 define a plane equation
+ normals[triangles][0] = normalx / area;
+ normals[triangles][1] = normaly / area;
+ normals[triangles][2] = normalz / area;
+ memcpy(corners[triangles][0], p0, 3 * sizeof(float));
+ memcpy(corners[triangles][1], p1, 3 * sizeof(float));
+ memcpy(corners[triangles][2], p2, 3 * sizeof(float));
+ triangles++;
+ }
+
+ meshopt_Bounds bounds = {};
+
+ // degenerate cluster, no valid triangles => trivial reject (cone data is 0)
+ if (triangles == 0)
+ return bounds;
+
+ // compute cluster bounding sphere; we'll use the center to determine normal cone apex as well
+ float psphere[4] = {};
+ computeBoundingSphere(psphere, corners[0], triangles * 3);
+
+ float center[3] = {psphere[0], psphere[1], psphere[2]};
+
+ // treating triangle normals as points, find the bounding sphere - the sphere center determines the optimal cone axis
+ float nsphere[4] = {};
+ computeBoundingSphere(nsphere, normals, triangles);
+
+ float axis[3] = {nsphere[0], nsphere[1], nsphere[2]};
+ float axislength = sqrtf(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]);
+ float invaxislength = axislength == 0.f ? 0.f : 1.f / axislength;
+
+ axis[0] *= invaxislength;
+ axis[1] *= invaxislength;
+ axis[2] *= invaxislength;
+
+ // compute a tight cone around all normals, mindp = cos(angle/2)
+ float mindp = 1.f;
+
+ for (size_t i = 0; i < triangles; ++i)
+ {
+ float dp = normals[i][0] * axis[0] + normals[i][1] * axis[1] + normals[i][2] * axis[2];
+
+ mindp = (dp < mindp) ? dp : mindp;
+ }
+
+ // fill bounding sphere info; note that below we can return bounds without cone information for degenerate cones
+ bounds.center[0] = center[0];
+ bounds.center[1] = center[1];
+ bounds.center[2] = center[2];
+ bounds.radius = psphere[3];
+
+ // degenerate cluster, normal cone is larger than a hemisphere => trivial accept
+ // note that if mindp is positive but close to 0, the triangle intersection code below gets less stable
+ // we arbitrarily decide that if a normal cone is ~168 degrees wide or more, the cone isn't useful
+ if (mindp <= 0.1f)
+ {
+ bounds.cone_cutoff = 1;
+ bounds.cone_cutoff_s8 = 127;
+ return bounds;
+ }
+
+ float maxt = 0;
+
+ // we need to find the point on center-t*axis ray that lies in negative half-space of all triangles
+ for (size_t i = 0; i < triangles; ++i)
+ {
+ // dot(center-t*axis-corner, trinormal) = 0
+ // dot(center-corner, trinormal) - t * dot(axis, trinormal) = 0
+ float cx = center[0] - corners[i][0][0];
+ float cy = center[1] - corners[i][0][1];
+ float cz = center[2] - corners[i][0][2];
+
+ float dc = cx * normals[i][0] + cy * normals[i][1] + cz * normals[i][2];
+ float dn = axis[0] * normals[i][0] + axis[1] * normals[i][1] + axis[2] * normals[i][2];
+
+ // dn should be larger than mindp cutoff above
+ assert(dn > 0.f);
+ float t = dc / dn;
+
+ maxt = (t > maxt) ? t : maxt;
+ }
+
+ // cone apex should be in the negative half-space of all cluster triangles by construction
+ bounds.cone_apex[0] = center[0] - axis[0] * maxt;
+ bounds.cone_apex[1] = center[1] - axis[1] * maxt;
+ bounds.cone_apex[2] = center[2] - axis[2] * maxt;
+
+ // note: this axis is the axis of the normal cone, but our test for perspective camera effectively negates the axis
+ bounds.cone_axis[0] = axis[0];
+ bounds.cone_axis[1] = axis[1];
+ bounds.cone_axis[2] = axis[2];
+
+ // cos(a) for normal cone is mindp; we need to add 90 degrees on both sides and invert the cone
+ // which gives us -cos(a+90) = -(-sin(a)) = sin(a) = sqrt(1 - cos^2(a))
+ bounds.cone_cutoff = sqrtf(1 - mindp * mindp);
+
+ // quantize axis & cutoff to 8-bit SNORM format
+ bounds.cone_axis_s8[0] = (signed char)(meshopt_quantizeSnorm(bounds.cone_axis[0], 8));
+ bounds.cone_axis_s8[1] = (signed char)(meshopt_quantizeSnorm(bounds.cone_axis[1], 8));
+ bounds.cone_axis_s8[2] = (signed char)(meshopt_quantizeSnorm(bounds.cone_axis[2], 8));
+
+ // for the 8-bit test to be conservative, we need to adjust the cutoff by measuring the max. error
+ float cone_axis_s8_e0 = fabsf(bounds.cone_axis_s8[0] / 127.f - bounds.cone_axis[0]);
+ float cone_axis_s8_e1 = fabsf(bounds.cone_axis_s8[1] / 127.f - bounds.cone_axis[1]);
+ float cone_axis_s8_e2 = fabsf(bounds.cone_axis_s8[2] / 127.f - bounds.cone_axis[2]);
+
+ // note that we need to round this up instead of rounding to nearest, hence +1
+ int cone_cutoff_s8 = int(127 * (bounds.cone_cutoff + cone_axis_s8_e0 + cone_axis_s8_e1 + cone_axis_s8_e2) + 1);
+
+ bounds.cone_cutoff_s8 = (cone_cutoff_s8 > 127) ? 127 : (signed char)(cone_cutoff_s8);
+
+ return bounds;
+}
+
+meshopt_Bounds meshopt_computeMeshletBounds(const meshopt_Meshlet* meshlet, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
+{
+ assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
+ assert(vertex_positions_stride % sizeof(float) == 0);
+
+ unsigned int indices[sizeof(meshlet->indices) / sizeof(meshlet->indices[0][0])];
+
+ for (size_t i = 0; i < meshlet->triangle_count; ++i)
+ {
+ unsigned int a = meshlet->vertices[meshlet->indices[i][0]];
+ unsigned int b = meshlet->vertices[meshlet->indices[i][1]];
+ unsigned int c = meshlet->vertices[meshlet->indices[i][2]];
+
+ assert(a < vertex_count && b < vertex_count && c < vertex_count);
+
+ indices[i * 3 + 0] = a;
+ indices[i * 3 + 1] = b;
+ indices[i * 3 + 2] = c;
+ }
+
+ return meshopt_computeClusterBounds(indices, meshlet->triangle_count * 3, vertex_positions, vertex_count, vertex_positions_stride);
+}
diff --git a/thirdparty/meshoptimizer/indexcodec.cpp b/thirdparty/meshoptimizer/indexcodec.cpp
new file mode 100644
index 0000000000..eeb541e5be
--- /dev/null
+++ b/thirdparty/meshoptimizer/indexcodec.cpp
@@ -0,0 +1,752 @@
+// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
+#include "meshoptimizer.h"
+
+#include <assert.h>
+#include <string.h>
+
+#ifndef TRACE
+#define TRACE 0
+#endif
+
+#if TRACE
+#include <stdio.h>
+#endif
+
+// This work is based on:
+// Fabian Giesen. Simple lossless index buffer compression & follow-up. 2013
+// Conor Stokes. Vertex Cache Optimised Index Buffer Compression. 2014
+namespace meshopt
+{
+
+const unsigned char kIndexHeader = 0xe0;
+const unsigned char kSequenceHeader = 0xd0;
+
+static int gEncodeIndexVersion = 0;
+
+typedef unsigned int VertexFifo[16];
+typedef unsigned int EdgeFifo[16][2];
+
+static const unsigned int kTriangleIndexOrder[3][3] = {
+ {0, 1, 2},
+ {1, 2, 0},
+ {2, 0, 1},
+};
+
+static const unsigned char kCodeAuxEncodingTable[16] = {
+ 0x00, 0x76, 0x87, 0x56, 0x67, 0x78, 0xa9, 0x86, 0x65, 0x89, 0x68, 0x98, 0x01, 0x69,
+ 0, 0, // last two entries aren't used for encoding
+};
+
+static int rotateTriangle(unsigned int a, unsigned int b, unsigned int c, unsigned int next)
+{
+ (void)a;
+
+ return (b == next) ? 1 : (c == next) ? 2 : 0;
+}
+
+static int getEdgeFifo(EdgeFifo fifo, unsigned int a, unsigned int b, unsigned int c, size_t offset)
+{
+ for (int i = 0; i < 16; ++i)
+ {
+ size_t index = (offset - 1 - i) & 15;
+
+ unsigned int e0 = fifo[index][0];
+ unsigned int e1 = fifo[index][1];
+
+ if (e0 == a && e1 == b)
+ return (i << 2) | 0;
+ if (e0 == b && e1 == c)
+ return (i << 2) | 1;
+ if (e0 == c && e1 == a)
+ return (i << 2) | 2;
+ }
+
+ return -1;
+}
+
+static void pushEdgeFifo(EdgeFifo fifo, unsigned int a, unsigned int b, size_t& offset)
+{
+ fifo[offset][0] = a;
+ fifo[offset][1] = b;
+ offset = (offset + 1) & 15;
+}
+
+static int getVertexFifo(VertexFifo fifo, unsigned int v, size_t offset)
+{
+ for (int i = 0; i < 16; ++i)
+ {
+ size_t index = (offset - 1 - i) & 15;
+
+ if (fifo[index] == v)
+ return i;
+ }
+
+ return -1;
+}
+
+static void pushVertexFifo(VertexFifo fifo, unsigned int v, size_t& offset, int cond = 1)
+{
+ fifo[offset] = v;
+ offset = (offset + cond) & 15;
+}
+
+static void encodeVByte(unsigned char*& data, unsigned int v)
+{
+ // encode 32-bit value in up to 5 7-bit groups
+ do
+ {
+ *data++ = (v & 127) | (v > 127 ? 128 : 0);
+ v >>= 7;
+ } while (v);
+}
+
+static unsigned int decodeVByte(const unsigned char*& data)
+{
+ unsigned char lead = *data++;
+
+ // fast path: single byte
+ if (lead < 128)
+ return lead;
+
+ // slow path: up to 4 extra bytes
+ // note that this loop always terminates, which is important for malformed data
+ unsigned int result = lead & 127;
+ unsigned int shift = 7;
+
+ for (int i = 0; i < 4; ++i)
+ {
+ unsigned char group = *data++;
+ result |= (group & 127) << shift;
+ shift += 7;
+
+ if (group < 128)
+ break;
+ }
+
+ return result;
+}
+
+static void encodeIndex(unsigned char*& data, unsigned int index, unsigned int last)
+{
+ unsigned int d = index - last;
+ unsigned int v = (d << 1) ^ (int(d) >> 31);
+
+ encodeVByte(data, v);
+}
+
+static unsigned int decodeIndex(const unsigned char*& data, unsigned int last)
+{
+ unsigned int v = decodeVByte(data);
+ unsigned int d = (v >> 1) ^ -int(v & 1);
+
+ return last + d;
+}
+
+static int getCodeAuxIndex(unsigned char v, const unsigned char* table)
+{
+ for (int i = 0; i < 16; ++i)
+ if (table[i] == v)
+ return i;
+
+ return -1;
+}
+
+static void writeTriangle(void* destination, size_t offset, size_t index_size, unsigned int a, unsigned int b, unsigned int c)
+{
+ if (index_size == 2)
+ {
+ static_cast<unsigned short*>(destination)[offset + 0] = (unsigned short)(a);
+ static_cast<unsigned short*>(destination)[offset + 1] = (unsigned short)(b);
+ static_cast<unsigned short*>(destination)[offset + 2] = (unsigned short)(c);
+ }
+ else
+ {
+ static_cast<unsigned int*>(destination)[offset + 0] = a;
+ static_cast<unsigned int*>(destination)[offset + 1] = b;
+ static_cast<unsigned int*>(destination)[offset + 2] = c;
+ }
+}
+
+#if TRACE
+static size_t sortTop16(unsigned char dest[16], size_t stats[256])
+{
+ size_t destsize = 0;
+
+ for (size_t i = 0; i < 256; ++i)
+ {
+ size_t j = 0;
+ for (; j < destsize; ++j)
+ {
+ if (stats[i] >= stats[dest[j]])
+ {
+ if (destsize < 16)
+ destsize++;
+
+ memmove(&dest[j + 1], &dest[j], destsize - 1 - j);
+ dest[j] = (unsigned char)i;
+ break;
+ }
+ }
+
+ if (j == destsize && destsize < 16)
+ {
+ dest[destsize] = (unsigned char)i;
+ destsize++;
+ }
+ }
+
+ return destsize;
+}
+#endif
+
+} // namespace meshopt
+
+size_t meshopt_encodeIndexBuffer(unsigned char* buffer, size_t buffer_size, const unsigned int* indices, size_t index_count)
+{
+ using namespace meshopt;
+
+ assert(index_count % 3 == 0);
+
+#if TRACE
+ size_t codestats[256] = {};
+ size_t codeauxstats[256] = {};
+#endif
+
+ // the minimum valid encoding is header, 1 byte per triangle and a 16-byte codeaux table
+ if (buffer_size < 1 + index_count / 3 + 16)
+ return 0;
+
+ int version = gEncodeIndexVersion;
+
+ buffer[0] = (unsigned char)(kIndexHeader | version);
+
+ EdgeFifo edgefifo;
+ memset(edgefifo, -1, sizeof(edgefifo));
+
+ VertexFifo vertexfifo;
+ memset(vertexfifo, -1, sizeof(vertexfifo));
+
+ size_t edgefifooffset = 0;
+ size_t vertexfifooffset = 0;
+
+ unsigned int next = 0;
+ unsigned int last = 0;
+
+ unsigned char* code = buffer + 1;
+ unsigned char* data = code + index_count / 3;
+ unsigned char* data_safe_end = buffer + buffer_size - 16;
+
+ int fecmax = version >= 1 ? 13 : 15;
+
+ // use static encoding table; it's possible to pack the result and then build an optimal table and repack
+ // for now we keep it simple and use the table that has been generated based on symbol frequency on a training mesh set
+ const unsigned char* codeaux_table = kCodeAuxEncodingTable;
+
+ for (size_t i = 0; i < index_count; i += 3)
+ {
+ // make sure we have enough space to write a triangle
+ // each triangle writes at most 16 bytes: 1b for codeaux and 5b for each free index
+ // after this we can be sure we can write without extra bounds checks
+ if (data > data_safe_end)
+ return 0;
+
+ int fer = getEdgeFifo(edgefifo, indices[i + 0], indices[i + 1], indices[i + 2], edgefifooffset);
+
+ if (fer >= 0 && (fer >> 2) < 15)
+ {
+ const unsigned int* order = kTriangleIndexOrder[fer & 3];
+
+ unsigned int a = indices[i + order[0]], b = indices[i + order[1]], c = indices[i + order[2]];
+
+ // encode edge index and vertex fifo index, next or free index
+ int fe = fer >> 2;
+ int fc = getVertexFifo(vertexfifo, c, vertexfifooffset);
+
+ int fec = (fc >= 1 && fc < fecmax) ? fc : (c == next) ? (next++, 0) : 15;
+
+ if (fec == 15 && version >= 1)
+ {
+ // encode last-1 and last+1 to optimize strip-like sequences
+ if (c + 1 == last)
+ fec = 13, last = c;
+ if (c == last + 1)
+ fec = 14, last = c;
+ }
+
+ *code++ = (unsigned char)((fe << 4) | fec);
+
+#if TRACE
+ codestats[code[-1]]++;
+#endif
+
+ // note that we need to update the last index since free indices are delta-encoded
+ if (fec == 15)
+ encodeIndex(data, c, last), last = c;
+
+ // we only need to push third vertex since first two are likely already in the vertex fifo
+ if (fec == 0 || fec >= fecmax)
+ pushVertexFifo(vertexfifo, c, vertexfifooffset);
+
+ // we only need to push two new edges to edge fifo since the third one is already there
+ pushEdgeFifo(edgefifo, c, b, edgefifooffset);
+ pushEdgeFifo(edgefifo, a, c, edgefifooffset);
+ }
+ else
+ {
+ int rotation = rotateTriangle(indices[i + 0], indices[i + 1], indices[i + 2], next);
+ const unsigned int* order = kTriangleIndexOrder[rotation];
+
+ unsigned int a = indices[i + order[0]], b = indices[i + order[1]], c = indices[i + order[2]];
+
+ // if a/b/c are 0/1/2, we emit a reset code
+ bool reset = false;
+
+ if (a == 0 && b == 1 && c == 2 && next > 0 && version >= 1)
+ {
+ reset = true;
+ next = 0;
+
+ // reset vertex fifo to make sure we don't accidentally reference vertices from that in the future
+ // this makes sure next continues to get incremented instead of being stuck
+ memset(vertexfifo, -1, sizeof(vertexfifo));
+ }
+
+ int fb = getVertexFifo(vertexfifo, b, vertexfifooffset);
+ int fc = getVertexFifo(vertexfifo, c, vertexfifooffset);
+
+ // after rotation, a is almost always equal to next, so we don't waste bits on FIFO encoding for a
+ int fea = (a == next) ? (next++, 0) : 15;
+ int feb = (fb >= 0 && fb < 14) ? (fb + 1) : (b == next) ? (next++, 0) : 15;
+ int fec = (fc >= 0 && fc < 14) ? (fc + 1) : (c == next) ? (next++, 0) : 15;
+
+ // we encode feb & fec in 4 bits using a table if possible, and as a full byte otherwise
+ unsigned char codeaux = (unsigned char)((feb << 4) | fec);
+ int codeauxindex = getCodeAuxIndex(codeaux, codeaux_table);
+
+ // <14 encodes an index into codeaux table, 14 encodes fea=0, 15 encodes fea=15
+ if (fea == 0 && codeauxindex >= 0 && codeauxindex < 14 && !reset)
+ {
+ *code++ = (unsigned char)((15 << 4) | codeauxindex);
+ }
+ else
+ {
+ *code++ = (unsigned char)((15 << 4) | 14 | fea);
+ *data++ = codeaux;
+ }
+
+#if TRACE
+ codestats[code[-1]]++;
+ codeauxstats[codeaux]++;
+#endif
+
+ // note that we need to update the last index since free indices are delta-encoded
+ if (fea == 15)
+ encodeIndex(data, a, last), last = a;
+
+ if (feb == 15)
+ encodeIndex(data, b, last), last = b;
+
+ if (fec == 15)
+ encodeIndex(data, c, last), last = c;
+
+ // only push vertices that weren't already in fifo
+ if (fea == 0 || fea == 15)
+ pushVertexFifo(vertexfifo, a, vertexfifooffset);
+
+ if (feb == 0 || feb == 15)
+ pushVertexFifo(vertexfifo, b, vertexfifooffset);
+
+ if (fec == 0 || fec == 15)
+ pushVertexFifo(vertexfifo, c, vertexfifooffset);
+
+ // all three edges aren't in the fifo; pushing all of them is important so that we can match them for later triangles
+ pushEdgeFifo(edgefifo, b, a, edgefifooffset);
+ pushEdgeFifo(edgefifo, c, b, edgefifooffset);
+ pushEdgeFifo(edgefifo, a, c, edgefifooffset);
+ }
+ }
+
+ // make sure we have enough space to write codeaux table
+ if (data > data_safe_end)
+ return 0;
+
+ // add codeaux encoding table to the end of the stream; this is used for decoding codeaux *and* as padding
+ // we need padding for decoding to be able to assume that each triangle is encoded as <= 16 bytes of extra data
+ // this is enough space for aux byte + 5 bytes per varint index which is the absolute worst case for any input
+ for (size_t i = 0; i < 16; ++i)
+ {
+ // decoder assumes that table entries never refer to separately encoded indices
+ assert((codeaux_table[i] & 0xf) != 0xf && (codeaux_table[i] >> 4) != 0xf);
+
+ *data++ = codeaux_table[i];
+ }
+
+ // since we encode restarts as codeaux without a table reference, we need to make sure 00 is encoded as a table reference
+ assert(codeaux_table[0] == 0);
+
+ assert(data >= buffer + index_count / 3 + 16);
+ assert(data <= buffer + buffer_size);
+
+#if TRACE
+ unsigned char codetop[16], codeauxtop[16];
+ size_t codetopsize = sortTop16(codetop, codestats);
+ size_t codeauxtopsize = sortTop16(codeauxtop, codeauxstats);
+
+ size_t sumcode = 0, sumcodeaux = 0;
+ for (size_t i = 0; i < 256; ++i)
+ sumcode += codestats[i], sumcodeaux += codeauxstats[i];
+
+ size_t acccode = 0, acccodeaux = 0;
+
+ printf("code\t\t\t\t\tcodeaux\n");
+
+ for (size_t i = 0; i < codetopsize && i < codeauxtopsize; ++i)
+ {
+ acccode += codestats[codetop[i]];
+ acccodeaux += codeauxstats[codeauxtop[i]];
+
+ printf("%2d: %02x = %d (%.1f%% ..%.1f%%)\t\t%2d: %02x = %d (%.1f%% ..%.1f%%)\n",
+ int(i), codetop[i], int(codestats[codetop[i]]), double(codestats[codetop[i]]) / double(sumcode) * 100, double(acccode) / double(sumcode) * 100,
+ int(i), codeauxtop[i], int(codeauxstats[codeauxtop[i]]), double(codeauxstats[codeauxtop[i]]) / double(sumcodeaux) * 100, double(acccodeaux) / double(sumcodeaux) * 100);
+ }
+#endif
+
+ return data - buffer;
+}
+
+size_t meshopt_encodeIndexBufferBound(size_t index_count, size_t vertex_count)
+{
+ assert(index_count % 3 == 0);
+
+ // compute number of bits required for each index
+ unsigned int vertex_bits = 1;
+
+ while (vertex_bits < 32 && vertex_count > size_t(1) << vertex_bits)
+ vertex_bits++;
+
+ // worst-case encoding is 2 header bytes + 3 varint-7 encoded index deltas
+ unsigned int vertex_groups = (vertex_bits + 1 + 6) / 7;
+
+ return 1 + (index_count / 3) * (2 + 3 * vertex_groups) + 16;
+}
+
+void meshopt_encodeIndexVersion(int version)
+{
+ assert(unsigned(version) <= 1);
+
+ meshopt::gEncodeIndexVersion = version;
+}
+
+int meshopt_decodeIndexBuffer(void* destination, size_t index_count, size_t index_size, const unsigned char* buffer, size_t buffer_size)
+{
+ using namespace meshopt;
+
+ assert(index_count % 3 == 0);
+ assert(index_size == 2 || index_size == 4);
+
+ // the minimum valid encoding is header, 1 byte per triangle and a 16-byte codeaux table
+ if (buffer_size < 1 + index_count / 3 + 16)
+ return -2;
+
+ if ((buffer[0] & 0xf0) != kIndexHeader)
+ return -1;
+
+ int version = buffer[0] & 0x0f;
+ if (version > 1)
+ return -1;
+
+ EdgeFifo edgefifo;
+ memset(edgefifo, -1, sizeof(edgefifo));
+
+ VertexFifo vertexfifo;
+ memset(vertexfifo, -1, sizeof(vertexfifo));
+
+ size_t edgefifooffset = 0;
+ size_t vertexfifooffset = 0;
+
+ unsigned int next = 0;
+ unsigned int last = 0;
+
+ int fecmax = version >= 1 ? 13 : 15;
+
+ // since we store 16-byte codeaux table at the end, triangle data has to begin before data_safe_end
+ const unsigned char* code = buffer + 1;
+ const unsigned char* data = code + index_count / 3;
+ const unsigned char* data_safe_end = buffer + buffer_size - 16;
+
+ const unsigned char* codeaux_table = data_safe_end;
+
+ for (size_t i = 0; i < index_count; i += 3)
+ {
+ // make sure we have enough data to read for a triangle
+ // each triangle reads at most 16 bytes of data: 1b for codeaux and 5b for each free index
+ // after this we can be sure we can read without extra bounds checks
+ if (data > data_safe_end)
+ return -2;
+
+ unsigned char codetri = *code++;
+
+ if (codetri < 0xf0)
+ {
+ int fe = codetri >> 4;
+
+ // fifo reads are wrapped around 16 entry buffer
+ unsigned int a = edgefifo[(edgefifooffset - 1 - fe) & 15][0];
+ unsigned int b = edgefifo[(edgefifooffset - 1 - fe) & 15][1];
+
+ int fec = codetri & 15;
+
+ // note: this is the most common path in the entire decoder
+ // inside this if we try to stay branchless (by using cmov/etc.) since these aren't predictable
+ if (fec < fecmax)
+ {
+ // fifo reads are wrapped around 16 entry buffer
+ unsigned int cf = vertexfifo[(vertexfifooffset - 1 - fec) & 15];
+ unsigned int c = (fec == 0) ? next : cf;
+
+ int fec0 = fec == 0;
+ next += fec0;
+
+ // output triangle
+ writeTriangle(destination, i, index_size, a, b, c);
+
+ // push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly
+ pushVertexFifo(vertexfifo, c, vertexfifooffset, fec0);
+
+ pushEdgeFifo(edgefifo, c, b, edgefifooffset);
+ pushEdgeFifo(edgefifo, a, c, edgefifooffset);
+ }
+ else
+ {
+ unsigned int c = 0;
+
+ // fec - (fec ^ 3) decodes 13, 14 into -1, 1
+ // note that we need to update the last index since free indices are delta-encoded
+ last = c = (fec != 15) ? last + (fec - (fec ^ 3)) : decodeIndex(data, last);
+
+ // output triangle
+ writeTriangle(destination, i, index_size, a, b, c);
+
+ // push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly
+ pushVertexFifo(vertexfifo, c, vertexfifooffset);
+
+ pushEdgeFifo(edgefifo, c, b, edgefifooffset);
+ pushEdgeFifo(edgefifo, a, c, edgefifooffset);
+ }
+ }
+ else
+ {
+ // fast path: read codeaux from the table
+ if (codetri < 0xfe)
+ {
+ unsigned char codeaux = codeaux_table[codetri & 15];
+
+ // note: table can't contain feb/fec=15
+ int feb = codeaux >> 4;
+ int fec = codeaux & 15;
+
+ // fifo reads are wrapped around 16 entry buffer
+ // also note that we increment next for all three vertices before decoding indices - this matches encoder behavior
+ unsigned int a = next++;
+
+ unsigned int bf = vertexfifo[(vertexfifooffset - feb) & 15];
+ unsigned int b = (feb == 0) ? next : bf;
+
+ int feb0 = feb == 0;
+ next += feb0;
+
+ unsigned int cf = vertexfifo[(vertexfifooffset - fec) & 15];
+ unsigned int c = (fec == 0) ? next : cf;
+
+ int fec0 = fec == 0;
+ next += fec0;
+
+ // output triangle
+ writeTriangle(destination, i, index_size, a, b, c);
+
+ // push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly
+ pushVertexFifo(vertexfifo, a, vertexfifooffset);
+ pushVertexFifo(vertexfifo, b, vertexfifooffset, feb0);
+ pushVertexFifo(vertexfifo, c, vertexfifooffset, fec0);
+
+ pushEdgeFifo(edgefifo, b, a, edgefifooffset);
+ pushEdgeFifo(edgefifo, c, b, edgefifooffset);
+ pushEdgeFifo(edgefifo, a, c, edgefifooffset);
+ }
+ else
+ {
+ // slow path: read a full byte for codeaux instead of using a table lookup
+ unsigned char codeaux = *data++;
+
+ int fea = codetri == 0xfe ? 0 : 15;
+ int feb = codeaux >> 4;
+ int fec = codeaux & 15;
+
+ // reset: codeaux is 0 but encoded as not-a-table
+ if (codeaux == 0)
+ next = 0;
+
+ // fifo reads are wrapped around 16 entry buffer
+ // also note that we increment next for all three vertices before decoding indices - this matches encoder behavior
+ unsigned int a = (fea == 0) ? next++ : 0;
+ unsigned int b = (feb == 0) ? next++ : vertexfifo[(vertexfifooffset - feb) & 15];
+ unsigned int c = (fec == 0) ? next++ : vertexfifo[(vertexfifooffset - fec) & 15];
+
+ // note that we need to update the last index since free indices are delta-encoded
+ if (fea == 15)
+ last = a = decodeIndex(data, last);
+
+ if (feb == 15)
+ last = b = decodeIndex(data, last);
+
+ if (fec == 15)
+ last = c = decodeIndex(data, last);
+
+ // output triangle
+ writeTriangle(destination, i, index_size, a, b, c);
+
+ // push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly
+ pushVertexFifo(vertexfifo, a, vertexfifooffset);
+ pushVertexFifo(vertexfifo, b, vertexfifooffset, (feb == 0) | (feb == 15));
+ pushVertexFifo(vertexfifo, c, vertexfifooffset, (fec == 0) | (fec == 15));
+
+ pushEdgeFifo(edgefifo, b, a, edgefifooffset);
+ pushEdgeFifo(edgefifo, c, b, edgefifooffset);
+ pushEdgeFifo(edgefifo, a, c, edgefifooffset);
+ }
+ }
+ }
+
+ // we should've read all data bytes and stopped at the boundary between data and codeaux table
+ if (data != data_safe_end)
+ return -3;
+
+ return 0;
+}
+
+size_t meshopt_encodeIndexSequence(unsigned char* buffer, size_t buffer_size, const unsigned int* indices, size_t index_count)
+{
+ using namespace meshopt;
+
+ // the minimum valid encoding is header, 1 byte per index and a 4-byte tail
+ if (buffer_size < 1 + index_count + 4)
+ return 0;
+
+ int version = gEncodeIndexVersion;
+
+ buffer[0] = (unsigned char)(kSequenceHeader | version);
+
+ unsigned int last[2] = {};
+ unsigned int current = 0;
+
+ unsigned char* data = buffer + 1;
+ unsigned char* data_safe_end = buffer + buffer_size - 4;
+
+ for (size_t i = 0; i < index_count; ++i)
+ {
+ // make sure we have enough data to write
+ // each index writes at most 5 bytes of data; there's a 4 byte tail after data_safe_end
+ // after this we can be sure we can write without extra bounds checks
+ if (data >= data_safe_end)
+ return 0;
+
+ unsigned int index = indices[i];
+
+ // this is a heuristic that switches between baselines when the delta grows too large
+ // we want the encoded delta to fit into one byte (7 bits), but 2 bits are used for sign and baseline index
+ // for now we immediately switch the baseline when delta grows too large - this can be adjusted arbitrarily
+ int cd = int(index - last[current]);
+ current ^= ((cd < 0 ? -cd : cd) >= 30);
+
+ // encode delta from the last index
+ unsigned int d = index - last[current];
+ unsigned int v = (d << 1) ^ (int(d) >> 31);
+
+ // note: low bit encodes the index of the last baseline which will be used for reconstruction
+ encodeVByte(data, (v << 1) | current);
+
+ // update last for the next iteration that uses it
+ last[current] = index;
+ }
+
+ // make sure we have enough space to write tail
+ if (data > data_safe_end)
+ return 0;
+
+ for (int k = 0; k < 4; ++k)
+ *data++ = 0;
+
+ return data - buffer;
+}
+
+size_t meshopt_encodeIndexSequenceBound(size_t index_count, size_t vertex_count)
+{
+ // compute number of bits required for each index
+ unsigned int vertex_bits = 1;
+
+ while (vertex_bits < 32 && vertex_count > size_t(1) << vertex_bits)
+ vertex_bits++;
+
+ // worst-case encoding is 1 varint-7 encoded index delta for a K bit value and an extra bit
+ unsigned int vertex_groups = (vertex_bits + 1 + 1 + 6) / 7;
+
+ return 1 + index_count * vertex_groups + 4;
+}
+
+int meshopt_decodeIndexSequence(void* destination, size_t index_count, size_t index_size, const unsigned char* buffer, size_t buffer_size)
+{
+ using namespace meshopt;
+
+ // the minimum valid encoding is header, 1 byte per index and a 4-byte tail
+ if (buffer_size < 1 + index_count + 4)
+ return -2;
+
+ if ((buffer[0] & 0xf0) != kSequenceHeader)
+ return -1;
+
+ int version = buffer[0] & 0x0f;
+ if (version > 1)
+ return -1;
+
+ const unsigned char* data = buffer + 1;
+ const unsigned char* data_safe_end = buffer + buffer_size - 4;
+
+ unsigned int last[2] = {};
+
+ for (size_t i = 0; i < index_count; ++i)
+ {
+ // make sure we have enough data to read
+ // each index reads at most 5 bytes of data; there's a 4 byte tail after data_safe_end
+ // after this we can be sure we can read without extra bounds checks
+ if (data >= data_safe_end)
+ return -2;
+
+ unsigned int v = decodeVByte(data);
+
+ // decode the index of the last baseline
+ unsigned int current = v & 1;
+ v >>= 1;
+
+ // reconstruct index as a delta
+ unsigned int d = (v >> 1) ^ -int(v & 1);
+ unsigned int index = last[current] + d;
+
+ // update last for the next iteration that uses it
+ last[current] = index;
+
+ if (index_size == 2)
+ {
+ static_cast<unsigned short*>(destination)[i] = (unsigned short)(index);
+ }
+ else
+ {
+ static_cast<unsigned int*>(destination)[i] = index;
+ }
+ }
+
+ // we should've read all data bytes and stopped at the boundary between data and tail
+ if (data != data_safe_end)
+ return -3;
+
+ return 0;
+}
diff --git a/thirdparty/meshoptimizer/indexgenerator.cpp b/thirdparty/meshoptimizer/indexgenerator.cpp
new file mode 100644
index 0000000000..aa4a30efa4
--- /dev/null
+++ b/thirdparty/meshoptimizer/indexgenerator.cpp
@@ -0,0 +1,347 @@
+// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
+#include "meshoptimizer.h"
+
+#include <assert.h>
+#include <string.h>
+
+namespace meshopt
+{
+
+static unsigned int hashUpdate4(unsigned int h, const unsigned char* key, size_t len)
+{
+ // MurmurHash2
+ const unsigned int m = 0x5bd1e995;
+ const int r = 24;
+
+ while (len >= 4)
+ {
+ unsigned int k = *reinterpret_cast<const unsigned int*>(key);
+
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+
+ h *= m;
+ h ^= k;
+
+ key += 4;
+ len -= 4;
+ }
+
+ return h;
+}
+
+struct VertexHasher
+{
+ const unsigned char* vertices;
+ size_t vertex_size;
+ size_t vertex_stride;
+
+ size_t hash(unsigned int index) const
+ {
+ return hashUpdate4(0, vertices + index * vertex_stride, vertex_size);
+ }
+
+ bool equal(unsigned int lhs, unsigned int rhs) const
+ {
+ return memcmp(vertices + lhs * vertex_stride, vertices + rhs * vertex_stride, vertex_size) == 0;
+ }
+};
+
+struct VertexStreamHasher
+{
+ const meshopt_Stream* streams;
+ size_t stream_count;
+
+ size_t hash(unsigned int index) const
+ {
+ unsigned int h = 0;
+
+ for (size_t i = 0; i < stream_count; ++i)
+ {
+ const meshopt_Stream& s = streams[i];
+ const unsigned char* data = static_cast<const unsigned char*>(s.data);
+
+ h = hashUpdate4(h, data + index * s.stride, s.size);
+ }
+
+ return h;
+ }
+
+ bool equal(unsigned int lhs, unsigned int rhs) const
+ {
+ for (size_t i = 0; i < stream_count; ++i)
+ {
+ const meshopt_Stream& s = streams[i];
+ const unsigned char* data = static_cast<const unsigned char*>(s.data);
+
+ if (memcmp(data + lhs * s.stride, data + rhs * s.stride, s.size) != 0)
+ return false;
+ }
+
+ return true;
+ }
+};
+
+static size_t hashBuckets(size_t count)
+{
+ size_t buckets = 1;
+ while (buckets < count)
+ buckets *= 2;
+
+ return buckets;
+}
+
+template <typename T, typename Hash>
+static T* hashLookup(T* table, size_t buckets, const Hash& hash, const T& key, const T& empty)
+{
+ assert(buckets > 0);
+ assert((buckets & (buckets - 1)) == 0);
+
+ size_t hashmod = buckets - 1;
+ size_t bucket = hash.hash(key) & hashmod;
+
+ for (size_t probe = 0; probe <= hashmod; ++probe)
+ {
+ T& item = table[bucket];
+
+ if (item == empty)
+ return &item;
+
+ if (hash.equal(item, key))
+ return &item;
+
+ // hash collision, quadratic probing
+ bucket = (bucket + probe + 1) & hashmod;
+ }
+
+ assert(false && "Hash table is full"); // unreachable
+ return 0;
+}
+
+} // namespace meshopt
+
+size_t meshopt_generateVertexRemap(unsigned int* destination, const unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size)
+{
+ using namespace meshopt;
+
+ assert(indices || index_count == vertex_count);
+ assert(index_count % 3 == 0);
+ assert(vertex_size > 0 && vertex_size <= 256);
+
+ meshopt_Allocator allocator;
+
+ memset(destination, -1, vertex_count * sizeof(unsigned int));
+
+ VertexHasher hasher = {static_cast<const unsigned char*>(vertices), vertex_size, vertex_size};
+
+ size_t table_size = hashBuckets(vertex_count);
+ unsigned int* table = allocator.allocate<unsigned int>(table_size);
+ memset(table, -1, table_size * sizeof(unsigned int));
+
+ unsigned int next_vertex = 0;
+
+ for (size_t i = 0; i < index_count; ++i)
+ {
+ unsigned int index = indices ? indices[i] : unsigned(i);
+ assert(index < vertex_count);
+
+ if (destination[index] == ~0u)
+ {
+ unsigned int* entry = hashLookup(table, table_size, hasher, index, ~0u);
+
+ if (*entry == ~0u)
+ {
+ *entry = index;
+
+ destination[index] = next_vertex++;
+ }
+ else
+ {
+ assert(destination[*entry] != ~0u);
+
+ destination[index] = destination[*entry];
+ }
+ }
+ }
+
+ assert(next_vertex <= vertex_count);
+
+ return next_vertex;
+}
+
+size_t meshopt_generateVertexRemapMulti(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, const struct meshopt_Stream* streams, size_t stream_count)
+{
+ using namespace meshopt;
+
+ assert(indices || index_count == vertex_count);
+ assert(index_count % 3 == 0);
+ assert(stream_count > 0 && stream_count <= 16);
+
+ for (size_t i = 0; i < stream_count; ++i)
+ {
+ assert(streams[i].size > 0 && streams[i].size <= 256);
+ assert(streams[i].size <= streams[i].stride);
+ }
+
+ meshopt_Allocator allocator;
+
+ memset(destination, -1, vertex_count * sizeof(unsigned int));
+
+ VertexStreamHasher hasher = {streams, stream_count};
+
+ size_t table_size = hashBuckets(vertex_count);
+ unsigned int* table = allocator.allocate<unsigned int>(table_size);
+ memset(table, -1, table_size * sizeof(unsigned int));
+
+ unsigned int next_vertex = 0;
+
+ for (size_t i = 0; i < index_count; ++i)
+ {
+ unsigned int index = indices ? indices[i] : unsigned(i);
+ assert(index < vertex_count);
+
+ if (destination[index] == ~0u)
+ {
+ unsigned int* entry = hashLookup(table, table_size, hasher, index, ~0u);
+
+ if (*entry == ~0u)
+ {
+ *entry = index;
+
+ destination[index] = next_vertex++;
+ }
+ else
+ {
+ assert(destination[*entry] != ~0u);
+
+ destination[index] = destination[*entry];
+ }
+ }
+ }
+
+ assert(next_vertex <= vertex_count);
+
+ return next_vertex;
+}
+
+void meshopt_remapVertexBuffer(void* destination, const void* vertices, size_t vertex_count, size_t vertex_size, const unsigned int* remap)
+{
+ assert(vertex_size > 0 && vertex_size <= 256);
+
+ meshopt_Allocator allocator;
+
+ // support in-place remap
+ if (destination == vertices)
+ {
+ unsigned char* vertices_copy = allocator.allocate<unsigned char>(vertex_count * vertex_size);
+ memcpy(vertices_copy, vertices, vertex_count * vertex_size);
+ vertices = vertices_copy;
+ }
+
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ if (remap[i] != ~0u)
+ {
+ assert(remap[i] < vertex_count);
+
+ memcpy(static_cast<unsigned char*>(destination) + remap[i] * vertex_size, static_cast<const unsigned char*>(vertices) + i * vertex_size, vertex_size);
+ }
+ }
+}
+
+void meshopt_remapIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const unsigned int* remap)
+{
+ assert(index_count % 3 == 0);
+
+ for (size_t i = 0; i < index_count; ++i)
+ {
+ unsigned int index = indices ? indices[i] : unsigned(i);
+ assert(remap[index] != ~0u);
+
+ destination[i] = remap[index];
+ }
+}
+
+void meshopt_generateShadowIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size, size_t vertex_stride)
+{
+ using namespace meshopt;
+
+ assert(indices);
+ assert(index_count % 3 == 0);
+ assert(vertex_size > 0 && vertex_size <= 256);
+ assert(vertex_size <= vertex_stride);
+
+ meshopt_Allocator allocator;
+
+ unsigned int* remap = allocator.allocate<unsigned int>(vertex_count);
+ memset(remap, -1, vertex_count * sizeof(unsigned int));
+
+ VertexHasher hasher = {static_cast<const unsigned char*>(vertices), vertex_size, vertex_stride};
+
+ size_t table_size = hashBuckets(vertex_count);
+ unsigned int* table = allocator.allocate<unsigned int>(table_size);
+ memset(table, -1, table_size * sizeof(unsigned int));
+
+ for (size_t i = 0; i < index_count; ++i)
+ {
+ unsigned int index = indices[i];
+ assert(index < vertex_count);
+
+ if (remap[index] == ~0u)
+ {
+ unsigned int* entry = hashLookup(table, table_size, hasher, index, ~0u);
+
+ if (*entry == ~0u)
+ *entry = index;
+
+ remap[index] = *entry;
+ }
+
+ destination[i] = remap[index];
+ }
+}
+
+void meshopt_generateShadowIndexBufferMulti(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, const struct meshopt_Stream* streams, size_t stream_count)
+{
+ using namespace meshopt;
+
+ assert(indices);
+ assert(index_count % 3 == 0);
+ assert(stream_count > 0 && stream_count <= 16);
+
+ for (size_t i = 0; i < stream_count; ++i)
+ {
+ assert(streams[i].size > 0 && streams[i].size <= 256);
+ assert(streams[i].size <= streams[i].stride);
+ }
+
+ meshopt_Allocator allocator;
+
+ unsigned int* remap = allocator.allocate<unsigned int>(vertex_count);
+ memset(remap, -1, vertex_count * sizeof(unsigned int));
+
+ VertexStreamHasher hasher = {streams, stream_count};
+
+ size_t table_size = hashBuckets(vertex_count);
+ unsigned int* table = allocator.allocate<unsigned int>(table_size);
+ memset(table, -1, table_size * sizeof(unsigned int));
+
+ for (size_t i = 0; i < index_count; ++i)
+ {
+ unsigned int index = indices[i];
+ assert(index < vertex_count);
+
+ if (remap[index] == ~0u)
+ {
+ unsigned int* entry = hashLookup(table, table_size, hasher, index, ~0u);
+
+ if (*entry == ~0u)
+ *entry = index;
+
+ remap[index] = *entry;
+ }
+
+ destination[i] = remap[index];
+ }
+}
diff --git a/thirdparty/meshoptimizer/meshoptimizer.h b/thirdparty/meshoptimizer/meshoptimizer.h
new file mode 100644
index 0000000000..fde00f9c82
--- /dev/null
+++ b/thirdparty/meshoptimizer/meshoptimizer.h
@@ -0,0 +1,951 @@
+/**
+ * meshoptimizer - version 0.15
+ *
+ * Copyright (C) 2016-2020, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
+ * Report bugs and download new versions at https://github.com/zeux/meshoptimizer
+ *
+ * This library is distributed under the MIT License. See notice at the end of this file.
+ */
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+
+/* Version macro; major * 1000 + minor * 10 + patch */
+#define MESHOPTIMIZER_VERSION 150 /* 0.15 */
+
+/* If no API is defined, assume default */
+#ifndef MESHOPTIMIZER_API
+#define MESHOPTIMIZER_API
+#endif
+
+/* Experimental APIs have unstable interface and might have implementation that's not fully tested or optimized */
+#define MESHOPTIMIZER_EXPERIMENTAL MESHOPTIMIZER_API
+
+/* C interface */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Vertex attribute stream, similar to glVertexPointer
+ * Each element takes size bytes, with stride controlling the spacing between successive elements.
+ */
+struct meshopt_Stream
+{
+ const void* data;
+ size_t size;
+ size_t stride;
+};
+
+/**
+ * Generates a vertex remap table from the vertex buffer and an optional index buffer and returns number of unique vertices
+ * As a result, all vertices that are binary equivalent map to the same (new) location, with no gaps in the resulting sequence.
+ * Resulting remap table maps old vertices to new vertices and can be used in meshopt_remapVertexBuffer/meshopt_remapIndexBuffer.
+ * Note that binary equivalence considers all vertex_size bytes, including padding which should be zero-initialized.
+ *
+ * destination must contain enough space for the resulting remap table (vertex_count elements)
+ * indices can be NULL if the input is unindexed
+ */
+MESHOPTIMIZER_API size_t meshopt_generateVertexRemap(unsigned int* destination, const unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size);
+
+/**
+ * Generates a vertex remap table from multiple vertex streams and an optional index buffer and returns number of unique vertices
+ * As a result, all vertices that are binary equivalent map to the same (new) location, with no gaps in the resulting sequence.
+ * Resulting remap table maps old vertices to new vertices and can be used in meshopt_remapVertexBuffer/meshopt_remapIndexBuffer.
+ * To remap vertex buffers, you will need to call meshopt_remapVertexBuffer for each vertex stream.
+ * Note that binary equivalence considers all size bytes in each stream, including padding which should be zero-initialized.
+ *
+ * destination must contain enough space for the resulting remap table (vertex_count elements)
+ * indices can be NULL if the input is unindexed
+ */
+MESHOPTIMIZER_API size_t meshopt_generateVertexRemapMulti(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, const struct meshopt_Stream* streams, size_t stream_count);
+
+/**
+ * Generates vertex buffer from the source vertex buffer and remap table generated by meshopt_generateVertexRemap
+ *
+ * destination must contain enough space for the resulting vertex buffer (unique_vertex_count elements, returned by meshopt_generateVertexRemap)
+ * vertex_count should be the initial vertex count and not the value returned by meshopt_generateVertexRemap
+ */
+MESHOPTIMIZER_API void meshopt_remapVertexBuffer(void* destination, const void* vertices, size_t vertex_count, size_t vertex_size, const unsigned int* remap);
+
+/**
+ * Generate index buffer from the source index buffer and remap table generated by meshopt_generateVertexRemap
+ *
+ * destination must contain enough space for the resulting index buffer (index_count elements)
+ * indices can be NULL if the input is unindexed
+ */
+MESHOPTIMIZER_API void meshopt_remapIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const unsigned int* remap);
+
+/**
+ * Generate index buffer that can be used for more efficient rendering when only a subset of the vertex attributes is necessary
+ * All vertices that are binary equivalent (wrt first vertex_size bytes) map to the first vertex in the original vertex buffer.
+ * This makes it possible to use the index buffer for Z pre-pass or shadowmap rendering, while using the original index buffer for regular rendering.
+ * Note that binary equivalence considers all vertex_size bytes, including padding which should be zero-initialized.
+ *
+ * destination must contain enough space for the resulting index buffer (index_count elements)
+ */
+MESHOPTIMIZER_API void meshopt_generateShadowIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size, size_t vertex_stride);
+
+/**
+ * Generate index buffer that can be used for more efficient rendering when only a subset of the vertex attributes is necessary
+ * All vertices that are binary equivalent (wrt specified streams) map to the first vertex in the original vertex buffer.
+ * This makes it possible to use the index buffer for Z pre-pass or shadowmap rendering, while using the original index buffer for regular rendering.
+ * Note that binary equivalence considers all size bytes in each stream, including padding which should be zero-initialized.
+ *
+ * destination must contain enough space for the resulting index buffer (index_count elements)
+ */
+MESHOPTIMIZER_API void meshopt_generateShadowIndexBufferMulti(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, const struct meshopt_Stream* streams, size_t stream_count);
+
+/**
+ * Vertex transform cache optimizer
+ * Reorders indices to reduce the number of GPU vertex shader invocations
+ * If index buffer contains multiple ranges for multiple draw calls, this functions needs to be called on each range individually.
+ *
+ * destination must contain enough space for the resulting index buffer (index_count elements)
+ */
+MESHOPTIMIZER_API void meshopt_optimizeVertexCache(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count);
+
+/**
+ * Vertex transform cache optimizer for strip-like caches
+ * Produces inferior results to meshopt_optimizeVertexCache from the GPU vertex cache perspective
+ * However, the resulting index order is more optimal if the goal is to reduce the triangle strip length or improve compression efficiency
+ *
+ * destination must contain enough space for the resulting index buffer (index_count elements)
+ */
+MESHOPTIMIZER_API void meshopt_optimizeVertexCacheStrip(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count);
+
+/**
+ * Vertex transform cache optimizer for FIFO caches
+ * Reorders indices to reduce the number of GPU vertex shader invocations
+ * Generally takes ~3x less time to optimize meshes but produces inferior results compared to meshopt_optimizeVertexCache
+ * If index buffer contains multiple ranges for multiple draw calls, this functions needs to be called on each range individually.
+ *
+ * destination must contain enough space for the resulting index buffer (index_count elements)
+ * cache_size should be less than the actual GPU cache size to avoid cache thrashing
+ */
+MESHOPTIMIZER_API void meshopt_optimizeVertexCacheFifo(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int cache_size);
+
+/**
+ * Overdraw optimizer
+ * Reorders indices to reduce the number of GPU vertex shader invocations and the pixel overdraw
+ * If index buffer contains multiple ranges for multiple draw calls, this functions needs to be called on each range individually.
+ *
+ * destination must contain enough space for the resulting index buffer (index_count elements)
+ * indices must contain index data that is the result of meshopt_optimizeVertexCache (*not* the original mesh indices!)
+ * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
+ * threshold indicates how much the overdraw optimizer can degrade vertex cache efficiency (1.05 = up to 5%) to reduce overdraw more efficiently
+ */
+MESHOPTIMIZER_API void meshopt_optimizeOverdraw(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, float threshold);
+
+/**
+ * Vertex fetch cache optimizer
+ * Reorders vertices and changes indices to reduce the amount of GPU memory fetches during vertex processing
+ * Returns the number of unique vertices, which is the same as input vertex count unless some vertices are unused
+ * This functions works for a single vertex stream; for multiple vertex streams, use meshopt_optimizeVertexFetchRemap + meshopt_remapVertexBuffer for each stream.
+ *
+ * destination must contain enough space for the resulting vertex buffer (vertex_count elements)
+ * indices is used both as an input and as an output index buffer
+ */
+MESHOPTIMIZER_API size_t meshopt_optimizeVertexFetch(void* destination, unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size);
+
+/**
+ * Vertex fetch cache optimizer
+ * Generates vertex remap to reduce the amount of GPU memory fetches during vertex processing
+ * Returns the number of unique vertices, which is the same as input vertex count unless some vertices are unused
+ * The resulting remap table should be used to reorder vertex/index buffers using meshopt_remapVertexBuffer/meshopt_remapIndexBuffer
+ *
+ * destination must contain enough space for the resulting remap table (vertex_count elements)
+ */
+MESHOPTIMIZER_API size_t meshopt_optimizeVertexFetchRemap(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count);
+
+/**
+ * Index buffer encoder
+ * Encodes index data into an array of bytes that is generally much smaller (<1.5 bytes/triangle) and compresses better (<1 bytes/triangle) compared to original.
+ * Input index buffer must represent a triangle list.
+ * Returns encoded data size on success, 0 on error; the only error condition is if buffer doesn't have enough space
+ * For maximum efficiency the index buffer being encoded has to be optimized for vertex cache and vertex fetch first.
+ *
+ * buffer must contain enough space for the encoded index buffer (use meshopt_encodeIndexBufferBound to compute worst case size)
+ */
+MESHOPTIMIZER_API size_t meshopt_encodeIndexBuffer(unsigned char* buffer, size_t buffer_size, const unsigned int* indices, size_t index_count);
+MESHOPTIMIZER_API size_t meshopt_encodeIndexBufferBound(size_t index_count, size_t vertex_count);
+
+/**
+ * Experimental: Set index encoder format version
+ * version must specify the data format version to encode; valid values are 0 (decodable by all library versions) and 1 (decodable by 0.14+)
+ */
+MESHOPTIMIZER_EXPERIMENTAL void meshopt_encodeIndexVersion(int version);
+
+/**
+ * Index buffer decoder
+ * Decodes index data from an array of bytes generated by meshopt_encodeIndexBuffer
+ * Returns 0 if decoding was successful, and an error code otherwise
+ * The decoder is safe to use for untrusted input, but it may produce garbage data (e.g. out of range indices).
+ *
+ * destination must contain enough space for the resulting index buffer (index_count elements)
+ */
+MESHOPTIMIZER_API int meshopt_decodeIndexBuffer(void* destination, size_t index_count, size_t index_size, const unsigned char* buffer, size_t buffer_size);
+
+/**
+ * Experimental: Index sequence encoder
+ * Encodes index sequence into an array of bytes that is generally smaller and compresses better compared to original.
+ * Input index sequence can represent arbitrary topology; for triangle lists meshopt_encodeIndexBuffer is likely to be better.
+ * Returns encoded data size on success, 0 on error; the only error condition is if buffer doesn't have enough space
+ *
+ * buffer must contain enough space for the encoded index sequence (use meshopt_encodeIndexSequenceBound to compute worst case size)
+ */
+MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_encodeIndexSequence(unsigned char* buffer, size_t buffer_size, const unsigned int* indices, size_t index_count);
+MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_encodeIndexSequenceBound(size_t index_count, size_t vertex_count);
+
+/**
+ * Index sequence decoder
+ * Decodes index data from an array of bytes generated by meshopt_encodeIndexSequence
+ * Returns 0 if decoding was successful, and an error code otherwise
+ * The decoder is safe to use for untrusted input, but it may produce garbage data (e.g. out of range indices).
+ *
+ * destination must contain enough space for the resulting index sequence (index_count elements)
+ */
+MESHOPTIMIZER_EXPERIMENTAL int meshopt_decodeIndexSequence(void* destination, size_t index_count, size_t index_size, const unsigned char* buffer, size_t buffer_size);
+
+/**
+ * Vertex buffer encoder
+ * Encodes vertex data into an array of bytes that is generally smaller and compresses better compared to original.
+ * Returns encoded data size on success, 0 on error; the only error condition is if buffer doesn't have enough space
+ * This function works for a single vertex stream; for multiple vertex streams, call meshopt_encodeVertexBuffer for each stream.
+ * Note that all vertex_size bytes of each vertex are encoded verbatim, including padding which should be zero-initialized.
+ *
+ * buffer must contain enough space for the encoded vertex buffer (use meshopt_encodeVertexBufferBound to compute worst case size)
+ */
+MESHOPTIMIZER_API size_t meshopt_encodeVertexBuffer(unsigned char* buffer, size_t buffer_size, const void* vertices, size_t vertex_count, size_t vertex_size);
+MESHOPTIMIZER_API size_t meshopt_encodeVertexBufferBound(size_t vertex_count, size_t vertex_size);
+
+/**
+ * Experimental: Set vertex encoder format version
+ * version must specify the data format version to encode; valid values are 0 (decodable by all library versions)
+ */
+MESHOPTIMIZER_EXPERIMENTAL void meshopt_encodeVertexVersion(int version);
+
+/**
+ * Vertex buffer decoder
+ * Decodes vertex data from an array of bytes generated by meshopt_encodeVertexBuffer
+ * Returns 0 if decoding was successful, and an error code otherwise
+ * The decoder is safe to use for untrusted input, but it may produce garbage data.
+ *
+ * destination must contain enough space for the resulting vertex buffer (vertex_count * vertex_size bytes)
+ */
+MESHOPTIMIZER_API int meshopt_decodeVertexBuffer(void* destination, size_t vertex_count, size_t vertex_size, const unsigned char* buffer, size_t buffer_size);
+
+/**
+ * Vertex buffer filters
+ * These functions can be used to filter output of meshopt_decodeVertexBuffer in-place.
+ * count must be aligned by 4 and stride is fixed for each function to facilitate SIMD implementation.
+ *
+ * meshopt_decodeFilterOct decodes octahedral encoding of a unit vector with K-bit (K <= 16) signed X/Y as an input; Z must store 1.0f.
+ * Each component is stored as an 8-bit or 16-bit normalized integer; stride must be equal to 4 or 8. W is preserved as is.
+ *
+ * meshopt_decodeFilterQuat decodes 3-component quaternion encoding with K-bit (4 <= K <= 16) component encoding and a 2-bit component index indicating which component to reconstruct.
+ * Each component is stored as an 16-bit integer; stride must be equal to 8.
+ *
+ * meshopt_decodeFilterExp decodes exponential encoding of floating-point data with 8-bit exponent and 24-bit integer mantissa as 2^E*M.
+ * Each 32-bit component is decoded in isolation; stride must be divisible by 4.
+ */
+MESHOPTIMIZER_EXPERIMENTAL void meshopt_decodeFilterOct(void* buffer, size_t vertex_count, size_t vertex_size);
+MESHOPTIMIZER_EXPERIMENTAL void meshopt_decodeFilterQuat(void* buffer, size_t vertex_count, size_t vertex_size);
+MESHOPTIMIZER_EXPERIMENTAL void meshopt_decodeFilterExp(void* buffer, size_t vertex_count, size_t vertex_size);
+
+/**
+ * Experimental: Mesh simplifier
+ * Reduces the number of triangles in the mesh, attempting to preserve mesh appearance as much as possible
+ * The algorithm tries to preserve mesh topology and can stop short of the target goal based on topology constraints or target error.
+ * If not all attributes from the input mesh are required, it's recommended to reindex the mesh using meshopt_generateShadowIndexBuffer prior to simplification.
+ * Returns the number of indices after simplification, with destination containing new index data
+ * The resulting index buffer references vertices from the original vertex buffer.
+ * If the original vertex data isn't required, creating a compact vertex buffer using meshopt_optimizeVertexFetch is recommended.
+ *
+ * destination must contain enough space for the *source* index buffer (since optimization is iterative, this means index_count elements - *not* target_index_count!)
+ * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
+ */
+// -- GODOT start --
+//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);
+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 *r_resulting_error);
+// -- GODOT end --
+
+/**
+ * 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 is always able to reach target triangle count.
+ * Returns the number of indices after simplification, with destination containing new index data
+ * The resulting index buffer references vertices from the original vertex buffer.
+ * If the original vertex data isn't required, creating a compact vertex buffer using meshopt_optimizeVertexFetch is recommended.
+ *
+ * destination must contain enough space for the target index buffer
+ * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
+ */
+MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifySloppy(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);
+
+/**
+ * Experimental: Point cloud simplifier
+ * Reduces the number of points in the cloud to reach the given target
+ * Returns the number of points after simplification, with destination containing new index data
+ * The resulting index buffer references vertices from the original vertex buffer.
+ * If the original vertex data isn't required, creating a compact vertex buffer using meshopt_optimizeVertexFetch is recommended.
+ *
+ * destination must contain enough space for the target index buffer
+ * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
+ */
+MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifyPoints(unsigned int* destination, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_vertex_count);
+
+/**
+ * Mesh stripifier
+ * Converts a previously vertex cache optimized triangle list to triangle strip, stitching strips using restart index or degenerate triangles
+ * Returns the number of indices in the resulting strip, with destination containing new index data
+ * For maximum efficiency the index buffer being converted has to be optimized for vertex cache first.
+ * Using restart indices can result in ~10% smaller index buffers, but on some GPUs restart indices may result in decreased performance.
+ *
+ * destination must contain enough space for the target index buffer, worst case can be computed with meshopt_stripifyBound
+ * restart_index should be 0xffff or 0xffffffff depending on index size, or 0 to use degenerate triangles
+ */
+MESHOPTIMIZER_API size_t meshopt_stripify(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int restart_index);
+MESHOPTIMIZER_API size_t meshopt_stripifyBound(size_t index_count);
+
+/**
+ * Mesh unstripifier
+ * Converts a triangle strip to a triangle list
+ * Returns the number of indices in the resulting list, with destination containing new index data
+ *
+ * destination must contain enough space for the target index buffer, worst case can be computed with meshopt_unstripifyBound
+ */
+MESHOPTIMIZER_API size_t meshopt_unstripify(unsigned int* destination, const unsigned int* indices, size_t index_count, unsigned int restart_index);
+MESHOPTIMIZER_API size_t meshopt_unstripifyBound(size_t index_count);
+
+struct meshopt_VertexCacheStatistics
+{
+ unsigned int vertices_transformed;
+ unsigned int warps_executed;
+ float acmr; /* transformed vertices / triangle count; best case 0.5, worst case 3.0, optimum depends on topology */
+ float atvr; /* transformed vertices / vertex count; best case 1.0, worst case 6.0, optimum is 1.0 (each vertex is transformed once) */
+};
+
+/**
+ * Vertex transform cache analyzer
+ * Returns cache hit statistics using a simplified FIFO model
+ * Results may not match actual GPU performance
+ */
+MESHOPTIMIZER_API struct meshopt_VertexCacheStatistics meshopt_analyzeVertexCache(const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int cache_size, unsigned int warp_size, unsigned int primgroup_size);
+
+struct meshopt_OverdrawStatistics
+{
+ unsigned int pixels_covered;
+ unsigned int pixels_shaded;
+ float overdraw; /* shaded pixels / covered pixels; best case 1.0 */
+};
+
+/**
+ * Overdraw analyzer
+ * Returns overdraw statistics using a software rasterizer
+ * Results may not match actual GPU performance
+ *
+ * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
+ */
+MESHOPTIMIZER_API struct meshopt_OverdrawStatistics meshopt_analyzeOverdraw(const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
+
+struct meshopt_VertexFetchStatistics
+{
+ unsigned int bytes_fetched;
+ float overfetch; /* fetched bytes / vertex buffer size; best case 1.0 (each byte is fetched once) */
+};
+
+/**
+ * Vertex fetch cache analyzer
+ * Returns cache hit statistics using a simplified direct mapped model
+ * Results may not match actual GPU performance
+ */
+MESHOPTIMIZER_API struct meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const unsigned int* indices, size_t index_count, size_t vertex_count, size_t vertex_size);
+
+struct meshopt_Meshlet
+{
+ unsigned int vertices[64];
+ unsigned char indices[126][3];
+ unsigned char triangle_count;
+ unsigned char vertex_count;
+};
+
+/**
+ * Experimental: Meshlet builder
+ * Splits the mesh into a set of meshlets where each meshlet has a micro index buffer indexing into meshlet vertices that refer to the original vertex buffer
+ * The resulting data can be used to render meshes using NVidia programmable mesh shading pipeline, or in other cluster-based renderers.
+ * For maximum efficiency the index buffer being converted has to be optimized for vertex cache first.
+ *
+ * destination must contain enough space for all meshlets, worst case size can be computed with meshopt_buildMeshletsBound
+ * max_vertices and max_triangles can't exceed limits statically declared in meshopt_Meshlet (max_vertices <= 64, max_triangles <= 126)
+ */
+MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_buildMeshlets(struct meshopt_Meshlet* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles);
+MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_buildMeshletsBound(size_t index_count, size_t max_vertices, size_t max_triangles);
+
+struct meshopt_Bounds
+{
+ /* bounding sphere, useful for frustum and occlusion culling */
+ float center[3];
+ float radius;
+
+ /* normal cone, useful for backface culling */
+ float cone_apex[3];
+ float cone_axis[3];
+ float cone_cutoff; /* = cos(angle/2) */
+
+ /* normal cone axis and cutoff, stored in 8-bit SNORM format; decode using x/127.0 */
+ signed char cone_axis_s8[3];
+ signed char cone_cutoff_s8;
+};
+
+/**
+ * Experimental: Cluster bounds generator
+ * Creates bounding volumes that can be used for frustum, backface and occlusion culling.
+ *
+ * For backface culling with orthographic projection, use the following formula to reject backfacing clusters:
+ * dot(view, cone_axis) >= cone_cutoff
+ *
+ * For perspective projection, you can the formula that needs cone apex in addition to axis & cutoff:
+ * dot(normalize(cone_apex - camera_position), cone_axis) >= cone_cutoff
+ *
+ * Alternatively, you can use the formula that doesn't need cone apex and uses bounding sphere instead:
+ * dot(normalize(center - camera_position), cone_axis) >= cone_cutoff + radius / length(center - camera_position)
+ * or an equivalent formula that doesn't have a singularity at center = camera_position:
+ * dot(center - camera_position, cone_axis) >= cone_cutoff * length(center - camera_position) + radius
+ *
+ * The formula that uses the apex is slightly more accurate but needs the apex; if you are already using bounding sphere
+ * to do frustum/occlusion culling, the formula that doesn't use the apex may be preferable.
+ *
+ * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
+ * index_count should be less than or equal to 256*3 (the function assumes clusters of limited size)
+ */
+MESHOPTIMIZER_EXPERIMENTAL struct meshopt_Bounds meshopt_computeClusterBounds(const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
+MESHOPTIMIZER_EXPERIMENTAL struct meshopt_Bounds meshopt_computeMeshletBounds(const struct meshopt_Meshlet* meshlet, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
+
+/**
+ * Experimental: Spatial sorter
+ * Generates a remap table that can be used to reorder points for spatial locality.
+ * Resulting remap table maps old vertices to new vertices and can be used in meshopt_remapVertexBuffer.
+ *
+ * destination must contain enough space for the resulting remap table (vertex_count elements)
+ */
+MESHOPTIMIZER_EXPERIMENTAL void meshopt_spatialSortRemap(unsigned int* destination, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
+
+/**
+ * Experimental: Spatial sorter
+ * Reorders triangles for spatial locality, and generates a new index buffer. The resulting index buffer can be used with other functions like optimizeVertexCache.
+ *
+ * destination must contain enough space for the resulting index buffer (index_count elements)
+ * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
+ */
+MESHOPTIMIZER_EXPERIMENTAL void meshopt_spatialSortTriangles(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
+
+/**
+ * Set allocation callbacks
+ * These callbacks will be used instead of the default operator new/operator delete for all temporary allocations in the library.
+ * Note that all algorithms only allocate memory for temporary use.
+ * allocate/deallocate are always called in a stack-like order - last pointer to be allocated is deallocated first.
+ */
+MESHOPTIMIZER_API void meshopt_setAllocator(void* (*allocate)(size_t), void (*deallocate)(void*));
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+/* Quantization into commonly supported data formats */
+#ifdef __cplusplus
+/**
+ * Quantize a float in [0..1] range into an N-bit fixed point unorm value
+ * Assumes reconstruction function (q / (2^N-1)), which is the case for fixed-function normalized fixed point conversion
+ * Maximum reconstruction error: 1/2^(N+1)
+ */
+inline int meshopt_quantizeUnorm(float v, int N);
+
+/**
+ * Quantize a float in [-1..1] range into an N-bit fixed point snorm value
+ * Assumes reconstruction function (q / (2^(N-1)-1)), which is the case for fixed-function normalized fixed point conversion (except early OpenGL versions)
+ * Maximum reconstruction error: 1/2^N
+ */
+inline int meshopt_quantizeSnorm(float v, int N);
+
+/**
+ * Quantize a float into half-precision floating point value
+ * Generates +-inf for overflow, preserves NaN, flushes denormals to zero, rounds to nearest
+ * Representable magnitude range: [6e-5; 65504]
+ * Maximum relative reconstruction error: 5e-4
+ */
+inline unsigned short meshopt_quantizeHalf(float v);
+
+/**
+ * Quantize a float into a floating point value with a limited number of significant mantissa bits
+ * Generates +-inf for overflow, preserves NaN, flushes denormals to zero, rounds to nearest
+ * Assumes N is in a valid mantissa precision range, which is 1..23
+ */
+inline float meshopt_quantizeFloat(float v, int N);
+#endif
+
+/**
+ * C++ template interface
+ *
+ * These functions mirror the C interface the library provides, providing template-based overloads so that
+ * the caller can use an arbitrary type for the index data, both for input and output.
+ * When the supplied type is the same size as that of unsigned int, the wrappers are zero-cost; when it's not,
+ * the wrappers end up allocating memory and copying index data to convert from one type to another.
+ */
+#if defined(__cplusplus) && !defined(MESHOPTIMIZER_NO_WRAPPERS)
+template <typename T>
+inline size_t meshopt_generateVertexRemap(unsigned int* destination, const T* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size);
+template <typename T>
+inline size_t meshopt_generateVertexRemapMulti(unsigned int* destination, const T* indices, size_t index_count, size_t vertex_count, const meshopt_Stream* streams, size_t stream_count);
+template <typename T>
+inline void meshopt_remapIndexBuffer(T* destination, const T* indices, size_t index_count, const unsigned int* remap);
+template <typename T>
+inline void meshopt_generateShadowIndexBuffer(T* destination, const T* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size, size_t vertex_stride);
+template <typename T>
+inline void meshopt_generateShadowIndexBufferMulti(T* destination, const T* indices, size_t index_count, size_t vertex_count, const meshopt_Stream* streams, size_t stream_count);
+template <typename T>
+inline void meshopt_optimizeVertexCache(T* destination, const T* indices, size_t index_count, size_t vertex_count);
+template <typename T>
+inline void meshopt_optimizeVertexCacheStrip(T* destination, const T* indices, size_t index_count, size_t vertex_count);
+template <typename T>
+inline void meshopt_optimizeVertexCacheFifo(T* destination, const T* indices, size_t index_count, size_t vertex_count, unsigned int cache_size);
+template <typename T>
+inline void meshopt_optimizeOverdraw(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, float threshold);
+template <typename T>
+inline size_t meshopt_optimizeVertexFetchRemap(unsigned int* destination, const T* indices, size_t index_count, size_t vertex_count);
+template <typename T>
+inline size_t meshopt_optimizeVertexFetch(void* destination, T* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size);
+template <typename T>
+inline size_t meshopt_encodeIndexBuffer(unsigned char* buffer, size_t buffer_size, const T* indices, size_t index_count);
+template <typename T>
+inline int meshopt_decodeIndexBuffer(T* destination, size_t index_count, const unsigned char* buffer, size_t buffer_size);
+template <typename T>
+inline size_t meshopt_encodeIndexSequence(unsigned char* buffer, size_t buffer_size, const T* indices, size_t index_count);
+template <typename T>
+inline int meshopt_decodeIndexSequence(T* destination, size_t index_count, const unsigned char* buffer, size_t buffer_size);
+template <typename T>
+inline size_t meshopt_simplify(T* destination, const T* 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);
+template <typename T>
+inline size_t meshopt_simplifySloppy(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count);
+template <typename T>
+inline size_t meshopt_stripify(T* destination, const T* indices, size_t index_count, size_t vertex_count, T restart_index);
+template <typename T>
+inline size_t meshopt_unstripify(T* destination, const T* indices, size_t index_count, T restart_index);
+template <typename T>
+inline meshopt_VertexCacheStatistics meshopt_analyzeVertexCache(const T* indices, size_t index_count, size_t vertex_count, unsigned int cache_size, unsigned int warp_size, unsigned int buffer_size);
+template <typename T>
+inline meshopt_OverdrawStatistics meshopt_analyzeOverdraw(const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
+template <typename T>
+inline meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const T* indices, size_t index_count, size_t vertex_count, size_t vertex_size);
+template <typename T>
+inline size_t meshopt_buildMeshlets(meshopt_Meshlet* destination, const T* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles);
+template <typename T>
+inline meshopt_Bounds meshopt_computeClusterBounds(const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
+template <typename T>
+inline void meshopt_spatialSortTriangles(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
+#endif
+
+/* Inline implementation */
+#ifdef __cplusplus
+inline int meshopt_quantizeUnorm(float v, int N)
+{
+ const float scale = float((1 << N) - 1);
+
+ v = (v >= 0) ? v : 0;
+ v = (v <= 1) ? v : 1;
+
+ return int(v * scale + 0.5f);
+}
+
+inline int meshopt_quantizeSnorm(float v, int N)
+{
+ const float scale = float((1 << (N - 1)) - 1);
+
+ float round = (v >= 0 ? 0.5f : -0.5f);
+
+ v = (v >= -1) ? v : -1;
+ v = (v <= +1) ? v : +1;
+
+ return int(v * scale + round);
+}
+
+inline unsigned short meshopt_quantizeHalf(float v)
+{
+ union { float f; unsigned int ui; } u = {v};
+ unsigned int ui = u.ui;
+
+ int s = (ui >> 16) & 0x8000;
+ int em = ui & 0x7fffffff;
+
+ /* bias exponent and round to nearest; 112 is relative exponent bias (127-15) */
+ int h = (em - (112 << 23) + (1 << 12)) >> 13;
+
+ /* underflow: flush to zero; 113 encodes exponent -14 */
+ h = (em < (113 << 23)) ? 0 : h;
+
+ /* overflow: infinity; 143 encodes exponent 16 */
+ h = (em >= (143 << 23)) ? 0x7c00 : h;
+
+ /* NaN; note that we convert all types of NaN to qNaN */
+ h = (em > (255 << 23)) ? 0x7e00 : h;
+
+ return (unsigned short)(s | h);
+}
+
+inline float meshopt_quantizeFloat(float v, int N)
+{
+ union { float f; unsigned int ui; } u = {v};
+ unsigned int ui = u.ui;
+
+ const int mask = (1 << (23 - N)) - 1;
+ const int round = (1 << (23 - N)) >> 1;
+
+ int e = ui & 0x7f800000;
+ unsigned int rui = (ui + round) & ~mask;
+
+ /* round all numbers except inf/nan; this is important to make sure nan doesn't overflow into -0 */
+ ui = e == 0x7f800000 ? ui : rui;
+
+ /* flush denormals to zero */
+ ui = e == 0 ? 0 : ui;
+
+ u.ui = ui;
+ return u.f;
+}
+#endif
+
+/* Internal implementation helpers */
+#ifdef __cplusplus
+class meshopt_Allocator
+{
+public:
+ template <typename T>
+ struct StorageT
+ {
+ static void* (*allocate)(size_t);
+ static void (*deallocate)(void*);
+ };
+
+ typedef StorageT<void> Storage;
+
+ meshopt_Allocator()
+ : blocks()
+ , count(0)
+ {
+ }
+
+ ~meshopt_Allocator()
+ {
+ for (size_t i = count; i > 0; --i)
+ Storage::deallocate(blocks[i - 1]);
+ }
+
+ template <typename T> T* allocate(size_t size)
+ {
+ assert(count < sizeof(blocks) / sizeof(blocks[0]));
+ T* result = static_cast<T*>(Storage::allocate(size > size_t(-1) / sizeof(T) ? size_t(-1) : size * sizeof(T)));
+ blocks[count++] = result;
+ return result;
+ }
+
+private:
+ void* blocks[24];
+ size_t count;
+};
+
+// This makes sure that allocate/deallocate are lazily generated in translation units that need them and are deduplicated by the linker
+template <typename T> void* (*meshopt_Allocator::StorageT<T>::allocate)(size_t) = operator new;
+template <typename T> void (*meshopt_Allocator::StorageT<T>::deallocate)(void*) = operator delete;
+#endif
+
+/* Inline implementation for C++ templated wrappers */
+#if defined(__cplusplus) && !defined(MESHOPTIMIZER_NO_WRAPPERS)
+template <typename T, bool ZeroCopy = sizeof(T) == sizeof(unsigned int)>
+struct meshopt_IndexAdapter;
+
+template <typename T>
+struct meshopt_IndexAdapter<T, false>
+{
+ T* result;
+ unsigned int* data;
+ size_t count;
+
+ meshopt_IndexAdapter(T* result_, const T* input, size_t count_)
+ : result(result_)
+ , data(0)
+ , count(count_)
+ {
+ size_t size = count > size_t(-1) / sizeof(unsigned int) ? size_t(-1) : count * sizeof(unsigned int);
+
+ data = static_cast<unsigned int*>(meshopt_Allocator::Storage::allocate(size));
+
+ if (input)
+ {
+ for (size_t i = 0; i < count; ++i)
+ data[i] = input[i];
+ }
+ }
+
+ ~meshopt_IndexAdapter()
+ {
+ if (result)
+ {
+ for (size_t i = 0; i < count; ++i)
+ result[i] = T(data[i]);
+ }
+
+ meshopt_Allocator::Storage::deallocate(data);
+ }
+};
+
+template <typename T>
+struct meshopt_IndexAdapter<T, true>
+{
+ unsigned int* data;
+
+ meshopt_IndexAdapter(T* result, const T* input, size_t)
+ : data(reinterpret_cast<unsigned int*>(result ? result : const_cast<T*>(input)))
+ {
+ }
+};
+
+template <typename T>
+inline size_t meshopt_generateVertexRemap(unsigned int* destination, const T* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size)
+{
+ meshopt_IndexAdapter<T> in(0, indices, indices ? index_count : 0);
+
+ return meshopt_generateVertexRemap(destination, indices ? in.data : 0, index_count, vertices, vertex_count, vertex_size);
+}
+
+template <typename T>
+inline size_t meshopt_generateVertexRemapMulti(unsigned int* destination, const T* indices, size_t index_count, size_t vertex_count, const meshopt_Stream* streams, size_t stream_count)
+{
+ meshopt_IndexAdapter<T> in(0, indices, indices ? index_count : 0);
+
+ return meshopt_generateVertexRemapMulti(destination, indices ? in.data : 0, index_count, vertex_count, streams, stream_count);
+}
+
+template <typename T>
+inline void meshopt_remapIndexBuffer(T* destination, const T* indices, size_t index_count, const unsigned int* remap)
+{
+ meshopt_IndexAdapter<T> in(0, indices, indices ? index_count : 0);
+ meshopt_IndexAdapter<T> out(destination, 0, index_count);
+
+ meshopt_remapIndexBuffer(out.data, indices ? in.data : 0, index_count, remap);
+}
+
+template <typename T>
+inline void meshopt_generateShadowIndexBuffer(T* destination, const T* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size, size_t vertex_stride)
+{
+ meshopt_IndexAdapter<T> in(0, indices, index_count);
+ meshopt_IndexAdapter<T> out(destination, 0, index_count);
+
+ meshopt_generateShadowIndexBuffer(out.data, in.data, index_count, vertices, vertex_count, vertex_size, vertex_stride);
+}
+
+template <typename T>
+inline void meshopt_generateShadowIndexBufferMulti(T* destination, const T* indices, size_t index_count, size_t vertex_count, const meshopt_Stream* streams, size_t stream_count)
+{
+ meshopt_IndexAdapter<T> in(0, indices, index_count);
+ meshopt_IndexAdapter<T> out(destination, 0, index_count);
+
+ meshopt_generateShadowIndexBufferMulti(out.data, in.data, index_count, vertex_count, streams, stream_count);
+}
+
+template <typename T>
+inline void meshopt_optimizeVertexCache(T* destination, const T* indices, size_t index_count, size_t vertex_count)
+{
+ meshopt_IndexAdapter<T> in(0, indices, index_count);
+ meshopt_IndexAdapter<T> out(destination, 0, index_count);
+
+ meshopt_optimizeVertexCache(out.data, in.data, index_count, vertex_count);
+}
+
+template <typename T>
+inline void meshopt_optimizeVertexCacheStrip(T* destination, const T* indices, size_t index_count, size_t vertex_count)
+{
+ meshopt_IndexAdapter<T> in(0, indices, index_count);
+ meshopt_IndexAdapter<T> out(destination, 0, index_count);
+
+ meshopt_optimizeVertexCacheStrip(out.data, in.data, index_count, vertex_count);
+}
+
+template <typename T>
+inline void meshopt_optimizeVertexCacheFifo(T* destination, const T* indices, size_t index_count, size_t vertex_count, unsigned int cache_size)
+{
+ meshopt_IndexAdapter<T> in(0, indices, index_count);
+ meshopt_IndexAdapter<T> out(destination, 0, index_count);
+
+ meshopt_optimizeVertexCacheFifo(out.data, in.data, index_count, vertex_count, cache_size);
+}
+
+template <typename T>
+inline void meshopt_optimizeOverdraw(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, float threshold)
+{
+ meshopt_IndexAdapter<T> in(0, indices, index_count);
+ meshopt_IndexAdapter<T> out(destination, 0, index_count);
+
+ meshopt_optimizeOverdraw(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, threshold);
+}
+
+template <typename T>
+inline size_t meshopt_optimizeVertexFetchRemap(unsigned int* destination, const T* indices, size_t index_count, size_t vertex_count)
+{
+ meshopt_IndexAdapter<T> in(0, indices, index_count);
+
+ return meshopt_optimizeVertexFetchRemap(destination, in.data, index_count, vertex_count);
+}
+
+template <typename T>
+inline size_t meshopt_optimizeVertexFetch(void* destination, T* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size)
+{
+ meshopt_IndexAdapter<T> inout(indices, indices, index_count);
+
+ return meshopt_optimizeVertexFetch(destination, inout.data, index_count, vertices, vertex_count, vertex_size);
+}
+
+template <typename T>
+inline size_t meshopt_encodeIndexBuffer(unsigned char* buffer, size_t buffer_size, const T* indices, size_t index_count)
+{
+ meshopt_IndexAdapter<T> in(0, indices, index_count);
+
+ return meshopt_encodeIndexBuffer(buffer, buffer_size, in.data, index_count);
+}
+
+template <typename T>
+inline int meshopt_decodeIndexBuffer(T* destination, size_t index_count, const unsigned char* buffer, size_t buffer_size)
+{
+ char index_size_valid[sizeof(T) == 2 || sizeof(T) == 4 ? 1 : -1];
+ (void)index_size_valid;
+
+ return meshopt_decodeIndexBuffer(destination, index_count, sizeof(T), buffer, buffer_size);
+}
+
+template <typename T>
+inline size_t meshopt_encodeIndexSequence(unsigned char* buffer, size_t buffer_size, const T* indices, size_t index_count)
+{
+ meshopt_IndexAdapter<T> in(0, indices, index_count);
+
+ return meshopt_encodeIndexSequence(buffer, buffer_size, in.data, index_count);
+}
+
+template <typename T>
+inline int meshopt_decodeIndexSequence(T* destination, size_t index_count, const unsigned char* buffer, size_t buffer_size)
+{
+ char index_size_valid[sizeof(T) == 2 || sizeof(T) == 4 ? 1 : -1];
+ (void)index_size_valid;
+
+ return meshopt_decodeIndexSequence(destination, index_count, sizeof(T), buffer, buffer_size);
+}
+
+template <typename T>
+inline size_t meshopt_simplify(T* destination, const T* 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)
+{
+ meshopt_IndexAdapter<T> in(0, indices, index_count);
+ meshopt_IndexAdapter<T> out(destination, 0, index_count);
+
+ return meshopt_simplify(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, target_index_count, target_error);
+}
+
+template <typename T>
+inline size_t meshopt_simplifySloppy(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count)
+{
+ meshopt_IndexAdapter<T> in(0, indices, index_count);
+ meshopt_IndexAdapter<T> out(destination, 0, target_index_count);
+
+ return meshopt_simplifySloppy(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, target_index_count);
+}
+
+template <typename T>
+inline size_t meshopt_stripify(T* destination, const T* indices, size_t index_count, size_t vertex_count, T restart_index)
+{
+ meshopt_IndexAdapter<T> in(0, indices, index_count);
+ meshopt_IndexAdapter<T> out(destination, 0, (index_count / 3) * 5);
+
+ return meshopt_stripify(out.data, in.data, index_count, vertex_count, unsigned(restart_index));
+}
+
+template <typename T>
+inline size_t meshopt_unstripify(T* destination, const T* indices, size_t index_count, T restart_index)
+{
+ meshopt_IndexAdapter<T> in(0, indices, index_count);
+ meshopt_IndexAdapter<T> out(destination, 0, (index_count - 2) * 3);
+
+ return meshopt_unstripify(out.data, in.data, index_count, unsigned(restart_index));
+}
+
+template <typename T>
+inline meshopt_VertexCacheStatistics meshopt_analyzeVertexCache(const T* indices, size_t index_count, size_t vertex_count, unsigned int cache_size, unsigned int warp_size, unsigned int buffer_size)
+{
+ meshopt_IndexAdapter<T> in(0, indices, index_count);
+
+ return meshopt_analyzeVertexCache(in.data, index_count, vertex_count, cache_size, warp_size, buffer_size);
+}
+
+template <typename T>
+inline meshopt_OverdrawStatistics meshopt_analyzeOverdraw(const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
+{
+ meshopt_IndexAdapter<T> in(0, indices, index_count);
+
+ return meshopt_analyzeOverdraw(in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride);
+}
+
+template <typename T>
+inline meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const T* indices, size_t index_count, size_t vertex_count, size_t vertex_size)
+{
+ meshopt_IndexAdapter<T> in(0, indices, index_count);
+
+ return meshopt_analyzeVertexFetch(in.data, index_count, vertex_count, vertex_size);
+}
+
+template <typename T>
+inline size_t meshopt_buildMeshlets(meshopt_Meshlet* destination, const T* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles)
+{
+ meshopt_IndexAdapter<T> in(0, indices, index_count);
+
+ return meshopt_buildMeshlets(destination, in.data, index_count, vertex_count, max_vertices, max_triangles);
+}
+
+template <typename T>
+inline meshopt_Bounds meshopt_computeClusterBounds(const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
+{
+ meshopt_IndexAdapter<T> in(0, indices, index_count);
+
+ return meshopt_computeClusterBounds(in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride);
+}
+
+template <typename T>
+inline void meshopt_spatialSortTriangles(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
+{
+ meshopt_IndexAdapter<T> in(0, indices, index_count);
+ meshopt_IndexAdapter<T> out(destination, 0, index_count);
+
+ meshopt_spatialSortTriangles(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride);
+}
+#endif
+
+/**
+ * Copyright (c) 2016-2020 Arseny Kapoulkine
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION 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/meshoptimizer/overdrawanalyzer.cpp b/thirdparty/meshoptimizer/overdrawanalyzer.cpp
new file mode 100644
index 0000000000..8d5859ba39
--- /dev/null
+++ b/thirdparty/meshoptimizer/overdrawanalyzer.cpp
@@ -0,0 +1,230 @@
+// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
+#include "meshoptimizer.h"
+
+#include <assert.h>
+#include <float.h>
+#include <string.h>
+
+// This work is based on:
+// Nicolas Capens. Advanced Rasterization. 2004
+namespace meshopt
+{
+
+const int kViewport = 256;
+
+struct OverdrawBuffer
+{
+ float z[kViewport][kViewport][2];
+ unsigned int overdraw[kViewport][kViewport][2];
+};
+
+#ifndef min
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+#ifndef max
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+static float computeDepthGradients(float& dzdx, float& dzdy, float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3)
+{
+ // z2 = z1 + dzdx * (x2 - x1) + dzdy * (y2 - y1)
+ // z3 = z1 + dzdx * (x3 - x1) + dzdy * (y3 - y1)
+ // (x2-x1 y2-y1)(dzdx) = (z2-z1)
+ // (x3-x1 y3-y1)(dzdy) (z3-z1)
+ // we'll solve it with Cramer's rule
+ float det = (x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1);
+ float invdet = (det == 0) ? 0 : 1 / det;
+
+ dzdx = (z2 - z1) * (y3 - y1) - (y2 - y1) * (z3 - z1) * invdet;
+ dzdy = (x2 - x1) * (z3 - z1) - (z2 - z1) * (x3 - x1) * invdet;
+
+ return det;
+}
+
+// half-space fixed point triangle rasterizer
+static void rasterize(OverdrawBuffer* buffer, float v1x, float v1y, float v1z, float v2x, float v2y, float v2z, float v3x, float v3y, float v3z)
+{
+ // compute depth gradients
+ float DZx, DZy;
+ float det = computeDepthGradients(DZx, DZy, v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z);
+ int sign = det > 0;
+
+ // flip backfacing triangles to simplify rasterization logic
+ if (sign)
+ {
+ // flipping v2 & v3 preserves depth gradients since they're based on v1
+ float t;
+ t = v2x, v2x = v3x, v3x = t;
+ t = v2y, v2y = v3y, v3y = t;
+ t = v2z, v2z = v3z, v3z = t;
+
+ // flip depth since we rasterize backfacing triangles to second buffer with reverse Z; only v1z is used below
+ v1z = kViewport - v1z;
+ DZx = -DZx;
+ DZy = -DZy;
+ }
+
+ // coordinates, 28.4 fixed point
+ int X1 = int(16.0f * v1x + 0.5f);
+ int X2 = int(16.0f * v2x + 0.5f);
+ int X3 = int(16.0f * v3x + 0.5f);
+
+ int Y1 = int(16.0f * v1y + 0.5f);
+ int Y2 = int(16.0f * v2y + 0.5f);
+ int Y3 = int(16.0f * v3y + 0.5f);
+
+ // bounding rectangle, clipped against viewport
+ // since we rasterize pixels with covered centers, min >0.5 should round up
+ // as for max, due to top-left filling convention we will never rasterize right/bottom edges
+ // so max >= 0.5 should round down
+ int minx = max((min(X1, min(X2, X3)) + 7) >> 4, 0);
+ int maxx = min((max(X1, max(X2, X3)) + 7) >> 4, kViewport);
+ int miny = max((min(Y1, min(Y2, Y3)) + 7) >> 4, 0);
+ int maxy = min((max(Y1, max(Y2, Y3)) + 7) >> 4, kViewport);
+
+ // deltas, 28.4 fixed point
+ int DX12 = X1 - X2;
+ int DX23 = X2 - X3;
+ int DX31 = X3 - X1;
+
+ int DY12 = Y1 - Y2;
+ int DY23 = Y2 - Y3;
+ int DY31 = Y3 - Y1;
+
+ // fill convention correction
+ int TL1 = DY12 < 0 || (DY12 == 0 && DX12 > 0);
+ int TL2 = DY23 < 0 || (DY23 == 0 && DX23 > 0);
+ int TL3 = DY31 < 0 || (DY31 == 0 && DX31 > 0);
+
+ // half edge equations, 24.8 fixed point
+ // note that we offset minx/miny by half pixel since we want to rasterize pixels with covered centers
+ int FX = (minx << 4) + 8;
+ int FY = (miny << 4) + 8;
+ int CY1 = DX12 * (FY - Y1) - DY12 * (FX - X1) + TL1 - 1;
+ int CY2 = DX23 * (FY - Y2) - DY23 * (FX - X2) + TL2 - 1;
+ int CY3 = DX31 * (FY - Y3) - DY31 * (FX - X3) + TL3 - 1;
+ float ZY = v1z + (DZx * float(FX - X1) + DZy * float(FY - Y1)) * (1 / 16.f);
+
+ for (int y = miny; y < maxy; y++)
+ {
+ int CX1 = CY1;
+ int CX2 = CY2;
+ int CX3 = CY3;
+ float ZX = ZY;
+
+ for (int x = minx; x < maxx; x++)
+ {
+ // check if all CXn are non-negative
+ if ((CX1 | CX2 | CX3) >= 0)
+ {
+ if (ZX >= buffer->z[y][x][sign])
+ {
+ buffer->z[y][x][sign] = ZX;
+ buffer->overdraw[y][x][sign]++;
+ }
+ }
+
+ // signed left shift is UB for negative numbers so use unsigned-signed casts
+ CX1 -= int(unsigned(DY12) << 4);
+ CX2 -= int(unsigned(DY23) << 4);
+ CX3 -= int(unsigned(DY31) << 4);
+ ZX += DZx;
+ }
+
+ // signed left shift is UB for negative numbers so use unsigned-signed casts
+ CY1 += int(unsigned(DX12) << 4);
+ CY2 += int(unsigned(DX23) << 4);
+ CY3 += int(unsigned(DX31) << 4);
+ ZY += DZy;
+ }
+}
+
+} // namespace meshopt
+
+meshopt_OverdrawStatistics meshopt_analyzeOverdraw(const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
+{
+ using namespace meshopt;
+
+ assert(index_count % 3 == 0);
+ assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
+ assert(vertex_positions_stride % sizeof(float) == 0);
+
+ meshopt_Allocator allocator;
+
+ size_t vertex_stride_float = vertex_positions_stride / sizeof(float);
+
+ meshopt_OverdrawStatistics result = {};
+
+ float minv[3] = {FLT_MAX, FLT_MAX, FLT_MAX};
+ float maxv[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
+
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ const float* v = vertex_positions + i * vertex_stride_float;
+
+ for (int j = 0; j < 3; ++j)
+ {
+ minv[j] = min(minv[j], v[j]);
+ maxv[j] = max(maxv[j], v[j]);
+ }
+ }
+
+ float extent = max(maxv[0] - minv[0], max(maxv[1] - minv[1], maxv[2] - minv[2]));
+ float scale = kViewport / extent;
+
+ float* triangles = allocator.allocate<float>(index_count * 3);
+
+ for (size_t i = 0; i < index_count; ++i)
+ {
+ unsigned int index = indices[i];
+ assert(index < vertex_count);
+
+ const float* v = vertex_positions + index * vertex_stride_float;
+
+ triangles[i * 3 + 0] = (v[0] - minv[0]) * scale;
+ triangles[i * 3 + 1] = (v[1] - minv[1]) * scale;
+ triangles[i * 3 + 2] = (v[2] - minv[2]) * scale;
+ }
+
+ OverdrawBuffer* buffer = allocator.allocate<OverdrawBuffer>(1);
+
+ for (int axis = 0; axis < 3; ++axis)
+ {
+ memset(buffer, 0, sizeof(OverdrawBuffer));
+
+ for (size_t i = 0; i < index_count; i += 3)
+ {
+ const float* vn0 = &triangles[3 * (i + 0)];
+ const float* vn1 = &triangles[3 * (i + 1)];
+ const float* vn2 = &triangles[3 * (i + 2)];
+
+ switch (axis)
+ {
+ case 0:
+ rasterize(buffer, vn0[2], vn0[1], vn0[0], vn1[2], vn1[1], vn1[0], vn2[2], vn2[1], vn2[0]);
+ break;
+ case 1:
+ rasterize(buffer, vn0[0], vn0[2], vn0[1], vn1[0], vn1[2], vn1[1], vn2[0], vn2[2], vn2[1]);
+ break;
+ case 2:
+ rasterize(buffer, vn0[1], vn0[0], vn0[2], vn1[1], vn1[0], vn1[2], vn2[1], vn2[0], vn2[2]);
+ break;
+ }
+ }
+
+ for (int y = 0; y < kViewport; ++y)
+ for (int x = 0; x < kViewport; ++x)
+ for (int s = 0; s < 2; ++s)
+ {
+ unsigned int overdraw = buffer->overdraw[y][x][s];
+
+ result.pixels_covered += overdraw > 0;
+ result.pixels_shaded += overdraw;
+ }
+ }
+
+ result.overdraw = result.pixels_covered ? float(result.pixels_shaded) / float(result.pixels_covered) : 0.f;
+
+ return result;
+}
diff --git a/thirdparty/meshoptimizer/overdrawoptimizer.cpp b/thirdparty/meshoptimizer/overdrawoptimizer.cpp
new file mode 100644
index 0000000000..143656ed76
--- /dev/null
+++ b/thirdparty/meshoptimizer/overdrawoptimizer.cpp
@@ -0,0 +1,333 @@
+// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
+#include "meshoptimizer.h"
+
+#include <assert.h>
+#include <math.h>
+#include <string.h>
+
+// This work is based on:
+// Pedro Sander, Diego Nehab and Joshua Barczak. Fast Triangle Reordering for Vertex Locality and Reduced Overdraw. 2007
+namespace meshopt
+{
+
+static void calculateSortData(float* sort_data, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_positions_stride, const unsigned int* clusters, size_t cluster_count)
+{
+ size_t vertex_stride_float = vertex_positions_stride / sizeof(float);
+
+ float mesh_centroid[3] = {};
+
+ for (size_t i = 0; i < index_count; ++i)
+ {
+ const float* p = vertex_positions + vertex_stride_float * indices[i];
+
+ mesh_centroid[0] += p[0];
+ mesh_centroid[1] += p[1];
+ mesh_centroid[2] += p[2];
+ }
+
+ mesh_centroid[0] /= index_count;
+ mesh_centroid[1] /= index_count;
+ mesh_centroid[2] /= index_count;
+
+ for (size_t cluster = 0; cluster < cluster_count; ++cluster)
+ {
+ size_t cluster_begin = clusters[cluster] * 3;
+ size_t cluster_end = (cluster + 1 < cluster_count) ? clusters[cluster + 1] * 3 : index_count;
+ assert(cluster_begin < cluster_end);
+
+ float cluster_area = 0;
+ float cluster_centroid[3] = {};
+ float cluster_normal[3] = {};
+
+ for (size_t i = cluster_begin; i < cluster_end; i += 3)
+ {
+ const float* p0 = vertex_positions + vertex_stride_float * indices[i + 0];
+ const float* p1 = vertex_positions + vertex_stride_float * indices[i + 1];
+ const float* p2 = vertex_positions + vertex_stride_float * indices[i + 2];
+
+ float p10[3] = {p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2]};
+ float p20[3] = {p2[0] - p0[0], p2[1] - p0[1], p2[2] - p0[2]};
+
+ float normalx = p10[1] * p20[2] - p10[2] * p20[1];
+ float normaly = p10[2] * p20[0] - p10[0] * p20[2];
+ float normalz = p10[0] * p20[1] - p10[1] * p20[0];
+
+ float area = sqrtf(normalx * normalx + normaly * normaly + normalz * normalz);
+
+ cluster_centroid[0] += (p0[0] + p1[0] + p2[0]) * (area / 3);
+ cluster_centroid[1] += (p0[1] + p1[1] + p2[1]) * (area / 3);
+ cluster_centroid[2] += (p0[2] + p1[2] + p2[2]) * (area / 3);
+ cluster_normal[0] += normalx;
+ cluster_normal[1] += normaly;
+ cluster_normal[2] += normalz;
+ cluster_area += area;
+ }
+
+ float inv_cluster_area = cluster_area == 0 ? 0 : 1 / cluster_area;
+
+ cluster_centroid[0] *= inv_cluster_area;
+ cluster_centroid[1] *= inv_cluster_area;
+ cluster_centroid[2] *= inv_cluster_area;
+
+ float cluster_normal_length = sqrtf(cluster_normal[0] * cluster_normal[0] + cluster_normal[1] * cluster_normal[1] + cluster_normal[2] * cluster_normal[2]);
+ float inv_cluster_normal_length = cluster_normal_length == 0 ? 0 : 1 / cluster_normal_length;
+
+ cluster_normal[0] *= inv_cluster_normal_length;
+ cluster_normal[1] *= inv_cluster_normal_length;
+ cluster_normal[2] *= inv_cluster_normal_length;
+
+ float centroid_vector[3] = {cluster_centroid[0] - mesh_centroid[0], cluster_centroid[1] - mesh_centroid[1], cluster_centroid[2] - mesh_centroid[2]};
+
+ sort_data[cluster] = centroid_vector[0] * cluster_normal[0] + centroid_vector[1] * cluster_normal[1] + centroid_vector[2] * cluster_normal[2];
+ }
+}
+
+static void calculateSortOrderRadix(unsigned int* sort_order, const float* sort_data, unsigned short* sort_keys, size_t cluster_count)
+{
+ // compute sort data bounds and renormalize, using fixed point snorm
+ float sort_data_max = 1e-3f;
+
+ for (size_t i = 0; i < cluster_count; ++i)
+ {
+ float dpa = fabsf(sort_data[i]);
+
+ sort_data_max = (sort_data_max < dpa) ? dpa : sort_data_max;
+ }
+
+ const int sort_bits = 11;
+
+ for (size_t i = 0; i < cluster_count; ++i)
+ {
+ // note that we flip distribution since high dot product should come first
+ float sort_key = 0.5f - 0.5f * (sort_data[i] / sort_data_max);
+
+ sort_keys[i] = meshopt_quantizeUnorm(sort_key, sort_bits) & ((1 << sort_bits) - 1);
+ }
+
+ // fill histogram for counting sort
+ unsigned int histogram[1 << sort_bits];
+ memset(histogram, 0, sizeof(histogram));
+
+ for (size_t i = 0; i < cluster_count; ++i)
+ {
+ histogram[sort_keys[i]]++;
+ }
+
+ // compute offsets based on histogram data
+ size_t histogram_sum = 0;
+
+ for (size_t i = 0; i < 1 << sort_bits; ++i)
+ {
+ size_t count = histogram[i];
+ histogram[i] = unsigned(histogram_sum);
+ histogram_sum += count;
+ }
+
+ assert(histogram_sum == cluster_count);
+
+ // compute sort order based on offsets
+ for (size_t i = 0; i < cluster_count; ++i)
+ {
+ sort_order[histogram[sort_keys[i]]++] = unsigned(i);
+ }
+}
+
+static unsigned int updateCache(unsigned int a, unsigned int b, unsigned int c, unsigned int cache_size, unsigned int* cache_timestamps, unsigned int& timestamp)
+{
+ unsigned int cache_misses = 0;
+
+ // if vertex is not in cache, put it in cache
+ if (timestamp - cache_timestamps[a] > cache_size)
+ {
+ cache_timestamps[a] = timestamp++;
+ cache_misses++;
+ }
+
+ if (timestamp - cache_timestamps[b] > cache_size)
+ {
+ cache_timestamps[b] = timestamp++;
+ cache_misses++;
+ }
+
+ if (timestamp - cache_timestamps[c] > cache_size)
+ {
+ cache_timestamps[c] = timestamp++;
+ cache_misses++;
+ }
+
+ return cache_misses;
+}
+
+static size_t generateHardBoundaries(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int cache_size, unsigned int* cache_timestamps)
+{
+ memset(cache_timestamps, 0, vertex_count * sizeof(unsigned int));
+
+ unsigned int timestamp = cache_size + 1;
+
+ size_t face_count = index_count / 3;
+
+ size_t result = 0;
+
+ for (size_t i = 0; i < face_count; ++i)
+ {
+ unsigned int m = updateCache(indices[i * 3 + 0], indices[i * 3 + 1], indices[i * 3 + 2], cache_size, &cache_timestamps[0], timestamp);
+
+ // when all three vertices are not in the cache it's usually relatively safe to assume that this is a new patch in the mesh
+ // that is disjoint from previous vertices; sometimes it might come back to reference existing vertices but that frequently
+ // suggests an inefficiency in the vertex cache optimization algorithm
+ // usually the first triangle has 3 misses unless it's degenerate - thus we make sure the first cluster always starts with 0
+ if (i == 0 || m == 3)
+ {
+ destination[result++] = unsigned(i);
+ }
+ }
+
+ assert(result <= index_count / 3);
+
+ return result;
+}
+
+static size_t generateSoftBoundaries(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, const unsigned int* clusters, size_t cluster_count, unsigned int cache_size, float threshold, unsigned int* cache_timestamps)
+{
+ memset(cache_timestamps, 0, vertex_count * sizeof(unsigned int));
+
+ unsigned int timestamp = 0;
+
+ size_t result = 0;
+
+ for (size_t it = 0; it < cluster_count; ++it)
+ {
+ size_t start = clusters[it];
+ size_t end = (it + 1 < cluster_count) ? clusters[it + 1] : index_count / 3;
+ assert(start < end);
+
+ // reset cache
+ timestamp += cache_size + 1;
+
+ // measure cluster ACMR
+ unsigned int cluster_misses = 0;
+
+ for (size_t i = start; i < end; ++i)
+ {
+ unsigned int m = updateCache(indices[i * 3 + 0], indices[i * 3 + 1], indices[i * 3 + 2], cache_size, &cache_timestamps[0], timestamp);
+
+ cluster_misses += m;
+ }
+
+ float cluster_threshold = threshold * (float(cluster_misses) / float(end - start));
+
+ // first cluster always starts from the hard cluster boundary
+ destination[result++] = unsigned(start);
+
+ // reset cache
+ timestamp += cache_size + 1;
+
+ unsigned int running_misses = 0;
+ unsigned int running_faces = 0;
+
+ for (size_t i = start; i < end; ++i)
+ {
+ unsigned int m = updateCache(indices[i * 3 + 0], indices[i * 3 + 1], indices[i * 3 + 2], cache_size, &cache_timestamps[0], timestamp);
+
+ running_misses += m;
+ running_faces += 1;
+
+ if (float(running_misses) / float(running_faces) <= cluster_threshold)
+ {
+ // we have reached the target ACMR with the current triangle so we need to start a new cluster on the next one
+ // note that this may mean that we add 'end` to destination for the last triangle, which will imply that the last
+ // cluster is empty; however, the 'pop_back' after the loop will clean it up
+ destination[result++] = unsigned(i + 1);
+
+ // reset cache
+ timestamp += cache_size + 1;
+
+ running_misses = 0;
+ running_faces = 0;
+ }
+ }
+
+ // each time we reach the target ACMR we flush the cluster
+ // this means that the last cluster is by definition not very good - there are frequent cases where we are left with a few triangles
+ // in the last cluster, producing a very bad ACMR and significantly penalizing the overall results
+ // thus we remove the last cluster boundary, merging the last complete cluster with the last incomplete one
+ // there are sometimes cases when the last cluster is actually good enough - in which case the code above would have added 'end'
+ // to the cluster boundary array which we need to remove anyway - this code will do that automatically
+ if (destination[result - 1] != start)
+ {
+ result--;
+ }
+ }
+
+ assert(result >= cluster_count);
+ assert(result <= index_count / 3);
+
+ return result;
+}
+
+} // namespace meshopt
+
+void meshopt_optimizeOverdraw(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, float threshold)
+{
+ using namespace meshopt;
+
+ assert(index_count % 3 == 0);
+ assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
+ assert(vertex_positions_stride % sizeof(float) == 0);
+
+ meshopt_Allocator allocator;
+
+ // guard for empty meshes
+ if (index_count == 0 || vertex_count == 0)
+ return;
+
+ // support in-place optimization
+ if (destination == indices)
+ {
+ unsigned int* indices_copy = allocator.allocate<unsigned int>(index_count);
+ memcpy(indices_copy, indices, index_count * sizeof(unsigned int));
+ indices = indices_copy;
+ }
+
+ unsigned int cache_size = 16;
+
+ unsigned int* cache_timestamps = allocator.allocate<unsigned int>(vertex_count);
+
+ // generate hard boundaries from full-triangle cache misses
+ unsigned int* hard_clusters = allocator.allocate<unsigned int>(index_count / 3);
+ size_t hard_cluster_count = generateHardBoundaries(hard_clusters, indices, index_count, vertex_count, cache_size, cache_timestamps);
+
+ // generate soft boundaries
+ unsigned int* soft_clusters = allocator.allocate<unsigned int>(index_count / 3 + 1);
+ size_t soft_cluster_count = generateSoftBoundaries(soft_clusters, indices, index_count, vertex_count, hard_clusters, hard_cluster_count, cache_size, threshold, cache_timestamps);
+
+ const unsigned int* clusters = soft_clusters;
+ size_t cluster_count = soft_cluster_count;
+
+ // fill sort data
+ float* sort_data = allocator.allocate<float>(cluster_count);
+ calculateSortData(sort_data, indices, index_count, vertex_positions, vertex_positions_stride, clusters, cluster_count);
+
+ // sort clusters using sort data
+ unsigned short* sort_keys = allocator.allocate<unsigned short>(cluster_count);
+ unsigned int* sort_order = allocator.allocate<unsigned int>(cluster_count);
+ calculateSortOrderRadix(sort_order, sort_data, sort_keys, cluster_count);
+
+ // fill output buffer
+ size_t offset = 0;
+
+ for (size_t it = 0; it < cluster_count; ++it)
+ {
+ unsigned int cluster = sort_order[it];
+ assert(cluster < cluster_count);
+
+ size_t cluster_begin = clusters[cluster] * 3;
+ size_t cluster_end = (cluster + 1 < cluster_count) ? clusters[cluster + 1] * 3 : index_count;
+ assert(cluster_begin < cluster_end);
+
+ memcpy(destination + offset, indices + cluster_begin, (cluster_end - cluster_begin) * sizeof(unsigned int));
+ offset += cluster_end - cluster_begin;
+ }
+
+ assert(offset == index_count);
+}
diff --git a/thirdparty/meshoptimizer/patches/simplifier_get_resulting_error.patch b/thirdparty/meshoptimizer/patches/simplifier_get_resulting_error.patch
new file mode 100644
index 0000000000..1be38e45d2
--- /dev/null
+++ b/thirdparty/meshoptimizer/patches/simplifier_get_resulting_error.patch
@@ -0,0 +1,96 @@
+diff --git a/thirdparty/meshoptimizer/meshoptimizer.h b/thirdparty/meshoptimizer/meshoptimizer.h
+index a442d103c8..fde00f9c82 100644
+--- a/thirdparty/meshoptimizer/meshoptimizer.h
++++ b/thirdparty/meshoptimizer/meshoptimizer.h
+@@ -266,7 +266,10 @@ MESHOPTIMIZER_EXPERIMENTAL void meshopt_decodeFilterExp(void* buffer, size_t ver
+ * destination must contain enough space for the *source* index buffer (since optimization is iterative, this means index_count elements - *not* target_index_count!)
+ * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
+ */
+-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);
++// -- GODOT start --
++//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);
++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 *r_resulting_error);
++// -- GODOT end --
+
+ /**
+ * Experimental: Mesh simplifier (sloppy)
+diff --git a/thirdparty/meshoptimizer/simplifier.cpp b/thirdparty/meshoptimizer/simplifier.cpp
+index bd523275ce..51cf634186 100644
+--- a/thirdparty/meshoptimizer/simplifier.cpp
++++ b/thirdparty/meshoptimizer/simplifier.cpp
+@@ -1143,7 +1143,10 @@ unsigned int* meshopt_simplifyDebugLoop = 0;
+ 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)
++// -- GODOT start --
++//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)
++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 *r_resulting_error)
++// -- GODOT end --
+ {
+ using namespace meshopt;
+
+@@ -1198,10 +1201,13 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
+ if (result != indices)
+ memcpy(result, indices, index_count * sizeof(unsigned int));
+
++// -- GODOT start --
+ #if TRACE
+ size_t pass_count = 0;
+- float worst_error = 0;
++ //float worst_error = 0;
+ #endif
++ float worst_error = 0;
++// -- GODOT end --
+
+ Collapse* edge_collapses = allocator.allocate<Collapse>(index_count);
+ unsigned int* collapse_order = allocator.allocate<unsigned int>(index_count);
+@@ -1213,6 +1219,12 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
+ // target_error input is linear; we need to adjust it to match quadricError units
+ float error_limit = target_error * target_error;
+
++// -- GODOT start --
++ if (r_resulting_error) {
++ *r_resulting_error = 1.0;
++ }
++// -- GODOT end --
++
+ while (result_count > target_index_count)
+ {
+ size_t edge_collapse_count = pickEdgeCollapses(edge_collapses, result, result_count, remap, vertex_kind, loop);
+@@ -1257,7 +1269,8 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
+ size_t new_count = remapIndexBuffer(result, result_count, collapse_remap);
+ assert(new_count < result_count);
+
+-#if TRACE
++// -- GODOT start --
++//#if TRACE
+ float pass_error = 0.f;
+ for (size_t i = 0; i < edge_collapse_count; ++i)
+ {
+@@ -1267,15 +1280,24 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
+ pass_error = c.error;
+ }
+
+- pass_count++;
++ //pass_count++;
+ worst_error = (worst_error < pass_error) ? pass_error : worst_error;
+
++#if TRACE
++ pass_count++;
+ printf("pass %d: triangles: %d -> %d, collapses: %d/%d (goal: %d), error: %e (limit %e goal %e)\n", int(pass_count), int(result_count / 3), int(new_count / 3), int(collapses), int(edge_collapse_count), int(edge_collapse_goal), pass_error, error_limit, error_goal);
+ #endif
++// -- GODOT end --
+
+ result_count = new_count;
+ }
+
++// -- GODOT start --
++ if (r_resulting_error) {
++ *r_resulting_error = sqrt(worst_error);
++ }
++// -- GODOT end --
++
+ #if TRACE
+ printf("passes: %d, worst error: %e\n", int(pass_count), worst_error);
+ #endif
diff --git a/thirdparty/meshoptimizer/simplifier.cpp b/thirdparty/meshoptimizer/simplifier.cpp
new file mode 100644
index 0000000000..b195a8cb5d
--- /dev/null
+++ b/thirdparty/meshoptimizer/simplifier.cpp
@@ -0,0 +1,1562 @@
+// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
+#include "meshoptimizer.h"
+
+#include <assert.h>
+#include <float.h>
+#include <math.h>
+#include <string.h>
+
+
+#ifndef TRACE
+#define TRACE 0
+#endif
+
+#if TRACE
+#include <stdio.h>
+#endif
+
+// 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
+// Peter Lindstrom. Out-of-Core Simplification of Large Polygonal Models. 2000
+// Matthias Teschner, Bruno Heidelberger, Matthias Mueller, Danat Pomeranets, Markus Gross. Optimized Spatial Hashing for Collision Detection of Deformable Objects. 2003
+// Peter Van Sandt, Yannis Chronis, Jignesh M. Patel. Efficiently Searching In-Memory Sorted Arrays: Revenge of the Interpolation Search? 2019
+namespace meshopt
+{
+
+struct EdgeAdjacency
+{
+ unsigned int* counts;
+ unsigned int* offsets;
+ unsigned int* data;
+};
+
+static void buildEdgeAdjacency(EdgeAdjacency& adjacency, const unsigned int* indices, size_t index_count, size_t vertex_count, meshopt_Allocator& allocator)
+{
+ size_t face_count = index_count / 3;
+
+ // allocate arrays
+ adjacency.counts = allocator.allocate<unsigned int>(vertex_count);
+ adjacency.offsets = allocator.allocate<unsigned int>(vertex_count);
+ adjacency.data = allocator.allocate<unsigned int>(index_count);
+
+ // fill edge counts
+ memset(adjacency.counts, 0, vertex_count * sizeof(unsigned int));
+
+ for (size_t i = 0; i < index_count; ++i)
+ {
+ assert(indices[i] < vertex_count);
+
+ adjacency.counts[indices[i]]++;
+ }
+
+ // fill offset table
+ unsigned int offset = 0;
+
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ adjacency.offsets[i] = offset;
+ offset += adjacency.counts[i];
+ }
+
+ assert(offset == index_count);
+
+ // fill edge data
+ for (size_t i = 0; i < face_count; ++i)
+ {
+ unsigned int a = indices[i * 3 + 0], b = indices[i * 3 + 1], c = indices[i * 3 + 2];
+
+ adjacency.data[adjacency.offsets[a]++] = b;
+ adjacency.data[adjacency.offsets[b]++] = c;
+ adjacency.data[adjacency.offsets[c]++] = a;
+ }
+
+ // fix offsets that have been disturbed by the previous pass
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ assert(adjacency.offsets[i] >= adjacency.counts[i]);
+
+ adjacency.offsets[i] -= adjacency.counts[i];
+ }
+}
+
+struct PositionHasher
+{
+ const float* vertex_positions;
+ size_t vertex_stride_float;
+
+ size_t hash(unsigned int index) const
+ {
+ const unsigned int* key = reinterpret_cast<const unsigned int*>(vertex_positions + index * vertex_stride_float);
+
+ // Optimized Spatial Hashing for Collision Detection of Deformable Objects
+ return (key[0] * 73856093) ^ (key[1] * 19349663) ^ (key[2] * 83492791);
+ }
+
+ bool equal(unsigned int lhs, unsigned int rhs) const
+ {
+ return memcmp(vertex_positions + lhs * vertex_stride_float, vertex_positions + rhs * vertex_stride_float, sizeof(float) * 3) == 0;
+ }
+};
+
+static size_t hashBuckets2(size_t count)
+{
+ size_t buckets = 1;
+ while (buckets < count)
+ buckets *= 2;
+
+ return buckets;
+}
+
+template <typename T, typename Hash>
+static T* hashLookup2(T* table, size_t buckets, const Hash& hash, const T& key, const T& empty)
+{
+ assert(buckets > 0);
+ assert((buckets & (buckets - 1)) == 0);
+
+ size_t hashmod = buckets - 1;
+ size_t bucket = hash.hash(key) & hashmod;
+
+ for (size_t probe = 0; probe <= hashmod; ++probe)
+ {
+ T& item = table[bucket];
+
+ if (item == empty)
+ return &item;
+
+ if (hash.equal(item, key))
+ return &item;
+
+ // hash collision, quadratic probing
+ bucket = (bucket + probe + 1) & hashmod;
+ }
+
+ assert(false && "Hash table is full"); // unreachable
+ return 0;
+}
+
+static void buildPositionRemap(unsigned int* remap, unsigned int* wedge, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, meshopt_Allocator& allocator)
+{
+ PositionHasher hasher = {vertex_positions_data, vertex_positions_stride / sizeof(float)};
+
+ size_t table_size = hashBuckets2(vertex_count);
+ unsigned int* table = allocator.allocate<unsigned int>(table_size);
+ memset(table, -1, table_size * sizeof(unsigned int));
+
+ // build forward remap: for each vertex, which other (canonical) vertex does it map to?
+ // we use position equivalence for this, and remap vertices to other existing vertices
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ unsigned int index = unsigned(i);
+ unsigned int* entry = hashLookup2(table, table_size, hasher, index, ~0u);
+
+ if (*entry == ~0u)
+ *entry = index;
+
+ remap[index] = *entry;
+ }
+
+ // build wedge table: for each vertex, which other vertex is the next wedge that also maps to the same vertex?
+ // entries in table form a (cyclic) wedge loop per vertex; for manifold vertices, wedge[i] == remap[i] == i
+ for (size_t i = 0; i < vertex_count; ++i)
+ wedge[i] = unsigned(i);
+
+ for (size_t i = 0; i < vertex_count; ++i)
+ if (remap[i] != i)
+ {
+ unsigned int r = remap[i];
+
+ wedge[i] = wedge[r];
+ wedge[r] = unsigned(i);
+ }
+}
+
+enum VertexKind
+{
+ Kind_Manifold, // not on an attribute seam, not on any boundary
+ Kind_Border, // not on an attribute seam, has exactly two open edges
+ Kind_Seam, // on an attribute seam with exactly two attribute seam edges
+ Kind_Complex, // none of the above; these vertices can move as long as all wedges move to the target vertex
+ Kind_Locked, // none of the above; these vertices can't move
+
+ Kind_Count
+};
+
+// manifold vertices can collapse onto anything
+// border/seam vertices can only be collapsed onto border/seam respectively
+// complex vertices can collapse onto complex/locked
+// a rule of thumb is that collapsing kind A into kind B preserves the kind B in the target vertex
+// for example, while we could collapse Complex into Manifold, this would mean the target vertex isn't Manifold anymore
+const unsigned char kCanCollapse[Kind_Count][Kind_Count] = {
+ {1, 1, 1, 1, 1},
+ {0, 1, 0, 0, 0},
+ {0, 0, 1, 0, 0},
+ {0, 0, 0, 1, 1},
+ {0, 0, 0, 0, 0},
+};
+
+// if a vertex is manifold or seam, adjoining edges are guaranteed to have an opposite edge
+// note that for seam edges, the opposite edge isn't present in the attribute-based topology
+// but is present if you consider a position-only mesh variant
+const unsigned char kHasOpposite[Kind_Count][Kind_Count] = {
+ {1, 1, 1, 0, 1},
+ {1, 0, 1, 0, 0},
+ {1, 1, 1, 0, 1},
+ {0, 0, 0, 0, 0},
+ {1, 0, 1, 0, 0},
+};
+
+static bool hasEdge(const EdgeAdjacency& adjacency, unsigned int a, unsigned int b)
+{
+ unsigned int count = adjacency.counts[a];
+ const unsigned int* data = adjacency.data + adjacency.offsets[a];
+
+ for (size_t i = 0; i < count; ++i)
+ if (data[i] == b)
+ return true;
+
+ return false;
+}
+
+static void classifyVertices(unsigned char* result, unsigned int* loop, unsigned int* loopback, size_t vertex_count, const EdgeAdjacency& adjacency, const unsigned int* remap, const unsigned int* wedge)
+{
+ memset(loop, -1, vertex_count * sizeof(unsigned int));
+ memset(loopback, -1, vertex_count * sizeof(unsigned int));
+
+ // incoming & outgoing open edges: ~0u if no open edges, i if there are more than 1
+ // note that this is the same data as required in loop[] arrays; loop[] data is only valid for border/seam
+ // but here it's okay to fill the data out for other types of vertices as well
+ unsigned int* openinc = loopback;
+ unsigned int* openout = loop;
+
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ unsigned int vertex = unsigned(i);
+
+ unsigned int count = adjacency.counts[vertex];
+ const unsigned int* data = adjacency.data + adjacency.offsets[vertex];
+
+ for (size_t j = 0; j < count; ++j)
+ {
+ unsigned int target = data[j];
+
+ if (!hasEdge(adjacency, target, vertex))
+ {
+ openinc[target] = (openinc[target] == ~0u) ? vertex : target;
+ openout[vertex] = (openout[vertex] == ~0u) ? target : vertex;
+ }
+ }
+ }
+
+#if TRACE
+ size_t lockedstats[4] = {};
+#define TRACELOCKED(i) lockedstats[i]++;
+#else
+#define TRACELOCKED(i) (void)0
+#endif
+
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ if (remap[i] == i)
+ {
+ if (wedge[i] == i)
+ {
+ // no attribute seam, need to check if it's manifold
+ unsigned int openi = openinc[i], openo = openout[i];
+
+ // note: we classify any vertices with no open edges as manifold
+ // this is technically incorrect - if 4 triangles share an edge, we'll classify vertices as manifold
+ // it's unclear if this is a problem in practice
+ if (openi == ~0u && openo == ~0u)
+ {
+ result[i] = Kind_Manifold;
+ }
+ else if (openi != i && openo != i)
+ {
+ result[i] = Kind_Border;
+ }
+ else
+ {
+ result[i] = Kind_Locked;
+ TRACELOCKED(0);
+ }
+ }
+ else if (wedge[wedge[i]] == i)
+ {
+ // attribute seam; need to distinguish between Seam and Locked
+ unsigned int w = wedge[i];
+ unsigned int openiv = openinc[i], openov = openout[i];
+ unsigned int openiw = openinc[w], openow = openout[w];
+
+ // seam should have one open half-edge for each vertex, and the edges need to "connect" - point to the same vertex post-remap
+ if (openiv != ~0u && openiv != i && openov != ~0u && openov != i &&
+ openiw != ~0u && openiw != w && openow != ~0u && openow != w)
+ {
+ if (remap[openiv] == remap[openow] && remap[openov] == remap[openiw])
+ {
+ result[i] = Kind_Seam;
+ }
+ else
+ {
+ result[i] = Kind_Locked;
+ TRACELOCKED(1);
+ }
+ }
+ else
+ {
+ result[i] = Kind_Locked;
+ TRACELOCKED(2);
+ }
+ }
+ else
+ {
+ // more than one vertex maps to this one; we don't have classification available
+ result[i] = Kind_Locked;
+ TRACELOCKED(3);
+ }
+ }
+ else
+ {
+ assert(remap[i] < i);
+
+ result[i] = result[remap[i]];
+ }
+ }
+
+#if TRACE
+ printf("locked: many open edges %d, disconnected seam %d, many seam edges %d, many wedges %d\n",
+ int(lockedstats[0]), int(lockedstats[1]), int(lockedstats[2]), int(lockedstats[3]));
+#endif
+}
+
+struct Vector3
+{
+ float x, y, z;
+};
+// -- GODOT start --
+//static void rescalePositions(Vector3* result, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride)
+static float rescalePositions(Vector3* result, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride)
+// -- GODOT end --
+
+{
+ size_t vertex_stride_float = vertex_positions_stride / sizeof(float);
+
+ float minv[3] = {FLT_MAX, FLT_MAX, FLT_MAX};
+ float maxv[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
+
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ const float* v = vertex_positions_data + i * vertex_stride_float;
+
+ result[i].x = v[0];
+ result[i].y = v[1];
+ result[i].z = v[2];
+
+ for (int j = 0; j < 3; ++j)
+ {
+ float vj = v[j];
+
+ minv[j] = minv[j] > vj ? vj : minv[j];
+ maxv[j] = maxv[j] < vj ? vj : maxv[j];
+ }
+ }
+
+ float extent = 0.f;
+
+ extent = (maxv[0] - minv[0]) < extent ? extent : (maxv[0] - minv[0]);
+ extent = (maxv[1] - minv[1]) < extent ? extent : (maxv[1] - minv[1]);
+ extent = (maxv[2] - minv[2]) < extent ? extent : (maxv[2] - minv[2]);
+
+ float scale = extent == 0 ? 0.f : 1.f / extent;
+
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ result[i].x = (result[i].x - minv[0]) * scale;
+ result[i].y = (result[i].y - minv[1]) * scale;
+ result[i].z = (result[i].z - minv[2]) * scale;
+ }
+// -- GODOT start --
+ return extent;
+// -- GODOT end --
+
+}
+
+struct Quadric
+{
+ float a00, a11, a22;
+ float a10, a20, a21;
+ float b0, b1, b2, c;
+ float w;
+};
+
+struct Collapse
+{
+ unsigned int v0;
+ unsigned int v1;
+
+ union
+ {
+ unsigned int bidi;
+ float error;
+ unsigned int errorui;
+ };
+};
+
+static float normalize(Vector3& v)
+{
+ float length = sqrtf(v.x * v.x + v.y * v.y + v.z * v.z);
+
+ if (length > 0)
+ {
+ v.x /= length;
+ v.y /= length;
+ v.z /= length;
+ }
+
+ return length;
+}
+
+static void quadricAdd(Quadric& Q, const Quadric& R)
+{
+ Q.a00 += R.a00;
+ Q.a11 += R.a11;
+ Q.a22 += R.a22;
+ Q.a10 += R.a10;
+ Q.a20 += R.a20;
+ Q.a21 += R.a21;
+ Q.b0 += R.b0;
+ Q.b1 += R.b1;
+ Q.b2 += R.b2;
+ Q.c += R.c;
+ Q.w += R.w;
+}
+
+static float quadricError(const Quadric& Q, const Vector3& v)
+{
+ float rx = Q.b0;
+ float ry = Q.b1;
+ float rz = Q.b2;
+
+ rx += Q.a10 * v.y;
+ ry += Q.a21 * v.z;
+ rz += Q.a20 * v.x;
+
+ rx *= 2;
+ ry *= 2;
+ rz *= 2;
+
+ rx += Q.a00 * v.x;
+ ry += Q.a11 * v.y;
+ rz += Q.a22 * v.z;
+
+ float r = Q.c;
+ r += rx * v.x;
+ r += ry * v.y;
+ r += rz * v.z;
+
+ float s = Q.w == 0.f ? 0.f : 1.f / Q.w;
+
+ return fabsf(r) * s;
+}
+
+static void quadricFromPlane(Quadric& Q, float a, float b, float c, float d, float w)
+{
+ float aw = a * w;
+ float bw = b * w;
+ float cw = c * w;
+ float dw = d * w;
+
+ Q.a00 = a * aw;
+ Q.a11 = b * bw;
+ Q.a22 = c * cw;
+ Q.a10 = a * bw;
+ Q.a20 = a * cw;
+ Q.a21 = b * cw;
+ Q.b0 = a * dw;
+ Q.b1 = b * dw;
+ Q.b2 = c * dw;
+ Q.c = d * dw;
+ Q.w = w;
+}
+
+static void quadricFromPoint(Quadric& Q, float x, float y, float z, float w)
+{
+ // we need to encode (x - X) ^ 2 + (y - Y)^2 + (z - Z)^2 into the quadric
+ Q.a00 = w;
+ Q.a11 = w;
+ Q.a22 = w;
+ Q.a10 = 0.f;
+ Q.a20 = 0.f;
+ Q.a21 = 0.f;
+ Q.b0 = -2.f * x * w;
+ Q.b1 = -2.f * y * w;
+ Q.b2 = -2.f * z * w;
+ Q.c = (x * x + y * y + z * z) * w;
+ Q.w = w;
+}
+
+static void quadricFromTriangle(Quadric& Q, const Vector3& p0, const Vector3& p1, const Vector3& p2, float weight)
+{
+ 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};
+
+ // normal = cross(p1 - p0, p2 - p0)
+ Vector3 normal = {p10.y * p20.z - p10.z * p20.y, p10.z * p20.x - p10.x * p20.z, p10.x * p20.y - p10.y * p20.x};
+ float area = normalize(normal);
+
+ float distance = normal.x * p0.x + normal.y * p0.y + normal.z * p0.z;
+
+ // we use sqrtf(area) so that the error is scaled linearly; this tends to improve silhouettes
+ quadricFromPlane(Q, normal.x, normal.y, normal.z, -distance, sqrtf(area) * weight);
+}
+
+static void quadricFromTriangleEdge(Quadric& Q, const Vector3& p0, const Vector3& p1, const Vector3& p2, float weight)
+{
+ Vector3 p10 = {p1.x - p0.x, p1.y - p0.y, p1.z - p0.z};
+ float length = normalize(p10);
+
+ // p20p = length of projection of p2-p0 onto normalize(p1 - p0)
+ Vector3 p20 = {p2.x - p0.x, p2.y - p0.y, p2.z - p0.z};
+ float p20p = p20.x * p10.x + p20.y * p10.y + p20.z * p10.z;
+
+ // normal = altitude of triangle from point p2 onto edge p1-p0
+ Vector3 normal = {p20.x - p10.x * p20p, p20.y - p10.y * p20p, p20.z - p10.z * p20p};
+ normalize(normal);
+
+ float distance = normal.x * p0.x + normal.y * p0.y + normal.z * p0.z;
+
+ // note: the weight is scaled linearly with edge length; this has to match the triangle weight
+ quadricFromPlane(Q, normal.x, normal.y, normal.z, -distance, length * weight);
+}
+
+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)
+ {
+ unsigned int i0 = indices[i + 0];
+ unsigned int i1 = indices[i + 1];
+ unsigned int i2 = indices[i + 2];
+
+ Quadric Q;
+ quadricFromTriangle(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], 1.f);
+
+ quadricAdd(vertex_quadrics[remap[i0]], Q);
+ quadricAdd(vertex_quadrics[remap[i1]], Q);
+ quadricAdd(vertex_quadrics[remap[i2]], Q);
+ }
+}
+
+static void fillEdgeQuadrics(Quadric* vertex_quadrics, const unsigned int* indices, size_t index_count, const Vector3* vertex_positions, const unsigned int* remap, const unsigned char* vertex_kind, const unsigned int* loop, const unsigned int* loopback)
+{
+ for (size_t i = 0; i < index_count; i += 3)
+ {
+ static const int next[3] = {1, 2, 0};
+
+ for (int e = 0; e < 3; ++e)
+ {
+ unsigned int i0 = indices[i + e];
+ unsigned int i1 = indices[i + next[e]];
+
+ unsigned char k0 = vertex_kind[i0];
+ unsigned char k1 = vertex_kind[i1];
+
+ // check that either i0 or i1 are border/seam and are on the same edge loop
+ // note that we need to add the error even for edged that connect e.g. border & locked
+ // if we don't do that, the adjacent border->border edge won't have correct errors for corners
+ if (k0 != Kind_Border && k0 != Kind_Seam && k1 != Kind_Border && k1 != Kind_Seam)
+ continue;
+
+ if ((k0 == Kind_Border || k0 == Kind_Seam) && loop[i0] != i1)
+ continue;
+
+ if ((k1 == Kind_Border || k1 == Kind_Seam) && loopback[i1] != i0)
+ continue;
+
+ // seam edges should occur twice (i0->i1 and i1->i0) - skip redundant edges
+ if (kHasOpposite[k0][k1] && remap[i1] > remap[i0])
+ continue;
+
+ unsigned int i2 = indices[i + next[next[e]]];
+
+ // we try hard to maintain border edge geometry; seam edges can move more freely
+ // due to topological restrictions on collapses, seam quadrics slightly improves collapse structure but aren't critical
+ const float kEdgeWeightSeam = 1.f;
+ const float kEdgeWeightBorder = 10.f;
+
+ float edgeWeight = (k0 == Kind_Border || k1 == Kind_Border) ? kEdgeWeightBorder : kEdgeWeightSeam;
+
+ Quadric Q;
+ quadricFromTriangleEdge(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], edgeWeight);
+
+ quadricAdd(vertex_quadrics[remap[i0]], Q);
+ quadricAdd(vertex_quadrics[remap[i1]], Q);
+ }
+ }
+}
+
+static size_t pickEdgeCollapses(Collapse* collapses, const unsigned int* indices, size_t index_count, const unsigned int* remap, const unsigned char* vertex_kind, const unsigned int* loop)
+{
+ size_t collapse_count = 0;
+
+ for (size_t i = 0; i < index_count; i += 3)
+ {
+ static const int next[3] = {1, 2, 0};
+
+ for (int e = 0; e < 3; ++e)
+ {
+ unsigned int i0 = indices[i + e];
+ unsigned int i1 = indices[i + next[e]];
+
+ // this can happen either when input has a zero-length edge, or when we perform collapses for complex
+ // topology w/seams and collapse a manifold vertex that connects to both wedges onto one of them
+ // we leave edges like this alone since they may be important for preserving mesh integrity
+ if (remap[i0] == remap[i1])
+ continue;
+
+ unsigned char k0 = vertex_kind[i0];
+ unsigned char k1 = vertex_kind[i1];
+
+ // the edge has to be collapsible in at least one direction
+ if (!(kCanCollapse[k0][k1] | kCanCollapse[k1][k0]))
+ continue;
+
+ // manifold and seam edges should occur twice (i0->i1 and i1->i0) - skip redundant edges
+ if (kHasOpposite[k0][k1] && remap[i1] > remap[i0])
+ continue;
+
+ // two vertices are on a border or a seam, but there's no direct edge between them
+ // this indicates that they belong to two different edge loops and we should not collapse this edge
+ // loop[] tracks half edges so we only need to check i0->i1
+ if (k0 == k1 && (k0 == Kind_Border || k0 == Kind_Seam) && loop[i0] != i1)
+ continue;
+
+ // edge can be collapsed in either direction - we will pick the one with minimum error
+ // note: we evaluate error later during collapse ranking, here we just tag the edge as bidirectional
+ if (kCanCollapse[k0][k1] & kCanCollapse[k1][k0])
+ {
+ Collapse c = {i0, i1, {/* bidi= */ 1}};
+ collapses[collapse_count++] = c;
+ }
+ else
+ {
+ // edge can only be collapsed in one direction
+ unsigned int e0 = kCanCollapse[k0][k1] ? i0 : i1;
+ unsigned int e1 = kCanCollapse[k0][k1] ? i1 : i0;
+
+ Collapse c = {e0, e1, {/* bidi= */ 0}};
+ collapses[collapse_count++] = c;
+ }
+ }
+ }
+
+ return collapse_count;
+}
+
+static void rankEdgeCollapses(Collapse* collapses, size_t collapse_count, const Vector3* vertex_positions, const Quadric* vertex_quadrics, const unsigned int* remap)
+{
+ for (size_t i = 0; i < collapse_count; ++i)
+ {
+ Collapse& c = collapses[i];
+
+ unsigned int i0 = c.v0;
+ unsigned int i1 = c.v1;
+
+ // most edges are bidirectional which means we need to evaluate errors for two collapses
+ // to keep this code branchless we just use the same edge for unidirectional edges
+ unsigned int j0 = c.bidi ? i1 : i0;
+ unsigned int j1 = c.bidi ? i0 : i1;
+
+ const Quadric& qi = vertex_quadrics[remap[i0]];
+ const Quadric& qj = vertex_quadrics[remap[j0]];
+
+ float ei = quadricError(qi, vertex_positions[i1]);
+ float ej = quadricError(qj, vertex_positions[j1]);
+
+ // pick edge direction with minimal error
+ c.v0 = ei <= ej ? i0 : j0;
+ c.v1 = ei <= ej ? i1 : j1;
+ c.error = ei <= ej ? ei : ej;
+ }
+}
+
+#if TRACE > 1
+static void dumpEdgeCollapses(const Collapse* collapses, size_t collapse_count, const unsigned char* vertex_kind)
+{
+ size_t ckinds[Kind_Count][Kind_Count] = {};
+ float cerrors[Kind_Count][Kind_Count] = {};
+
+ for (int k0 = 0; k0 < Kind_Count; ++k0)
+ for (int k1 = 0; k1 < Kind_Count; ++k1)
+ cerrors[k0][k1] = FLT_MAX;
+
+ for (size_t i = 0; i < collapse_count; ++i)
+ {
+ unsigned int i0 = collapses[i].v0;
+ unsigned int i1 = collapses[i].v1;
+
+ unsigned char k0 = vertex_kind[i0];
+ unsigned char k1 = vertex_kind[i1];
+
+ ckinds[k0][k1]++;
+ cerrors[k0][k1] = (collapses[i].error < cerrors[k0][k1]) ? collapses[i].error : cerrors[k0][k1];
+ }
+
+ for (int k0 = 0; k0 < Kind_Count; ++k0)
+ for (int k1 = 0; k1 < Kind_Count; ++k1)
+ if (ckinds[k0][k1])
+ printf("collapses %d -> %d: %d, min error %e\n", k0, k1, int(ckinds[k0][k1]), cerrors[k0][k1]);
+}
+
+static void dumpLockedCollapses(const unsigned int* indices, size_t index_count, const unsigned char* vertex_kind)
+{
+ size_t locked_collapses[Kind_Count][Kind_Count] = {};
+
+ for (size_t i = 0; i < index_count; i += 3)
+ {
+ static const int next[3] = {1, 2, 0};
+
+ for (int e = 0; e < 3; ++e)
+ {
+ unsigned int i0 = indices[i + e];
+ unsigned int i1 = indices[i + next[e]];
+
+ unsigned char k0 = vertex_kind[i0];
+ unsigned char k1 = vertex_kind[i1];
+
+ locked_collapses[k0][k1] += !kCanCollapse[k0][k1] && !kCanCollapse[k1][k0];
+ }
+ }
+
+ for (int k0 = 0; k0 < Kind_Count; ++k0)
+ for (int k1 = 0; k1 < Kind_Count; ++k1)
+ if (locked_collapses[k0][k1])
+ printf("locked collapses %d -> %d: %d\n", k0, k1, int(locked_collapses[k0][k1]));
+}
+#endif
+
+static void sortEdgeCollapses(unsigned int* sort_order, const Collapse* collapses, size_t collapse_count)
+{
+ const int sort_bits = 11;
+
+ // fill histogram for counting sort
+ unsigned int histogram[1 << sort_bits];
+ memset(histogram, 0, sizeof(histogram));
+
+ for (size_t i = 0; i < collapse_count; ++i)
+ {
+ // skip sign bit since error is non-negative
+ unsigned int key = (collapses[i].errorui << 1) >> (32 - sort_bits);
+
+ histogram[key]++;
+ }
+
+ // compute offsets based on histogram data
+ size_t histogram_sum = 0;
+
+ for (size_t i = 0; i < 1 << sort_bits; ++i)
+ {
+ size_t count = histogram[i];
+ histogram[i] = unsigned(histogram_sum);
+ histogram_sum += count;
+ }
+
+ assert(histogram_sum == collapse_count);
+
+ // compute sort order based on offsets
+ for (size_t i = 0; i < collapse_count; ++i)
+ {
+ // skip sign bit since error is non-negative
+ unsigned int key = (collapses[i].errorui << 1) >> (32 - sort_bits);
+
+ sort_order[histogram[key]++] = unsigned(i);
+ }
+}
+
+static size_t performEdgeCollapses(unsigned int* collapse_remap, unsigned char* collapse_locked, Quadric* vertex_quadrics, const Collapse* collapses, size_t collapse_count, const unsigned int* collapse_order, const unsigned int* remap, const unsigned int* wedge, const unsigned char* vertex_kind, size_t triangle_collapse_goal, float error_goal, float error_limit)
+{
+ size_t edge_collapses = 0;
+ size_t triangle_collapses = 0;
+
+ for (size_t i = 0; i < collapse_count; ++i)
+ {
+ const Collapse& c = collapses[collapse_order[i]];
+
+ if (c.error > error_limit)
+ break;
+
+ if (c.error > error_goal && triangle_collapses > triangle_collapse_goal / 10)
+ break;
+
+ if (triangle_collapses >= triangle_collapse_goal)
+ break;
+
+ unsigned int i0 = c.v0;
+ unsigned int i1 = c.v1;
+
+ unsigned int r0 = remap[i0];
+ unsigned int r1 = remap[i1];
+
+ // we don't collapse vertices that had source or target vertex involved in a collapse
+ // it's important to not move the vertices twice since it complicates the tracking/remapping logic
+ // it's important to not move other vertices towards a moved vertex to preserve error since we don't re-rank collapses mid-pass
+ if (collapse_locked[r0] | collapse_locked[r1])
+ continue;
+
+ assert(collapse_remap[r0] == r0);
+ assert(collapse_remap[r1] == r1);
+
+ quadricAdd(vertex_quadrics[r1], vertex_quadrics[r0]);
+
+ if (vertex_kind[i0] == Kind_Complex)
+ {
+ unsigned int v = i0;
+
+ do
+ {
+ collapse_remap[v] = r1;
+ v = wedge[v];
+ } while (v != i0);
+ }
+ else if (vertex_kind[i0] == Kind_Seam)
+ {
+ // remap v0 to v1 and seam pair of v0 to seam pair of v1
+ unsigned int s0 = wedge[i0];
+ unsigned int s1 = wedge[i1];
+
+ assert(s0 != i0 && s1 != i1);
+ assert(wedge[s0] == i0 && wedge[s1] == i1);
+
+ collapse_remap[i0] = i1;
+ collapse_remap[s0] = s1;
+ }
+ else
+ {
+ assert(wedge[i0] == i0);
+
+ collapse_remap[i0] = i1;
+ }
+
+ collapse_locked[r0] = 1;
+ collapse_locked[r1] = 1;
+
+ // border edges collapse 1 triangle, other edges collapse 2 or more
+ triangle_collapses += (vertex_kind[i0] == Kind_Border) ? 1 : 2;
+ edge_collapses++;
+ }
+
+ return edge_collapses;
+}
+
+static size_t remapIndexBuffer(unsigned int* indices, size_t index_count, const unsigned int* collapse_remap)
+{
+ size_t write = 0;
+
+ for (size_t i = 0; i < index_count; i += 3)
+ {
+ unsigned int v0 = collapse_remap[indices[i + 0]];
+ unsigned int v1 = collapse_remap[indices[i + 1]];
+ unsigned int v2 = collapse_remap[indices[i + 2]];
+
+ // we never move the vertex twice during a single pass
+ assert(collapse_remap[v0] == v0);
+ assert(collapse_remap[v1] == v1);
+ assert(collapse_remap[v2] == v2);
+
+ if (v0 != v1 && v0 != v2 && v1 != v2)
+ {
+ indices[write + 0] = v0;
+ indices[write + 1] = v1;
+ indices[write + 2] = v2;
+ write += 3;
+ }
+ }
+
+ return write;
+}
+
+static void remapEdgeLoops(unsigned int* loop, size_t vertex_count, const unsigned int* collapse_remap)
+{
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ if (loop[i] != ~0u)
+ {
+ unsigned int l = loop[i];
+ unsigned int r = collapse_remap[l];
+
+ // i == r is a special case when the seam edge is collapsed in a direction opposite to where loop goes
+ loop[i] = (i == r) ? loop[l] : r;
+ }
+ }
+}
+
+struct CellHasher
+{
+ const unsigned int* vertex_ids;
+
+ size_t hash(unsigned int i) const
+ {
+ unsigned int h = vertex_ids[i];
+
+ // MurmurHash2 finalizer
+ h ^= h >> 13;
+ h *= 0x5bd1e995;
+ h ^= h >> 15;
+ return h;
+ }
+
+ bool equal(unsigned int lhs, unsigned int rhs) const
+ {
+ return vertex_ids[lhs] == vertex_ids[rhs];
+ }
+};
+
+struct IdHasher
+{
+ size_t hash(unsigned int id) const
+ {
+ unsigned int h = id;
+
+ // MurmurHash2 finalizer
+ h ^= h >> 13;
+ h *= 0x5bd1e995;
+ h ^= h >> 15;
+ return h;
+ }
+
+ bool equal(unsigned int lhs, unsigned int rhs) const
+ {
+ return lhs == rhs;
+ }
+};
+
+struct TriangleHasher
+{
+ unsigned int* indices;
+
+ size_t hash(unsigned int i) const
+ {
+ const unsigned int* tri = indices + i * 3;
+
+ // Optimized Spatial Hashing for Collision Detection of Deformable Objects
+ return (tri[0] * 73856093) ^ (tri[1] * 19349663) ^ (tri[2] * 83492791);
+ }
+
+ bool equal(unsigned int lhs, unsigned int rhs) const
+ {
+ const unsigned int* lt = indices + lhs * 3;
+ const unsigned int* rt = indices + rhs * 3;
+
+ return lt[0] == rt[0] && lt[1] == rt[1] && lt[2] == rt[2];
+ }
+};
+
+static void computeVertexIds(unsigned int* vertex_ids, const Vector3* vertex_positions, size_t vertex_count, int grid_size)
+{
+ assert(grid_size >= 1 && grid_size <= 1024);
+ float cell_scale = float(grid_size - 1);
+
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ const Vector3& v = vertex_positions[i];
+
+ int xi = int(v.x * cell_scale + 0.5f);
+ int yi = int(v.y * cell_scale + 0.5f);
+ int zi = int(v.z * cell_scale + 0.5f);
+
+ vertex_ids[i] = (xi << 20) | (yi << 10) | zi;
+ }
+}
+
+static size_t countTriangles(const unsigned int* vertex_ids, const unsigned int* indices, size_t index_count)
+{
+ size_t result = 0;
+
+ for (size_t i = 0; i < index_count; i += 3)
+ {
+ unsigned int id0 = vertex_ids[indices[i + 0]];
+ unsigned int id1 = vertex_ids[indices[i + 1]];
+ unsigned int id2 = vertex_ids[indices[i + 2]];
+
+ result += (id0 != id1) & (id0 != id2) & (id1 != id2);
+ }
+
+ return result;
+}
+
+static size_t fillVertexCells(unsigned int* table, size_t table_size, unsigned int* vertex_cells, const unsigned int* vertex_ids, size_t vertex_count)
+{
+ CellHasher hasher = {vertex_ids};
+
+ memset(table, -1, table_size * sizeof(unsigned int));
+
+ size_t result = 0;
+
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ unsigned int* entry = hashLookup2(table, table_size, hasher, unsigned(i), ~0u);
+
+ if (*entry == ~0u)
+ {
+ *entry = unsigned(i);
+ vertex_cells[i] = unsigned(result++);
+ }
+ else
+ {
+ vertex_cells[i] = vertex_cells[*entry];
+ }
+ }
+
+ return result;
+}
+
+static size_t countVertexCells(unsigned int* table, size_t table_size, const unsigned int* vertex_ids, size_t vertex_count)
+{
+ IdHasher hasher;
+
+ memset(table, -1, table_size * sizeof(unsigned int));
+
+ size_t result = 0;
+
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ unsigned int id = vertex_ids[i];
+ unsigned int* entry = hashLookup2(table, table_size, hasher, id, ~0u);
+
+ result += (*entry == ~0u);
+ *entry = id;
+ }
+
+ return result;
+}
+
+static void fillCellQuadrics(Quadric* cell_quadrics, const unsigned int* indices, size_t index_count, const Vector3* vertex_positions, const unsigned int* vertex_cells)
+{
+ for (size_t i = 0; i < index_count; i += 3)
+ {
+ unsigned int i0 = indices[i + 0];
+ unsigned int i1 = indices[i + 1];
+ unsigned int i2 = indices[i + 2];
+
+ unsigned int c0 = vertex_cells[i0];
+ unsigned int c1 = vertex_cells[i1];
+ unsigned int c2 = vertex_cells[i2];
+
+ bool single_cell = (c0 == c1) & (c0 == c2);
+
+ Quadric Q;
+ quadricFromTriangle(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], single_cell ? 3.f : 1.f);
+
+ if (single_cell)
+ {
+ quadricAdd(cell_quadrics[c0], Q);
+ }
+ else
+ {
+ quadricAdd(cell_quadrics[c0], Q);
+ quadricAdd(cell_quadrics[c1], Q);
+ quadricAdd(cell_quadrics[c2], Q);
+ }
+ }
+}
+
+static void fillCellQuadrics(Quadric* cell_quadrics, const Vector3* vertex_positions, size_t vertex_count, const unsigned int* vertex_cells)
+{
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ unsigned int c = vertex_cells[i];
+ const Vector3& v = vertex_positions[i];
+
+ Quadric Q;
+ quadricFromPoint(Q, v.x, v.y, v.z, 1.f);
+
+ quadricAdd(cell_quadrics[c], Q);
+ }
+}
+
+static void fillCellRemap(unsigned int* cell_remap, float* cell_errors, size_t cell_count, const unsigned int* vertex_cells, const Quadric* cell_quadrics, const Vector3* vertex_positions, size_t vertex_count)
+{
+ memset(cell_remap, -1, cell_count * sizeof(unsigned int));
+
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ unsigned int cell = vertex_cells[i];
+ float error = quadricError(cell_quadrics[cell], vertex_positions[i]);
+
+ if (cell_remap[cell] == ~0u || cell_errors[cell] > error)
+ {
+ cell_remap[cell] = unsigned(i);
+ cell_errors[cell] = error;
+ }
+ }
+}
+
+static size_t filterTriangles(unsigned int* destination, unsigned int* tritable, size_t tritable_size, const unsigned int* indices, size_t index_count, const unsigned int* vertex_cells, const unsigned int* cell_remap)
+{
+ TriangleHasher hasher = {destination};
+
+ memset(tritable, -1, tritable_size * sizeof(unsigned int));
+
+ size_t result = 0;
+
+ for (size_t i = 0; i < index_count; i += 3)
+ {
+ unsigned int c0 = vertex_cells[indices[i + 0]];
+ unsigned int c1 = vertex_cells[indices[i + 1]];
+ unsigned int c2 = vertex_cells[indices[i + 2]];
+
+ if (c0 != c1 && c0 != c2 && c1 != c2)
+ {
+ unsigned int a = cell_remap[c0];
+ unsigned int b = cell_remap[c1];
+ unsigned int c = cell_remap[c2];
+
+ if (b < a && b < c)
+ {
+ unsigned int t = a;
+ a = b, b = c, c = t;
+ }
+ else if (c < a && c < b)
+ {
+ unsigned int t = c;
+ c = b, b = a, a = t;
+ }
+
+ destination[result * 3 + 0] = a;
+ destination[result * 3 + 1] = b;
+ destination[result * 3 + 2] = c;
+
+ unsigned int* entry = hashLookup2(tritable, tritable_size, hasher, unsigned(result), ~0u);
+
+ if (*entry == ~0u)
+ *entry = unsigned(result++);
+ }
+ }
+
+ return result * 3;
+}
+
+static float interpolate(float y, float x0, float y0, float x1, float y1, float x2, float y2)
+{
+ // three point interpolation from "revenge of interpolation search" paper
+ float num = (y1 - y) * (x1 - x2) * (x1 - x0) * (y2 - y0);
+ float den = (y2 - y) * (x1 - x2) * (y0 - y1) + (y0 - y) * (x1 - x0) * (y1 - y2);
+ return x1 + num / den;
+}
+
+} // namespace meshopt
+
+#ifndef NDEBUG
+unsigned char* meshopt_simplifyDebugKind = 0;
+unsigned int* meshopt_simplifyDebugLoop = 0;
+unsigned int* meshopt_simplifyDebugLoopBack = 0;
+#endif
+
+// -- GODOT start --
+//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)
+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 *r_resulting_error)
+// -- GODOT end --
+{
+ 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(target_index_count <= index_count);
+
+ meshopt_Allocator allocator;
+
+ unsigned int* result = destination;
+
+ // build adjacency information
+ EdgeAdjacency adjacency = {};
+ buildEdgeAdjacency(adjacency, indices, index_count, vertex_count, allocator);
+
+ // 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);
+
+ // classify vertices; vertex kind determines collapse rules, see kCanCollapse
+ unsigned char* vertex_kind = allocator.allocate<unsigned char>(vertex_count);
+ unsigned int* loop = allocator.allocate<unsigned int>(vertex_count);
+ unsigned int* loopback = allocator.allocate<unsigned int>(vertex_count);
+ classifyVertices(vertex_kind, loop, loopback, vertex_count, adjacency, remap, wedge);
+
+#if TRACE
+ size_t unique_positions = 0;
+ for (size_t i = 0; i < vertex_count; ++i)
+ unique_positions += remap[i] == i;
+
+ printf("position remap: %d vertices => %d positions\n", int(vertex_count), int(unique_positions));
+
+ size_t kinds[Kind_Count] = {};
+ for (size_t i = 0; i < vertex_count; ++i)
+ kinds[vertex_kind[i]] += remap[i] == i;
+
+ printf("kinds: manifold %d, border %d, seam %d, complex %d, locked %d\n",
+ int(kinds[Kind_Manifold]), int(kinds[Kind_Border]), int(kinds[Kind_Seam]), int(kinds[Kind_Complex]), int(kinds[Kind_Locked]));
+#endif
+
+ Vector3* vertex_positions = allocator.allocate<Vector3>(vertex_count);
+// -- GODOT start --
+ //rescalePositions(vertex_positions, vertex_positions_data, vertex_count, vertex_positions_stride);
+ float extent = rescalePositions(vertex_positions, vertex_positions_data, vertex_count, vertex_positions_stride);
+// -- GODOT end --
+
+ Quadric* vertex_quadrics = allocator.allocate<Quadric>(vertex_count);
+ memset(vertex_quadrics, 0, vertex_count * sizeof(Quadric));
+
+ fillFaceQuadrics(vertex_quadrics, indices, index_count, vertex_positions, remap);
+ fillEdgeQuadrics(vertex_quadrics, indices, index_count, vertex_positions, remap, vertex_kind, loop, loopback);
+
+ if (result != indices)
+ memcpy(result, indices, index_count * sizeof(unsigned int));
+
+// -- GODOT start --
+#if TRACE
+ size_t pass_count = 0;
+ //float worst_error = 0;
+#endif
+ float worst_error = 0;
+// -- GODOT end --
+
+ Collapse* edge_collapses = allocator.allocate<Collapse>(index_count);
+ unsigned int* collapse_order = allocator.allocate<unsigned int>(index_count);
+ unsigned int* collapse_remap = allocator.allocate<unsigned int>(vertex_count);
+ unsigned char* collapse_locked = allocator.allocate<unsigned char>(vertex_count);
+
+ size_t result_count = index_count;
+
+ // target_error input is linear; we need to adjust it to match quadricError units
+ float error_limit = target_error * target_error;
+
+// -- GODOT start --
+ if (r_resulting_error) {
+ *r_resulting_error = 1.0;
+ }
+// -- GODOT end --
+
+ while (result_count > target_index_count)
+ {
+ size_t edge_collapse_count = pickEdgeCollapses(edge_collapses, result, result_count, remap, vertex_kind, loop);
+
+ // no edges can be collapsed any more due to topology restrictions
+ if (edge_collapse_count == 0)
+ break;
+
+ rankEdgeCollapses(edge_collapses, edge_collapse_count, vertex_positions, vertex_quadrics, remap);
+
+#if TRACE > 1
+ dumpEdgeCollapses(edge_collapses, edge_collapse_count, vertex_kind);
+#endif
+
+ sortEdgeCollapses(collapse_order, edge_collapses, edge_collapse_count);
+
+ // most collapses remove 2 triangles; use this to establish a bound on the pass in terms of error limit
+ // note that edge_collapse_goal is an estimate; triangle_collapse_goal will be used to actually limit collapses
+ size_t triangle_collapse_goal = (result_count - target_index_count) / 3;
+ size_t edge_collapse_goal = triangle_collapse_goal / 2;
+
+ // we limit the error in each pass based on the error of optimal last collapse; since many collapses will be locked
+ // as they will share vertices with other successfull collapses, we need to increase the acceptable error by this factor
+ const float kPassErrorBound = 1.5f;
+
+ float error_goal = edge_collapse_goal < edge_collapse_count ? edge_collapses[collapse_order[edge_collapse_goal]].error * kPassErrorBound : FLT_MAX;
+
+ for (size_t i = 0; i < vertex_count; ++i)
+ collapse_remap[i] = unsigned(i);
+
+ memset(collapse_locked, 0, vertex_count);
+
+ size_t collapses = performEdgeCollapses(collapse_remap, collapse_locked, vertex_quadrics, edge_collapses, edge_collapse_count, collapse_order, remap, wedge, vertex_kind, triangle_collapse_goal, error_goal, error_limit);
+
+ // no edges can be collapsed any more due to hitting the error limit or triangle collapse limit
+ if (collapses == 0)
+ break;
+
+ remapEdgeLoops(loop, vertex_count, collapse_remap);
+ remapEdgeLoops(loopback, vertex_count, collapse_remap);
+
+ size_t new_count = remapIndexBuffer(result, result_count, collapse_remap);
+ assert(new_count < result_count);
+
+// -- GODOT start --
+//#if TRACE
+ float pass_error = 0.f;
+ for (size_t i = 0; i < edge_collapse_count; ++i)
+ {
+ Collapse& c = edge_collapses[collapse_order[i]];
+
+ if (collapse_remap[c.v0] == c.v1)
+ pass_error = c.error;
+ }
+
+ //pass_count++;
+ worst_error = (worst_error < pass_error) ? pass_error : worst_error;
+
+#if TRACE
+ pass_count++;
+ printf("pass %d: triangles: %d -> %d, collapses: %d/%d (goal: %d), error: %e (limit %e goal %e)\n", int(pass_count), int(result_count / 3), int(new_count / 3), int(collapses), int(edge_collapse_count), int(edge_collapse_goal), pass_error, error_limit, error_goal);
+#endif
+// -- GODOT end --
+
+ result_count = new_count;
+ }
+
+// -- GODOT start --
+ if (r_resulting_error) {
+ *r_resulting_error = sqrt(worst_error) * extent;
+ }
+// -- GODOT end --
+
+#if TRACE
+ printf("passes: %d, worst error: %e\n", int(pass_count), worst_error);
+#endif
+
+#if TRACE > 1
+ dumpLockedCollapses(result, result_count, vertex_kind);
+#endif
+
+#ifndef NDEBUG
+ if (meshopt_simplifyDebugKind)
+ memcpy(meshopt_simplifyDebugKind, vertex_kind, vertex_count);
+
+ if (meshopt_simplifyDebugLoop)
+ memcpy(meshopt_simplifyDebugLoop, loop, vertex_count * sizeof(unsigned int));
+
+ if (meshopt_simplifyDebugLoopBack)
+ memcpy(meshopt_simplifyDebugLoopBack, loopback, vertex_count * sizeof(unsigned int));
+#endif
+
+ return result_count;
+}
+
+size_t meshopt_simplifySloppy(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)
+{
+ 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(target_index_count <= index_count);
+
+ // we expect to get ~2 triangles/vertex in the output
+ size_t target_cell_count = target_index_count / 6;
+
+ if (target_cell_count == 0)
+ return 0;
+
+ meshopt_Allocator allocator;
+
+ Vector3* vertex_positions = allocator.allocate<Vector3>(vertex_count);
+ rescalePositions(vertex_positions, vertex_positions_data, vertex_count, vertex_positions_stride);
+
+ // find the optimal grid size using guided binary search
+#if TRACE
+ printf("source: %d vertices, %d triangles\n", int(vertex_count), int(index_count / 3));
+ printf("target: %d cells, %d triangles\n", int(target_cell_count), int(target_index_count / 3));
+#endif
+
+ unsigned int* vertex_ids = allocator.allocate<unsigned int>(vertex_count);
+
+ const int kInterpolationPasses = 5;
+
+ // invariant: # of triangles in min_grid <= target_count
+ int min_grid = 0;
+ int max_grid = 1025;
+ size_t min_triangles = 0;
+ size_t max_triangles = index_count / 3;
+
+ // instead of starting in the middle, let's guess as to what the answer might be! triangle count usually grows as a square of grid size...
+ int next_grid_size = int(sqrtf(float(target_cell_count)) + 0.5f);
+
+ for (int pass = 0; pass < 10 + kInterpolationPasses; ++pass)
+ {
+ assert(min_triangles < target_index_count / 3);
+ assert(max_grid - min_grid > 1);
+
+ // we clamp the prediction of the grid size to make sure that the search converges
+ int grid_size = next_grid_size;
+ grid_size = (grid_size <= min_grid) ? min_grid + 1 : (grid_size >= max_grid) ? max_grid - 1 : grid_size;
+
+ computeVertexIds(vertex_ids, vertex_positions, vertex_count, grid_size);
+ size_t triangles = countTriangles(vertex_ids, indices, index_count);
+
+#if TRACE
+ printf("pass %d (%s): grid size %d, triangles %d, %s\n",
+ pass, (pass == 0) ? "guess" : (pass <= kInterpolationPasses) ? "lerp" : "binary",
+ grid_size, int(triangles),
+ (triangles <= target_index_count / 3) ? "under" : "over");
+#endif
+
+ float tip = interpolate(float(target_index_count / 3), float(min_grid), float(min_triangles), float(grid_size), float(triangles), float(max_grid), float(max_triangles));
+
+ if (triangles <= target_index_count / 3)
+ {
+ min_grid = grid_size;
+ min_triangles = triangles;
+ }
+ else
+ {
+ max_grid = grid_size;
+ max_triangles = triangles;
+ }
+
+ if (triangles == target_index_count / 3 || max_grid - min_grid <= 1)
+ break;
+
+ // we start by using interpolation search - it usually converges faster
+ // however, interpolation search has a worst case of O(N) so we switch to binary search after a few iterations which converges in O(logN)
+ next_grid_size = (pass < kInterpolationPasses) ? int(tip + 0.5f) : (min_grid + max_grid) / 2;
+ }
+
+ if (min_triangles == 0)
+ return 0;
+
+ // build vertex->cell association by mapping all vertices with the same quantized position to the same cell
+ size_t table_size = hashBuckets2(vertex_count);
+ unsigned int* table = allocator.allocate<unsigned int>(table_size);
+
+ unsigned int* vertex_cells = allocator.allocate<unsigned int>(vertex_count);
+
+ computeVertexIds(vertex_ids, vertex_positions, vertex_count, min_grid);
+ size_t cell_count = fillVertexCells(table, table_size, vertex_cells, vertex_ids, vertex_count);
+
+ // build a quadric for each target cell
+ Quadric* cell_quadrics = allocator.allocate<Quadric>(cell_count);
+ memset(cell_quadrics, 0, cell_count * sizeof(Quadric));
+
+ fillCellQuadrics(cell_quadrics, indices, index_count, vertex_positions, vertex_cells);
+
+ // for each target cell, find the vertex with the minimal error
+ unsigned int* cell_remap = allocator.allocate<unsigned int>(cell_count);
+ float* cell_errors = allocator.allocate<float>(cell_count);
+
+ fillCellRemap(cell_remap, cell_errors, cell_count, vertex_cells, cell_quadrics, vertex_positions, vertex_count);
+
+ // collapse triangles!
+ // note that we need to filter out triangles that we've already output because we very frequently generate redundant triangles between cells :(
+ size_t tritable_size = hashBuckets2(min_triangles);
+ unsigned int* tritable = allocator.allocate<unsigned int>(tritable_size);
+
+ size_t write = filterTriangles(destination, tritable, tritable_size, indices, index_count, vertex_cells, cell_remap);
+ assert(write <= target_index_count);
+
+#if TRACE
+ printf("result: %d cells, %d triangles (%d unfiltered)\n", int(cell_count), int(write / 3), int(min_triangles));
+#endif
+
+ return write;
+}
+
+size_t meshopt_simplifyPoints(unsigned int* destination, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, size_t target_vertex_count)
+{
+ using namespace meshopt;
+
+ assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
+ assert(vertex_positions_stride % sizeof(float) == 0);
+ assert(target_vertex_count <= vertex_count);
+
+ size_t target_cell_count = target_vertex_count;
+
+ if (target_cell_count == 0)
+ return 0;
+
+ meshopt_Allocator allocator;
+
+ Vector3* vertex_positions = allocator.allocate<Vector3>(vertex_count);
+ rescalePositions(vertex_positions, vertex_positions_data, vertex_count, vertex_positions_stride);
+
+ // find the optimal grid size using guided binary search
+#if TRACE
+ printf("source: %d vertices\n", int(vertex_count));
+ printf("target: %d cells\n", int(target_cell_count));
+#endif
+
+ unsigned int* vertex_ids = allocator.allocate<unsigned int>(vertex_count);
+
+ size_t table_size = hashBuckets2(vertex_count);
+ unsigned int* table = allocator.allocate<unsigned int>(table_size);
+
+ const int kInterpolationPasses = 5;
+
+ // invariant: # of vertices in min_grid <= target_count
+ int min_grid = 0;
+ int max_grid = 1025;
+ size_t min_vertices = 0;
+ size_t max_vertices = vertex_count;
+
+ // instead of starting in the middle, let's guess as to what the answer might be! triangle count usually grows as a square of grid size...
+ int next_grid_size = int(sqrtf(float(target_cell_count)) + 0.5f);
+
+ for (int pass = 0; pass < 10 + kInterpolationPasses; ++pass)
+ {
+ assert(min_vertices < target_vertex_count);
+ assert(max_grid - min_grid > 1);
+
+ // we clamp the prediction of the grid size to make sure that the search converges
+ int grid_size = next_grid_size;
+ grid_size = (grid_size <= min_grid) ? min_grid + 1 : (grid_size >= max_grid) ? max_grid - 1 : grid_size;
+
+ computeVertexIds(vertex_ids, vertex_positions, vertex_count, grid_size);
+ size_t vertices = countVertexCells(table, table_size, vertex_ids, vertex_count);
+
+#if TRACE
+ printf("pass %d (%s): grid size %d, vertices %d, %s\n",
+ pass, (pass == 0) ? "guess" : (pass <= kInterpolationPasses) ? "lerp" : "binary",
+ grid_size, int(vertices),
+ (vertices <= target_vertex_count) ? "under" : "over");
+#endif
+
+ float tip = interpolate(float(target_vertex_count), float(min_grid), float(min_vertices), float(grid_size), float(vertices), float(max_grid), float(max_vertices));
+
+ if (vertices <= target_vertex_count)
+ {
+ min_grid = grid_size;
+ min_vertices = vertices;
+ }
+ else
+ {
+ max_grid = grid_size;
+ max_vertices = vertices;
+ }
+
+ if (vertices == target_vertex_count || max_grid - min_grid <= 1)
+ break;
+
+ // we start by using interpolation search - it usually converges faster
+ // however, interpolation search has a worst case of O(N) so we switch to binary search after a few iterations which converges in O(logN)
+ next_grid_size = (pass < kInterpolationPasses) ? int(tip + 0.5f) : (min_grid + max_grid) / 2;
+ }
+
+ if (min_vertices == 0)
+ return 0;
+
+ // build vertex->cell association by mapping all vertices with the same quantized position to the same cell
+ unsigned int* vertex_cells = allocator.allocate<unsigned int>(vertex_count);
+
+ computeVertexIds(vertex_ids, vertex_positions, vertex_count, min_grid);
+ size_t cell_count = fillVertexCells(table, table_size, vertex_cells, vertex_ids, vertex_count);
+
+ // build a quadric for each target cell
+ Quadric* cell_quadrics = allocator.allocate<Quadric>(cell_count);
+ memset(cell_quadrics, 0, cell_count * sizeof(Quadric));
+
+ fillCellQuadrics(cell_quadrics, vertex_positions, vertex_count, vertex_cells);
+
+ // for each target cell, find the vertex with the minimal error
+ unsigned int* cell_remap = allocator.allocate<unsigned int>(cell_count);
+ float* cell_errors = allocator.allocate<float>(cell_count);
+
+ fillCellRemap(cell_remap, cell_errors, cell_count, vertex_cells, cell_quadrics, vertex_positions, vertex_count);
+
+ // copy results to the output
+ assert(cell_count <= target_vertex_count);
+ memcpy(destination, cell_remap, sizeof(unsigned int) * cell_count);
+
+#if TRACE
+ printf("result: %d cells\n", int(cell_count));
+#endif
+
+ return cell_count;
+}
diff --git a/thirdparty/meshoptimizer/spatialorder.cpp b/thirdparty/meshoptimizer/spatialorder.cpp
new file mode 100644
index 0000000000..b09f80ac6f
--- /dev/null
+++ b/thirdparty/meshoptimizer/spatialorder.cpp
@@ -0,0 +1,194 @@
+// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
+#include "meshoptimizer.h"
+
+#include <assert.h>
+#include <float.h>
+#include <string.h>
+
+// This work is based on:
+// Fabian Giesen. Decoding Morton codes. 2009
+namespace meshopt
+{
+
+// "Insert" two 0 bits after each of the 10 low bits of x
+inline unsigned int part1By2(unsigned int x)
+{
+ x &= 0x000003ff; // x = ---- ---- ---- ---- ---- --98 7654 3210
+ x = (x ^ (x << 16)) & 0xff0000ff; // x = ---- --98 ---- ---- ---- ---- 7654 3210
+ x = (x ^ (x << 8)) & 0x0300f00f; // x = ---- --98 ---- ---- 7654 ---- ---- 3210
+ x = (x ^ (x << 4)) & 0x030c30c3; // x = ---- --98 ---- 76-- --54 ---- 32-- --10
+ x = (x ^ (x << 2)) & 0x09249249; // x = ---- 9--8 --7- -6-- 5--4 --3- -2-- 1--0
+ return x;
+}
+
+static void computeOrder(unsigned int* result, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride)
+{
+ size_t vertex_stride_float = vertex_positions_stride / sizeof(float);
+
+ float minv[3] = {FLT_MAX, FLT_MAX, FLT_MAX};
+ float maxv[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
+
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ const float* v = vertex_positions_data + i * vertex_stride_float;
+
+ for (int j = 0; j < 3; ++j)
+ {
+ float vj = v[j];
+
+ minv[j] = minv[j] > vj ? vj : minv[j];
+ maxv[j] = maxv[j] < vj ? vj : maxv[j];
+ }
+ }
+
+ float extent = 0.f;
+
+ extent = (maxv[0] - minv[0]) < extent ? extent : (maxv[0] - minv[0]);
+ extent = (maxv[1] - minv[1]) < extent ? extent : (maxv[1] - minv[1]);
+ extent = (maxv[2] - minv[2]) < extent ? extent : (maxv[2] - minv[2]);
+
+ float scale = extent == 0 ? 0.f : 1.f / extent;
+
+ // generate Morton order based on the position inside a unit cube
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ const float* v = vertex_positions_data + i * vertex_stride_float;
+
+ int x = int((v[0] - minv[0]) * scale * 1023.f + 0.5f);
+ int y = int((v[1] - minv[1]) * scale * 1023.f + 0.5f);
+ int z = int((v[2] - minv[2]) * scale * 1023.f + 0.5f);
+
+ result[i] = part1By2(x) | (part1By2(y) << 1) | (part1By2(z) << 2);
+ }
+}
+
+static void computeHistogram(unsigned int (&hist)[1024][3], const unsigned int* data, size_t count)
+{
+ memset(hist, 0, sizeof(hist));
+
+ // compute 3 10-bit histograms in parallel
+ for (size_t i = 0; i < count; ++i)
+ {
+ unsigned int id = data[i];
+
+ hist[(id >> 0) & 1023][0]++;
+ hist[(id >> 10) & 1023][1]++;
+ hist[(id >> 20) & 1023][2]++;
+ }
+
+ unsigned int sumx = 0, sumy = 0, sumz = 0;
+
+ // replace histogram data with prefix histogram sums in-place
+ for (int i = 0; i < 1024; ++i)
+ {
+ unsigned int hx = hist[i][0], hy = hist[i][1], hz = hist[i][2];
+
+ hist[i][0] = sumx;
+ hist[i][1] = sumy;
+ hist[i][2] = sumz;
+
+ sumx += hx;
+ sumy += hy;
+ sumz += hz;
+ }
+
+ assert(sumx == count && sumy == count && sumz == count);
+}
+
+static void radixPass(unsigned int* destination, const unsigned int* source, const unsigned int* keys, size_t count, unsigned int (&hist)[1024][3], int pass)
+{
+ int bitoff = pass * 10;
+
+ for (size_t i = 0; i < count; ++i)
+ {
+ unsigned int id = (keys[source[i]] >> bitoff) & 1023;
+
+ destination[hist[id][pass]++] = source[i];
+ }
+}
+
+} // namespace meshopt
+
+void meshopt_spatialSortRemap(unsigned int* destination, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
+{
+ using namespace meshopt;
+
+ assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
+ assert(vertex_positions_stride % sizeof(float) == 0);
+
+ meshopt_Allocator allocator;
+
+ unsigned int* keys = allocator.allocate<unsigned int>(vertex_count);
+ computeOrder(keys, vertex_positions, vertex_count, vertex_positions_stride);
+
+ unsigned int hist[1024][3];
+ computeHistogram(hist, keys, vertex_count);
+
+ unsigned int* scratch = allocator.allocate<unsigned int>(vertex_count);
+
+ for (size_t i = 0; i < vertex_count; ++i)
+ destination[i] = unsigned(i);
+
+ // 3-pass radix sort computes the resulting order into scratch
+ radixPass(scratch, destination, keys, vertex_count, hist, 0);
+ radixPass(destination, scratch, keys, vertex_count, hist, 1);
+ radixPass(scratch, destination, keys, vertex_count, hist, 2);
+
+ // since our remap table is mapping old=>new, we need to reverse it
+ for (size_t i = 0; i < vertex_count; ++i)
+ destination[scratch[i]] = unsigned(i);
+}
+
+void meshopt_spatialSortTriangles(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
+{
+ using namespace meshopt;
+
+ assert(index_count % 3 == 0);
+ assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
+ assert(vertex_positions_stride % sizeof(float) == 0);
+
+ (void)vertex_count;
+
+ size_t face_count = index_count / 3;
+ size_t vertex_stride_float = vertex_positions_stride / sizeof(float);
+
+ meshopt_Allocator allocator;
+
+ float* centroids = allocator.allocate<float>(face_count * 3);
+
+ for (size_t i = 0; i < face_count; ++i)
+ {
+ unsigned int a = indices[i * 3 + 0], b = indices[i * 3 + 1], c = indices[i * 3 + 2];
+ assert(a < vertex_count && b < vertex_count && c < vertex_count);
+
+ const float* va = vertex_positions + a * vertex_stride_float;
+ const float* vb = vertex_positions + b * vertex_stride_float;
+ const float* vc = vertex_positions + c * vertex_stride_float;
+
+ centroids[i * 3 + 0] = (va[0] + vb[0] + vc[0]) / 3.f;
+ centroids[i * 3 + 1] = (va[1] + vb[1] + vc[1]) / 3.f;
+ centroids[i * 3 + 2] = (va[2] + vb[2] + vc[2]) / 3.f;
+ }
+
+ unsigned int* remap = allocator.allocate<unsigned int>(face_count);
+
+ meshopt_spatialSortRemap(remap, centroids, face_count, sizeof(float) * 3);
+
+ // support in-order remap
+ if (destination == indices)
+ {
+ unsigned int* indices_copy = allocator.allocate<unsigned int>(index_count);
+ memcpy(indices_copy, indices, index_count * sizeof(unsigned int));
+ indices = indices_copy;
+ }
+
+ for (size_t i = 0; i < face_count; ++i)
+ {
+ unsigned int a = indices[i * 3 + 0], b = indices[i * 3 + 1], c = indices[i * 3 + 2];
+ unsigned int r = remap[i];
+
+ destination[r * 3 + 0] = a;
+ destination[r * 3 + 1] = b;
+ destination[r * 3 + 2] = c;
+ }
+}
diff --git a/thirdparty/meshoptimizer/stripifier.cpp b/thirdparty/meshoptimizer/stripifier.cpp
new file mode 100644
index 0000000000..8ce17ef3dc
--- /dev/null
+++ b/thirdparty/meshoptimizer/stripifier.cpp
@@ -0,0 +1,295 @@
+// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
+#include "meshoptimizer.h"
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+
+// This work is based on:
+// Francine Evans, Steven Skiena and Amitabh Varshney. Optimizing Triangle Strips for Fast Rendering. 1996
+namespace meshopt
+{
+
+static unsigned int findStripFirst(const unsigned int buffer[][3], unsigned int buffer_size, const unsigned int* valence)
+{
+ unsigned int index = 0;
+ unsigned int iv = ~0u;
+
+ for (size_t i = 0; i < buffer_size; ++i)
+ {
+ unsigned int va = valence[buffer[i][0]], vb = valence[buffer[i][1]], vc = valence[buffer[i][2]];
+ unsigned int v = (va < vb && va < vc) ? va : (vb < vc) ? vb : vc;
+
+ if (v < iv)
+ {
+ index = unsigned(i);
+ iv = v;
+ }
+ }
+
+ return index;
+}
+
+static int findStripNext(const unsigned int buffer[][3], unsigned int buffer_size, unsigned int e0, unsigned int e1)
+{
+ for (size_t i = 0; i < buffer_size; ++i)
+ {
+ unsigned int a = buffer[i][0], b = buffer[i][1], c = buffer[i][2];
+
+ if (e0 == a && e1 == b)
+ return (int(i) << 2) | 2;
+ else if (e0 == b && e1 == c)
+ return (int(i) << 2) | 0;
+ else if (e0 == c && e1 == a)
+ return (int(i) << 2) | 1;
+ }
+
+ return -1;
+}
+
+} // namespace meshopt
+
+size_t meshopt_stripify(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int restart_index)
+{
+ assert(destination != indices);
+ assert(index_count % 3 == 0);
+
+ using namespace meshopt;
+
+ meshopt_Allocator allocator;
+
+ const size_t buffer_capacity = 8;
+
+ unsigned int buffer[buffer_capacity][3] = {};
+ unsigned int buffer_size = 0;
+
+ size_t index_offset = 0;
+
+ unsigned int strip[2] = {};
+ unsigned int parity = 0;
+
+ size_t strip_size = 0;
+
+ // compute vertex valence; this is used to prioritize starting triangle for strips
+ unsigned int* valence = allocator.allocate<unsigned int>(vertex_count);
+ memset(valence, 0, vertex_count * sizeof(unsigned int));
+
+ for (size_t i = 0; i < index_count; ++i)
+ {
+ unsigned int index = indices[i];
+ assert(index < vertex_count);
+
+ valence[index]++;
+ }
+
+ int next = -1;
+
+ while (buffer_size > 0 || index_offset < index_count)
+ {
+ assert(next < 0 || (size_t(next >> 2) < buffer_size && (next & 3) < 3));
+
+ // fill triangle buffer
+ while (buffer_size < buffer_capacity && index_offset < index_count)
+ {
+ buffer[buffer_size][0] = indices[index_offset + 0];
+ buffer[buffer_size][1] = indices[index_offset + 1];
+ buffer[buffer_size][2] = indices[index_offset + 2];
+
+ buffer_size++;
+ index_offset += 3;
+ }
+
+ assert(buffer_size > 0);
+
+ if (next >= 0)
+ {
+ unsigned int i = next >> 2;
+ unsigned int a = buffer[i][0], b = buffer[i][1], c = buffer[i][2];
+ unsigned int v = buffer[i][next & 3];
+
+ // ordered removal from the buffer
+ memmove(buffer[i], buffer[i + 1], (buffer_size - i - 1) * sizeof(buffer[0]));
+ buffer_size--;
+
+ // update vertex valences for strip start heuristic
+ valence[a]--;
+ valence[b]--;
+ valence[c]--;
+
+ // find next triangle (note that edge order flips on every iteration)
+ // in some cases we need to perform a swap to pick a different outgoing triangle edge
+ // for [a b c], the default strip edge is [b c], but we might want to use [a c]
+ int cont = findStripNext(buffer, buffer_size, parity ? strip[1] : v, parity ? v : strip[1]);
+ int swap = cont < 0 ? findStripNext(buffer, buffer_size, parity ? v : strip[0], parity ? strip[0] : v) : -1;
+
+ if (cont < 0 && swap >= 0)
+ {
+ // [a b c] => [a b a c]
+ destination[strip_size++] = strip[0];
+ destination[strip_size++] = v;
+
+ // next strip has same winding
+ // ? a b => b a v
+ strip[1] = v;
+
+ next = swap;
+ }
+ else
+ {
+ // emit the next vertex in the strip
+ destination[strip_size++] = v;
+
+ // next strip has flipped winding
+ strip[0] = strip[1];
+ strip[1] = v;
+ parity ^= 1;
+
+ next = cont;
+ }
+ }
+ else
+ {
+ // if we didn't find anything, we need to find the next new triangle
+ // we use a heuristic to maximize the strip length
+ unsigned int i = findStripFirst(buffer, buffer_size, &valence[0]);
+ unsigned int a = buffer[i][0], b = buffer[i][1], c = buffer[i][2];
+
+ // ordered removal from the buffer
+ memmove(buffer[i], buffer[i + 1], (buffer_size - i - 1) * sizeof(buffer[0]));
+ buffer_size--;
+
+ // update vertex valences for strip start heuristic
+ valence[a]--;
+ valence[b]--;
+ valence[c]--;
+
+ // we need to pre-rotate the triangle so that we will find a match in the existing buffer on the next iteration
+ int ea = findStripNext(buffer, buffer_size, c, b);
+ int eb = findStripNext(buffer, buffer_size, a, c);
+ int ec = findStripNext(buffer, buffer_size, b, a);
+
+ // in some cases we can have several matching edges; since we can pick any edge, we pick the one with the smallest
+ // triangle index in the buffer. this reduces the effect of stripification on ACMR and additionally - for unclear
+ // reasons - slightly improves the stripification efficiency
+ int mine = INT_MAX;
+ mine = (ea >= 0 && mine > ea) ? ea : mine;
+ mine = (eb >= 0 && mine > eb) ? eb : mine;
+ mine = (ec >= 0 && mine > ec) ? ec : mine;
+
+ if (ea == mine)
+ {
+ // keep abc
+ next = ea;
+ }
+ else if (eb == mine)
+ {
+ // abc -> bca
+ unsigned int t = a;
+ a = b, b = c, c = t;
+
+ next = eb;
+ }
+ else if (ec == mine)
+ {
+ // abc -> cab
+ unsigned int t = c;
+ c = b, b = a, a = t;
+
+ next = ec;
+ }
+
+ if (restart_index)
+ {
+ if (strip_size)
+ destination[strip_size++] = restart_index;
+
+ destination[strip_size++] = a;
+ destination[strip_size++] = b;
+ destination[strip_size++] = c;
+
+ // new strip always starts with the same edge winding
+ strip[0] = b;
+ strip[1] = c;
+ parity = 1;
+ }
+ else
+ {
+ if (strip_size)
+ {
+ // connect last strip using degenerate triangles
+ destination[strip_size++] = strip[1];
+ destination[strip_size++] = a;
+ }
+
+ // note that we may need to flip the emitted triangle based on parity
+ // we always end up with outgoing edge "cb" in the end
+ unsigned int e0 = parity ? c : b;
+ unsigned int e1 = parity ? b : c;
+
+ destination[strip_size++] = a;
+ destination[strip_size++] = e0;
+ destination[strip_size++] = e1;
+
+ strip[0] = e0;
+ strip[1] = e1;
+ parity ^= 1;
+ }
+ }
+ }
+
+ return strip_size;
+}
+
+size_t meshopt_stripifyBound(size_t index_count)
+{
+ assert(index_count % 3 == 0);
+
+ // worst case without restarts is 2 degenerate indices and 3 indices per triangle
+ // worst case with restarts is 1 restart index and 3 indices per triangle
+ return (index_count / 3) * 5;
+}
+
+size_t meshopt_unstripify(unsigned int* destination, const unsigned int* indices, size_t index_count, unsigned int restart_index)
+{
+ assert(destination != indices);
+
+ size_t offset = 0;
+ size_t start = 0;
+
+ for (size_t i = 0; i < index_count; ++i)
+ {
+ if (restart_index && indices[i] == restart_index)
+ {
+ start = i + 1;
+ }
+ else if (i - start >= 2)
+ {
+ unsigned int a = indices[i - 2], b = indices[i - 1], c = indices[i];
+
+ // flip winding for odd triangles
+ if ((i - start) & 1)
+ {
+ unsigned int t = a;
+ a = b, b = t;
+ }
+
+ // although we use restart indices, strip swaps still produce degenerate triangles, so skip them
+ if (a != b && a != c && b != c)
+ {
+ destination[offset + 0] = a;
+ destination[offset + 1] = b;
+ destination[offset + 2] = c;
+ offset += 3;
+ }
+ }
+ }
+
+ return offset;
+}
+
+size_t meshopt_unstripifyBound(size_t index_count)
+{
+ assert(index_count == 0 || index_count >= 3);
+
+ return (index_count == 0) ? 0 : (index_count - 2) * 3;
+}
diff --git a/thirdparty/meshoptimizer/vcacheanalyzer.cpp b/thirdparty/meshoptimizer/vcacheanalyzer.cpp
new file mode 100644
index 0000000000..3682743820
--- /dev/null
+++ b/thirdparty/meshoptimizer/vcacheanalyzer.cpp
@@ -0,0 +1,73 @@
+// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
+#include "meshoptimizer.h"
+
+#include <assert.h>
+#include <string.h>
+
+meshopt_VertexCacheStatistics meshopt_analyzeVertexCache(const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int cache_size, unsigned int warp_size, unsigned int primgroup_size)
+{
+ assert(index_count % 3 == 0);
+ assert(cache_size >= 3);
+ assert(warp_size == 0 || warp_size >= 3);
+
+ meshopt_Allocator allocator;
+
+ meshopt_VertexCacheStatistics result = {};
+
+ unsigned int warp_offset = 0;
+ unsigned int primgroup_offset = 0;
+
+ unsigned int* cache_timestamps = allocator.allocate<unsigned int>(vertex_count);
+ memset(cache_timestamps, 0, vertex_count * sizeof(unsigned int));
+
+ unsigned int timestamp = cache_size + 1;
+
+ for (size_t i = 0; i < index_count; i += 3)
+ {
+ unsigned int a = indices[i + 0], b = indices[i + 1], c = indices[i + 2];
+ assert(a < vertex_count && b < vertex_count && c < vertex_count);
+
+ bool ac = (timestamp - cache_timestamps[a]) > cache_size;
+ bool bc = (timestamp - cache_timestamps[b]) > cache_size;
+ bool cc = (timestamp - cache_timestamps[c]) > cache_size;
+
+ // flush cache if triangle doesn't fit into warp or into the primitive buffer
+ if ((primgroup_size && primgroup_offset == primgroup_size) || (warp_size && warp_offset + ac + bc + cc > warp_size))
+ {
+ result.warps_executed += warp_offset > 0;
+
+ warp_offset = 0;
+ primgroup_offset = 0;
+
+ // reset cache
+ timestamp += cache_size + 1;
+ }
+
+ // update cache and add vertices to warp
+ for (int j = 0; j < 3; ++j)
+ {
+ unsigned int index = indices[i + j];
+
+ if (timestamp - cache_timestamps[index] > cache_size)
+ {
+ cache_timestamps[index] = timestamp++;
+ result.vertices_transformed++;
+ warp_offset++;
+ }
+ }
+
+ primgroup_offset++;
+ }
+
+ size_t unique_vertex_count = 0;
+
+ for (size_t i = 0; i < vertex_count; ++i)
+ unique_vertex_count += cache_timestamps[i] > 0;
+
+ result.warps_executed += warp_offset > 0;
+
+ result.acmr = index_count == 0 ? 0 : float(result.vertices_transformed) / float(index_count / 3);
+ result.atvr = unique_vertex_count == 0 ? 0 : float(result.vertices_transformed) / float(unique_vertex_count);
+
+ return result;
+}
diff --git a/thirdparty/meshoptimizer/vcacheoptimizer.cpp b/thirdparty/meshoptimizer/vcacheoptimizer.cpp
new file mode 100644
index 0000000000..fb8ade4b77
--- /dev/null
+++ b/thirdparty/meshoptimizer/vcacheoptimizer.cpp
@@ -0,0 +1,473 @@
+// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
+#include "meshoptimizer.h"
+
+#include <assert.h>
+#include <string.h>
+
+// This work is based on:
+// Tom Forsyth. Linear-Speed Vertex Cache Optimisation. 2006
+// Pedro Sander, Diego Nehab and Joshua Barczak. Fast Triangle Reordering for Vertex Locality and Reduced Overdraw. 2007
+namespace meshopt
+{
+
+const size_t kCacheSizeMax = 16;
+const size_t kValenceMax = 8;
+
+struct VertexScoreTable
+{
+ float cache[1 + kCacheSizeMax];
+ float live[1 + kValenceMax];
+};
+
+// Tuned to minimize the ACMR of a GPU that has a cache profile similar to NVidia and AMD
+static const VertexScoreTable kVertexScoreTable = {
+ {0.f, 0.779f, 0.791f, 0.789f, 0.981f, 0.843f, 0.726f, 0.847f, 0.882f, 0.867f, 0.799f, 0.642f, 0.613f, 0.600f, 0.568f, 0.372f, 0.234f},
+ {0.f, 0.995f, 0.713f, 0.450f, 0.404f, 0.059f, 0.005f, 0.147f, 0.006f},
+};
+
+// Tuned to minimize the encoded index buffer size
+static const VertexScoreTable kVertexScoreTableStrip = {
+ {0.f, 1.000f, 1.000f, 1.000f, 0.453f, 0.561f, 0.490f, 0.459f, 0.179f, 0.526f, 0.000f, 0.227f, 0.184f, 0.490f, 0.112f, 0.050f, 0.131f},
+ {0.f, 0.956f, 0.786f, 0.577f, 0.558f, 0.618f, 0.549f, 0.499f, 0.489f},
+};
+
+struct TriangleAdjacency
+{
+ unsigned int* counts;
+ unsigned int* offsets;
+ unsigned int* data;
+};
+
+static void buildTriangleAdjacency(TriangleAdjacency& adjacency, const unsigned int* indices, size_t index_count, size_t vertex_count, meshopt_Allocator& allocator)
+{
+ size_t face_count = index_count / 3;
+
+ // allocate arrays
+ adjacency.counts = allocator.allocate<unsigned int>(vertex_count);
+ adjacency.offsets = allocator.allocate<unsigned int>(vertex_count);
+ adjacency.data = allocator.allocate<unsigned int>(index_count);
+
+ // fill triangle counts
+ memset(adjacency.counts, 0, vertex_count * sizeof(unsigned int));
+
+ for (size_t i = 0; i < index_count; ++i)
+ {
+ assert(indices[i] < vertex_count);
+
+ adjacency.counts[indices[i]]++;
+ }
+
+ // fill offset table
+ unsigned int offset = 0;
+
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ adjacency.offsets[i] = offset;
+ offset += adjacency.counts[i];
+ }
+
+ assert(offset == index_count);
+
+ // fill triangle data
+ for (size_t i = 0; i < face_count; ++i)
+ {
+ unsigned int a = indices[i * 3 + 0], b = indices[i * 3 + 1], c = indices[i * 3 + 2];
+
+ adjacency.data[adjacency.offsets[a]++] = unsigned(i);
+ adjacency.data[adjacency.offsets[b]++] = unsigned(i);
+ adjacency.data[adjacency.offsets[c]++] = unsigned(i);
+ }
+
+ // fix offsets that have been disturbed by the previous pass
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ assert(adjacency.offsets[i] >= adjacency.counts[i]);
+
+ adjacency.offsets[i] -= adjacency.counts[i];
+ }
+}
+
+static unsigned int getNextVertexDeadEnd(const unsigned int* dead_end, unsigned int& dead_end_top, unsigned int& input_cursor, const unsigned int* live_triangles, size_t vertex_count)
+{
+ // check dead-end stack
+ while (dead_end_top)
+ {
+ unsigned int vertex = dead_end[--dead_end_top];
+
+ if (live_triangles[vertex] > 0)
+ return vertex;
+ }
+
+ // input order
+ while (input_cursor < vertex_count)
+ {
+ if (live_triangles[input_cursor] > 0)
+ return input_cursor;
+
+ ++input_cursor;
+ }
+
+ return ~0u;
+}
+
+static unsigned int getNextVertexNeighbour(const unsigned int* next_candidates_begin, const unsigned int* next_candidates_end, const unsigned int* live_triangles, const unsigned int* cache_timestamps, unsigned int timestamp, unsigned int cache_size)
+{
+ unsigned int best_candidate = ~0u;
+ int best_priority = -1;
+
+ for (const unsigned int* next_candidate = next_candidates_begin; next_candidate != next_candidates_end; ++next_candidate)
+ {
+ unsigned int vertex = *next_candidate;
+
+ // otherwise we don't need to process it
+ if (live_triangles[vertex] > 0)
+ {
+ int priority = 0;
+
+ // will it be in cache after fanning?
+ if (2 * live_triangles[vertex] + timestamp - cache_timestamps[vertex] <= cache_size)
+ {
+ priority = timestamp - cache_timestamps[vertex]; // position in cache
+ }
+
+ if (priority > best_priority)
+ {
+ best_candidate = vertex;
+ best_priority = priority;
+ }
+ }
+ }
+
+ return best_candidate;
+}
+
+static float vertexScore(const VertexScoreTable* table, int cache_position, unsigned int live_triangles)
+{
+ assert(cache_position >= -1 && cache_position < int(kCacheSizeMax));
+
+ unsigned int live_triangles_clamped = live_triangles < kValenceMax ? live_triangles : kValenceMax;
+
+ return table->cache[1 + cache_position] + table->live[live_triangles_clamped];
+}
+
+static unsigned int getNextTriangleDeadEnd(unsigned int& input_cursor, const unsigned char* emitted_flags, size_t face_count)
+{
+ // input order
+ while (input_cursor < face_count)
+ {
+ if (!emitted_flags[input_cursor])
+ return input_cursor;
+
+ ++input_cursor;
+ }
+
+ return ~0u;
+}
+
+} // namespace meshopt
+
+void meshopt_optimizeVertexCacheTable(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, const meshopt::VertexScoreTable* table)
+{
+ using namespace meshopt;
+
+ assert(index_count % 3 == 0);
+
+ meshopt_Allocator allocator;
+
+ // guard for empty meshes
+ if (index_count == 0 || vertex_count == 0)
+ return;
+
+ // support in-place optimization
+ if (destination == indices)
+ {
+ unsigned int* indices_copy = allocator.allocate<unsigned int>(index_count);
+ memcpy(indices_copy, indices, index_count * sizeof(unsigned int));
+ indices = indices_copy;
+ }
+
+ unsigned int cache_size = 16;
+ assert(cache_size <= kCacheSizeMax);
+
+ size_t face_count = index_count / 3;
+
+ // build adjacency information
+ TriangleAdjacency adjacency = {};
+ buildTriangleAdjacency(adjacency, indices, index_count, vertex_count, allocator);
+
+ // live triangle counts
+ unsigned int* live_triangles = allocator.allocate<unsigned int>(vertex_count);
+ memcpy(live_triangles, adjacency.counts, vertex_count * sizeof(unsigned int));
+
+ // emitted flags
+ unsigned char* emitted_flags = allocator.allocate<unsigned char>(face_count);
+ memset(emitted_flags, 0, face_count);
+
+ // compute initial vertex scores
+ float* vertex_scores = allocator.allocate<float>(vertex_count);
+
+ for (size_t i = 0; i < vertex_count; ++i)
+ vertex_scores[i] = vertexScore(table, -1, live_triangles[i]);
+
+ // compute triangle scores
+ float* triangle_scores = allocator.allocate<float>(face_count);
+
+ for (size_t i = 0; i < face_count; ++i)
+ {
+ unsigned int a = indices[i * 3 + 0];
+ unsigned int b = indices[i * 3 + 1];
+ unsigned int c = indices[i * 3 + 2];
+
+ triangle_scores[i] = vertex_scores[a] + vertex_scores[b] + vertex_scores[c];
+ }
+
+ unsigned int cache_holder[2 * (kCacheSizeMax + 3)];
+ unsigned int* cache = cache_holder;
+ unsigned int* cache_new = cache_holder + kCacheSizeMax + 3;
+ size_t cache_count = 0;
+
+ unsigned int current_triangle = 0;
+ unsigned int input_cursor = 1;
+
+ unsigned int output_triangle = 0;
+
+ while (current_triangle != ~0u)
+ {
+ assert(output_triangle < face_count);
+
+ unsigned int a = indices[current_triangle * 3 + 0];
+ unsigned int b = indices[current_triangle * 3 + 1];
+ unsigned int c = indices[current_triangle * 3 + 2];
+
+ // output indices
+ destination[output_triangle * 3 + 0] = a;
+ destination[output_triangle * 3 + 1] = b;
+ destination[output_triangle * 3 + 2] = c;
+ output_triangle++;
+
+ // update emitted flags
+ emitted_flags[current_triangle] = true;
+ triangle_scores[current_triangle] = 0;
+
+ // new triangle
+ size_t cache_write = 0;
+ cache_new[cache_write++] = a;
+ cache_new[cache_write++] = b;
+ cache_new[cache_write++] = c;
+
+ // old triangles
+ for (size_t i = 0; i < cache_count; ++i)
+ {
+ unsigned int index = cache[i];
+
+ if (index != a && index != b && index != c)
+ {
+ cache_new[cache_write++] = index;
+ }
+ }
+
+ unsigned int* cache_temp = cache;
+ cache = cache_new, cache_new = cache_temp;
+ cache_count = cache_write > cache_size ? cache_size : cache_write;
+
+ // update live triangle counts
+ live_triangles[a]--;
+ live_triangles[b]--;
+ live_triangles[c]--;
+
+ // remove emitted triangle from adjacency data
+ // this makes sure that we spend less time traversing these lists on subsequent iterations
+ for (size_t k = 0; k < 3; ++k)
+ {
+ unsigned int index = indices[current_triangle * 3 + k];
+
+ unsigned int* neighbours = &adjacency.data[0] + adjacency.offsets[index];
+ size_t neighbours_size = adjacency.counts[index];
+
+ for (size_t i = 0; i < neighbours_size; ++i)
+ {
+ unsigned int tri = neighbours[i];
+
+ if (tri == current_triangle)
+ {
+ neighbours[i] = neighbours[neighbours_size - 1];
+ adjacency.counts[index]--;
+ break;
+ }
+ }
+ }
+
+ unsigned int best_triangle = ~0u;
+ float best_score = 0;
+
+ // update cache positions, vertex scores and triangle scores, and find next best triangle
+ for (size_t i = 0; i < cache_write; ++i)
+ {
+ unsigned int index = cache[i];
+
+ int cache_position = i >= cache_size ? -1 : int(i);
+
+ // update vertex score
+ float score = vertexScore(table, cache_position, live_triangles[index]);
+ float score_diff = score - vertex_scores[index];
+
+ vertex_scores[index] = score;
+
+ // update scores of vertex triangles
+ const unsigned int* neighbours_begin = &adjacency.data[0] + adjacency.offsets[index];
+ const unsigned int* neighbours_end = neighbours_begin + adjacency.counts[index];
+
+ for (const unsigned int* it = neighbours_begin; it != neighbours_end; ++it)
+ {
+ unsigned int tri = *it;
+ assert(!emitted_flags[tri]);
+
+ float tri_score = triangle_scores[tri] + score_diff;
+ assert(tri_score > 0);
+
+ if (best_score < tri_score)
+ {
+ best_triangle = tri;
+ best_score = tri_score;
+ }
+
+ triangle_scores[tri] = tri_score;
+ }
+ }
+
+ // step through input triangles in order if we hit a dead-end
+ current_triangle = best_triangle;
+
+ if (current_triangle == ~0u)
+ {
+ current_triangle = getNextTriangleDeadEnd(input_cursor, &emitted_flags[0], face_count);
+ }
+ }
+
+ assert(input_cursor == face_count);
+ assert(output_triangle == face_count);
+}
+
+void meshopt_optimizeVertexCache(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count)
+{
+ meshopt_optimizeVertexCacheTable(destination, indices, index_count, vertex_count, &meshopt::kVertexScoreTable);
+}
+
+void meshopt_optimizeVertexCacheStrip(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count)
+{
+ meshopt_optimizeVertexCacheTable(destination, indices, index_count, vertex_count, &meshopt::kVertexScoreTableStrip);
+}
+
+void meshopt_optimizeVertexCacheFifo(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int cache_size)
+{
+ using namespace meshopt;
+
+ assert(index_count % 3 == 0);
+ assert(cache_size >= 3);
+
+ meshopt_Allocator allocator;
+
+ // guard for empty meshes
+ if (index_count == 0 || vertex_count == 0)
+ return;
+
+ // support in-place optimization
+ if (destination == indices)
+ {
+ unsigned int* indices_copy = allocator.allocate<unsigned int>(index_count);
+ memcpy(indices_copy, indices, index_count * sizeof(unsigned int));
+ indices = indices_copy;
+ }
+
+ size_t face_count = index_count / 3;
+
+ // build adjacency information
+ TriangleAdjacency adjacency = {};
+ buildTriangleAdjacency(adjacency, indices, index_count, vertex_count, allocator);
+
+ // live triangle counts
+ unsigned int* live_triangles = allocator.allocate<unsigned int>(vertex_count);
+ memcpy(live_triangles, adjacency.counts, vertex_count * sizeof(unsigned int));
+
+ // cache time stamps
+ unsigned int* cache_timestamps = allocator.allocate<unsigned int>(vertex_count);
+ memset(cache_timestamps, 0, vertex_count * sizeof(unsigned int));
+
+ // dead-end stack
+ unsigned int* dead_end = allocator.allocate<unsigned int>(index_count);
+ unsigned int dead_end_top = 0;
+
+ // emitted flags
+ unsigned char* emitted_flags = allocator.allocate<unsigned char>(face_count);
+ memset(emitted_flags, 0, face_count);
+
+ unsigned int current_vertex = 0;
+
+ unsigned int timestamp = cache_size + 1;
+ unsigned int input_cursor = 1; // vertex to restart from in case of dead-end
+
+ unsigned int output_triangle = 0;
+
+ while (current_vertex != ~0u)
+ {
+ const unsigned int* next_candidates_begin = &dead_end[0] + dead_end_top;
+
+ // emit all vertex neighbours
+ const unsigned int* neighbours_begin = &adjacency.data[0] + adjacency.offsets[current_vertex];
+ const unsigned int* neighbours_end = neighbours_begin + adjacency.counts[current_vertex];
+
+ for (const unsigned int* it = neighbours_begin; it != neighbours_end; ++it)
+ {
+ unsigned int triangle = *it;
+
+ if (!emitted_flags[triangle])
+ {
+ unsigned int a = indices[triangle * 3 + 0], b = indices[triangle * 3 + 1], c = indices[triangle * 3 + 2];
+
+ // output indices
+ destination[output_triangle * 3 + 0] = a;
+ destination[output_triangle * 3 + 1] = b;
+ destination[output_triangle * 3 + 2] = c;
+ output_triangle++;
+
+ // update dead-end stack
+ dead_end[dead_end_top + 0] = a;
+ dead_end[dead_end_top + 1] = b;
+ dead_end[dead_end_top + 2] = c;
+ dead_end_top += 3;
+
+ // update live triangle counts
+ live_triangles[a]--;
+ live_triangles[b]--;
+ live_triangles[c]--;
+
+ // update cache info
+ // if vertex is not in cache, put it in cache
+ if (timestamp - cache_timestamps[a] > cache_size)
+ cache_timestamps[a] = timestamp++;
+
+ if (timestamp - cache_timestamps[b] > cache_size)
+ cache_timestamps[b] = timestamp++;
+
+ if (timestamp - cache_timestamps[c] > cache_size)
+ cache_timestamps[c] = timestamp++;
+
+ // update emitted flags
+ emitted_flags[triangle] = true;
+ }
+ }
+
+ // next candidates are the ones we pushed to dead-end stack just now
+ const unsigned int* next_candidates_end = &dead_end[0] + dead_end_top;
+
+ // get next vertex
+ current_vertex = getNextVertexNeighbour(next_candidates_begin, next_candidates_end, &live_triangles[0], &cache_timestamps[0], timestamp, cache_size);
+
+ if (current_vertex == ~0u)
+ {
+ current_vertex = getNextVertexDeadEnd(&dead_end[0], dead_end_top, input_cursor, &live_triangles[0], vertex_count);
+ }
+ }
+
+ assert(output_triangle == face_count);
+}
diff --git a/thirdparty/meshoptimizer/vertexcodec.cpp b/thirdparty/meshoptimizer/vertexcodec.cpp
new file mode 100644
index 0000000000..784c9a13db
--- /dev/null
+++ b/thirdparty/meshoptimizer/vertexcodec.cpp
@@ -0,0 +1,1265 @@
+// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
+#include "meshoptimizer.h"
+
+#include <assert.h>
+#include <string.h>
+
+// The block below auto-detects SIMD ISA that can be used on the target platform
+#ifndef MESHOPTIMIZER_NO_SIMD
+
+// The SIMD implementation requires SSSE3, which can be enabled unconditionally through compiler settings
+#if defined(__AVX__) || defined(__SSSE3__)
+#define SIMD_SSE
+#endif
+
+// An experimental implementation using AVX512 instructions; it's only enabled when AVX512 is enabled through compiler settings
+#if defined(__AVX512VBMI2__) && defined(__AVX512VBMI__) && defined(__AVX512VL__) && defined(__POPCNT__)
+#undef SIMD_SSE
+#define SIMD_AVX
+#endif
+
+// MSVC supports compiling SSSE3 code regardless of compile options; we use a cpuid-based scalar fallback
+#if !defined(SIMD_SSE) && !defined(SIMD_AVX) && defined(_MSC_VER) && !defined(__clang__) && (defined(_M_IX86) || defined(_M_X64))
+#define SIMD_SSE
+#define SIMD_FALLBACK
+#endif
+
+// GCC 4.9+ and clang 3.8+ support targeting SIMD ISA from individual functions; we use a cpuid-based scalar fallback
+#if !defined(SIMD_SSE) && !defined(SIMD_AVX) && ((defined(__clang__) && __clang_major__ * 100 + __clang_minor__ >= 308) || (defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ >= 409)) && (defined(__i386__) || defined(__x86_64__))
+#define SIMD_SSE
+#define SIMD_FALLBACK
+#define SIMD_TARGET __attribute__((target("ssse3")))
+#endif
+
+// GCC/clang define these when NEON support is available
+#if defined(__ARM_NEON__) || defined(__ARM_NEON)
+#define SIMD_NEON
+#endif
+
+// On MSVC, we assume that ARM builds always target NEON-capable devices
+#if !defined(SIMD_NEON) && defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
+#define SIMD_NEON
+#endif
+
+// When targeting Wasm SIMD we can't use runtime cpuid checks so we unconditionally enable SIMD
+#if defined(__wasm_simd128__)
+#define SIMD_WASM
+#endif
+
+#ifndef SIMD_TARGET
+#define SIMD_TARGET
+#endif
+
+#endif // !MESHOPTIMIZER_NO_SIMD
+
+#ifdef SIMD_SSE
+#include <tmmintrin.h>
+#endif
+
+#if defined(SIMD_SSE) && defined(SIMD_FALLBACK)
+#ifdef _MSC_VER
+#include <intrin.h> // __cpuid
+#else
+#include <cpuid.h> // __cpuid
+#endif
+#endif
+
+#ifdef SIMD_AVX
+#include <immintrin.h>
+#endif
+
+#ifdef SIMD_NEON
+#if defined(_MSC_VER) && defined(_M_ARM64)
+#include <arm64_neon.h>
+#else
+#include <arm_neon.h>
+#endif
+#endif
+
+#ifdef SIMD_WASM
+#include <wasm_simd128.h>
+#endif
+
+#ifndef TRACE
+#define TRACE 0
+#endif
+
+#if TRACE
+#include <stdio.h>
+#endif
+
+#ifdef SIMD_WASM
+#define wasmx_splat_v32x4(v, i) wasm_v32x4_shuffle(v, v, i, i, i, i)
+#define wasmx_unpacklo_v8x16(a, b) wasm_v8x16_shuffle(a, b, 0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23)
+#define wasmx_unpackhi_v8x16(a, b) wasm_v8x16_shuffle(a, b, 8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31)
+#define wasmx_unpacklo_v16x8(a, b) wasm_v16x8_shuffle(a, b, 0, 8, 1, 9, 2, 10, 3, 11)
+#define wasmx_unpackhi_v16x8(a, b) wasm_v16x8_shuffle(a, b, 4, 12, 5, 13, 6, 14, 7, 15)
+#define wasmx_unpacklo_v64x2(a, b) wasm_v64x2_shuffle(a, b, 0, 2)
+#define wasmx_unpackhi_v64x2(a, b) wasm_v64x2_shuffle(a, b, 1, 3)
+#endif
+
+namespace meshopt
+{
+
+const unsigned char kVertexHeader = 0xa0;
+
+static int gEncodeVertexVersion = 0;
+
+const size_t kVertexBlockSizeBytes = 8192;
+const size_t kVertexBlockMaxSize = 256;
+const size_t kByteGroupSize = 16;
+const size_t kByteGroupDecodeLimit = 24;
+const size_t kTailMaxSize = 32;
+
+static size_t getVertexBlockSize(size_t vertex_size)
+{
+ // make sure the entire block fits into the scratch buffer
+ size_t result = kVertexBlockSizeBytes / vertex_size;
+
+ // align to byte group size; we encode each byte as a byte group
+ // if vertex block is misaligned, it results in wasted bytes, so just truncate the block size
+ result &= ~(kByteGroupSize - 1);
+
+ return (result < kVertexBlockMaxSize) ? result : kVertexBlockMaxSize;
+}
+
+inline unsigned char zigzag8(unsigned char v)
+{
+ return ((signed char)(v) >> 7) ^ (v << 1);
+}
+
+inline unsigned char unzigzag8(unsigned char v)
+{
+ return -(v & 1) ^ (v >> 1);
+}
+
+#if TRACE
+struct Stats
+{
+ size_t size;
+ size_t header;
+ size_t bitg[4];
+ size_t bitb[4];
+};
+
+Stats* bytestats;
+Stats vertexstats[256];
+#endif
+
+static bool encodeBytesGroupZero(const unsigned char* buffer)
+{
+ for (size_t i = 0; i < kByteGroupSize; ++i)
+ if (buffer[i])
+ return false;
+
+ return true;
+}
+
+static size_t encodeBytesGroupMeasure(const unsigned char* buffer, int bits)
+{
+ assert(bits >= 1 && bits <= 8);
+
+ if (bits == 1)
+ return encodeBytesGroupZero(buffer) ? 0 : size_t(-1);
+
+ if (bits == 8)
+ return kByteGroupSize;
+
+ size_t result = kByteGroupSize * bits / 8;
+
+ unsigned char sentinel = (1 << bits) - 1;
+
+ for (size_t i = 0; i < kByteGroupSize; ++i)
+ result += buffer[i] >= sentinel;
+
+ return result;
+}
+
+static unsigned char* encodeBytesGroup(unsigned char* data, const unsigned char* buffer, int bits)
+{
+ assert(bits >= 1 && bits <= 8);
+
+ if (bits == 1)
+ return data;
+
+ if (bits == 8)
+ {
+ memcpy(data, buffer, kByteGroupSize);
+ return data + kByteGroupSize;
+ }
+
+ size_t byte_size = 8 / bits;
+ assert(kByteGroupSize % byte_size == 0);
+
+ // fixed portion: bits bits for each value
+ // variable portion: full byte for each out-of-range value (using 1...1 as sentinel)
+ unsigned char sentinel = (1 << bits) - 1;
+
+ for (size_t i = 0; i < kByteGroupSize; i += byte_size)
+ {
+ unsigned char byte = 0;
+
+ for (size_t k = 0; k < byte_size; ++k)
+ {
+ unsigned char enc = (buffer[i + k] >= sentinel) ? sentinel : buffer[i + k];
+
+ byte <<= bits;
+ byte |= enc;
+ }
+
+ *data++ = byte;
+ }
+
+ for (size_t i = 0; i < kByteGroupSize; ++i)
+ {
+ if (buffer[i] >= sentinel)
+ {
+ *data++ = buffer[i];
+ }
+ }
+
+ return data;
+}
+
+static unsigned char* encodeBytes(unsigned char* data, unsigned char* data_end, const unsigned char* buffer, size_t buffer_size)
+{
+ assert(buffer_size % kByteGroupSize == 0);
+
+ unsigned char* header = data;
+
+ // round number of groups to 4 to get number of header bytes
+ size_t header_size = (buffer_size / kByteGroupSize + 3) / 4;
+
+ if (size_t(data_end - data) < header_size)
+ return 0;
+
+ data += header_size;
+
+ memset(header, 0, header_size);
+
+ for (size_t i = 0; i < buffer_size; i += kByteGroupSize)
+ {
+ if (size_t(data_end - data) < kByteGroupDecodeLimit)
+ return 0;
+
+ int best_bits = 8;
+ size_t best_size = encodeBytesGroupMeasure(buffer + i, 8);
+
+ for (int bits = 1; bits < 8; bits *= 2)
+ {
+ size_t size = encodeBytesGroupMeasure(buffer + i, bits);
+
+ if (size < best_size)
+ {
+ best_bits = bits;
+ best_size = size;
+ }
+ }
+
+ int bitslog2 = (best_bits == 1) ? 0 : (best_bits == 2) ? 1 : (best_bits == 4) ? 2 : 3;
+ assert((1 << bitslog2) == best_bits);
+
+ size_t header_offset = i / kByteGroupSize;
+
+ header[header_offset / 4] |= bitslog2 << ((header_offset % 4) * 2);
+
+ unsigned char* next = encodeBytesGroup(data, buffer + i, best_bits);
+
+ assert(data + best_size == next);
+ data = next;
+
+#if TRACE > 1
+ bytestats->bitg[bitslog2]++;
+ bytestats->bitb[bitslog2] += best_size;
+#endif
+ }
+
+#if TRACE > 1
+ bytestats->header += header_size;
+#endif
+
+ return data;
+}
+
+static unsigned char* encodeVertexBlock(unsigned char* data, unsigned char* data_end, const unsigned char* vertex_data, size_t vertex_count, size_t vertex_size, unsigned char last_vertex[256])
+{
+ assert(vertex_count > 0 && vertex_count <= kVertexBlockMaxSize);
+
+ unsigned char buffer[kVertexBlockMaxSize];
+ assert(sizeof(buffer) % kByteGroupSize == 0);
+
+ // we sometimes encode elements we didn't fill when rounding to kByteGroupSize
+ memset(buffer, 0, sizeof(buffer));
+
+ for (size_t k = 0; k < vertex_size; ++k)
+ {
+ size_t vertex_offset = k;
+
+ unsigned char p = last_vertex[k];
+
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ buffer[i] = zigzag8(vertex_data[vertex_offset] - p);
+
+ p = vertex_data[vertex_offset];
+
+ vertex_offset += vertex_size;
+ }
+
+#if TRACE
+ const unsigned char* olddata = data;
+ bytestats = &vertexstats[k];
+#endif
+
+ data = encodeBytes(data, data_end, buffer, (vertex_count + kByteGroupSize - 1) & ~(kByteGroupSize - 1));
+ if (!data)
+ return 0;
+
+#if TRACE
+ bytestats = 0;
+ vertexstats[k].size += data - olddata;
+#endif
+ }
+
+ memcpy(last_vertex, &vertex_data[vertex_size * (vertex_count - 1)], vertex_size);
+
+ return data;
+}
+
+#if defined(SIMD_FALLBACK) || (!defined(SIMD_SSE) && !defined(SIMD_NEON) && !defined(SIMD_AVX))
+static const unsigned char* decodeBytesGroup(const unsigned char* data, unsigned char* buffer, int bitslog2)
+{
+#define READ() byte = *data++
+#define NEXT(bits) enc = byte >> (8 - bits), byte <<= bits, encv = *data_var, *buffer++ = (enc == (1 << bits) - 1) ? encv : enc, data_var += (enc == (1 << bits) - 1)
+
+ unsigned char byte, enc, encv;
+ const unsigned char* data_var;
+
+ switch (bitslog2)
+ {
+ case 0:
+ memset(buffer, 0, kByteGroupSize);
+ return data;
+ case 1:
+ data_var = data + 4;
+
+ // 4 groups with 4 2-bit values in each byte
+ READ(), NEXT(2), NEXT(2), NEXT(2), NEXT(2);
+ READ(), NEXT(2), NEXT(2), NEXT(2), NEXT(2);
+ READ(), NEXT(2), NEXT(2), NEXT(2), NEXT(2);
+ READ(), NEXT(2), NEXT(2), NEXT(2), NEXT(2);
+
+ return data_var;
+ case 2:
+ data_var = data + 8;
+
+ // 8 groups with 2 4-bit values in each byte
+ READ(), NEXT(4), NEXT(4);
+ READ(), NEXT(4), NEXT(4);
+ READ(), NEXT(4), NEXT(4);
+ READ(), NEXT(4), NEXT(4);
+ READ(), NEXT(4), NEXT(4);
+ READ(), NEXT(4), NEXT(4);
+ READ(), NEXT(4), NEXT(4);
+ READ(), NEXT(4), NEXT(4);
+
+ return data_var;
+ case 3:
+ memcpy(buffer, data, kByteGroupSize);
+ return data + kByteGroupSize;
+ default:
+ assert(!"Unexpected bit length"); // unreachable since bitslog2 is a 2-bit value
+ return data;
+ }
+
+#undef READ
+#undef NEXT
+}
+
+static const unsigned char* decodeBytes(const unsigned char* data, const unsigned char* data_end, unsigned char* buffer, size_t buffer_size)
+{
+ assert(buffer_size % kByteGroupSize == 0);
+
+ const unsigned char* header = data;
+
+ // round number of groups to 4 to get number of header bytes
+ size_t header_size = (buffer_size / kByteGroupSize + 3) / 4;
+
+ if (size_t(data_end - data) < header_size)
+ return 0;
+
+ data += header_size;
+
+ for (size_t i = 0; i < buffer_size; i += kByteGroupSize)
+ {
+ if (size_t(data_end - data) < kByteGroupDecodeLimit)
+ return 0;
+
+ size_t header_offset = i / kByteGroupSize;
+
+ int bitslog2 = (header[header_offset / 4] >> ((header_offset % 4) * 2)) & 3;
+
+ data = decodeBytesGroup(data, buffer + i, bitslog2);
+ }
+
+ return data;
+}
+
+static const unsigned char* decodeVertexBlock(const unsigned char* data, const unsigned char* data_end, unsigned char* vertex_data, size_t vertex_count, size_t vertex_size, unsigned char last_vertex[256])
+{
+ assert(vertex_count > 0 && vertex_count <= kVertexBlockMaxSize);
+
+ unsigned char buffer[kVertexBlockMaxSize];
+ unsigned char transposed[kVertexBlockSizeBytes];
+
+ size_t vertex_count_aligned = (vertex_count + kByteGroupSize - 1) & ~(kByteGroupSize - 1);
+
+ for (size_t k = 0; k < vertex_size; ++k)
+ {
+ data = decodeBytes(data, data_end, buffer, vertex_count_aligned);
+ if (!data)
+ return 0;
+
+ size_t vertex_offset = k;
+
+ unsigned char p = last_vertex[k];
+
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ unsigned char v = unzigzag8(buffer[i]) + p;
+
+ transposed[vertex_offset] = v;
+ p = v;
+
+ vertex_offset += vertex_size;
+ }
+ }
+
+ memcpy(vertex_data, transposed, vertex_count * vertex_size);
+
+ memcpy(last_vertex, &transposed[vertex_size * (vertex_count - 1)], vertex_size);
+
+ return data;
+}
+#endif
+
+#if defined(SIMD_SSE) || defined(SIMD_NEON) || defined(SIMD_WASM)
+static unsigned char kDecodeBytesGroupShuffle[256][8];
+static unsigned char kDecodeBytesGroupCount[256];
+
+#ifdef __wasm__
+__attribute__((cold)) // this saves 500 bytes in the output binary - we don't need to vectorize this loop!
+#endif
+static bool
+decodeBytesGroupBuildTables()
+{
+ for (int mask = 0; mask < 256; ++mask)
+ {
+ unsigned char shuffle[8];
+ unsigned char count = 0;
+
+ for (int i = 0; i < 8; ++i)
+ {
+ int maski = (mask >> i) & 1;
+ shuffle[i] = maski ? count : 0x80;
+ count += (unsigned char)(maski);
+ }
+
+ memcpy(kDecodeBytesGroupShuffle[mask], shuffle, 8);
+ kDecodeBytesGroupCount[mask] = count;
+ }
+
+ return true;
+}
+
+static bool gDecodeBytesGroupInitialized = decodeBytesGroupBuildTables();
+#endif
+
+#ifdef SIMD_SSE
+SIMD_TARGET
+static __m128i decodeShuffleMask(unsigned char mask0, unsigned char mask1)
+{
+ __m128i sm0 = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(&kDecodeBytesGroupShuffle[mask0]));
+ __m128i sm1 = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(&kDecodeBytesGroupShuffle[mask1]));
+ __m128i sm1off = _mm_set1_epi8(kDecodeBytesGroupCount[mask0]);
+
+ __m128i sm1r = _mm_add_epi8(sm1, sm1off);
+
+ return _mm_unpacklo_epi64(sm0, sm1r);
+}
+
+SIMD_TARGET
+static const unsigned char* decodeBytesGroupSimd(const unsigned char* data, unsigned char* buffer, int bitslog2)
+{
+ switch (bitslog2)
+ {
+ case 0:
+ {
+ __m128i result = _mm_setzero_si128();
+
+ _mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), result);
+
+ return data;
+ }
+
+ case 1:
+ {
+#ifdef __GNUC__
+ typedef int __attribute__((aligned(1))) unaligned_int;
+#else
+ typedef int unaligned_int;
+#endif
+
+ __m128i sel2 = _mm_cvtsi32_si128(*reinterpret_cast<const unaligned_int*>(data));
+ __m128i rest = _mm_loadu_si128(reinterpret_cast<const __m128i*>(data + 4));
+
+ __m128i sel22 = _mm_unpacklo_epi8(_mm_srli_epi16(sel2, 4), sel2);
+ __m128i sel2222 = _mm_unpacklo_epi8(_mm_srli_epi16(sel22, 2), sel22);
+ __m128i sel = _mm_and_si128(sel2222, _mm_set1_epi8(3));
+
+ __m128i mask = _mm_cmpeq_epi8(sel, _mm_set1_epi8(3));
+ int mask16 = _mm_movemask_epi8(mask);
+ unsigned char mask0 = (unsigned char)(mask16 & 255);
+ unsigned char mask1 = (unsigned char)(mask16 >> 8);
+
+ __m128i shuf = decodeShuffleMask(mask0, mask1);
+
+ __m128i result = _mm_or_si128(_mm_shuffle_epi8(rest, shuf), _mm_andnot_si128(mask, sel));
+
+ _mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), result);
+
+ return data + 4 + kDecodeBytesGroupCount[mask0] + kDecodeBytesGroupCount[mask1];
+ }
+
+ case 2:
+ {
+ __m128i sel4 = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(data));
+ __m128i rest = _mm_loadu_si128(reinterpret_cast<const __m128i*>(data + 8));
+
+ __m128i sel44 = _mm_unpacklo_epi8(_mm_srli_epi16(sel4, 4), sel4);
+ __m128i sel = _mm_and_si128(sel44, _mm_set1_epi8(15));
+
+ __m128i mask = _mm_cmpeq_epi8(sel, _mm_set1_epi8(15));
+ int mask16 = _mm_movemask_epi8(mask);
+ unsigned char mask0 = (unsigned char)(mask16 & 255);
+ unsigned char mask1 = (unsigned char)(mask16 >> 8);
+
+ __m128i shuf = decodeShuffleMask(mask0, mask1);
+
+ __m128i result = _mm_or_si128(_mm_shuffle_epi8(rest, shuf), _mm_andnot_si128(mask, sel));
+
+ _mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), result);
+
+ return data + 8 + kDecodeBytesGroupCount[mask0] + kDecodeBytesGroupCount[mask1];
+ }
+
+ case 3:
+ {
+ __m128i result = _mm_loadu_si128(reinterpret_cast<const __m128i*>(data));
+
+ _mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), result);
+
+ return data + 16;
+ }
+
+ default:
+ assert(!"Unexpected bit length"); // unreachable since bitslog2 is a 2-bit value
+ return data;
+ }
+}
+#endif
+
+#ifdef SIMD_AVX
+static const __m128i decodeBytesGroupConfig[] = {
+ _mm_set1_epi8(3),
+ _mm_set1_epi8(15),
+ _mm_setr_epi8(6, 4, 2, 0, 14, 12, 10, 8, 22, 20, 18, 16, 30, 28, 26, 24),
+ _mm_setr_epi8(4, 0, 12, 8, 20, 16, 28, 24, 36, 32, 44, 40, 52, 48, 60, 56),
+};
+
+static const unsigned char* decodeBytesGroupSimd(const unsigned char* data, unsigned char* buffer, int bitslog2)
+{
+ switch (bitslog2)
+ {
+ case 0:
+ {
+ __m128i result = _mm_setzero_si128();
+
+ _mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), result);
+
+ return data;
+ }
+
+ case 1:
+ case 2:
+ {
+ const unsigned char* skip = data + (bitslog2 << 2);
+
+ __m128i selb = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(data));
+ __m128i rest = _mm_loadu_si128(reinterpret_cast<const __m128i*>(skip));
+
+ __m128i sent = decodeBytesGroupConfig[bitslog2 - 1];
+ __m128i ctrl = decodeBytesGroupConfig[bitslog2 + 1];
+
+ __m128i selw = _mm_shuffle_epi32(selb, 0x44);
+ __m128i sel = _mm_and_si128(sent, _mm_multishift_epi64_epi8(ctrl, selw));
+ __mmask16 mask16 = _mm_cmp_epi8_mask(sel, sent, _MM_CMPINT_EQ);
+
+ __m128i result = _mm_mask_expand_epi8(sel, mask16, rest);
+
+ _mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), result);
+
+ return skip + _mm_popcnt_u32(mask16);
+ }
+
+ case 3:
+ {
+ __m128i result = _mm_loadu_si128(reinterpret_cast<const __m128i*>(data));
+
+ _mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), result);
+
+ return data + 16;
+ }
+
+ default:
+ assert(!"Unexpected bit length"); // unreachable since bitslog2 is a 2-bit value
+ return data;
+ }
+}
+#endif
+
+#ifdef SIMD_NEON
+static uint8x16_t shuffleBytes(unsigned char mask0, unsigned char mask1, uint8x8_t rest0, uint8x8_t rest1)
+{
+ uint8x8_t sm0 = vld1_u8(kDecodeBytesGroupShuffle[mask0]);
+ uint8x8_t sm1 = vld1_u8(kDecodeBytesGroupShuffle[mask1]);
+
+ uint8x8_t r0 = vtbl1_u8(rest0, sm0);
+ uint8x8_t r1 = vtbl1_u8(rest1, sm1);
+
+ return vcombine_u8(r0, r1);
+}
+
+static void neonMoveMask(uint8x16_t mask, unsigned char& mask0, unsigned char& mask1)
+{
+ static const unsigned char byte_mask_data[16] = {1, 2, 4, 8, 16, 32, 64, 128, 1, 2, 4, 8, 16, 32, 64, 128};
+
+ uint8x16_t byte_mask = vld1q_u8(byte_mask_data);
+ uint8x16_t masked = vandq_u8(mask, byte_mask);
+
+#ifdef __aarch64__
+ // aarch64 has horizontal sums; MSVC doesn't expose this via arm64_neon.h so this path is exclusive to clang/gcc
+ mask0 = vaddv_u8(vget_low_u8(masked));
+ mask1 = vaddv_u8(vget_high_u8(masked));
+#else
+ // we need horizontal sums of each half of masked, which can be done in 3 steps (yielding sums of sizes 2, 4, 8)
+ uint8x8_t sum1 = vpadd_u8(vget_low_u8(masked), vget_high_u8(masked));
+ uint8x8_t sum2 = vpadd_u8(sum1, sum1);
+ uint8x8_t sum3 = vpadd_u8(sum2, sum2);
+
+ mask0 = vget_lane_u8(sum3, 0);
+ mask1 = vget_lane_u8(sum3, 1);
+#endif
+}
+
+static const unsigned char* decodeBytesGroupSimd(const unsigned char* data, unsigned char* buffer, int bitslog2)
+{
+ switch (bitslog2)
+ {
+ case 0:
+ {
+ uint8x16_t result = vdupq_n_u8(0);
+
+ vst1q_u8(buffer, result);
+
+ return data;
+ }
+
+ case 1:
+ {
+ uint8x8_t sel2 = vld1_u8(data);
+ uint8x8_t sel22 = vzip_u8(vshr_n_u8(sel2, 4), sel2).val[0];
+ uint8x8x2_t sel2222 = vzip_u8(vshr_n_u8(sel22, 2), sel22);
+ uint8x16_t sel = vandq_u8(vcombine_u8(sel2222.val[0], sel2222.val[1]), vdupq_n_u8(3));
+
+ uint8x16_t mask = vceqq_u8(sel, vdupq_n_u8(3));
+ unsigned char mask0, mask1;
+ neonMoveMask(mask, mask0, mask1);
+
+ uint8x8_t rest0 = vld1_u8(data + 4);
+ uint8x8_t rest1 = vld1_u8(data + 4 + kDecodeBytesGroupCount[mask0]);
+
+ uint8x16_t result = vbslq_u8(mask, shuffleBytes(mask0, mask1, rest0, rest1), sel);
+
+ vst1q_u8(buffer, result);
+
+ return data + 4 + kDecodeBytesGroupCount[mask0] + kDecodeBytesGroupCount[mask1];
+ }
+
+ case 2:
+ {
+ uint8x8_t sel4 = vld1_u8(data);
+ uint8x8x2_t sel44 = vzip_u8(vshr_n_u8(sel4, 4), vand_u8(sel4, vdup_n_u8(15)));
+ uint8x16_t sel = vcombine_u8(sel44.val[0], sel44.val[1]);
+
+ uint8x16_t mask = vceqq_u8(sel, vdupq_n_u8(15));
+ unsigned char mask0, mask1;
+ neonMoveMask(mask, mask0, mask1);
+
+ uint8x8_t rest0 = vld1_u8(data + 8);
+ uint8x8_t rest1 = vld1_u8(data + 8 + kDecodeBytesGroupCount[mask0]);
+
+ uint8x16_t result = vbslq_u8(mask, shuffleBytes(mask0, mask1, rest0, rest1), sel);
+
+ vst1q_u8(buffer, result);
+
+ return data + 8 + kDecodeBytesGroupCount[mask0] + kDecodeBytesGroupCount[mask1];
+ }
+
+ case 3:
+ {
+ uint8x16_t result = vld1q_u8(data);
+
+ vst1q_u8(buffer, result);
+
+ return data + 16;
+ }
+
+ default:
+ assert(!"Unexpected bit length"); // unreachable since bitslog2 is a 2-bit value
+ return data;
+ }
+}
+#endif
+
+#ifdef SIMD_WASM
+SIMD_TARGET
+static v128_t decodeShuffleMask(unsigned char mask0, unsigned char mask1)
+{
+ v128_t sm0 = wasm_v128_load(&kDecodeBytesGroupShuffle[mask0]);
+ v128_t sm1 = wasm_v128_load(&kDecodeBytesGroupShuffle[mask1]);
+
+ v128_t sm1off = wasm_v128_load(&kDecodeBytesGroupCount[mask0]);
+ sm1off = wasm_v8x16_shuffle(sm1off, sm1off, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+ v128_t sm1r = wasm_i8x16_add(sm1, sm1off);
+
+ return wasmx_unpacklo_v64x2(sm0, sm1r);
+}
+
+SIMD_TARGET
+static void wasmMoveMask(v128_t mask, unsigned char& mask0, unsigned char& mask1)
+{
+ v128_t mask_0 = wasm_v32x4_shuffle(mask, mask, 0, 2, 1, 3);
+
+ uint64_t mask_1a = wasm_i64x2_extract_lane(mask_0, 0) & 0x0804020108040201ull;
+ uint64_t mask_1b = wasm_i64x2_extract_lane(mask_0, 1) & 0x8040201080402010ull;
+
+ // TODO: This can use v8x16_bitmask in the future
+ uint64_t mask_2 = mask_1a | mask_1b;
+ uint64_t mask_4 = mask_2 | (mask_2 >> 16);
+ uint64_t mask_8 = mask_4 | (mask_4 >> 8);
+
+ mask0 = uint8_t(mask_8);
+ mask1 = uint8_t(mask_8 >> 32);
+}
+
+SIMD_TARGET
+static const unsigned char* decodeBytesGroupSimd(const unsigned char* data, unsigned char* buffer, int bitslog2)
+{
+ unsigned char byte, enc, encv;
+ const unsigned char* data_var;
+
+ switch (bitslog2)
+ {
+ case 0:
+ {
+ v128_t result = wasm_i8x16_splat(0);
+
+ wasm_v128_store(buffer, result);
+
+ return data;
+ }
+
+ case 1:
+ {
+ v128_t sel2 = wasm_v128_load(data);
+ v128_t rest = wasm_v128_load(data + 4);
+
+ v128_t sel22 = wasmx_unpacklo_v8x16(wasm_i16x8_shr(sel2, 4), sel2);
+ v128_t sel2222 = wasmx_unpacklo_v8x16(wasm_i16x8_shr(sel22, 2), sel22);
+ v128_t sel = wasm_v128_and(sel2222, wasm_i8x16_splat(3));
+
+ v128_t mask = wasm_i8x16_eq(sel, wasm_i8x16_splat(3));
+
+ unsigned char mask0, mask1;
+ wasmMoveMask(mask, mask0, mask1);
+
+ v128_t shuf = decodeShuffleMask(mask0, mask1);
+
+ v128_t result = wasm_v128_bitselect(wasm_v8x16_swizzle(rest, shuf), sel, mask);
+
+ wasm_v128_store(buffer, result);
+
+ return data + 4 + kDecodeBytesGroupCount[mask0] + kDecodeBytesGroupCount[mask1];
+ }
+
+ case 2:
+ {
+ v128_t sel4 = wasm_v128_load(data);
+ v128_t rest = wasm_v128_load(data + 8);
+
+ v128_t sel44 = wasmx_unpacklo_v8x16(wasm_i16x8_shr(sel4, 4), sel4);
+ v128_t sel = wasm_v128_and(sel44, wasm_i8x16_splat(15));
+
+ v128_t mask = wasm_i8x16_eq(sel, wasm_i8x16_splat(15));
+
+ unsigned char mask0, mask1;
+ wasmMoveMask(mask, mask0, mask1);
+
+ v128_t shuf = decodeShuffleMask(mask0, mask1);
+
+ v128_t result = wasm_v128_bitselect(wasm_v8x16_swizzle(rest, shuf), sel, mask);
+
+ wasm_v128_store(buffer, result);
+
+ return data + 8 + kDecodeBytesGroupCount[mask0] + kDecodeBytesGroupCount[mask1];
+ }
+
+ case 3:
+ {
+ v128_t result = wasm_v128_load(data);
+
+ wasm_v128_store(buffer, result);
+
+ return data + 16;
+ }
+
+ default:
+ assert(!"Unexpected bit length"); // unreachable since bitslog2 is a 2-bit value
+ return data;
+ }
+}
+#endif
+
+#if defined(SIMD_SSE) || defined(SIMD_AVX)
+SIMD_TARGET
+static void transpose8(__m128i& x0, __m128i& x1, __m128i& x2, __m128i& x3)
+{
+ __m128i t0 = _mm_unpacklo_epi8(x0, x1);
+ __m128i t1 = _mm_unpackhi_epi8(x0, x1);
+ __m128i t2 = _mm_unpacklo_epi8(x2, x3);
+ __m128i t3 = _mm_unpackhi_epi8(x2, x3);
+
+ x0 = _mm_unpacklo_epi16(t0, t2);
+ x1 = _mm_unpackhi_epi16(t0, t2);
+ x2 = _mm_unpacklo_epi16(t1, t3);
+ x3 = _mm_unpackhi_epi16(t1, t3);
+}
+
+SIMD_TARGET
+static __m128i unzigzag8(__m128i v)
+{
+ __m128i xl = _mm_sub_epi8(_mm_setzero_si128(), _mm_and_si128(v, _mm_set1_epi8(1)));
+ __m128i xr = _mm_and_si128(_mm_srli_epi16(v, 1), _mm_set1_epi8(127));
+
+ return _mm_xor_si128(xl, xr);
+}
+#endif
+
+#ifdef SIMD_NEON
+static void transpose8(uint8x16_t& x0, uint8x16_t& x1, uint8x16_t& x2, uint8x16_t& x3)
+{
+ uint8x16x2_t t01 = vzipq_u8(x0, x1);
+ uint8x16x2_t t23 = vzipq_u8(x2, x3);
+
+ uint16x8x2_t x01 = vzipq_u16(vreinterpretq_u16_u8(t01.val[0]), vreinterpretq_u16_u8(t23.val[0]));
+ uint16x8x2_t x23 = vzipq_u16(vreinterpretq_u16_u8(t01.val[1]), vreinterpretq_u16_u8(t23.val[1]));
+
+ x0 = vreinterpretq_u8_u16(x01.val[0]);
+ x1 = vreinterpretq_u8_u16(x01.val[1]);
+ x2 = vreinterpretq_u8_u16(x23.val[0]);
+ x3 = vreinterpretq_u8_u16(x23.val[1]);
+}
+
+static uint8x16_t unzigzag8(uint8x16_t v)
+{
+ uint8x16_t xl = vreinterpretq_u8_s8(vnegq_s8(vreinterpretq_s8_u8(vandq_u8(v, vdupq_n_u8(1)))));
+ uint8x16_t xr = vshrq_n_u8(v, 1);
+
+ return veorq_u8(xl, xr);
+}
+#endif
+
+#ifdef SIMD_WASM
+SIMD_TARGET
+static void transpose8(v128_t& x0, v128_t& x1, v128_t& x2, v128_t& x3)
+{
+ v128_t t0 = wasmx_unpacklo_v8x16(x0, x1);
+ v128_t t1 = wasmx_unpackhi_v8x16(x0, x1);
+ v128_t t2 = wasmx_unpacklo_v8x16(x2, x3);
+ v128_t t3 = wasmx_unpackhi_v8x16(x2, x3);
+
+ x0 = wasmx_unpacklo_v16x8(t0, t2);
+ x1 = wasmx_unpackhi_v16x8(t0, t2);
+ x2 = wasmx_unpacklo_v16x8(t1, t3);
+ x3 = wasmx_unpackhi_v16x8(t1, t3);
+}
+
+SIMD_TARGET
+static v128_t unzigzag8(v128_t v)
+{
+ v128_t xl = wasm_i8x16_neg(wasm_v128_and(v, wasm_i8x16_splat(1)));
+ v128_t xr = wasm_u8x16_shr(v, 1);
+
+ return wasm_v128_xor(xl, xr);
+}
+#endif
+
+#if defined(SIMD_SSE) || defined(SIMD_AVX) || defined(SIMD_NEON) || defined(SIMD_WASM)
+SIMD_TARGET
+static const unsigned char* decodeBytesSimd(const unsigned char* data, const unsigned char* data_end, unsigned char* buffer, size_t buffer_size)
+{
+ assert(buffer_size % kByteGroupSize == 0);
+ assert(kByteGroupSize == 16);
+
+ const unsigned char* header = data;
+
+ // round number of groups to 4 to get number of header bytes
+ size_t header_size = (buffer_size / kByteGroupSize + 3) / 4;
+
+ if (size_t(data_end - data) < header_size)
+ return 0;
+
+ data += header_size;
+
+ size_t i = 0;
+
+ // fast-path: process 4 groups at a time, do a shared bounds check - each group reads <=24b
+ for (; i + kByteGroupSize * 4 <= buffer_size && size_t(data_end - data) >= kByteGroupDecodeLimit * 4; i += kByteGroupSize * 4)
+ {
+ size_t header_offset = i / kByteGroupSize;
+ unsigned char header_byte = header[header_offset / 4];
+
+ data = decodeBytesGroupSimd(data, buffer + i + kByteGroupSize * 0, (header_byte >> 0) & 3);
+ data = decodeBytesGroupSimd(data, buffer + i + kByteGroupSize * 1, (header_byte >> 2) & 3);
+ data = decodeBytesGroupSimd(data, buffer + i + kByteGroupSize * 2, (header_byte >> 4) & 3);
+ data = decodeBytesGroupSimd(data, buffer + i + kByteGroupSize * 3, (header_byte >> 6) & 3);
+ }
+
+ // slow-path: process remaining groups
+ for (; i < buffer_size; i += kByteGroupSize)
+ {
+ if (size_t(data_end - data) < kByteGroupDecodeLimit)
+ return 0;
+
+ size_t header_offset = i / kByteGroupSize;
+
+ int bitslog2 = (header[header_offset / 4] >> ((header_offset % 4) * 2)) & 3;
+
+ data = decodeBytesGroupSimd(data, buffer + i, bitslog2);
+ }
+
+ return data;
+}
+
+SIMD_TARGET
+static const unsigned char* decodeVertexBlockSimd(const unsigned char* data, const unsigned char* data_end, unsigned char* vertex_data, size_t vertex_count, size_t vertex_size, unsigned char last_vertex[256])
+{
+ assert(vertex_count > 0 && vertex_count <= kVertexBlockMaxSize);
+
+ unsigned char buffer[kVertexBlockMaxSize * 4];
+ unsigned char transposed[kVertexBlockSizeBytes];
+
+ size_t vertex_count_aligned = (vertex_count + kByteGroupSize - 1) & ~(kByteGroupSize - 1);
+
+ for (size_t k = 0; k < vertex_size; k += 4)
+ {
+ for (size_t j = 0; j < 4; ++j)
+ {
+ data = decodeBytesSimd(data, data_end, buffer + j * vertex_count_aligned, vertex_count_aligned);
+ if (!data)
+ return 0;
+ }
+
+#if defined(SIMD_SSE) || defined(SIMD_AVX)
+#define TEMP __m128i
+#define PREP() __m128i pi = _mm_cvtsi32_si128(*reinterpret_cast<const int*>(last_vertex + k))
+#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast<const __m128i*>(buffer + j + i * vertex_count_aligned))
+#define GRP4(i) t0 = _mm_shuffle_epi32(r##i, 0), t1 = _mm_shuffle_epi32(r##i, 1), t2 = _mm_shuffle_epi32(r##i, 2), t3 = _mm_shuffle_epi32(r##i, 3)
+#define FIXD(i) t##i = pi = _mm_add_epi8(pi, t##i)
+#define SAVE(i) *reinterpret_cast<int*>(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size
+#endif
+
+#ifdef SIMD_NEON
+#define TEMP uint8x8_t
+#define PREP() uint8x8_t pi = vreinterpret_u8_u32(vld1_lane_u32(reinterpret_cast<uint32_t*>(last_vertex + k), vdup_n_u32(0), 0))
+#define LOAD(i) uint8x16_t r##i = vld1q_u8(buffer + j + i * vertex_count_aligned)
+#define GRP4(i) t0 = vget_low_u8(r##i), t1 = vreinterpret_u8_u32(vdup_lane_u32(vreinterpret_u32_u8(t0), 1)), t2 = vget_high_u8(r##i), t3 = vreinterpret_u8_u32(vdup_lane_u32(vreinterpret_u32_u8(t2), 1))
+#define FIXD(i) t##i = pi = vadd_u8(pi, t##i)
+#define SAVE(i) vst1_lane_u32(reinterpret_cast<uint32_t*>(savep), vreinterpret_u32_u8(t##i), 0), savep += vertex_size
+#endif
+
+#ifdef SIMD_WASM
+#define TEMP v128_t
+#define PREP() v128_t pi = wasm_v128_load(last_vertex + k)
+#define LOAD(i) v128_t r##i = wasm_v128_load(buffer + j + i * vertex_count_aligned)
+#define GRP4(i) t0 = wasmx_splat_v32x4(r##i, 0), t1 = wasmx_splat_v32x4(r##i, 1), t2 = wasmx_splat_v32x4(r##i, 2), t3 = wasmx_splat_v32x4(r##i, 3)
+#define FIXD(i) t##i = pi = wasm_i8x16_add(pi, t##i)
+#define SAVE(i) *reinterpret_cast<int*>(savep) = wasm_i32x4_extract_lane(t##i, 0), savep += vertex_size
+#endif
+
+ PREP();
+
+ unsigned char* savep = transposed + k;
+
+ for (size_t j = 0; j < vertex_count_aligned; j += 16)
+ {
+ LOAD(0);
+ LOAD(1);
+ LOAD(2);
+ LOAD(3);
+
+ r0 = unzigzag8(r0);
+ r1 = unzigzag8(r1);
+ r2 = unzigzag8(r2);
+ r3 = unzigzag8(r3);
+
+ transpose8(r0, r1, r2, r3);
+
+ TEMP t0, t1, t2, t3;
+
+ GRP4(0);
+ FIXD(0), FIXD(1), FIXD(2), FIXD(3);
+ SAVE(0), SAVE(1), SAVE(2), SAVE(3);
+
+ GRP4(1);
+ FIXD(0), FIXD(1), FIXD(2), FIXD(3);
+ SAVE(0), SAVE(1), SAVE(2), SAVE(3);
+
+ GRP4(2);
+ FIXD(0), FIXD(1), FIXD(2), FIXD(3);
+ SAVE(0), SAVE(1), SAVE(2), SAVE(3);
+
+ GRP4(3);
+ FIXD(0), FIXD(1), FIXD(2), FIXD(3);
+ SAVE(0), SAVE(1), SAVE(2), SAVE(3);
+
+#undef TEMP
+#undef PREP
+#undef LOAD
+#undef GRP4
+#undef FIXD
+#undef SAVE
+ }
+ }
+
+ memcpy(vertex_data, transposed, vertex_count * vertex_size);
+
+ memcpy(last_vertex, &transposed[vertex_size * (vertex_count - 1)], vertex_size);
+
+ return data;
+}
+#endif
+
+#if defined(SIMD_SSE) && defined(SIMD_FALLBACK)
+static unsigned int getCpuFeatures()
+{
+ int cpuinfo[4] = {};
+#ifdef _MSC_VER
+ __cpuid(cpuinfo, 1);
+#else
+ __cpuid(1, cpuinfo[0], cpuinfo[1], cpuinfo[2], cpuinfo[3]);
+#endif
+ return cpuinfo[2];
+}
+
+unsigned int cpuid = getCpuFeatures();
+#endif
+
+} // namespace meshopt
+
+size_t meshopt_encodeVertexBuffer(unsigned char* buffer, size_t buffer_size, const void* vertices, size_t vertex_count, size_t vertex_size)
+{
+ using namespace meshopt;
+
+ assert(vertex_size > 0 && vertex_size <= 256);
+ assert(vertex_size % 4 == 0);
+
+#if TRACE
+ memset(vertexstats, 0, sizeof(vertexstats));
+#endif
+
+ const unsigned char* vertex_data = static_cast<const unsigned char*>(vertices);
+
+ unsigned char* data = buffer;
+ unsigned char* data_end = buffer + buffer_size;
+
+ if (size_t(data_end - data) < 1 + vertex_size)
+ return 0;
+
+ int version = gEncodeVertexVersion;
+
+ *data++ = (unsigned char)(kVertexHeader | version);
+
+ unsigned char first_vertex[256] = {};
+ if (vertex_count > 0)
+ memcpy(first_vertex, vertex_data, vertex_size);
+
+ unsigned char last_vertex[256] = {};
+ memcpy(last_vertex, first_vertex, vertex_size);
+
+ size_t vertex_block_size = getVertexBlockSize(vertex_size);
+
+ size_t vertex_offset = 0;
+
+ while (vertex_offset < vertex_count)
+ {
+ size_t block_size = (vertex_offset + vertex_block_size < vertex_count) ? vertex_block_size : vertex_count - vertex_offset;
+
+ data = encodeVertexBlock(data, data_end, vertex_data + vertex_offset * vertex_size, block_size, vertex_size, last_vertex);
+ if (!data)
+ return 0;
+
+ vertex_offset += block_size;
+ }
+
+ size_t tail_size = vertex_size < kTailMaxSize ? kTailMaxSize : vertex_size;
+
+ if (size_t(data_end - data) < tail_size)
+ return 0;
+
+ // write first vertex to the end of the stream and pad it to 32 bytes; this is important to simplify bounds checks in decoder
+ if (vertex_size < kTailMaxSize)
+ {
+ memset(data, 0, kTailMaxSize - vertex_size);
+ data += kTailMaxSize - vertex_size;
+ }
+
+ memcpy(data, first_vertex, vertex_size);
+ data += vertex_size;
+
+ assert(data >= buffer + tail_size);
+ assert(data <= buffer + buffer_size);
+
+#if TRACE
+ size_t total_size = data - buffer;
+
+ for (size_t k = 0; k < vertex_size; ++k)
+ {
+ const Stats& vsk = vertexstats[k];
+
+ printf("%2d: %d bytes\t%.1f%%\t%.1f bpv", int(k), int(vsk.size), double(vsk.size) / double(total_size) * 100, double(vsk.size) / double(vertex_count) * 8);
+
+#if TRACE > 1
+ printf("\t\thdr %d bytes\tbit0 %d (%d bytes)\tbit1 %d (%d bytes)\tbit2 %d (%d bytes)\tbit3 %d (%d bytes)",
+ int(vsk.header),
+ int(vsk.bitg[0]), int(vsk.bitb[0]),
+ int(vsk.bitg[1]), int(vsk.bitb[1]),
+ int(vsk.bitg[2]), int(vsk.bitb[2]),
+ int(vsk.bitg[3]), int(vsk.bitb[3]));
+#endif
+
+ printf("\n");
+ }
+#endif
+
+ return data - buffer;
+}
+
+size_t meshopt_encodeVertexBufferBound(size_t vertex_count, size_t vertex_size)
+{
+ using namespace meshopt;
+
+ assert(vertex_size > 0 && vertex_size <= 256);
+ assert(vertex_size % 4 == 0);
+
+ size_t vertex_block_size = getVertexBlockSize(vertex_size);
+ size_t vertex_block_count = (vertex_count + vertex_block_size - 1) / vertex_block_size;
+
+ size_t vertex_block_header_size = (vertex_block_size / kByteGroupSize + 3) / 4;
+ size_t vertex_block_data_size = vertex_block_size;
+
+ size_t tail_size = vertex_size < kTailMaxSize ? kTailMaxSize : vertex_size;
+
+ return 1 + vertex_block_count * vertex_size * (vertex_block_header_size + vertex_block_data_size) + tail_size;
+}
+
+void meshopt_encodeVertexVersion(int version)
+{
+ assert(unsigned(version) <= 0);
+
+ meshopt::gEncodeVertexVersion = version;
+}
+
+int meshopt_decodeVertexBuffer(void* destination, size_t vertex_count, size_t vertex_size, const unsigned char* buffer, size_t buffer_size)
+{
+ using namespace meshopt;
+
+ assert(vertex_size > 0 && vertex_size <= 256);
+ assert(vertex_size % 4 == 0);
+
+ const unsigned char* (*decode)(const unsigned char*, const unsigned char*, unsigned char*, size_t, size_t, unsigned char[256]) = 0;
+
+#if defined(SIMD_SSE) && defined(SIMD_FALLBACK)
+ decode = (cpuid & (1 << 9)) ? decodeVertexBlockSimd : decodeVertexBlock;
+#elif defined(SIMD_SSE) || defined(SIMD_AVX) || defined(SIMD_NEON) || defined(SIMD_WASM)
+ decode = decodeVertexBlockSimd;
+#else
+ decode = decodeVertexBlock;
+#endif
+
+#if defined(SIMD_SSE) || defined(SIMD_NEON) || defined(SIMD_WASM)
+ assert(gDecodeBytesGroupInitialized);
+ (void)gDecodeBytesGroupInitialized;
+#endif
+
+ unsigned char* vertex_data = static_cast<unsigned char*>(destination);
+
+ const unsigned char* data = buffer;
+ const unsigned char* data_end = buffer + buffer_size;
+
+ if (size_t(data_end - data) < 1 + vertex_size)
+ return -2;
+
+ unsigned char data_header = *data++;
+
+ if ((data_header & 0xf0) != kVertexHeader)
+ return -1;
+
+ int version = data_header & 0x0f;
+ if (version > 0)
+ return -1;
+
+ unsigned char last_vertex[256];
+ memcpy(last_vertex, data_end - vertex_size, vertex_size);
+
+ size_t vertex_block_size = getVertexBlockSize(vertex_size);
+
+ size_t vertex_offset = 0;
+
+ while (vertex_offset < vertex_count)
+ {
+ size_t block_size = (vertex_offset + vertex_block_size < vertex_count) ? vertex_block_size : vertex_count - vertex_offset;
+
+ data = decode(data, data_end, vertex_data + vertex_offset * vertex_size, block_size, vertex_size, last_vertex);
+ if (!data)
+ return -2;
+
+ vertex_offset += block_size;
+ }
+
+ size_t tail_size = vertex_size < kTailMaxSize ? kTailMaxSize : vertex_size;
+
+ if (size_t(data_end - data) != tail_size)
+ return -3;
+
+ return 0;
+}
+
+#undef SIMD_NEON
+#undef SIMD_SSE
+#undef SIMD_AVX
+#undef SIMD_WASM
+#undef SIMD_FALLBACK
+#undef SIMD_TARGET
diff --git a/thirdparty/meshoptimizer/vertexfilter.cpp b/thirdparty/meshoptimizer/vertexfilter.cpp
new file mode 100644
index 0000000000..e7ad2c9d39
--- /dev/null
+++ b/thirdparty/meshoptimizer/vertexfilter.cpp
@@ -0,0 +1,825 @@
+// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
+#include "meshoptimizer.h"
+
+#include <math.h>
+
+// The block below auto-detects SIMD ISA that can be used on the target platform
+#ifndef MESHOPTIMIZER_NO_SIMD
+
+// The SIMD implementation requires SSE2, which can be enabled unconditionally through compiler settings
+#if defined(__SSE2__)
+#define SIMD_SSE
+#endif
+
+// MSVC supports compiling SSE2 code regardless of compile options; we assume all 32-bit CPUs support SSE2
+#if !defined(SIMD_SSE) && defined(_MSC_VER) && !defined(__clang__) && (defined(_M_IX86) || defined(_M_X64))
+#define SIMD_SSE
+#endif
+
+// GCC/clang define these when NEON support is available
+#if defined(__ARM_NEON__) || defined(__ARM_NEON)
+#define SIMD_NEON
+#endif
+
+// On MSVC, we assume that ARM builds always target NEON-capable devices
+#if !defined(SIMD_NEON) && defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
+#define SIMD_NEON
+#endif
+
+// When targeting Wasm SIMD we can't use runtime cpuid checks so we unconditionally enable SIMD
+#if defined(__wasm_simd128__)
+#define SIMD_WASM
+#endif
+
+#endif // !MESHOPTIMIZER_NO_SIMD
+
+#ifdef SIMD_SSE
+#include <emmintrin.h>
+#include <stdint.h>
+#endif
+
+#ifdef _MSC_VER
+#include <intrin.h>
+#endif
+
+#ifdef SIMD_NEON
+#if defined(_MSC_VER) && defined(_M_ARM64)
+#include <arm64_neon.h>
+#else
+#include <arm_neon.h>
+#endif
+#endif
+
+#ifdef SIMD_WASM
+#include <wasm_simd128.h>
+#endif
+
+#ifdef SIMD_WASM
+#define wasmx_unpacklo_v16x8(a, b) wasm_v16x8_shuffle(a, b, 0, 8, 1, 9, 2, 10, 3, 11)
+#define wasmx_unpackhi_v16x8(a, b) wasm_v16x8_shuffle(a, b, 4, 12, 5, 13, 6, 14, 7, 15)
+#define wasmx_unziplo_v32x4(a, b) wasm_v32x4_shuffle(a, b, 0, 2, 4, 6)
+#define wasmx_unziphi_v32x4(a, b) wasm_v32x4_shuffle(a, b, 1, 3, 5, 7)
+#endif
+
+namespace meshopt
+{
+
+#if !defined(SIMD_SSE) && !defined(SIMD_NEON) && !defined(SIMD_WASM)
+template <typename T>
+static void decodeFilterOct(T* data, size_t count)
+{
+ const float max = float((1 << (sizeof(T) * 8 - 1)) - 1);
+
+ for (size_t i = 0; i < count; ++i)
+ {
+ // convert x and y to floats and reconstruct z; this assumes zf encodes 1.f at the same bit count
+ float x = float(data[i * 4 + 0]);
+ float y = float(data[i * 4 + 1]);
+ float z = float(data[i * 4 + 2]) - fabsf(x) - fabsf(y);
+
+ // fixup octahedral coordinates for z<0
+ float t = (z >= 0.f) ? 0.f : z;
+
+ x += (x >= 0.f) ? t : -t;
+ y += (y >= 0.f) ? t : -t;
+
+ // compute normal length & scale
+ float l = sqrtf(x * x + y * y + z * z);
+ float s = max / l;
+
+ // rounded signed float->int
+ int xf = int(x * s + (x >= 0.f ? 0.5f : -0.5f));
+ int yf = int(y * s + (y >= 0.f ? 0.5f : -0.5f));
+ int zf = int(z * s + (z >= 0.f ? 0.5f : -0.5f));
+
+ data[i * 4 + 0] = T(xf);
+ data[i * 4 + 1] = T(yf);
+ data[i * 4 + 2] = T(zf);
+ }
+}
+
+static void decodeFilterQuat(short* data, size_t count)
+{
+ const float scale = 1.f / sqrtf(2.f);
+
+ for (size_t i = 0; i < count; ++i)
+ {
+ // recover scale from the high byte of the component
+ int sf = data[i * 4 + 3] | 3;
+ float ss = scale / float(sf);
+
+ // convert x/y/z to [-1..1] (scaled...)
+ float x = float(data[i * 4 + 0]) * ss;
+ float y = float(data[i * 4 + 1]) * ss;
+ float z = float(data[i * 4 + 2]) * ss;
+
+ // reconstruct w as a square root; we clamp to 0.f to avoid NaN due to precision errors
+ float ww = 1.f - x * x - y * y - z * z;
+ float w = sqrtf(ww >= 0.f ? ww : 0.f);
+
+ // rounded signed float->int
+ int xf = int(x * 32767.f + (x >= 0.f ? 0.5f : -0.5f));
+ int yf = int(y * 32767.f + (y >= 0.f ? 0.5f : -0.5f));
+ int zf = int(z * 32767.f + (z >= 0.f ? 0.5f : -0.5f));
+ int wf = int(w * 32767.f + 0.5f);
+
+ int qc = data[i * 4 + 3] & 3;
+
+ // output order is dictated by input index
+ data[i * 4 + ((qc + 1) & 3)] = short(xf);
+ data[i * 4 + ((qc + 2) & 3)] = short(yf);
+ data[i * 4 + ((qc + 3) & 3)] = short(zf);
+ data[i * 4 + ((qc + 0) & 3)] = short(wf);
+ }
+}
+
+static void decodeFilterExp(unsigned int* data, size_t count)
+{
+ for (size_t i = 0; i < count; ++i)
+ {
+ unsigned int v = data[i];
+
+ // decode mantissa and exponent
+ int m = int(v << 8) >> 8;
+ int e = int(v) >> 24;
+
+ union
+ {
+ float f;
+ unsigned int ui;
+ } u;
+
+ // optimized version of ldexp(float(m), e)
+ u.ui = unsigned(e + 127) << 23;
+ u.f = u.f * float(m);
+
+ data[i] = u.ui;
+ }
+}
+#endif
+
+#if defined(SIMD_SSE) || defined(SIMD_NEON) || defined(SIMD_WASM)
+inline uint64_t rotateleft64(uint64_t v, int x)
+{
+#if defined(_MSC_VER) && !defined(__clang__)
+ return _rotl64(v, x);
+// Apple's Clang 8 is actually vanilla Clang 3.9, there we need to look for
+// version 11 instead: https://en.wikipedia.org/wiki/Xcode#Toolchain_versions
+#elif defined(__clang__) && ((!defined(__apple_build_version__) && __clang_major__ >= 8) || __clang_major__ >= 11)
+ return __builtin_rotateleft64(v, x);
+#else
+ return (v << (x & 63)) | (v >> ((64 - x) & 63));
+#endif
+}
+#endif
+
+#ifdef SIMD_SSE
+static void decodeFilterOctSimd(signed char* data, size_t count)
+{
+ const __m128 sign = _mm_set1_ps(-0.f);
+
+ for (size_t i = 0; i < count; i += 4)
+ {
+ __m128i n4 = _mm_loadu_si128(reinterpret_cast<__m128i*>(&data[i * 4]));
+
+ // sign-extends each of x,y in [x y ? ?] with arithmetic shifts
+ __m128i xf = _mm_srai_epi32(_mm_slli_epi32(n4, 24), 24);
+ __m128i yf = _mm_srai_epi32(_mm_slli_epi32(n4, 16), 24);
+
+ // unpack z; note that z is unsigned so we technically don't need to sign extend it
+ __m128i zf = _mm_srai_epi32(_mm_slli_epi32(n4, 8), 24);
+
+ // convert x and y to floats and reconstruct z; this assumes zf encodes 1.f at the same bit count
+ __m128 x = _mm_cvtepi32_ps(xf);
+ __m128 y = _mm_cvtepi32_ps(yf);
+ __m128 z = _mm_sub_ps(_mm_cvtepi32_ps(zf), _mm_add_ps(_mm_andnot_ps(sign, x), _mm_andnot_ps(sign, y)));
+
+ // fixup octahedral coordinates for z<0
+ __m128 t = _mm_min_ps(z, _mm_setzero_ps());
+
+ x = _mm_add_ps(x, _mm_xor_ps(t, _mm_and_ps(x, sign)));
+ y = _mm_add_ps(y, _mm_xor_ps(t, _mm_and_ps(y, sign)));
+
+ // compute normal length & scale
+ __m128 ll = _mm_add_ps(_mm_mul_ps(x, x), _mm_add_ps(_mm_mul_ps(y, y), _mm_mul_ps(z, z)));
+ __m128 s = _mm_mul_ps(_mm_set1_ps(127.f), _mm_rsqrt_ps(ll));
+
+ // rounded signed float->int
+ __m128i xr = _mm_cvtps_epi32(_mm_mul_ps(x, s));
+ __m128i yr = _mm_cvtps_epi32(_mm_mul_ps(y, s));
+ __m128i zr = _mm_cvtps_epi32(_mm_mul_ps(z, s));
+
+ // combine xr/yr/zr into final value
+ __m128i res = _mm_and_si128(n4, _mm_set1_epi32(0xff000000));
+ res = _mm_or_si128(res, _mm_and_si128(xr, _mm_set1_epi32(0xff)));
+ res = _mm_or_si128(res, _mm_slli_epi32(_mm_and_si128(yr, _mm_set1_epi32(0xff)), 8));
+ res = _mm_or_si128(res, _mm_slli_epi32(_mm_and_si128(zr, _mm_set1_epi32(0xff)), 16));
+
+ _mm_storeu_si128(reinterpret_cast<__m128i*>(&data[i * 4]), res);
+ }
+}
+
+static void decodeFilterOctSimd(short* data, size_t count)
+{
+ const __m128 sign = _mm_set1_ps(-0.f);
+
+ for (size_t i = 0; i < count; i += 4)
+ {
+ __m128 n4_0 = _mm_loadu_ps(reinterpret_cast<float*>(&data[(i + 0) * 4]));
+ __m128 n4_1 = _mm_loadu_ps(reinterpret_cast<float*>(&data[(i + 2) * 4]));
+
+ // gather both x/y 16-bit pairs in each 32-bit lane
+ __m128i n4 = _mm_castps_si128(_mm_shuffle_ps(n4_0, n4_1, _MM_SHUFFLE(2, 0, 2, 0)));
+
+ // sign-extends each of x,y in [x y] with arithmetic shifts
+ __m128i xf = _mm_srai_epi32(_mm_slli_epi32(n4, 16), 16);
+ __m128i yf = _mm_srai_epi32(n4, 16);
+
+ // unpack z; note that z is unsigned so we don't need to sign extend it
+ __m128i z4 = _mm_castps_si128(_mm_shuffle_ps(n4_0, n4_1, _MM_SHUFFLE(3, 1, 3, 1)));
+ __m128i zf = _mm_and_si128(z4, _mm_set1_epi32(0x7fff));
+
+ // convert x and y to floats and reconstruct z; this assumes zf encodes 1.f at the same bit count
+ __m128 x = _mm_cvtepi32_ps(xf);
+ __m128 y = _mm_cvtepi32_ps(yf);
+ __m128 z = _mm_sub_ps(_mm_cvtepi32_ps(zf), _mm_add_ps(_mm_andnot_ps(sign, x), _mm_andnot_ps(sign, y)));
+
+ // fixup octahedral coordinates for z<0
+ __m128 t = _mm_min_ps(z, _mm_setzero_ps());
+
+ x = _mm_add_ps(x, _mm_xor_ps(t, _mm_and_ps(x, sign)));
+ y = _mm_add_ps(y, _mm_xor_ps(t, _mm_and_ps(y, sign)));
+
+ // compute normal length & scale
+ __m128 ll = _mm_add_ps(_mm_mul_ps(x, x), _mm_add_ps(_mm_mul_ps(y, y), _mm_mul_ps(z, z)));
+ __m128 s = _mm_div_ps(_mm_set1_ps(32767.f), _mm_sqrt_ps(ll));
+
+ // rounded signed float->int
+ __m128i xr = _mm_cvtps_epi32(_mm_mul_ps(x, s));
+ __m128i yr = _mm_cvtps_epi32(_mm_mul_ps(y, s));
+ __m128i zr = _mm_cvtps_epi32(_mm_mul_ps(z, s));
+
+ // mix x/z and y/0 to make 16-bit unpack easier
+ __m128i xzr = _mm_or_si128(_mm_and_si128(xr, _mm_set1_epi32(0xffff)), _mm_slli_epi32(zr, 16));
+ __m128i y0r = _mm_and_si128(yr, _mm_set1_epi32(0xffff));
+
+ // pack x/y/z using 16-bit unpacks; note that this has 0 where we should have .w
+ __m128i res_0 = _mm_unpacklo_epi16(xzr, y0r);
+ __m128i res_1 = _mm_unpackhi_epi16(xzr, y0r);
+
+ // patch in .w
+ res_0 = _mm_or_si128(res_0, _mm_and_si128(_mm_castps_si128(n4_0), _mm_set1_epi64x(0xffff000000000000)));
+ res_1 = _mm_or_si128(res_1, _mm_and_si128(_mm_castps_si128(n4_1), _mm_set1_epi64x(0xffff000000000000)));
+
+ _mm_storeu_si128(reinterpret_cast<__m128i*>(&data[(i + 0) * 4]), res_0);
+ _mm_storeu_si128(reinterpret_cast<__m128i*>(&data[(i + 2) * 4]), res_1);
+ }
+}
+
+static void decodeFilterQuatSimd(short* data, size_t count)
+{
+ const float scale = 1.f / sqrtf(2.f);
+
+ for (size_t i = 0; i < count; i += 4)
+ {
+ __m128 q4_0 = _mm_loadu_ps(reinterpret_cast<float*>(&data[(i + 0) * 4]));
+ __m128 q4_1 = _mm_loadu_ps(reinterpret_cast<float*>(&data[(i + 2) * 4]));
+
+ // gather both x/y 16-bit pairs in each 32-bit lane
+ __m128i q4_xy = _mm_castps_si128(_mm_shuffle_ps(q4_0, q4_1, _MM_SHUFFLE(2, 0, 2, 0)));
+ __m128i q4_zc = _mm_castps_si128(_mm_shuffle_ps(q4_0, q4_1, _MM_SHUFFLE(3, 1, 3, 1)));
+
+ // sign-extends each of x,y in [x y] with arithmetic shifts
+ __m128i xf = _mm_srai_epi32(_mm_slli_epi32(q4_xy, 16), 16);
+ __m128i yf = _mm_srai_epi32(q4_xy, 16);
+ __m128i zf = _mm_srai_epi32(_mm_slli_epi32(q4_zc, 16), 16);
+ __m128i cf = _mm_srai_epi32(q4_zc, 16);
+
+ // get a floating-point scaler using zc with bottom 2 bits set to 1 (which represents 1.f)
+ __m128i sf = _mm_or_si128(cf, _mm_set1_epi32(3));
+ __m128 ss = _mm_div_ps(_mm_set1_ps(scale), _mm_cvtepi32_ps(sf));
+
+ // convert x/y/z to [-1..1] (scaled...)
+ __m128 x = _mm_mul_ps(_mm_cvtepi32_ps(xf), ss);
+ __m128 y = _mm_mul_ps(_mm_cvtepi32_ps(yf), ss);
+ __m128 z = _mm_mul_ps(_mm_cvtepi32_ps(zf), ss);
+
+ // reconstruct w as a square root; we clamp to 0.f to avoid NaN due to precision errors
+ __m128 ww = _mm_sub_ps(_mm_set1_ps(1.f), _mm_add_ps(_mm_mul_ps(x, x), _mm_add_ps(_mm_mul_ps(y, y), _mm_mul_ps(z, z))));
+ __m128 w = _mm_sqrt_ps(_mm_max_ps(ww, _mm_setzero_ps()));
+
+ __m128 s = _mm_set1_ps(32767.f);
+
+ // rounded signed float->int
+ __m128i xr = _mm_cvtps_epi32(_mm_mul_ps(x, s));
+ __m128i yr = _mm_cvtps_epi32(_mm_mul_ps(y, s));
+ __m128i zr = _mm_cvtps_epi32(_mm_mul_ps(z, s));
+ __m128i wr = _mm_cvtps_epi32(_mm_mul_ps(w, s));
+
+ // mix x/z and w/y to make 16-bit unpack easier
+ __m128i xzr = _mm_or_si128(_mm_and_si128(xr, _mm_set1_epi32(0xffff)), _mm_slli_epi32(zr, 16));
+ __m128i wyr = _mm_or_si128(_mm_and_si128(wr, _mm_set1_epi32(0xffff)), _mm_slli_epi32(yr, 16));
+
+ // pack x/y/z/w using 16-bit unpacks; we pack wxyz by default (for qc=0)
+ __m128i res_0 = _mm_unpacklo_epi16(wyr, xzr);
+ __m128i res_1 = _mm_unpackhi_epi16(wyr, xzr);
+
+ // store results to stack so that we can rotate using scalar instructions
+ uint64_t res[4];
+ _mm_storeu_si128(reinterpret_cast<__m128i*>(&res[0]), res_0);
+ _mm_storeu_si128(reinterpret_cast<__m128i*>(&res[2]), res_1);
+
+ // rotate and store
+ uint64_t* out = reinterpret_cast<uint64_t*>(&data[i * 4]);
+
+ out[0] = rotateleft64(res[0], data[(i + 0) * 4 + 3] << 4);
+ out[1] = rotateleft64(res[1], data[(i + 1) * 4 + 3] << 4);
+ out[2] = rotateleft64(res[2], data[(i + 2) * 4 + 3] << 4);
+ out[3] = rotateleft64(res[3], data[(i + 3) * 4 + 3] << 4);
+ }
+}
+
+static void decodeFilterExpSimd(unsigned int* data, size_t count)
+{
+ for (size_t i = 0; i < count; i += 4)
+ {
+ __m128i v = _mm_loadu_si128(reinterpret_cast<__m128i*>(&data[i]));
+
+ // decode exponent into 2^x directly
+ __m128i ef = _mm_srai_epi32(v, 24);
+ __m128i es = _mm_slli_epi32(_mm_add_epi32(ef, _mm_set1_epi32(127)), 23);
+
+ // decode 24-bit mantissa into floating-point value
+ __m128i mf = _mm_srai_epi32(_mm_slli_epi32(v, 8), 8);
+ __m128 m = _mm_cvtepi32_ps(mf);
+
+ __m128 r = _mm_mul_ps(_mm_castsi128_ps(es), m);
+
+ _mm_storeu_ps(reinterpret_cast<float*>(&data[i]), r);
+ }
+}
+#endif
+
+#if defined(SIMD_NEON) && !defined(__aarch64__) && !defined(_M_ARM64)
+inline float32x4_t vsqrtq_f32(float32x4_t x)
+{
+ float32x4_t r = vrsqrteq_f32(x);
+ r = vmulq_f32(r, vrsqrtsq_f32(vmulq_f32(r, x), r)); // refine rsqrt estimate
+ return vmulq_f32(r, x);
+}
+
+inline float32x4_t vdivq_f32(float32x4_t x, float32x4_t y)
+{
+ float32x4_t r = vrecpeq_f32(y);
+ r = vmulq_f32(r, vrecpsq_f32(y, r)); // refine rcp estimate
+ return vmulq_f32(x, r);
+}
+#endif
+
+#ifdef SIMD_NEON
+static void decodeFilterOctSimd(signed char* data, size_t count)
+{
+ const int32x4_t sign = vdupq_n_s32(0x80000000);
+
+ for (size_t i = 0; i < count; i += 4)
+ {
+ int32x4_t n4 = vld1q_s32(reinterpret_cast<int32_t*>(&data[i * 4]));
+
+ // sign-extends each of x,y in [x y ? ?] with arithmetic shifts
+ int32x4_t xf = vshrq_n_s32(vshlq_n_s32(n4, 24), 24);
+ int32x4_t yf = vshrq_n_s32(vshlq_n_s32(n4, 16), 24);
+
+ // unpack z; note that z is unsigned so we technically don't need to sign extend it
+ int32x4_t zf = vshrq_n_s32(vshlq_n_s32(n4, 8), 24);
+
+ // convert x and y to floats and reconstruct z; this assumes zf encodes 1.f at the same bit count
+ float32x4_t x = vcvtq_f32_s32(xf);
+ float32x4_t y = vcvtq_f32_s32(yf);
+ float32x4_t z = vsubq_f32(vcvtq_f32_s32(zf), vaddq_f32(vabsq_f32(x), vabsq_f32(y)));
+
+ // fixup octahedral coordinates for z<0
+ float32x4_t t = vminq_f32(z, vdupq_n_f32(0.f));
+
+ x = vaddq_f32(x, vreinterpretq_f32_s32(veorq_s32(vreinterpretq_s32_f32(t), vandq_s32(vreinterpretq_s32_f32(x), sign))));
+ y = vaddq_f32(y, vreinterpretq_f32_s32(veorq_s32(vreinterpretq_s32_f32(t), vandq_s32(vreinterpretq_s32_f32(y), sign))));
+
+ // compute normal length & scale
+ float32x4_t ll = vaddq_f32(vmulq_f32(x, x), vaddq_f32(vmulq_f32(y, y), vmulq_f32(z, z)));
+ float32x4_t rl = vrsqrteq_f32(ll);
+ float32x4_t s = vmulq_f32(vdupq_n_f32(127.f), rl);
+
+ // fast rounded signed float->int: addition triggers renormalization after which mantissa stores the integer value
+ // note: the result is offset by 0x4B40_0000, but we only need the low 16 bits so we can omit the subtraction
+ const float32x4_t fsnap = vdupq_n_f32(3 << 22);
+
+ int32x4_t xr = vreinterpretq_s32_f32(vaddq_f32(vmulq_f32(x, s), fsnap));
+ int32x4_t yr = vreinterpretq_s32_f32(vaddq_f32(vmulq_f32(y, s), fsnap));
+ int32x4_t zr = vreinterpretq_s32_f32(vaddq_f32(vmulq_f32(z, s), fsnap));
+
+ // combine xr/yr/zr into final value
+ int32x4_t res = vandq_s32(n4, vdupq_n_s32(0xff000000));
+ res = vorrq_s32(res, vandq_s32(xr, vdupq_n_s32(0xff)));
+ res = vorrq_s32(res, vshlq_n_s32(vandq_s32(yr, vdupq_n_s32(0xff)), 8));
+ res = vorrq_s32(res, vshlq_n_s32(vandq_s32(zr, vdupq_n_s32(0xff)), 16));
+
+ vst1q_s32(reinterpret_cast<int32_t*>(&data[i * 4]), res);
+ }
+}
+
+static void decodeFilterOctSimd(short* data, size_t count)
+{
+ const int32x4_t sign = vdupq_n_s32(0x80000000);
+
+ for (size_t i = 0; i < count; i += 4)
+ {
+ int32x4_t n4_0 = vld1q_s32(reinterpret_cast<int32_t*>(&data[(i + 0) * 4]));
+ int32x4_t n4_1 = vld1q_s32(reinterpret_cast<int32_t*>(&data[(i + 2) * 4]));
+
+ // gather both x/y 16-bit pairs in each 32-bit lane
+ int32x4_t n4 = vuzpq_s32(n4_0, n4_1).val[0];
+
+ // sign-extends each of x,y in [x y] with arithmetic shifts
+ int32x4_t xf = vshrq_n_s32(vshlq_n_s32(n4, 16), 16);
+ int32x4_t yf = vshrq_n_s32(n4, 16);
+
+ // unpack z; note that z is unsigned so we don't need to sign extend it
+ int32x4_t z4 = vuzpq_s32(n4_0, n4_1).val[1];
+ int32x4_t zf = vandq_s32(z4, vdupq_n_s32(0x7fff));
+
+ // convert x and y to floats and reconstruct z; this assumes zf encodes 1.f at the same bit count
+ float32x4_t x = vcvtq_f32_s32(xf);
+ float32x4_t y = vcvtq_f32_s32(yf);
+ float32x4_t z = vsubq_f32(vcvtq_f32_s32(zf), vaddq_f32(vabsq_f32(x), vabsq_f32(y)));
+
+ // fixup octahedral coordinates for z<0
+ float32x4_t t = vminq_f32(z, vdupq_n_f32(0.f));
+
+ x = vaddq_f32(x, vreinterpretq_f32_s32(veorq_s32(vreinterpretq_s32_f32(t), vandq_s32(vreinterpretq_s32_f32(x), sign))));
+ y = vaddq_f32(y, vreinterpretq_f32_s32(veorq_s32(vreinterpretq_s32_f32(t), vandq_s32(vreinterpretq_s32_f32(y), sign))));
+
+ // compute normal length & scale
+ float32x4_t ll = vaddq_f32(vmulq_f32(x, x), vaddq_f32(vmulq_f32(y, y), vmulq_f32(z, z)));
+ float32x4_t rl = vrsqrteq_f32(ll);
+ rl = vmulq_f32(rl, vrsqrtsq_f32(vmulq_f32(rl, ll), rl)); // refine rsqrt estimate
+ float32x4_t s = vmulq_f32(vdupq_n_f32(32767.f), rl);
+
+ // fast rounded signed float->int: addition triggers renormalization after which mantissa stores the integer value
+ // note: the result is offset by 0x4B40_0000, but we only need the low 16 bits so we can omit the subtraction
+ const float32x4_t fsnap = vdupq_n_f32(3 << 22);
+
+ int32x4_t xr = vreinterpretq_s32_f32(vaddq_f32(vmulq_f32(x, s), fsnap));
+ int32x4_t yr = vreinterpretq_s32_f32(vaddq_f32(vmulq_f32(y, s), fsnap));
+ int32x4_t zr = vreinterpretq_s32_f32(vaddq_f32(vmulq_f32(z, s), fsnap));
+
+ // mix x/z and y/0 to make 16-bit unpack easier
+ int32x4_t xzr = vorrq_s32(vandq_s32(xr, vdupq_n_s32(0xffff)), vshlq_n_s32(zr, 16));
+ int32x4_t y0r = vandq_s32(yr, vdupq_n_s32(0xffff));
+
+ // pack x/y/z using 16-bit unpacks; note that this has 0 where we should have .w
+ int32x4_t res_0 = vreinterpretq_s32_s16(vzipq_s16(vreinterpretq_s16_s32(xzr), vreinterpretq_s16_s32(y0r)).val[0]);
+ int32x4_t res_1 = vreinterpretq_s32_s16(vzipq_s16(vreinterpretq_s16_s32(xzr), vreinterpretq_s16_s32(y0r)).val[1]);
+
+ // patch in .w
+ res_0 = vbslq_s32(vreinterpretq_u32_u64(vdupq_n_u64(0xffff000000000000)), n4_0, res_0);
+ res_1 = vbslq_s32(vreinterpretq_u32_u64(vdupq_n_u64(0xffff000000000000)), n4_1, res_1);
+
+ vst1q_s32(reinterpret_cast<int32_t*>(&data[(i + 0) * 4]), res_0);
+ vst1q_s32(reinterpret_cast<int32_t*>(&data[(i + 2) * 4]), res_1);
+ }
+}
+
+static void decodeFilterQuatSimd(short* data, size_t count)
+{
+ const float scale = 1.f / sqrtf(2.f);
+
+ for (size_t i = 0; i < count; i += 4)
+ {
+ int32x4_t q4_0 = vld1q_s32(reinterpret_cast<int32_t*>(&data[(i + 0) * 4]));
+ int32x4_t q4_1 = vld1q_s32(reinterpret_cast<int32_t*>(&data[(i + 2) * 4]));
+
+ // gather both x/y 16-bit pairs in each 32-bit lane
+ int32x4_t q4_xy = vuzpq_s32(q4_0, q4_1).val[0];
+ int32x4_t q4_zc = vuzpq_s32(q4_0, q4_1).val[1];
+
+ // sign-extends each of x,y in [x y] with arithmetic shifts
+ int32x4_t xf = vshrq_n_s32(vshlq_n_s32(q4_xy, 16), 16);
+ int32x4_t yf = vshrq_n_s32(q4_xy, 16);
+ int32x4_t zf = vshrq_n_s32(vshlq_n_s32(q4_zc, 16), 16);
+ int32x4_t cf = vshrq_n_s32(q4_zc, 16);
+
+ // get a floating-point scaler using zc with bottom 2 bits set to 1 (which represents 1.f)
+ int32x4_t sf = vorrq_s32(cf, vdupq_n_s32(3));
+ float32x4_t ss = vdivq_f32(vdupq_n_f32(scale), vcvtq_f32_s32(sf));
+
+ // convert x/y/z to [-1..1] (scaled...)
+ float32x4_t x = vmulq_f32(vcvtq_f32_s32(xf), ss);
+ float32x4_t y = vmulq_f32(vcvtq_f32_s32(yf), ss);
+ float32x4_t z = vmulq_f32(vcvtq_f32_s32(zf), ss);
+
+ // reconstruct w as a square root; we clamp to 0.f to avoid NaN due to precision errors
+ float32x4_t ww = vsubq_f32(vdupq_n_f32(1.f), vaddq_f32(vmulq_f32(x, x), vaddq_f32(vmulq_f32(y, y), vmulq_f32(z, z))));
+ float32x4_t w = vsqrtq_f32(vmaxq_f32(ww, vdupq_n_f32(0.f)));
+
+ float32x4_t s = vdupq_n_f32(32767.f);
+
+ // fast rounded signed float->int: addition triggers renormalization after which mantissa stores the integer value
+ // note: the result is offset by 0x4B40_0000, but we only need the low 16 bits so we can omit the subtraction
+ const float32x4_t fsnap = vdupq_n_f32(3 << 22);
+
+ int32x4_t xr = vreinterpretq_s32_f32(vaddq_f32(vmulq_f32(x, s), fsnap));
+ int32x4_t yr = vreinterpretq_s32_f32(vaddq_f32(vmulq_f32(y, s), fsnap));
+ int32x4_t zr = vreinterpretq_s32_f32(vaddq_f32(vmulq_f32(z, s), fsnap));
+ int32x4_t wr = vreinterpretq_s32_f32(vaddq_f32(vmulq_f32(w, s), fsnap));
+
+ // mix x/z and w/y to make 16-bit unpack easier
+ int32x4_t xzr = vorrq_s32(vandq_s32(xr, vdupq_n_s32(0xffff)), vshlq_n_s32(zr, 16));
+ int32x4_t wyr = vorrq_s32(vandq_s32(wr, vdupq_n_s32(0xffff)), vshlq_n_s32(yr, 16));
+
+ // pack x/y/z/w using 16-bit unpacks; we pack wxyz by default (for qc=0)
+ int32x4_t res_0 = vreinterpretq_s32_s16(vzipq_s16(vreinterpretq_s16_s32(wyr), vreinterpretq_s16_s32(xzr)).val[0]);
+ int32x4_t res_1 = vreinterpretq_s32_s16(vzipq_s16(vreinterpretq_s16_s32(wyr), vreinterpretq_s16_s32(xzr)).val[1]);
+
+ // rotate and store
+ uint64_t* out = (uint64_t*)&data[i * 4];
+
+ out[0] = rotateleft64(vgetq_lane_u64(vreinterpretq_u64_s32(res_0), 0), vgetq_lane_s32(cf, 0) << 4);
+ out[1] = rotateleft64(vgetq_lane_u64(vreinterpretq_u64_s32(res_0), 1), vgetq_lane_s32(cf, 1) << 4);
+ out[2] = rotateleft64(vgetq_lane_u64(vreinterpretq_u64_s32(res_1), 0), vgetq_lane_s32(cf, 2) << 4);
+ out[3] = rotateleft64(vgetq_lane_u64(vreinterpretq_u64_s32(res_1), 1), vgetq_lane_s32(cf, 3) << 4);
+ }
+}
+
+static void decodeFilterExpSimd(unsigned int* data, size_t count)
+{
+ for (size_t i = 0; i < count; i += 4)
+ {
+ int32x4_t v = vld1q_s32(reinterpret_cast<int32_t*>(&data[i]));
+
+ // decode exponent into 2^x directly
+ int32x4_t ef = vshrq_n_s32(v, 24);
+ int32x4_t es = vshlq_n_s32(vaddq_s32(ef, vdupq_n_s32(127)), 23);
+
+ // decode 24-bit mantissa into floating-point value
+ int32x4_t mf = vshrq_n_s32(vshlq_n_s32(v, 8), 8);
+ float32x4_t m = vcvtq_f32_s32(mf);
+
+ float32x4_t r = vmulq_f32(vreinterpretq_f32_s32(es), m);
+
+ vst1q_f32(reinterpret_cast<float*>(&data[i]), r);
+ }
+}
+#endif
+
+#ifdef SIMD_WASM
+static void decodeFilterOctSimd(signed char* data, size_t count)
+{
+ const v128_t sign = wasm_f32x4_splat(-0.f);
+
+ for (size_t i = 0; i < count; i += 4)
+ {
+ v128_t n4 = wasm_v128_load(&data[i * 4]);
+
+ // sign-extends each of x,y in [x y ? ?] with arithmetic shifts
+ v128_t xf = wasm_i32x4_shr(wasm_i32x4_shl(n4, 24), 24);
+ v128_t yf = wasm_i32x4_shr(wasm_i32x4_shl(n4, 16), 24);
+
+ // unpack z; note that z is unsigned so we technically don't need to sign extend it
+ v128_t zf = wasm_i32x4_shr(wasm_i32x4_shl(n4, 8), 24);
+
+ // convert x and y to floats and reconstruct z; this assumes zf encodes 1.f at the same bit count
+ v128_t x = wasm_f32x4_convert_i32x4(xf);
+ v128_t y = wasm_f32x4_convert_i32x4(yf);
+ v128_t z = wasm_f32x4_sub(wasm_f32x4_convert_i32x4(zf), wasm_f32x4_add(wasm_f32x4_abs(x), wasm_f32x4_abs(y)));
+
+ // fixup octahedral coordinates for z<0
+ // note: i32x4_min with 0 is equvalent to f32x4_min
+ v128_t t = wasm_i32x4_min(z, wasm_i32x4_splat(0));
+
+ x = wasm_f32x4_add(x, wasm_v128_xor(t, wasm_v128_and(x, sign)));
+ y = wasm_f32x4_add(y, wasm_v128_xor(t, wasm_v128_and(y, sign)));
+
+ // compute normal length & scale
+ v128_t ll = wasm_f32x4_add(wasm_f32x4_mul(x, x), wasm_f32x4_add(wasm_f32x4_mul(y, y), wasm_f32x4_mul(z, z)));
+ v128_t s = wasm_f32x4_div(wasm_f32x4_splat(127.f), wasm_f32x4_sqrt(ll));
+
+ // fast rounded signed float->int: addition triggers renormalization after which mantissa stores the integer value
+ // note: the result is offset by 0x4B40_0000, but we only need the low 8 bits so we can omit the subtraction
+ const v128_t fsnap = wasm_f32x4_splat(3 << 22);
+
+ v128_t xr = wasm_f32x4_add(wasm_f32x4_mul(x, s), fsnap);
+ v128_t yr = wasm_f32x4_add(wasm_f32x4_mul(y, s), fsnap);
+ v128_t zr = wasm_f32x4_add(wasm_f32x4_mul(z, s), fsnap);
+
+ // combine xr/yr/zr into final value
+ v128_t res = wasm_v128_and(n4, wasm_i32x4_splat(0xff000000));
+ res = wasm_v128_or(res, wasm_v128_and(xr, wasm_i32x4_splat(0xff)));
+ res = wasm_v128_or(res, wasm_i32x4_shl(wasm_v128_and(yr, wasm_i32x4_splat(0xff)), 8));
+ res = wasm_v128_or(res, wasm_i32x4_shl(wasm_v128_and(zr, wasm_i32x4_splat(0xff)), 16));
+
+ wasm_v128_store(&data[i * 4], res);
+ }
+}
+
+static void decodeFilterOctSimd(short* data, size_t count)
+{
+ const v128_t sign = wasm_f32x4_splat(-0.f);
+ const v128_t zmask = wasm_i32x4_splat(0x7fff);
+
+ for (size_t i = 0; i < count; i += 4)
+ {
+ v128_t n4_0 = wasm_v128_load(&data[(i + 0) * 4]);
+ v128_t n4_1 = wasm_v128_load(&data[(i + 2) * 4]);
+
+ // gather both x/y 16-bit pairs in each 32-bit lane
+ v128_t n4 = wasmx_unziplo_v32x4(n4_0, n4_1);
+
+ // sign-extends each of x,y in [x y] with arithmetic shifts
+ v128_t xf = wasm_i32x4_shr(wasm_i32x4_shl(n4, 16), 16);
+ v128_t yf = wasm_i32x4_shr(n4, 16);
+
+ // unpack z; note that z is unsigned so we don't need to sign extend it
+ v128_t z4 = wasmx_unziphi_v32x4(n4_0, n4_1);
+ v128_t zf = wasm_v128_and(z4, zmask);
+
+ // convert x and y to floats and reconstruct z; this assumes zf encodes 1.f at the same bit count
+ v128_t x = wasm_f32x4_convert_i32x4(xf);
+ v128_t y = wasm_f32x4_convert_i32x4(yf);
+ v128_t z = wasm_f32x4_sub(wasm_f32x4_convert_i32x4(zf), wasm_f32x4_add(wasm_f32x4_abs(x), wasm_f32x4_abs(y)));
+
+ // fixup octahedral coordinates for z<0
+ // note: i32x4_min with 0 is equvalent to f32x4_min
+ v128_t t = wasm_i32x4_min(z, wasm_i32x4_splat(0));
+
+ x = wasm_f32x4_add(x, wasm_v128_xor(t, wasm_v128_and(x, sign)));
+ y = wasm_f32x4_add(y, wasm_v128_xor(t, wasm_v128_and(y, sign)));
+
+ // compute normal length & scale
+ v128_t ll = wasm_f32x4_add(wasm_f32x4_mul(x, x), wasm_f32x4_add(wasm_f32x4_mul(y, y), wasm_f32x4_mul(z, z)));
+ v128_t s = wasm_f32x4_div(wasm_f32x4_splat(32767.f), wasm_f32x4_sqrt(ll));
+
+ // fast rounded signed float->int: addition triggers renormalization after which mantissa stores the integer value
+ // note: the result is offset by 0x4B40_0000, but we only need the low 16 bits so we can omit the subtraction
+ const v128_t fsnap = wasm_f32x4_splat(3 << 22);
+
+ v128_t xr = wasm_f32x4_add(wasm_f32x4_mul(x, s), fsnap);
+ v128_t yr = wasm_f32x4_add(wasm_f32x4_mul(y, s), fsnap);
+ v128_t zr = wasm_f32x4_add(wasm_f32x4_mul(z, s), fsnap);
+
+ // mix x/z and y/0 to make 16-bit unpack easier
+ v128_t xzr = wasm_v128_or(wasm_v128_and(xr, wasm_i32x4_splat(0xffff)), wasm_i32x4_shl(zr, 16));
+ v128_t y0r = wasm_v128_and(yr, wasm_i32x4_splat(0xffff));
+
+ // pack x/y/z using 16-bit unpacks; note that this has 0 where we should have .w
+ v128_t res_0 = wasmx_unpacklo_v16x8(xzr, y0r);
+ v128_t res_1 = wasmx_unpackhi_v16x8(xzr, y0r);
+
+ // patch in .w
+ res_0 = wasm_v128_or(res_0, wasm_v128_and(n4_0, wasm_i64x2_splat(0xffff000000000000)));
+ res_1 = wasm_v128_or(res_1, wasm_v128_and(n4_1, wasm_i64x2_splat(0xffff000000000000)));
+
+ wasm_v128_store(&data[(i + 0) * 4], res_0);
+ wasm_v128_store(&data[(i + 2) * 4], res_1);
+ }
+}
+
+static void decodeFilterQuatSimd(short* data, size_t count)
+{
+ const float scale = 1.f / sqrtf(2.f);
+
+ for (size_t i = 0; i < count; i += 4)
+ {
+ v128_t q4_0 = wasm_v128_load(&data[(i + 0) * 4]);
+ v128_t q4_1 = wasm_v128_load(&data[(i + 2) * 4]);
+
+ // gather both x/y 16-bit pairs in each 32-bit lane
+ v128_t q4_xy = wasmx_unziplo_v32x4(q4_0, q4_1);
+ v128_t q4_zc = wasmx_unziphi_v32x4(q4_0, q4_1);
+
+ // sign-extends each of x,y in [x y] with arithmetic shifts
+ v128_t xf = wasm_i32x4_shr(wasm_i32x4_shl(q4_xy, 16), 16);
+ v128_t yf = wasm_i32x4_shr(q4_xy, 16);
+ v128_t zf = wasm_i32x4_shr(wasm_i32x4_shl(q4_zc, 16), 16);
+ v128_t cf = wasm_i32x4_shr(q4_zc, 16);
+
+ // get a floating-point scaler using zc with bottom 2 bits set to 1 (which represents 1.f)
+ v128_t sf = wasm_v128_or(cf, wasm_i32x4_splat(3));
+ v128_t ss = wasm_f32x4_div(wasm_f32x4_splat(scale), wasm_f32x4_convert_i32x4(sf));
+
+ // convert x/y/z to [-1..1] (scaled...)
+ v128_t x = wasm_f32x4_mul(wasm_f32x4_convert_i32x4(xf), ss);
+ v128_t y = wasm_f32x4_mul(wasm_f32x4_convert_i32x4(yf), ss);
+ v128_t z = wasm_f32x4_mul(wasm_f32x4_convert_i32x4(zf), ss);
+
+ // reconstruct w as a square root; we clamp to 0.f to avoid NaN due to precision errors
+ // note: i32x4_max with 0 is equivalent to f32x4_max
+ v128_t ww = wasm_f32x4_sub(wasm_f32x4_splat(1.f), wasm_f32x4_add(wasm_f32x4_mul(x, x), wasm_f32x4_add(wasm_f32x4_mul(y, y), wasm_f32x4_mul(z, z))));
+ v128_t w = wasm_f32x4_sqrt(wasm_i32x4_max(ww, wasm_i32x4_splat(0)));
+
+ v128_t s = wasm_f32x4_splat(32767.f);
+
+ // fast rounded signed float->int: addition triggers renormalization after which mantissa stores the integer value
+ // note: the result is offset by 0x4B40_0000, but we only need the low 16 bits so we can omit the subtraction
+ const v128_t fsnap = wasm_f32x4_splat(3 << 22);
+
+ v128_t xr = wasm_f32x4_add(wasm_f32x4_mul(x, s), fsnap);
+ v128_t yr = wasm_f32x4_add(wasm_f32x4_mul(y, s), fsnap);
+ v128_t zr = wasm_f32x4_add(wasm_f32x4_mul(z, s), fsnap);
+ v128_t wr = wasm_f32x4_add(wasm_f32x4_mul(w, s), fsnap);
+
+ // mix x/z and w/y to make 16-bit unpack easier
+ v128_t xzr = wasm_v128_or(wasm_v128_and(xr, wasm_i32x4_splat(0xffff)), wasm_i32x4_shl(zr, 16));
+ v128_t wyr = wasm_v128_or(wasm_v128_and(wr, wasm_i32x4_splat(0xffff)), wasm_i32x4_shl(yr, 16));
+
+ // pack x/y/z/w using 16-bit unpacks; we pack wxyz by default (for qc=0)
+ v128_t res_0 = wasmx_unpacklo_v16x8(wyr, xzr);
+ v128_t res_1 = wasmx_unpackhi_v16x8(wyr, xzr);
+
+ // compute component index shifted left by 4 (and moved into i32x4 slot)
+ // TODO: volatile here works around LLVM mis-optimizing code; https://github.com/emscripten-core/emscripten/issues/11449
+ volatile v128_t cm = wasm_i32x4_shl(cf, 4);
+
+ // rotate and store
+ uint64_t* out = reinterpret_cast<uint64_t*>(&data[i * 4]);
+
+ out[0] = rotateleft64(wasm_i64x2_extract_lane(res_0, 0), wasm_i32x4_extract_lane(cm, 0));
+ out[1] = rotateleft64(wasm_i64x2_extract_lane(res_0, 1), wasm_i32x4_extract_lane(cm, 1));
+ out[2] = rotateleft64(wasm_i64x2_extract_lane(res_1, 0), wasm_i32x4_extract_lane(cm, 2));
+ out[3] = rotateleft64(wasm_i64x2_extract_lane(res_1, 1), wasm_i32x4_extract_lane(cm, 3));
+ }
+}
+
+static void decodeFilterExpSimd(unsigned int* data, size_t count)
+{
+ for (size_t i = 0; i < count; i += 4)
+ {
+ v128_t v = wasm_v128_load(&data[i]);
+
+ // decode exponent into 2^x directly
+ v128_t ef = wasm_i32x4_shr(v, 24);
+ v128_t es = wasm_i32x4_shl(wasm_i32x4_add(ef, wasm_i32x4_splat(127)), 23);
+
+ // decode 24-bit mantissa into floating-point value
+ v128_t mf = wasm_i32x4_shr(wasm_i32x4_shl(v, 8), 8);
+ v128_t m = wasm_f32x4_convert_i32x4(mf);
+
+ v128_t r = wasm_f32x4_mul(es, m);
+
+ wasm_v128_store(&data[i], r);
+ }
+}
+#endif
+
+} // namespace meshopt
+
+void meshopt_decodeFilterOct(void* buffer, size_t vertex_count, size_t vertex_size)
+{
+ using namespace meshopt;
+
+ assert(vertex_count % 4 == 0);
+ assert(vertex_size == 4 || vertex_size == 8);
+
+#if defined(SIMD_SSE) || defined(SIMD_NEON) || defined(SIMD_WASM)
+ if (vertex_size == 4)
+ decodeFilterOctSimd(static_cast<signed char*>(buffer), vertex_count);
+ else
+ decodeFilterOctSimd(static_cast<short*>(buffer), vertex_count);
+#else
+ if (vertex_size == 4)
+ decodeFilterOct(static_cast<signed char*>(buffer), vertex_count);
+ else
+ decodeFilterOct(static_cast<short*>(buffer), vertex_count);
+#endif
+}
+
+void meshopt_decodeFilterQuat(void* buffer, size_t vertex_count, size_t vertex_size)
+{
+ using namespace meshopt;
+
+ assert(vertex_count % 4 == 0);
+ assert(vertex_size == 8);
+ (void)vertex_size;
+
+#if defined(SIMD_SSE) || defined(SIMD_NEON) || defined(SIMD_WASM)
+ decodeFilterQuatSimd(static_cast<short*>(buffer), vertex_count);
+#else
+ decodeFilterQuat(static_cast<short*>(buffer), vertex_count);
+#endif
+}
+
+void meshopt_decodeFilterExp(void* buffer, size_t vertex_count, size_t vertex_size)
+{
+ using namespace meshopt;
+
+ assert(vertex_count % 4 == 0);
+ assert(vertex_size % 4 == 0);
+
+#if defined(SIMD_SSE) || defined(SIMD_NEON) || defined(SIMD_WASM)
+ decodeFilterExpSimd(static_cast<unsigned int*>(buffer), vertex_count * (vertex_size / 4));
+#else
+ decodeFilterExp(static_cast<unsigned int*>(buffer), vertex_count * (vertex_size / 4));
+#endif
+}
+
+#undef SIMD_SSE
+#undef SIMD_NEON
+#undef SIMD_WASM
diff --git a/thirdparty/meshoptimizer/vfetchanalyzer.cpp b/thirdparty/meshoptimizer/vfetchanalyzer.cpp
new file mode 100644
index 0000000000..51dca873f8
--- /dev/null
+++ b/thirdparty/meshoptimizer/vfetchanalyzer.cpp
@@ -0,0 +1,58 @@
+// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
+#include "meshoptimizer.h"
+
+#include <assert.h>
+#include <string.h>
+
+meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const unsigned int* indices, size_t index_count, size_t vertex_count, size_t vertex_size)
+{
+ assert(index_count % 3 == 0);
+ assert(vertex_size > 0 && vertex_size <= 256);
+
+ meshopt_Allocator allocator;
+
+ meshopt_VertexFetchStatistics result = {};
+
+ unsigned char* vertex_visited = allocator.allocate<unsigned char>(vertex_count);
+ memset(vertex_visited, 0, vertex_count);
+
+ const size_t kCacheLine = 64;
+ const size_t kCacheSize = 128 * 1024;
+
+ // simple direct mapped cache; on typical mesh data this is close to 4-way cache, and this model is a gross approximation anyway
+ size_t cache[kCacheSize / kCacheLine] = {};
+
+ for (size_t i = 0; i < index_count; ++i)
+ {
+ unsigned int index = indices[i];
+ assert(index < vertex_count);
+
+ vertex_visited[index] = 1;
+
+ size_t start_address = index * vertex_size;
+ size_t end_address = start_address + vertex_size;
+
+ size_t start_tag = start_address / kCacheLine;
+ size_t end_tag = (end_address + kCacheLine - 1) / kCacheLine;
+
+ assert(start_tag < end_tag);
+
+ for (size_t tag = start_tag; tag < end_tag; ++tag)
+ {
+ size_t line = tag % (sizeof(cache) / sizeof(cache[0]));
+
+ // we store +1 since cache is filled with 0 by default
+ result.bytes_fetched += (cache[line] != tag + 1) * kCacheLine;
+ cache[line] = tag + 1;
+ }
+ }
+
+ size_t unique_vertex_count = 0;
+
+ for (size_t i = 0; i < vertex_count; ++i)
+ unique_vertex_count += vertex_visited[i];
+
+ result.overfetch = unique_vertex_count == 0 ? 0 : float(result.bytes_fetched) / float(unique_vertex_count * vertex_size);
+
+ return result;
+}
diff --git a/thirdparty/meshoptimizer/vfetchoptimizer.cpp b/thirdparty/meshoptimizer/vfetchoptimizer.cpp
new file mode 100644
index 0000000000..465d6df5ca
--- /dev/null
+++ b/thirdparty/meshoptimizer/vfetchoptimizer.cpp
@@ -0,0 +1,74 @@
+// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
+#include "meshoptimizer.h"
+
+#include <assert.h>
+#include <string.h>
+
+size_t meshopt_optimizeVertexFetchRemap(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count)
+{
+ assert(index_count % 3 == 0);
+
+ memset(destination, -1, vertex_count * sizeof(unsigned int));
+
+ unsigned int next_vertex = 0;
+
+ for (size_t i = 0; i < index_count; ++i)
+ {
+ unsigned int index = indices[i];
+ assert(index < vertex_count);
+
+ if (destination[index] == ~0u)
+ {
+ destination[index] = next_vertex++;
+ }
+ }
+
+ assert(next_vertex <= vertex_count);
+
+ return next_vertex;
+}
+
+size_t meshopt_optimizeVertexFetch(void* destination, unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size)
+{
+ assert(index_count % 3 == 0);
+ assert(vertex_size > 0 && vertex_size <= 256);
+
+ meshopt_Allocator allocator;
+
+ // support in-place optimization
+ if (destination == vertices)
+ {
+ unsigned char* vertices_copy = allocator.allocate<unsigned char>(vertex_count * vertex_size);
+ memcpy(vertices_copy, vertices, vertex_count * vertex_size);
+ vertices = vertices_copy;
+ }
+
+ // build vertex remap table
+ unsigned int* vertex_remap = allocator.allocate<unsigned int>(vertex_count);
+ memset(vertex_remap, -1, vertex_count * sizeof(unsigned int));
+
+ unsigned int next_vertex = 0;
+
+ for (size_t i = 0; i < index_count; ++i)
+ {
+ unsigned int index = indices[i];
+ assert(index < vertex_count);
+
+ unsigned int& remap = vertex_remap[index];
+
+ if (remap == ~0u) // vertex was not added to destination VB
+ {
+ // add vertex
+ memcpy(static_cast<unsigned char*>(destination) + next_vertex * vertex_size, static_cast<const unsigned char*>(vertices) + index * vertex_size, vertex_size);
+
+ remap = next_vertex++;
+ }
+
+ // modify indices in place
+ indices[i] = remap;
+ }
+
+ assert(next_vertex <= vertex_count);
+
+ return next_vertex;
+}
diff --git a/thirdparty/rvo2/src/API.h b/thirdparty/rvo2/API.h
index c64efb452c..c64efb452c 100644
--- a/thirdparty/rvo2/src/API.h
+++ b/thirdparty/rvo2/API.h
diff --git a/thirdparty/rvo2/src/Agent.cpp b/thirdparty/rvo2/Agent.cpp
index 851d780758..851d780758 100644
--- a/thirdparty/rvo2/src/Agent.cpp
+++ b/thirdparty/rvo2/Agent.cpp
diff --git a/thirdparty/rvo2/src/Agent.h b/thirdparty/rvo2/Agent.h
index 16f75a08f6..16f75a08f6 100644
--- a/thirdparty/rvo2/src/Agent.h
+++ b/thirdparty/rvo2/Agent.h
diff --git a/thirdparty/rvo2/src/Definitions.h b/thirdparty/rvo2/Definitions.h
index a73aca9908..a73aca9908 100644
--- a/thirdparty/rvo2/src/Definitions.h
+++ b/thirdparty/rvo2/Definitions.h
diff --git a/thirdparty/rvo2/src/KdTree.cpp b/thirdparty/rvo2/KdTree.cpp
index bc224614f0..bc224614f0 100644
--- a/thirdparty/rvo2/src/KdTree.cpp
+++ b/thirdparty/rvo2/KdTree.cpp
diff --git a/thirdparty/rvo2/src/KdTree.h b/thirdparty/rvo2/KdTree.h
index 1dbad00ea4..1dbad00ea4 100644
--- a/thirdparty/rvo2/src/KdTree.h
+++ b/thirdparty/rvo2/KdTree.h
diff --git a/thirdparty/rvo2/src/Vector3.h b/thirdparty/rvo2/Vector3.h
index 8c8835c865..8c8835c865 100644
--- a/thirdparty/rvo2/src/Vector3.h
+++ b/thirdparty/rvo2/Vector3.h