summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/basis_universal/SCsub6
-rw-r--r--modules/basis_universal/register_types.cpp46
-rw-r--r--modules/basis_universal/register_types.h6
-rw-r--r--modules/bmp/image_loader_bmp.cpp13
-rw-r--r--modules/bmp/image_loader_bmp.h3
-rw-r--r--modules/bmp/register_types.cpp12
-rw-r--r--modules/bmp/register_types.h6
-rw-r--r--modules/camera/register_types.cpp11
-rw-r--r--modules/camera/register_types.h6
-rw-r--r--modules/csg/SCsub3
-rw-r--r--modules/csg/csg.cpp6
-rw-r--r--modules/csg/csg_shape.cpp2
-rw-r--r--modules/csg/csg_shape.h2
-rw-r--r--modules/csg/doc_classes/CSGSphere3D.xml2
-rw-r--r--modules/csg/editor/csg_gizmos.cpp (renamed from modules/csg/csg_gizmos.cpp)18
-rw-r--r--modules/csg/editor/csg_gizmos.h (renamed from modules/csg/csg_gizmos.h)6
-rw-r--r--modules/csg/register_types.cpp40
-rw-r--r--modules/csg/register_types.h6
-rw-r--r--modules/cvtt/image_compress_cvtt.cpp4
-rw-r--r--modules/cvtt/register_types.cpp12
-rw-r--r--modules/cvtt/register_types.h6
-rw-r--r--modules/dds/register_types.cpp12
-rw-r--r--modules/dds/register_types.h6
-rw-r--r--modules/dds/texture_loader_dds.cpp28
-rw-r--r--modules/dds/texture_loader_dds.h2
-rw-r--r--modules/denoise/register_types.cpp11
-rw-r--r--modules/denoise/register_types.h6
-rw-r--r--modules/enet/register_types.cpp12
-rw-r--r--modules/enet/register_types.h6
-rw-r--r--modules/etcpak/register_types.cpp11
-rw-r--r--modules/etcpak/register_types.h8
-rw-r--r--modules/fbx/README.md196
-rw-r--r--modules/fbx/SCsub18
-rw-r--r--modules/fbx/config.py16
-rw-r--r--modules/fbx/data/fbx_anim_container.h46
-rw-r--r--modules/fbx/data/fbx_bone.h90
-rw-r--r--modules/fbx/data/fbx_material.cpp468
-rw-r--r--modules/fbx/data/fbx_material.h285
-rw-r--r--modules/fbx/data/fbx_mesh_data.cpp1435
-rw-r--r--modules/fbx/data/fbx_mesh_data.h200
-rw-r--r--modules/fbx/data/fbx_skeleton.cpp130
-rw-r--r--modules/fbx/data/import_state.h112
-rw-r--r--modules/fbx/data/model_abstraction.h52
-rw-r--r--modules/fbx/data/pivot_transform.cpp307
-rw-r--r--modules/fbx/data/pivot_transform.h115
-rw-r--r--modules/fbx/editor_scene_importer_fbx.cpp1475
-rw-r--r--modules/fbx/editor_scene_importer_fbx.h137
-rw-r--r--modules/fbx/fbx_parser/ByteSwapper.h283
-rw-r--r--modules/fbx/fbx_parser/CREDITS183
-rw-r--r--modules/fbx/fbx_parser/FBXAnimation.cpp273
-rw-r--r--modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp442
-rw-r--r--modules/fbx/fbx_parser/FBXCommon.h110
-rw-r--r--modules/fbx/fbx_parser/FBXDeformer.cpp271
-rw-r--r--modules/fbx/fbx_parser/FBXDocument.cpp636
-rw-r--r--modules/fbx/fbx_parser/FBXDocument.h1252
-rw-r--r--modules/fbx/fbx_parser/FBXDocumentUtil.cpp141
-rw-r--r--modules/fbx/fbx_parser/FBXDocumentUtil.h134
-rw-r--r--modules/fbx/fbx_parser/FBXImportSettings.h162
-rw-r--r--modules/fbx/fbx_parser/FBXMaterial.cpp388
-rw-r--r--modules/fbx/fbx_parser/FBXMeshGeometry.cpp459
-rw-r--r--modules/fbx/fbx_parser/FBXMeshGeometry.h263
-rw-r--r--modules/fbx/fbx_parser/FBXModel.cpp171
-rw-r--r--modules/fbx/fbx_parser/FBXNodeAttribute.cpp174
-rw-r--r--modules/fbx/fbx_parser/FBXParseTools.h111
-rw-r--r--modules/fbx/fbx_parser/FBXParser.cpp1322
-rw-r--r--modules/fbx/fbx_parser/FBXParser.h270
-rw-r--r--modules/fbx/fbx_parser/FBXPose.cpp104
-rw-r--r--modules/fbx/fbx_parser/FBXProperties.cpp245
-rw-r--r--modules/fbx/fbx_parser/FBXProperties.h212
-rw-r--r--modules/fbx/fbx_parser/FBXTokenizer.cpp253
-rw-r--r--modules/fbx/fbx_parser/FBXTokenizer.h203
-rw-r--r--modules/fbx/fbx_parser/FBXUtil.cpp222
-rw-r--r--modules/fbx/fbx_parser/FBXUtil.h122
-rw-r--r--modules/fbx/fbx_parser/LICENSE39
-rw-r--r--modules/fbx/tools/import_utils.cpp151
-rw-r--r--modules/fbx/tools/import_utils.h400
-rw-r--r--modules/freetype/SCsub20
-rw-r--r--modules/freetype/register_types.cpp12
-rw-r--r--modules/freetype/register_types.h6
-rw-r--r--modules/gdscript/SCsub5
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml2
-rw-r--r--modules/gdscript/editor/gdscript_translation_parser_plugin.cpp2
-rw-r--r--modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd (renamed from modules/gdscript/editor_templates/CharacterBody2D/basic_movement.gd)5
-rw-r--r--modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd (renamed from modules/gdscript/editor_templates/CharacterBody3D/basic_movement.gd)5
-rw-r--r--modules/gdscript/editor/script_templates/EditorPlugin/plugin.gd (renamed from modules/gdscript/editor_templates/EditorPlugin/plugin.gd)10
-rw-r--r--modules/gdscript/editor/script_templates/EditorScript/basic_editor_script.gd (renamed from modules/gdscript/editor_templates/EditorScript/basic_editor_script.gd)5
-rw-r--r--modules/gdscript/editor/script_templates/Node/default.gd (renamed from modules/gdscript/editor_templates/Node/default.gd)2
-rw-r--r--modules/gdscript/editor/script_templates/Object/empty.gd (renamed from modules/gdscript/editor_templates/Object/empty.gd)0
-rw-r--r--modules/gdscript/editor/script_templates/SCsub (renamed from modules/gdscript/editor_templates/SCsub)0
-rw-r--r--modules/gdscript/editor/script_templates/VisualShaderNodeCustom/basic.gd (renamed from modules/gdscript/editor_templates/VisualShaderNodeCustom/basic.gd)16
-rw-r--r--modules/gdscript/gdscript.cpp74
-rw-r--r--modules/gdscript/gdscript.h30
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp123
-rw-r--r--modules/gdscript/gdscript_analyzer.h3
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp24
-rw-r--r--modules/gdscript/gdscript_byte_codegen.h3
-rw-r--r--modules/gdscript/gdscript_cache.cpp3
-rw-r--r--modules/gdscript/gdscript_codegen.h3
-rw-r--r--modules/gdscript/gdscript_compiler.cpp9
-rw-r--r--modules/gdscript/gdscript_disassembler.cpp43
-rw-r--r--modules/gdscript/gdscript_editor.cpp456
-rw-r--r--modules/gdscript/gdscript_function.h4
-rw-r--r--modules/gdscript/gdscript_lambda_callable.cpp78
-rw-r--r--modules/gdscript/gdscript_lambda_callable.h25
-rw-r--r--modules/gdscript/gdscript_parser.cpp22
-rw-r--r--modules/gdscript/gdscript_parser.h6
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp2
-rw-r--r--modules/gdscript/gdscript_utility_functions.cpp12
-rw-r--r--modules/gdscript/gdscript_vm.cpp92
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.cpp4
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp30
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.h3
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.cpp8
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.h2
-rw-r--r--modules/gdscript/register_types.cpp70
-rw-r--r--modules/gdscript/register_types.h6
-rw-r--r--modules/gdscript/tests/gdscript_test_runner.cpp13
-rw-r--r--modules/gdscript/tests/gdscript_test_runner.h4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/arrays_dictionaries_nested_const.gd58
-rw-r--r--modules/gdscript/tests/scripts/parser/features/arrays_dictionaries_nested_const.out5
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/lambda_use_self.gd23
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/lambda_use_self.out5
-rw-r--r--modules/gdscript/tests/test_gdscript.cpp4
-rw-r--r--modules/glslang/register_types.cpp13
-rw-r--r--modules/glslang/register_types.h7
-rw-r--r--modules/gltf/SCsub3
-rw-r--r--modules/gltf/config.py8
-rw-r--r--modules/gltf/doc_classes/EditorSceneFormatImporterBlend.xml15
-rw-r--r--modules/gltf/doc_classes/EditorSceneFormatImporterFBX.xml13
-rw-r--r--modules/gltf/doc_classes/EditorSceneFormatImporterGLTF.xml9
-rw-r--r--modules/gltf/doc_classes/GLTFDocument.xml1
-rw-r--r--modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp (renamed from modules/gltf/editor_scene_exporter_gltf_plugin.cpp)20
-rw-r--r--modules/gltf/editor/editor_scene_exporter_gltf_plugin.h (renamed from modules/gltf/editor_scene_exporter_gltf_plugin.h)5
-rw-r--r--modules/gltf/editor/editor_scene_importer_blend.cpp575
-rw-r--r--modules/gltf/editor/editor_scene_importer_blend.h112
-rw-r--r--modules/gltf/editor/editor_scene_importer_fbx.cpp117
-rw-r--r--modules/gltf/editor/editor_scene_importer_fbx.h (renamed from modules/fbx/tools/validation_tools.cpp)34
-rw-r--r--modules/gltf/editor/editor_scene_importer_gltf.cpp (renamed from modules/gltf/editor_scene_importer_gltf.cpp)30
-rw-r--r--modules/gltf/editor/editor_scene_importer_gltf.h (renamed from modules/gltf/editor_scene_importer_gltf.h)15
-rw-r--r--modules/gltf/gltf_document.cpp201
-rw-r--r--modules/gltf/gltf_document.h6
-rw-r--r--modules/gltf/gltf_mesh.cpp1
-rw-r--r--modules/gltf/gltf_mesh.h2
-rw-r--r--modules/gltf/gltf_state.cpp8
-rw-r--r--modules/gltf/gltf_state.h4
-rw-r--r--modules/gltf/register_types.cpp127
-rw-r--r--modules/gltf/register_types.h6
-rw-r--r--modules/gridmap/SCsub3
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.cpp (renamed from modules/gridmap/grid_map_editor_plugin.cpp)8
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.h (renamed from modules/gridmap/grid_map_editor_plugin.h)44
-rw-r--r--modules/gridmap/grid_map.cpp2
-rw-r--r--modules/gridmap/grid_map.h2
-rw-r--r--modules/gridmap/register_types.cpp27
-rw-r--r--modules/gridmap/register_types.h6
-rw-r--r--modules/hdr/image_loader_hdr.cpp4
-rw-r--r--modules/hdr/image_loader_hdr.h2
-rw-r--r--modules/hdr/register_types.cpp12
-rw-r--r--modules/hdr/register_types.h6
-rw-r--r--modules/jpg/image_loader_jpegd.cpp4
-rw-r--r--modules/jpg/image_loader_jpegd.h2
-rw-r--r--modules/jpg/register_types.cpp12
-rw-r--r--modules/jpg/register_types.h6
-rw-r--r--modules/jsonrpc/register_types.cpp11
-rw-r--r--modules/jsonrpc/register_types.h6
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.cpp47
-rw-r--r--modules/lightmapper_rd/register_types.cpp11
-rw-r--r--modules/lightmapper_rd/register_types.h6
-rw-r--r--modules/mbedtls/crypto_mbedtls.cpp22
-rw-r--r--modules/mbedtls/packet_peer_mbed_dtls.cpp10
-rw-r--r--modules/mbedtls/register_types.cpp12
-rw-r--r--modules/mbedtls/register_types.h6
-rw-r--r--modules/mbedtls/stream_peer_mbedtls.cpp8
-rw-r--r--modules/meshoptimizer/register_types.cpp12
-rw-r--r--modules/meshoptimizer/register_types.h6
-rw-r--r--modules/minimp3/register_types.cpp11
-rw-r--r--modules/minimp3/register_types.h6
-rw-r--r--modules/minimp3/resource_importer_mp3.cpp7
-rw-r--r--modules/mobile_vr/mobile_vr_interface.cpp12
-rw-r--r--modules/mobile_vr/register_types.cpp12
-rw-r--r--modules/mobile_vr/register_types.h6
-rw-r--r--modules/mono/SCsub3
-rw-r--r--modules/mono/class_db_api_json.cpp5
-rw-r--r--modules/mono/csharp_script.cpp42
-rw-r--r--modules/mono/csharp_script.h12
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs4
-rw-r--r--modules/mono/editor/bindings_generator.cpp85
-rw-r--r--modules/mono/editor/bindings_generator.h5
-rw-r--r--modules/mono/editor/code_completion.cpp2
-rw-r--r--modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs (renamed from modules/mono/editor_templates/CharacterBody2D/basic_movement.cs)0
-rw-r--r--modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs (renamed from modules/mono/editor_templates/CharacterBody3D/basic_movement.cs)0
-rw-r--r--modules/mono/editor/script_templates/EditorPlugin/plugin.cs (renamed from modules/mono/editor_templates/EditorPlugin/plugin.cs)1
-rw-r--r--modules/mono/editor/script_templates/EditorScript/basic_editor_script.cs (renamed from modules/mono/editor_templates/EditorScript/basic_editor_script.cs)3
-rw-r--r--modules/mono/editor/script_templates/Node/default.cs (renamed from modules/mono/editor_templates/Node/default.cs)2
-rw-r--r--modules/mono/editor/script_templates/Object/empty.cs (renamed from modules/mono/editor_templates/Object/empty.cs)1
-rw-r--r--modules/mono/editor/script_templates/SCsub (renamed from modules/mono/editor_templates/SCsub)0
-rw-r--r--modules/mono/editor/script_templates/VisualShaderNodeCustom/basic.cs (renamed from modules/mono/editor_templates/VisualShaderNodeCustom/basic.cs)0
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs8
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs4
-rw-r--r--modules/mono/glue/arguments_vector.h2
-rw-r--r--modules/mono/glue/base_object_glue.cpp2
-rw-r--r--modules/mono/godotsharp_dirs.cpp2
-rw-r--r--modules/mono/managed_callable.h2
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp4
-rw-r--r--modules/mono/mono_gd/gd_mono.h18
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.h4
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.h144
-rw-r--r--modules/mono/mono_gd/gd_mono_class.cpp2
-rw-r--r--modules/mono/mono_gd/gd_mono_class.h6
-rw-r--r--modules/mono/mono_gd/gd_mono_field.h6
-rw-r--r--modules/mono/mono_gd/gd_mono_log.cpp28
-rw-r--r--modules/mono/mono_gd/gd_mono_log.h2
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.h22
-rw-r--r--modules/mono/mono_gd/gd_mono_method.h2
-rw-r--r--modules/mono/mono_gd/gd_mono_property.h6
-rw-r--r--modules/mono/mono_gd/gd_mono_wasm_m2n.h4
-rw-r--r--modules/mono/register_types.cpp12
-rw-r--r--modules/mono/register_types.h6
-rw-r--r--modules/mono/signal_awaiter_utils.h2
-rw-r--r--modules/mono/utils/string_utils.cpp4
-rw-r--r--modules/msdfgen/register_types.cpp12
-rw-r--r--modules/msdfgen/register_types.h6
-rw-r--r--modules/navigation/SCsub2
-rw-r--r--modules/navigation/editor/navigation_mesh_editor_plugin.cpp (renamed from modules/navigation/navigation_mesh_editor_plugin.cpp)7
-rw-r--r--modules/navigation/editor/navigation_mesh_editor_plugin.h (renamed from modules/navigation/navigation_mesh_editor_plugin.h)18
-rw-r--r--modules/navigation/godot_navigation_server.cpp76
-rw-r--r--modules/navigation/godot_navigation_server.h52
-rw-r--r--modules/navigation/nav_map.cpp32
-rw-r--r--modules/navigation/nav_map.h7
-rw-r--r--modules/navigation/nav_utils.h2
-rw-r--r--modules/navigation/navigation_mesh_generator.cpp122
-rw-r--r--modules/navigation/navigation_mesh_generator.h1
-rw-r--r--modules/navigation/register_types.cpp24
-rw-r--r--modules/navigation/register_types.h6
-rw-r--r--modules/noise/SCsub (renamed from modules/opensimplex/SCsub)13
-rw-r--r--modules/noise/config.py (renamed from modules/opensimplex/config.py)3
-rw-r--r--modules/noise/doc_classes/FastNoiseLite.xml163
-rw-r--r--modules/noise/doc_classes/Noise.xml74
-rw-r--r--modules/noise/doc_classes/NoiseTexture.xml58
-rw-r--r--modules/noise/editor/noise_editor_plugin.cpp149
-rw-r--r--modules/noise/editor/noise_editor_plugin.h (renamed from modules/fbx/register_types.h)24
-rw-r--r--modules/noise/fastnoise_lite.cpp486
-rw-r--r--modules/noise/fastnoise_lite.h224
-rw-r--r--modules/noise/icons/NoiseTexture.svg (renamed from modules/opensimplex/icons/NoiseTexture.svg)0
-rw-r--r--modules/noise/noise.cpp116
-rw-r--r--modules/noise/noise.h240
-rw-r--r--modules/noise/noise_texture.cpp (renamed from modules/opensimplex/noise_texture.cpp)150
-rw-r--r--modules/noise/noise_texture.h (renamed from modules/opensimplex/noise_texture.h)37
-rw-r--r--modules/noise/register_types.cpp (renamed from modules/fbx/register_types.cpp)36
-rw-r--r--modules/noise/register_types.h (renamed from modules/opensimplex/register_types.h)12
-rw-r--r--modules/ogg/register_types.cpp12
-rw-r--r--modules/ogg/register_types.h6
-rw-r--r--modules/opensimplex/doc_classes/NoiseTexture.xml44
-rw-r--r--modules/opensimplex/doc_classes/OpenSimplexNoise.xml112
-rw-r--r--modules/opensimplex/open_simplex_noise.cpp250
-rw-r--r--modules/opensimplex/open_simplex_noise.h99
-rw-r--r--modules/opensimplex/register_types.cpp41
-rw-r--r--modules/openxr/SCsub5
-rw-r--r--modules/openxr/action_map/openxr_action.cpp23
-rw-r--r--modules/openxr/action_map/openxr_action.h29
-rw-r--r--modules/openxr/action_map/openxr_action_map.cpp262
-rw-r--r--modules/openxr/action_map/openxr_action_map.h34
-rw-r--r--modules/openxr/action_map/openxr_action_set.cpp44
-rw-r--r--modules/openxr/action_map/openxr_action_set.h25
-rw-r--r--modules/openxr/action_map/openxr_defs.cpp493
-rw-r--r--modules/openxr/action_map/openxr_defs.h103
-rw-r--r--modules/openxr/action_map/openxr_interaction_profile.cpp61
-rw-r--r--modules/openxr/action_map/openxr_interaction_profile.h40
-rw-r--r--modules/openxr/doc_classes/OpenXRActionMap.xml44
-rw-r--r--modules/openxr/doc_classes/OpenXRActionSet.xml9
-rw-r--r--modules/openxr/doc_classes/OpenXRIPBinding.xml33
-rw-r--r--modules/openxr/doc_classes/OpenXRInteractionProfile.xml15
-rw-r--r--modules/openxr/editor/SCsub5
-rw-r--r--modules/openxr/editor/openxr_action_editor.cpp112
-rw-r--r--modules/openxr/editor/openxr_action_editor.h67
-rw-r--r--modules/openxr/editor/openxr_action_map_editor.cpp370
-rw-r--r--modules/openxr/editor/openxr_action_map_editor.h100
-rw-r--r--modules/openxr/editor/openxr_action_set_editor.cpp218
-rw-r--r--modules/openxr/editor/openxr_action_set_editor.h88
-rw-r--r--modules/openxr/editor/openxr_editor_plugin.cpp (renamed from modules/fbx/data/fbx_bone.cpp)42
-rw-r--r--modules/openxr/editor/openxr_editor_plugin.h (renamed from modules/fbx/data/fbx_skeleton.h)34
-rw-r--r--modules/openxr/editor/openxr_interaction_profile_editor.cpp274
-rw-r--r--modules/openxr/editor/openxr_interaction_profile_editor.h (renamed from modules/fbx/tools/validation_tools.h)101
-rw-r--r--modules/openxr/editor/openxr_select_action_dialog.cpp135
-rw-r--r--modules/openxr/editor/openxr_select_action_dialog.h (renamed from modules/fbx/data/fbx_node.h)54
-rw-r--r--modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp125
-rw-r--r--modules/openxr/editor/openxr_select_interaction_profile_dialog.h66
-rw-r--r--modules/openxr/extensions/openxr_extension_wrapper.h3
-rw-r--r--modules/openxr/extensions/openxr_vulkan_extension.cpp9
-rw-r--r--modules/openxr/extensions/openxr_vulkan_extension.h10
-rw-r--r--modules/openxr/openxr_api.cpp95
-rw-r--r--modules/openxr/openxr_api.h21
-rw-r--r--modules/openxr/openxr_interface.cpp6
-rw-r--r--modules/openxr/openxr_interface.h2
-rw-r--r--modules/openxr/register_types.cpp80
-rw-r--r--modules/openxr/register_types.h7
-rw-r--r--modules/raycast/raycast_occlusion_cull.cpp4
-rw-r--r--modules/raycast/raycast_occlusion_cull.h4
-rw-r--r--modules/raycast/register_types.cpp12
-rw-r--r--modules/raycast/register_types.h6
-rw-r--r--modules/regex/regex.h2
-rw-r--r--modules/regex/register_types.cpp11
-rw-r--r--modules/regex/register_types.h6
-rw-r--r--modules/register_module_types.h14
-rw-r--r--modules/squish/register_types.cpp12
-rw-r--r--modules/squish/register_types.h6
-rw-r--r--modules/svg/image_loader_svg.cpp2
-rw-r--r--modules/svg/image_loader_svg.h2
-rw-r--r--modules/svg/register_types.cpp14
-rw-r--r--modules/svg/register_types.h6
-rw-r--r--modules/text_server_adv/.gitignore2
-rw-r--r--modules/text_server_adv/SCsub80
-rw-r--r--modules/text_server_adv/doc_classes/TextServerAdvanced.xml2
-rw-r--r--modules/text_server_adv/gdextension_build/SConstruct645
-rw-r--r--modules/text_server_adv/gdextension_build/methods.py130
-rw-r--r--modules/text_server_adv/gdextension_build/text_server_adv.gdextension12
-rw-r--r--modules/text_server_adv/register_types.cpp39
-rw-r--r--modules/text_server_adv/register_types.h12
-rw-r--r--modules/text_server_adv/script_iterator.cpp4
-rw-r--r--modules/text_server_adv/script_iterator.h17
-rw-r--r--modules/text_server_adv/text_server_adv.cpp1621
-rw-r--r--modules/text_server_adv/text_server_adv.h478
-rw-r--r--modules/text_server_fb/.gitignore2
-rw-r--r--modules/text_server_fb/SCsub18
-rw-r--r--modules/text_server_fb/doc_classes/TextServerFallback.xml2
-rw-r--r--modules/text_server_fb/gdextension_build/SConstruct205
-rw-r--r--modules/text_server_fb/gdextension_build/methods.py130
-rw-r--r--modules/text_server_fb/gdextension_build/text_server_fb.gdextension12
-rw-r--r--modules/text_server_fb/register_types.cpp39
-rw-r--r--modules/text_server_fb/register_types.h12
-rw-r--r--modules/text_server_fb/text_server_fb.cpp1032
-rw-r--r--modules/text_server_fb/text_server_fb.h446
-rw-r--r--modules/tga/image_loader_tga.cpp11
-rw-r--r--modules/tga/image_loader_tga.h2
-rw-r--r--modules/tga/register_types.cpp12
-rw-r--r--modules/tga/register_types.h6
-rw-r--r--modules/theora/register_types.cpp12
-rw-r--r--modules/theora/register_types.h6
-rw-r--r--modules/theora/video_stream_theora.cpp34
-rw-r--r--modules/theora/video_stream_theora.h8
-rw-r--r--modules/tinyexr/image_loader_tinyexr.cpp8
-rw-r--r--modules/tinyexr/image_loader_tinyexr.h2
-rw-r--r--modules/tinyexr/image_saver_tinyexr.cpp4
-rw-r--r--modules/tinyexr/register_types.cpp12
-rw-r--r--modules/tinyexr/register_types.h6
-rw-r--r--modules/upnp/register_types.cpp11
-rw-r--r--modules/upnp/register_types.h6
-rw-r--r--modules/vhacd/register_types.cpp12
-rw-r--r--modules/vhacd/register_types.h6
-rw-r--r--modules/visual_script/doc_classes/VisualScript.xml2
-rw-r--r--modules/visual_script/editor/visual_script_editor.cpp50
-rw-r--r--modules/visual_script/editor/visual_script_editor.h7
-rw-r--r--modules/visual_script/editor/visual_script_property_selector.cpp65
-rw-r--r--modules/visual_script/editor/visual_script_property_selector.h52
-rw-r--r--modules/visual_script/register_types.cpp171
-rw-r--r--modules/visual_script/register_types.h6
-rw-r--r--modules/visual_script/visual_script.cpp2
-rw-r--r--modules/visual_script/visual_script.h6
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.cpp10
-rw-r--r--modules/visual_script/visual_script_expression.cpp8
-rw-r--r--modules/visual_script/visual_script_flow_control.cpp58
-rw-r--r--modules/visual_script/visual_script_func_nodes.cpp40
-rw-r--r--modules/visual_script/visual_script_nodes.cpp170
-rw-r--r--modules/visual_script/visual_script_yield_nodes.cpp16
-rw-r--r--modules/vorbis/register_types.cpp12
-rw-r--r--modules/vorbis/register_types.h6
-rw-r--r--modules/vorbis/resource_importer_ogg_vorbis.cpp7
-rw-r--r--modules/webp/image_loader_webp.cpp4
-rw-r--r--modules/webp/image_loader_webp.h2
-rw-r--r--modules/webp/register_types.cpp12
-rw-r--r--modules/webp/register_types.h6
-rw-r--r--modules/webrtc/register_types.cpp12
-rw-r--r--modules/webrtc/register_types.h6
-rw-r--r--modules/webrtc/webrtc_peer_connection_js.h18
-rw-r--r--modules/websocket/SCsub2
-rw-r--r--modules/websocket/doc_classes/WebSocketServer.xml7
-rw-r--r--modules/websocket/editor/editor_debugger_server_websocket.cpp (renamed from modules/websocket/editor_debugger_server_websocket.cpp)6
-rw-r--r--modules/websocket/editor/editor_debugger_server_websocket.h (renamed from modules/websocket/editor_debugger_server_websocket.h)6
-rw-r--r--modules/websocket/emws_client.h18
-rw-r--r--modules/websocket/emws_peer.h26
-rw-r--r--modules/websocket/emws_server.cpp3
-rw-r--r--modules/websocket/emws_server.h23
-rw-r--r--modules/websocket/library_godot_websocket.js2
-rw-r--r--modules/websocket/register_types.cpp39
-rw-r--r--modules/websocket/register_types.h6
-rw-r--r--modules/websocket/remote_debugger_peer_websocket.h23
-rw-r--r--modules/websocket/websocket_server.cpp1
-rw-r--r--modules/websocket/websocket_server.h1
-rw-r--r--modules/websocket/wsl_client.cpp27
-rw-r--r--modules/websocket/wsl_client.h23
-rw-r--r--modules/websocket/wsl_peer.cpp10
-rw-r--r--modules/websocket/wsl_peer.h28
-rw-r--r--modules/websocket/wsl_server.cpp15
-rw-r--r--modules/websocket/wsl_server.h26
-rw-r--r--modules/webxr/register_types.cpp12
-rw-r--r--modules/webxr/register_types.h6
-rw-r--r--modules/webxr/webxr_interface_js.cpp22
-rw-r--r--modules/xatlas_unwrap/register_types.cpp11
-rw-r--r--modules/xatlas_unwrap/register_types.h6
402 files changed, 11844 insertions, 18299 deletions
diff --git a/modules/basis_universal/SCsub b/modules/basis_universal/SCsub
index 1f9fde966d..a44a7f0db3 100644
--- a/modules/basis_universal/SCsub
+++ b/modules/basis_universal/SCsub
@@ -13,16 +13,14 @@ thirdparty_obj = []
thirdparty_dir = "#thirdparty/basis_universal/"
# Sync list with upstream CMakeLists.txt
encoder_sources = [
- "apg_bmp.c",
- "basisu_astc_decomp.cpp",
"basisu_backend.cpp",
"basisu_basis_file.cpp",
"basisu_bc7enc.cpp",
+ "basisu_opencl.cpp",
"basisu_comp.cpp",
"basisu_enc.cpp",
"basisu_etc.cpp",
"basisu_frontend.cpp",
- "basisu_global_selector_palette_helpers.cpp",
"basisu_gpu_texture.cpp",
"basisu_kernels_sse.cpp",
"basisu_pvrtc1_4.cpp",
@@ -31,7 +29,7 @@ encoder_sources = [
"basisu_ssim.cpp",
"basisu_uastc_enc.cpp",
"jpgd.cpp",
- "lodepng.cpp",
+ "pvpngreader.cpp",
]
encoder_sources = [thirdparty_dir + "encoder/" + file for file in encoder_sources]
transcoder_sources = [thirdparty_dir + "transcoder/basisu_transcoder.cpp"]
diff --git a/modules/basis_universal/register_types.cpp b/modules/basis_universal/register_types.cpp
index a3c662ba08..e80d453df7 100644
--- a/modules/basis_universal/register_types.cpp
+++ b/modules/basis_universal/register_types.cpp
@@ -49,8 +49,6 @@ enum BasisDecompressFormat {
//workaround for lack of ETC2 RG
#define USE_RG_AS_RGBA
-basist::etc1_global_selector_codebook *sel_codebook = nullptr;
-
#ifdef TOOLS_ENABLED
static Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedChannels p_channels) {
Vector<uint8_t> budata;
@@ -77,18 +75,14 @@ static Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::
memcpy(buimg.get_ptr(), r, vec.size());
}
- //image->save_png("pepeche.png");
-
basisu::basis_compressor_params params;
+ params.m_uastc = true;
params.m_max_endpoint_clusters = 512;
params.m_max_selector_clusters = 512;
params.m_multithreading = true;
- //params.m_no_hybrid_sel_cb = true; //fixme, default on this causes crashes //seems fixed?
- params.m_pSel_codebook = sel_codebook;
//params.m_quality_level = 0;
//params.m_disable_hierarchical_endpoint_codebooks = true;
//params.m_no_selector_rdo = true;
- params.m_auto_global_sel_pal = false;
basisu::job_pool jpool(OS::get_singleton()->get_processor_count());
params.m_pJob_pool = &jpool;
@@ -149,12 +143,11 @@ static Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::
}
#endif // TOOLS_ENABLED
-static Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) {
+static Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) {
Ref<Image> image;
- const uint8_t *r = p_buffer.ptr();
- const uint8_t *ptr = r;
- int size = p_buffer.size();
+ const uint8_t *ptr = p_data;
+ int size = p_size;
basist::transcoder_texture_format format = basist::transcoder_texture_format::cTFTotalTextureFormats;
Image::Format imgfmt = Image::FORMAT_MAX;
@@ -225,7 +218,7 @@ static Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) {
ptr += 4;
size -= 4;
- basist::basisu_transcoder tr(nullptr);
+ basist::basisu_transcoder tr;
ERR_FAIL_COND_V(!tr.validate_header(ptr, size), image);
@@ -251,7 +244,7 @@ static Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) {
bool ret = tr.transcode_image_level(ptr, size, 0, i, dst + ofs, level.m_total_blocks - i, format);
if (!ret) {
- printf("failed! on level %i\n", i);
+ printf("failed! on level %u\n", i);
break;
};
@@ -265,18 +258,37 @@ static Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) {
return image;
}
-void register_basis_universal_types() {
+static Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) {
+ Ref<Image> image;
+
+ const uint8_t *r = p_buffer.ptr();
+ int size = p_buffer.size();
+ return basis_universal_unpacker_ptr(r, size);
+}
+
+void initialize_basis_universal_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
#ifdef TOOLS_ENABLED
- sel_codebook = new basist::etc1_global_selector_codebook(basist::g_global_selector_cb_size, basist::g_global_selector_cb);
+ using namespace basisu;
+ using namespace basist;
+ basisu_encoder_init();
Image::basis_universal_packer = basis_universal_packer;
#endif
Image::basis_universal_unpacker = basis_universal_unpacker;
+ Image::basis_universal_unpacker_ptr = basis_universal_unpacker_ptr;
}
-void unregister_basis_universal_types() {
+void uninitialize_basis_universal_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
#ifdef TOOLS_ENABLED
- delete sel_codebook;
Image::basis_universal_packer = nullptr;
#endif
Image::basis_universal_unpacker = nullptr;
+ Image::basis_universal_unpacker_ptr = nullptr;
}
diff --git a/modules/basis_universal/register_types.h b/modules/basis_universal/register_types.h
index 7275c2ebb7..68d5dd64f3 100644
--- a/modules/basis_universal/register_types.h
+++ b/modules/basis_universal/register_types.h
@@ -31,7 +31,9 @@
#ifndef BASIS_UNIVERSAL_REGISTER_TYPES_H
#define BASIS_UNIVERSAL_REGISTER_TYPES_H
-void register_basis_universal_types();
-void unregister_basis_universal_types();
+#include "modules/register_module_types.h"
+
+void initialize_basis_universal_module(ModuleInitializationLevel p_level);
+void uninitialize_basis_universal_module(ModuleInitializationLevel p_level);
#endif // BASIS_UNIVERSAL_REGISTER_TYPES_H
diff --git a/modules/bmp/image_loader_bmp.cpp b/modules/bmp/image_loader_bmp.cpp
index ad2c7d6a3e..8813c3827a 100644
--- a/modules/bmp/image_loader_bmp.cpp
+++ b/modules/bmp/image_loader_bmp.cpp
@@ -200,8 +200,7 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image,
return err;
}
-Error ImageLoaderBMP::load_image(Ref<Image> p_image, FileAccess *f,
- bool p_force_linear, float p_scale) {
+Error ImageLoaderBMP::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) {
bmp_header_s bmp_header;
Error err = ERR_INVALID_DATA;
@@ -241,7 +240,6 @@ Error ImageLoaderBMP::load_image(Ref<Image> p_image, FileAccess *f,
case BI_CMYKRLE8:
case BI_CMYKRLE4: {
// Stop parsing.
- f->close();
ERR_FAIL_V_MSG(ERR_UNAVAILABLE,
vformat("Compressed BMP files are not supported: %s", f->get_path()));
} break;
@@ -283,7 +281,6 @@ Error ImageLoaderBMP::load_image(Ref<Image> p_image, FileAccess *f,
err = convert_to_image(p_image, bmp_buffer_r,
bmp_color_table_r, color_table_size, bmp_header);
}
- f->close();
}
}
return err;
@@ -294,12 +291,14 @@ void ImageLoaderBMP::get_recognized_extensions(List<String> *p_extensions) const
}
static Ref<Image> _bmp_mem_loader_func(const uint8_t *p_bmp, int p_size) {
- FileAccessMemory memfile;
- Error open_memfile_error = memfile.open_custom(p_bmp, p_size);
+ Ref<FileAccessMemory> memfile;
+ memfile.instantiate();
+ Error open_memfile_error = memfile->open_custom(p_bmp, p_size);
ERR_FAIL_COND_V_MSG(open_memfile_error, Ref<Image>(), "Could not create memfile for BMP image buffer.");
+
Ref<Image> img;
img.instantiate();
- Error load_error = ImageLoaderBMP().load_image(img, &memfile, false, 1.0f);
+ Error load_error = ImageLoaderBMP().load_image(img, memfile, false, 1.0f);
ERR_FAIL_COND_V_MSG(load_error, Ref<Image>(), "Failed to load BMP image.");
return img;
}
diff --git a/modules/bmp/image_loader_bmp.h b/modules/bmp/image_loader_bmp.h
index 9c9a16a9f5..63dee0a969 100644
--- a/modules/bmp/image_loader_bmp.h
+++ b/modules/bmp/image_loader_bmp.h
@@ -83,8 +83,7 @@ protected:
const bmp_header_s &p_header);
public:
- virtual Error load_image(Ref<Image> p_image, FileAccess *f,
- bool p_force_linear, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderBMP();
};
diff --git a/modules/bmp/register_types.cpp b/modules/bmp/register_types.cpp
index 13e44099e5..7c4a2085b2 100644
--- a/modules/bmp/register_types.cpp
+++ b/modules/bmp/register_types.cpp
@@ -34,11 +34,19 @@
static ImageLoaderBMP *image_loader_bmp = nullptr;
-void register_bmp_types() {
+void initialize_bmp_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
image_loader_bmp = memnew(ImageLoaderBMP);
ImageLoader::add_image_format_loader(image_loader_bmp);
}
-void unregister_bmp_types() {
+void uninitialize_bmp_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
memdelete(image_loader_bmp);
}
diff --git a/modules/bmp/register_types.h b/modules/bmp/register_types.h
index 1e53f4c2f7..45c8499c58 100644
--- a/modules/bmp/register_types.h
+++ b/modules/bmp/register_types.h
@@ -31,7 +31,9 @@
#ifndef BMP_REGISTER_TYPES_H
#define BMP_REGISTER_TYPES_H
-void register_bmp_types();
-void unregister_bmp_types();
+#include "modules/register_module_types.h"
+
+void initialize_bmp_module(ModuleInitializationLevel p_level);
+void uninitialize_bmp_module(ModuleInitializationLevel p_level);
#endif // BMP_REGISTER_TYPES_H
diff --git a/modules/camera/register_types.cpp b/modules/camera/register_types.cpp
index b0b1276436..98a4b5ca1a 100644
--- a/modules/camera/register_types.cpp
+++ b/modules/camera/register_types.cpp
@@ -37,7 +37,11 @@
#include "camera_osx.h"
#endif
-void register_camera_types() {
+void initialize_camera_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
#if defined(WINDOWS_ENABLED)
CameraServer::make_default<CameraWindows>();
#endif
@@ -46,5 +50,8 @@ void register_camera_types() {
#endif
}
-void unregister_camera_types() {
+void uninitialize_camera_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
diff --git a/modules/camera/register_types.h b/modules/camera/register_types.h
index 5ee7aec886..4ac4426588 100644
--- a/modules/camera/register_types.h
+++ b/modules/camera/register_types.h
@@ -31,7 +31,9 @@
#ifndef CAMERA_REGISTER_TYPES_H
#define CAMERA_REGISTER_TYPES_H
-void register_camera_types();
-void unregister_camera_types();
+#include "modules/register_module_types.h"
+
+void initialize_camera_module(ModuleInitializationLevel p_level);
+void uninitialize_camera_module(ModuleInitializationLevel p_level);
#endif // CAMERA_REGISTER_TYPES_H
diff --git a/modules/csg/SCsub b/modules/csg/SCsub
index 641a42c187..c7307ddefd 100644
--- a/modules/csg/SCsub
+++ b/modules/csg/SCsub
@@ -3,7 +3,10 @@
Import("env")
Import("env_modules")
+# Godot's own source files
env_csg = env_modules.Clone()
# Godot's own source files
env_csg.add_source_files(env.modules_sources, "*.cpp")
+if env["tools"]:
+ env_csg.add_source_files(env.modules_sources, "editor/*.cpp")
diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp
index 82dc4a4175..760ee0846d 100644
--- a/modules/csg/csg.cpp
+++ b/modules/csg/csg.cpp
@@ -1336,9 +1336,9 @@ CSGBrushOperation::Build2DFaces::Build2DFaces(const CSGBrush &p_brush, int p_fac
plane = Plane(points_3D[0], points_3D[1], points_3D[2]);
to_3D.origin = points_3D[0];
- to_3D.basis.set_axis(2, plane.normal);
- to_3D.basis.set_axis(0, (points_3D[1] - points_3D[2]).normalized());
- to_3D.basis.set_axis(1, to_3D.basis.get_axis(0).cross(to_3D.basis.get_axis(2)).normalized());
+ to_3D.basis.set_column(2, plane.normal);
+ to_3D.basis.set_column(0, (points_3D[1] - points_3D[2]).normalized());
+ to_3D.basis.set_column(1, to_3D.basis.get_column(0).cross(to_3D.basis.get_column(2)).normalized());
to_2D = to_3D.affine_inverse();
Face2D face;
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index be9bf9538f..0a2427e4e6 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -1110,7 +1110,7 @@ Ref<Material> CSGSphere3D::get_material() const {
CSGSphere3D::CSGSphere3D() {
// defaults
- radius = 1.0;
+ radius = 0.5;
radial_segments = 12;
rings = 6;
smooth_faces = true;
diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h
index 4721d0c11c..b5d5f97cf3 100644
--- a/modules/csg/csg_shape.h
+++ b/modules/csg/csg_shape.h
@@ -368,7 +368,7 @@ private:
PathRotation path_rotation;
bool path_local;
- Path3D *path;
+ Path3D *path = nullptr;
bool smooth_faces;
bool path_continuous_u;
diff --git a/modules/csg/doc_classes/CSGSphere3D.xml b/modules/csg/doc_classes/CSGSphere3D.xml
index 227f620a4e..d2f985b3a2 100644
--- a/modules/csg/doc_classes/CSGSphere3D.xml
+++ b/modules/csg/doc_classes/CSGSphere3D.xml
@@ -17,7 +17,7 @@
<member name="radial_segments" type="int" setter="set_radial_segments" getter="get_radial_segments" default="12">
Number of vertical slices for the sphere.
</member>
- <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
+ <member name="radius" type="float" setter="set_radius" getter="get_radius" default="0.5">
Radius of the sphere.
</member>
<member name="rings" type="int" setter="set_rings" getter="get_rings" default="6">
diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/editor/csg_gizmos.cpp
index 95a0fc7ada..4d972e46c6 100644
--- a/modules/csg/csg_gizmos.cpp
+++ b/modules/csg/editor/csg_gizmos.cpp
@@ -30,6 +30,8 @@
#include "csg_gizmos.h"
+#ifdef TOOLS_ENABLED
+
#include "editor/editor_settings.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/camera_3d.h"
@@ -345,14 +347,12 @@ void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->add_lines(lines, material);
p_gizmo->add_collision_segments(lines);
- Array csg_meshes = cs->get_meshes();
- if (csg_meshes.size() != 2) {
- return;
- }
-
- Ref<Mesh> csg_mesh = csg_meshes[1];
- if (csg_mesh.is_valid()) {
- p_gizmo->add_collision_triangles(csg_mesh->generate_triangle_mesh());
+ if (cs->is_root_shape()) {
+ Array csg_meshes = cs->get_meshes();
+ Ref<Mesh> csg_mesh = csg_meshes[1];
+ if (csg_mesh.is_valid()) {
+ p_gizmo->add_collision_triangles(csg_mesh->generate_triangle_mesh());
+ }
}
if (p_gizmo->is_selected()) {
@@ -425,3 +425,5 @@ EditorPluginCSG::EditorPluginCSG() {
Ref<CSGShape3DGizmoPlugin> gizmo_plugin = Ref<CSGShape3DGizmoPlugin>(memnew(CSGShape3DGizmoPlugin));
Node3DEditor::get_singleton()->add_gizmo_plugin(gizmo_plugin);
}
+
+#endif // TOOLS_ENABLED
diff --git a/modules/csg/csg_gizmos.h b/modules/csg/editor/csg_gizmos.h
index 43efe57e64..fa51010f98 100644
--- a/modules/csg/csg_gizmos.h
+++ b/modules/csg/editor/csg_gizmos.h
@@ -31,7 +31,9 @@
#ifndef CSG_GIZMOS_H
#define CSG_GIZMOS_H
-#include "csg_shape.h"
+#ifdef TOOLS_ENABLED
+
+#include "../csg_shape.h"
#include "editor/editor_plugin.h"
#include "editor/plugins/node_3d_editor_gizmos.h"
@@ -60,4 +62,6 @@ public:
EditorPluginCSG();
};
+#endif // TOOLS_ENABLED
+
#endif // CSG_GIZMOS_H
diff --git a/modules/csg/register_types.cpp b/modules/csg/register_types.cpp
index f8db42b1a9..9b5888dafe 100644
--- a/modules/csg/register_types.cpp
+++ b/modules/csg/register_types.cpp
@@ -30,27 +30,37 @@
#include "register_types.h"
-#include "csg_gizmos.h"
-#include "csg_shape.h"
-
-void register_csg_types() {
#ifndef _3D_DISABLED
- GDREGISTER_ABSTRACT_CLASS(CSGShape3D);
- GDREGISTER_ABSTRACT_CLASS(CSGPrimitive3D);
- GDREGISTER_CLASS(CSGMesh3D);
- GDREGISTER_CLASS(CSGSphere3D);
- GDREGISTER_CLASS(CSGBox3D);
- GDREGISTER_CLASS(CSGCylinder3D);
- GDREGISTER_CLASS(CSGTorus3D);
- GDREGISTER_CLASS(CSGPolygon3D);
- GDREGISTER_CLASS(CSGCombiner3D);
+#include "csg_shape.h"
#ifdef TOOLS_ENABLED
- EditorPlugins::add_by_type<EditorPluginCSG>();
+#include "editor/csg_gizmos.h"
#endif
+
+void initialize_csg_module(ModuleInitializationLevel p_level) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
+ GDREGISTER_ABSTRACT_CLASS(CSGShape3D);
+ GDREGISTER_ABSTRACT_CLASS(CSGPrimitive3D);
+ GDREGISTER_CLASS(CSGMesh3D);
+ GDREGISTER_CLASS(CSGSphere3D);
+ GDREGISTER_CLASS(CSGBox3D);
+ GDREGISTER_CLASS(CSGCylinder3D);
+ GDREGISTER_CLASS(CSGTorus3D);
+ GDREGISTER_CLASS(CSGPolygon3D);
+ GDREGISTER_CLASS(CSGCombiner3D);
+ }
+#ifdef TOOLS_ENABLED
+ if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
+ EditorPlugins::add_by_type<EditorPluginCSG>();
+ }
#endif
}
-void unregister_csg_types() {
+void uninitialize_csg_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
+
+#endif // _3D_DISABLED
diff --git a/modules/csg/register_types.h b/modules/csg/register_types.h
index 59d84dd52a..ec65adde9c 100644
--- a/modules/csg/register_types.h
+++ b/modules/csg/register_types.h
@@ -31,7 +31,9 @@
#ifndef CSG_REGISTER_TYPES_H
#define CSG_REGISTER_TYPES_H
-void register_csg_types();
-void unregister_csg_types();
+#include "modules/register_module_types.h"
+
+void initialize_csg_module(ModuleInitializationLevel p_level);
+void uninitialize_csg_module(ModuleInitializationLevel p_level);
#endif // CSG_REGISTER_TYPES_H
diff --git a/modules/cvtt/image_compress_cvtt.cpp b/modules/cvtt/image_compress_cvtt.cpp
index d18340a2c8..a7cfcaa262 100644
--- a/modules/cvtt/image_compress_cvtt.cpp
+++ b/modules/cvtt/image_compress_cvtt.cpp
@@ -46,7 +46,7 @@ struct CVTTCompressionJobParams {
};
struct CVTTCompressionRowTask {
- const uint8_t *in_mm_bytes;
+ const uint8_t *in_mm_bytes = nullptr;
uint8_t *out_mm_bytes = nullptr;
int y_start = 0;
int width = 0;
@@ -55,7 +55,7 @@ struct CVTTCompressionRowTask {
struct CVTTCompressionJobQueue {
CVTTCompressionJobParams job_params;
- const CVTTCompressionRowTask *job_tasks;
+ const CVTTCompressionRowTask *job_tasks = nullptr;
uint32_t num_tasks = 0;
SafeNumeric<uint32_t> current_task;
};
diff --git a/modules/cvtt/register_types.cpp b/modules/cvtt/register_types.cpp
index 13903f700b..ff22c0f53e 100644
--- a/modules/cvtt/register_types.cpp
+++ b/modules/cvtt/register_types.cpp
@@ -34,11 +34,19 @@
#include "image_compress_cvtt.h"
-void register_cvtt_types() {
+void initialize_cvtt_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
Image::set_compress_bptc_func(image_compress_cvtt);
Image::_image_decompress_bptc = image_decompress_cvtt;
}
-void unregister_cvtt_types() {}
+void uninitialize_cvtt_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+}
#endif
diff --git a/modules/cvtt/register_types.h b/modules/cvtt/register_types.h
index 9cbca75c7b..38a375eb44 100644
--- a/modules/cvtt/register_types.h
+++ b/modules/cvtt/register_types.h
@@ -33,8 +33,10 @@
#ifdef TOOLS_ENABLED
-void register_cvtt_types();
-void unregister_cvtt_types();
+#include "modules/register_module_types.h"
+
+void initialize_cvtt_module(ModuleInitializationLevel p_level);
+void uninitialize_cvtt_module(ModuleInitializationLevel p_level);
#endif // TOOLS_ENABLED
diff --git a/modules/dds/register_types.cpp b/modules/dds/register_types.cpp
index 15a93050ee..e819c92dd3 100644
--- a/modules/dds/register_types.cpp
+++ b/modules/dds/register_types.cpp
@@ -34,12 +34,20 @@
static Ref<ResourceFormatDDS> resource_loader_dds;
-void register_dds_types() {
+void initialize_dds_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
resource_loader_dds.instantiate();
ResourceLoader::add_resource_format_loader(resource_loader_dds);
}
-void unregister_dds_types() {
+void uninitialize_dds_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
ResourceLoader::remove_resource_format_loader(resource_loader_dds);
resource_loader_dds.unref();
}
diff --git a/modules/dds/register_types.h b/modules/dds/register_types.h
index d676346e02..3cd154d576 100644
--- a/modules/dds/register_types.h
+++ b/modules/dds/register_types.h
@@ -31,7 +31,9 @@
#ifndef DDS_REGISTER_TYPES_H
#define DDS_REGISTER_TYPES_H
-void register_dds_types();
-void unregister_dds_types();
+#include "modules/register_module_types.h"
+
+void initialize_dds_module(ModuleInitializationLevel p_level);
+void uninitialize_dds_module(ModuleInitializationLevel p_level);
#endif // DDS_REGISTER_TYPES_H
diff --git a/modules/dds/texture_loader_dds.cpp b/modules/dds/texture_loader_dds.cpp
index 7bfe849106..2c0e604e66 100644
--- a/modules/dds/texture_loader_dds.cpp
+++ b/modules/dds/texture_loader_dds.cpp
@@ -68,7 +68,7 @@ enum DDSFormat {
};
struct DDSFormatInfo {
- const char *name;
+ const char *name = nullptr;
bool compressed = false;
bool palette = false;
uint32_t divisor = 0;
@@ -94,23 +94,23 @@ static const DDSFormatInfo dds_format_info[DDS_MAX] = {
{ "GRAYSCALE_ALPHA", false, false, 1, 2, Image::FORMAT_LA8 }
};
-RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_CANT_OPEN;
}
Error err;
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
- if (!f) {
- return RES();
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
+ if (f.is_null()) {
+ return Ref<Resource>();
}
- FileAccessRef fref(f);
+ Ref<FileAccess> fref(f);
if (r_error) {
*r_error = ERR_FILE_CORRUPT;
}
- ERR_FAIL_COND_V_MSG(err != OK, RES(), "Unable to open DDS texture file '" + p_path + "'.");
+ ERR_FAIL_COND_V_MSG(err != OK, Ref<Resource>(), "Unable to open DDS texture file '" + p_path + "'.");
uint32_t magic = f->get_32();
uint32_t hsize = f->get_32();
@@ -131,7 +131,7 @@ RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path,
// We don't check DDSD_CAPS or DDSD_PIXELFORMAT, as they're mandatory when writing,
// but non-mandatory when reading (as some writers don't set them)...
if (magic != DDS_MAGIC || hsize != 124) {
- ERR_FAIL_V_MSG(RES(), "Invalid or unsupported DDS texture file '" + p_path + "'.");
+ ERR_FAIL_V_MSG(Ref<Resource>(), "Invalid or unsupported DDS texture file '" + p_path + "'.");
}
/* uint32_t format_size = */ f->get_32();
@@ -204,7 +204,7 @@ RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path,
dds_format = DDS_BGR565;
} else {
printf("unrecognized fourcc %x format_flags: %x - rgbbits %i - red_mask %x green mask %x blue mask %x alpha mask %x\n", format_fourcc, format_flags, format_rgb_bits, format_red_mask, format_green_mask, format_blue_mask, format_alpha_mask);
- ERR_FAIL_V_MSG(RES(), "Unrecognized or unsupported color layout in DDS '" + p_path + "'.");
+ ERR_FAIL_V_MSG(Ref<Resource>(), "Unrecognized or unsupported color layout in DDS '" + p_path + "'.");
}
if (!(flags & DDSD_MIPMAPCOUNT)) {
@@ -221,8 +221,8 @@ RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path,
//compressed bc
uint32_t size = MAX(info.divisor, w) / info.divisor * MAX(info.divisor, h) / info.divisor * info.block_size;
- ERR_FAIL_COND_V(size != pitch, RES());
- ERR_FAIL_COND_V(!(flags & DDSD_LINEARSIZE), RES());
+ ERR_FAIL_COND_V(size != pitch, Ref<Resource>());
+ ERR_FAIL_COND_V(!(flags & DDSD_LINEARSIZE), Ref<Resource>());
for (uint32_t i = 1; i < mipmaps; i++) {
w = MAX(1u, w >> 1);
@@ -238,11 +238,11 @@ RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path,
} else if (info.palette) {
//indexed
- ERR_FAIL_COND_V(!(flags & DDSD_PITCH), RES());
- ERR_FAIL_COND_V(format_rgb_bits != 8, RES());
+ ERR_FAIL_COND_V(!(flags & DDSD_PITCH), Ref<Resource>());
+ ERR_FAIL_COND_V(format_rgb_bits != 8, Ref<Resource>());
uint32_t size = pitch * height;
- ERR_FAIL_COND_V(size != width * height * info.block_size, RES());
+ ERR_FAIL_COND_V(size != width * height * info.block_size, Ref<Resource>());
uint8_t palette[256 * 4];
f->get_buffer(palette, 256 * 4);
diff --git a/modules/dds/texture_loader_dds.h b/modules/dds/texture_loader_dds.h
index 25ded4e168..701f8f4a13 100644
--- a/modules/dds/texture_loader_dds.h
+++ b/modules/dds/texture_loader_dds.h
@@ -36,7 +36,7 @@
class ResourceFormatDDS : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/modules/denoise/register_types.cpp b/modules/denoise/register_types.cpp
index 07393d0f5c..891a03c657 100644
--- a/modules/denoise/register_types.cpp
+++ b/modules/denoise/register_types.cpp
@@ -32,9 +32,16 @@
#include "core/config/engine.h"
#include "lightmap_denoiser.h"
-void register_denoise_types() {
+void initialize_denoise_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
LightmapDenoiserOIDN::make_default_denoiser();
}
-void unregister_denoise_types() {
+void uninitialize_denoise_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
diff --git a/modules/denoise/register_types.h b/modules/denoise/register_types.h
index 6ce386dc5d..13eba88d17 100644
--- a/modules/denoise/register_types.h
+++ b/modules/denoise/register_types.h
@@ -31,7 +31,9 @@
#ifndef DENOISE_REGISTER_TYPES_H
#define DENOISE_REGISTER_TYPES_H
-void register_denoise_types();
-void unregister_denoise_types();
+#include "modules/register_module_types.h"
+
+void initialize_denoise_module(ModuleInitializationLevel p_level);
+void uninitialize_denoise_module(ModuleInitializationLevel p_level);
#endif // DENOISE_REGISTER_TYPES_H
diff --git a/modules/enet/register_types.cpp b/modules/enet/register_types.cpp
index ebc5d95348..14f3374e24 100644
--- a/modules/enet/register_types.cpp
+++ b/modules/enet/register_types.cpp
@@ -36,7 +36,11 @@
static bool enet_ok = false;
-void register_enet_types() {
+void initialize_enet_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
if (enet_initialize() != 0) {
ERR_PRINT("ENet initialization failure");
} else {
@@ -48,7 +52,11 @@ void register_enet_types() {
GDREGISTER_CLASS(ENetConnection);
}
-void unregister_enet_types() {
+void uninitialize_enet_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
if (enet_ok) {
enet_deinitialize();
}
diff --git a/modules/enet/register_types.h b/modules/enet/register_types.h
index a94ecccc61..b4f491287d 100644
--- a/modules/enet/register_types.h
+++ b/modules/enet/register_types.h
@@ -31,7 +31,9 @@
#ifndef ENET_REGISTER_TYPES_H
#define ENET_REGISTER_TYPES_H
-void register_enet_types();
-void unregister_enet_types();
+#include "modules/register_module_types.h"
+
+void initialize_enet_module(ModuleInitializationLevel p_level);
+void uninitialize_enet_module(ModuleInitializationLevel p_level);
#endif // ENET_REGISTER_TYPES_H
diff --git a/modules/etcpak/register_types.cpp b/modules/etcpak/register_types.cpp
index e835004406..eaad1e7b01 100644
--- a/modules/etcpak/register_types.cpp
+++ b/modules/etcpak/register_types.cpp
@@ -32,11 +32,18 @@
#include "image_compress_etcpak.h"
-void register_etcpak_types() {
+void initialize_etcpak_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
Image::_image_compress_etc1_func = _compress_etc1;
Image::_image_compress_etc2_func = _compress_etc2;
Image::_image_compress_bc_func = _compress_bc;
}
-void unregister_etcpak_types() {
+void uninitialize_etcpak_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
diff --git a/modules/etcpak/register_types.h b/modules/etcpak/register_types.h
index 30ce974d08..2048a62737 100644
--- a/modules/etcpak/register_types.h
+++ b/modules/etcpak/register_types.h
@@ -31,7 +31,11 @@
#ifndef ETCPAK_REGISTER_TYPES_H
#define ETCPAK_REGISTER_TYPES_H
-void register_etcpak_types();
-void unregister_etcpak_types();
+#include "modules/register_module_types.h"
+
+#include "modules/register_module_types.h"
+
+void initialize_etcpak_module(ModuleInitializationLevel p_level);
+void uninitialize_etcpak_module(ModuleInitializationLevel p_level);
#endif // ETCPAK_REGISTER_TYPES_H
diff --git a/modules/fbx/README.md b/modules/fbx/README.md
deleted file mode 100644
index 8eca4bd3c9..0000000000
--- a/modules/fbx/README.md
+++ /dev/null
@@ -1,196 +0,0 @@
-# Open Source FBX Specification for the Importer
-
-The goal of this document is to make everything in FBX clearly stated, any errors will be corrected over time this
-is a first draft.
-
-## fbx parser - originally from assimp
-
-- Folder: /modules/fbx/fbx_parser
-- Upstream: assimp
-- Original Version: git (308db73d0b3c2d1870cd3e465eaa283692a4cf23, 2019)
-- License: BSD-3-Clause
-
-This can never be updated from upstream, we have heavily modified the parser to provide memory safety and add some
-functionality. If anything we should give this parser back to assimp at some point as it has a lot of new features.
-
-# Updating assimp fbx parser
-
-Don't. It's not possible the code is rewritten in many areas to remove thirdparty deps and various bugs are fixed.
-
-Many days were put into rewriting the parser to use safe code and safe memory accessors.
-
-# File Headers
-
-FBX Binaries start with the header "Kaydara FBX Binary"
-
-FBX ASCII documents contain a larger header, sometimes with copyright information for a file.
-
-Detecting these is pretty simple.
-
-# What is an OP link?
-It's an object to property link. It lists the properties for that object in some cases. Source and destination based by
-ID.
-
-# What is a OO link?
-Its an object to object link, it contains the ID source and destination ID.
-
-# FBX Node connections
-
-Nodes in FBX are connected using OO links, This means Object to Object.
-
-FBX has a single other kind of link which is Object Property, this is used for Object to Property Links, this can be
- extra attributes, defaults, or even some simple settings.
-
-# Bones / Joints / Locators
-
-Bones in FBX are nodes, they initially have the Model:: Type, then have links to SubDeformer the sub deformer
-is part of the skin there is also an explicit Skin link, which then links to the geometry using OO links in the
-document.
-
-# Rotation Order in FBX compared to Godot
-
-**Godot uses the rotation order:** YXZ
-
-**FBX has dynamic rotation order to prevent gimbal lock with complex animations**
-
-```cpp
-enum RotOrder {
- RotOrder_EulerXYZ = 0
- RotOrder_EulerXZY,
- RotOrder_EulerYZX,
- RotOrder_EulerYXZ,
- RotOrder_EulerZXY,
- RotOrder_EulerZYX,
- RotOrder_SphericXYZ // nobody uses this - as far as we can tell
-};
-```
-
-
-# Pivot transforms
-
-### Pivot description:
-- Maya and 3DS max consider everything to be in node space (bones joints, skins, lights, cameras, etc)
-- Everything is a node, this means essentially nodes are auto or variants
-- They are local to the node in the tree.
-- They are used to calculate where a node is in space
-```c++
-// For a better reference you can check editor_scene_importer_fbx.h
-// references: GenFBXTransform / read the data in
-// references: ComputePivotTransform / run the calculation
-// This is the local pivot transform for the node, not the global transforms
-Transform ComputePivotTransform(
- Transform3D chain[TransformationComp_MAXIMUM],
- Transform3D &geometric_transform) {
- // Maya pivots
- Transform3D T = chain[TransformationComp_Translation];
- Transform3D Roff = chain[TransformationComp_RotationOffset];
- Transform3D Rp = chain[TransformationComp_RotationPivot];
- Transform3D Rpre = chain[TransformationComp_PreRotation];
- Transform3D R = chain[TransformationComp_Rotation];
- Transform3D Rpost = chain[TransformationComp_PostRotation];
- Transform3D Soff = chain[TransformationComp_ScalingOffset];
- Transform3D Sp = chain[TransformationComp_ScalingPivot];
- Transform3D S = chain[TransformationComp_Scaling];
-
- // 3DS Max Pivots
- Transform3D OT = chain[TransformationComp_GeometricTranslation];
- Transform3D OR = chain[TransformationComp_GeometricRotation];
- Transform3D OS = chain[TransformationComp_GeometricScaling];
-
- // Calculate 3DS max pivot transform - use geometric space (e.g doesn't effect children nodes only the current node)
- geometric_transform = OT * OR * OS;
- // Calculate standard maya pivots
- return T * Roff * Rp * Rpre * R * Rpost.inverse() * Rp.inverse() * Soff * Sp * S * Sp.inverse();
-}
-```
-
-# Transform inheritance for FBX Nodes
-
-The goal of below is to explain why they implement this in the first place.
-
-The use case is to make nodes have an option to override their local scaling or to make scaling influenced by orientation, which i would imagine would be useful for when you need to rotate a node and the child to scale based on the orientation rather than setting on the rotation matrix planes.
-```cpp
-// not modified the formatting here since this code must remain clear
-enum TransformInheritance {
- Transform_RrSs = 0,
- // Parent Rotation * Local Rotation * Parent Scale * Local Scale -- Parent Rotation Offset * Parent ScalingOffset (Local scaling is offset by rotation of parent node)
- Transform_RSrs = 1, // Parent Rotation * Parent Scale * Local Rotation * Local Scale -- Parent * Local (normal mode)
- Transform_Rrs = 2, // Parent Rotation * Local Rotation * Local Scale -- Node transform scale is the only relevant component
- TransformInheritance_MAX // end-of-enum sentinel
-};
-
-enum TransformInheritance {
- Transform_RrSs = 0,
- // Local scaling is offset by rotation of parent node
- Transform_RSrs = 1,
- // Parent * Local (normal mode)
- Transform_Rrs = 2,
- // Node transform scale is the only relevant component
- TransformInheritance_MAX // end-of-enum sentinel
-};
-```
-
-# Axis in FBX
-
-Godot has one format for the declared axis
-
-AXIS X, AXIS Y, -AXIS Z
-
-FBX supports any format you can think of. As it has to support Maya and 3DS Max.
-
-#### FBX File Header
-```json
-GlobalSettings: {
- Version: 1000
- Properties70: {
- P: "UpAxis", "int", "Integer", "",1
- P: "UpAxisSign", "int", "Integer", "",1
- P: "FrontAxis", "int", "Integer", "",2
- P: "FrontAxisSign", "int", "Integer", "",1
- P: "CoordAxis", "int", "Integer", "",0
- P: "CoordAxisSign", "int", "Integer", "",1
- P: "OriginalUpAxis", "int", "Integer", "",1
- P: "OriginalUpAxisSign", "int", "Integer", "",1
- P: "UnitScaleFactor", "double", "Number", "",1
- P: "OriginalUnitScaleFactor", "double", "Number", "",1
- P: "AmbientColor", "ColorRGB", "Color", "",0,0,0
- P: "DefaultCamera", "KString", "", "", "Producer Perspective"
- P: "TimeMode", "enum", "", "",6
- P: "TimeProtocol", "enum", "", "",2
- P: "SnapOnFrameMode", "enum", "", "",0
- P: "TimeSpanStart", "KTime", "Time", "",0
- P: "TimeSpanStop", "KTime", "Time", "",92372316000
- P: "CustomFrameRate", "double", "Number", "",-1
- P: "TimeMarker", "Compound", "", ""
- P: "CurrentTimeMarker", "int", "Integer", "",-1
- }
-}
-```
-
-#### FBX FILE declares axis dynamically using FBX header
-Coord is X
-Up is Y
-Front is Z
-
-#### GODOT - constant reference point
-Coord is X positive,
-Y is up positive,
-Front is -Z negative
-
-### Explaining MeshGeometry indexing
-
-Reference type declared:
-- Direct (directly related to the mapping information type)
-- IndexToDirect (Map with key value, meaning depends on the MappingInformationType)
-
-ControlPoint is a vertex
-* None The mapping is undetermined.
-* ByVertex There will be one mapping coordinate for each surface control point/vertex.
- * If you have direct reference type vertices [x]
- * If you have IndexToDirect reference type the UV
-* ByPolygonVertex There will be one mapping coordinate for each vertex, for every polygon of which it is a part. This means that a vertex will have as many mapping coordinates as polygons of which it is a part. (Sorted by polygon, referencing vertex)
-* ByPolygon There can be only one mapping coordinate for the whole polygon.
- * One mapping per polygon polygon x has this normal x
- * For each vertex of the polygon then set the normal to x
-* ByEdge There will be one mapping coordinate for each unique edge in the mesh. This is meant to be used with smoothing layer elements. (Mapping is referencing the edge id)
-* AllSame There can be only one mapping coordinate for the whole surface.
diff --git a/modules/fbx/SCsub b/modules/fbx/SCsub
deleted file mode 100644
index 0311fddfee..0000000000
--- a/modules/fbx/SCsub
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/usr/bin/env python
-
-Import("env")
-Import("env_modules")
-
-env_fbx = env_modules.Clone()
-
-# Make includes relative to the folder path specified here so our includes are clean
-env_fbx.Prepend(CPPPATH=["#modules/fbx/"])
-
-if env["builtin_zlib"]:
- env_fbx.Prepend(CPPPATH=["#thirdparty/zlib/"])
-
-# Godot's own source files
-env_fbx.add_source_files(env.modules_sources, "tools/*.cpp")
-env_fbx.add_source_files(env.modules_sources, "data/*.cpp")
-env_fbx.add_source_files(env.modules_sources, "fbx_parser/*.cpp")
-env_fbx.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/fbx/config.py b/modules/fbx/config.py
deleted file mode 100644
index 78929800b3..0000000000
--- a/modules/fbx/config.py
+++ /dev/null
@@ -1,16 +0,0 @@
-def can_build(env, platform):
- return env["tools"]
-
-
-def configure(env):
- pass
-
-
-def get_doc_classes():
- return [
- "EditorSceneImporterFBX",
- ]
-
-
-def get_doc_path():
- return "doc_classes"
diff --git a/modules/fbx/data/fbx_anim_container.h b/modules/fbx/data/fbx_anim_container.h
deleted file mode 100644
index 6559add858..0000000000
--- a/modules/fbx/data/fbx_anim_container.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*************************************************************************/
-/* fbx_anim_container.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef FBX_ANIM_CONTAINER_H
-#define FBX_ANIM_CONTAINER_H
-
-#include "core/math/vector3.h"
-
-// Generic keyframes 99.99 percent of files will be vector3, except if quat interp is used, or visibility tracks
-// FBXTrack is used in a map in the implementation in fbx/editor_scene_importer_fbx.cpp
-// to avoid having to rewrite the entire logic I refactored this into the code instead.
-// once it works I can rewrite so we can add the fun misc features / small features
-struct FBXTrack {
- bool has_default = false;
- Vector3 default_value;
- std::map<int64_t, Vector3> keyframes;
-};
-
-#endif //MODEL_ABSTRACTION_ANIM_CONTAINER_H
diff --git a/modules/fbx/data/fbx_bone.h b/modules/fbx/data/fbx_bone.h
deleted file mode 100644
index 6c8f7f7cae..0000000000
--- a/modules/fbx/data/fbx_bone.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*************************************************************************/
-/* fbx_bone.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef FBX_BONE_H
-#define FBX_BONE_H
-
-#include "fbx_node.h"
-#include "import_state.h"
-
-#include "fbx_parser/FBXDocument.h"
-
-struct PivotTransform;
-
-struct FBXBone : public RefCounted {
- uint64_t parent_bone_id = 0;
- uint64_t bone_id = 0;
-
- bool valid_parent = false; // if the parent bone id is set up.
- String bone_name = String(); // bone name
-
- bool is_root_bone() const {
- return !valid_parent;
- }
-
- // Godot specific data
- int godot_bone_id = -2; // godot internal bone id assigned after import
-
- // if a bone / armature is the root then FBX skeleton will contain the bone not any other skeleton.
- // this is to support joints by themselves in scenes
- bool valid_armature_id = false;
- uint64_t armature_id = 0;
-
- /* link node is the parent bone */
- mutable const FBXDocParser::Geometry *geometry = nullptr;
- mutable const FBXDocParser::ModelLimbNode *limb_node = nullptr;
-
- void set_node(Ref<FBXNode> p_node) {
- node = p_node;
- }
-
- // Stores the pivot xform for this bone
-
- Ref<FBXNode> node = nullptr;
- Ref<FBXBone> parent_bone = nullptr;
- Ref<FBXSkeleton> fbx_skeleton = nullptr;
-};
-
-struct FBXSkinDeformer {
- FBXSkinDeformer(Ref<FBXBone> p_bone, const FBXDocParser::Cluster *p_cluster) :
- cluster(p_cluster), bone(p_bone) {}
- ~FBXSkinDeformer() {}
- const FBXDocParser::Cluster *cluster;
- Ref<FBXBone> bone;
-
- /* get associate model - the model can be invalid sometimes */
- Ref<FBXBone> get_associate_model() const {
- return bone->parent_bone;
- }
-
- Ref<FBXNode> get_link(const ImportState &state) const;
-};
-
-#endif // FBX_BONE_H
diff --git a/modules/fbx/data/fbx_material.cpp b/modules/fbx/data/fbx_material.cpp
deleted file mode 100644
index 36e20df3a9..0000000000
--- a/modules/fbx/data/fbx_material.cpp
+++ /dev/null
@@ -1,468 +0,0 @@
-/*************************************************************************/
-/* fbx_material.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "fbx_material.h"
-
-// FIXME: Shouldn't depend on core_bind.h! Use DirAccessRef like the rest of
-// the engine instead of core_bind::Directory.
-#include "core/core_bind.h"
-#include "scene/resources/material.h"
-#include "scene/resources/texture.h"
-#include "tools/validation_tools.h"
-
-String FBXMaterial::get_material_name() const {
- return material_name;
-}
-
-void FBXMaterial::set_imported_material(FBXDocParser::Material *p_material) {
- material = p_material;
-}
-
-void FBXMaterial::add_search_string(String p_filename, String p_current_directory, String search_directory, Vector<String> &texture_search_paths) {
- if (search_directory.is_empty()) {
- texture_search_paths.push_back(p_current_directory.get_base_dir().plus_file(p_filename));
- } else {
- texture_search_paths.push_back(p_current_directory.get_base_dir().plus_file(search_directory + "/" + p_filename));
- texture_search_paths.push_back(p_current_directory.get_base_dir().plus_file("../" + search_directory + "/" + p_filename));
- }
-}
-
-String find_file(const String &p_base, const String &p_file_to_find) {
- core_bind::Directory dir;
- dir.open(p_base);
-
- dir.list_dir_begin();
- String n = dir.get_next();
- while (!n.is_empty()) {
- if (n == "." || n == "..") {
- n = dir.get_next();
- continue;
- }
- if (dir.current_is_dir()) {
- // Don't use `path_to` or the returned path will be wrong.
- const String f = find_file(p_base + "/" + n, p_file_to_find);
- if (!f.is_empty()) {
- return f;
- }
- } else if (n == p_file_to_find) {
- return p_base + "/" + n;
- }
- n = dir.get_next();
- }
- dir.list_dir_end();
-
- return String();
-}
-
-// fbx will not give us good path information and let's not regex them to fix them
-// no relative paths are in fbx generally they have a rel field but it's populated incorrectly by the SDK.
-String FBXMaterial::find_texture_path_by_filename(const String p_filename, const String p_current_directory) {
- core_bind::Directory dir;
- Vector<String> paths;
- add_search_string(p_filename, p_current_directory, "", paths);
- add_search_string(p_filename, p_current_directory, "texture", paths);
- add_search_string(p_filename, p_current_directory, "textures", paths);
- add_search_string(p_filename, p_current_directory, "Textures", paths);
- add_search_string(p_filename, p_current_directory, "materials", paths);
- add_search_string(p_filename, p_current_directory, "mats", paths);
- add_search_string(p_filename, p_current_directory, "pictures", paths);
- add_search_string(p_filename, p_current_directory, "images", paths);
-
- for (int i = 0; i < paths.size(); i++) {
- if (dir.file_exists(paths[i])) {
- return paths[i];
- }
- }
-
- // We were not able to find the texture in the common locations,
- // try to find it into the project globally.
- // The common textures can be stored into one of those folders:
- // res://asset
- // res://texture
- // res://material
- // res://mat
- // res://image
- // res://picture
- //
- // Note the folders can also be called with custom names, like:
- // res://my_assets
- // since the keyword `asset` is into the directory name the textures will be
- // searched there too.
-
- dir.open("res://");
- dir.list_dir_begin();
- String n = dir.get_next();
- while (!n.is_empty()) {
- if (n == "." || n == "..") {
- n = dir.get_next();
- continue;
- }
- if (dir.current_is_dir()) {
- const String lower_n = n.to_lower();
- if (
- // Don't need to use plural.
- lower_n.find("asset") >= 0 ||
- lower_n.find("texture") >= 0 ||
- lower_n.find("material") >= 0 ||
- lower_n.find("mat") >= 0 ||
- lower_n.find("image") >= 0 ||
- lower_n.find("picture") >= 0) {
- // Don't use `path_to` or the returned path will be wrong.
- const String f = find_file(String("res://") + n, p_filename);
- if (!f.is_empty()) {
- return f;
- }
- }
- }
- n = dir.get_next();
- }
- dir.list_dir_end();
-
- return "";
-}
-
-template <class T>
-T extract_from_prop(FBXDocParser::PropertyPtr prop, const T &p_default, const std::string &p_name, const String &p_type) {
- ERR_FAIL_COND_V_MSG(prop == nullptr, p_default, "invalid property passed to extractor");
- const FBXDocParser::TypedProperty<T> *val = dynamic_cast<const FBXDocParser::TypedProperty<T> *>(prop);
-
- ERR_FAIL_COND_V_MSG(val == nullptr, p_default, "The FBX is corrupted, the property `" + String(p_name.c_str()) + "` is a `" + String(typeid(*prop).name()) + "` but should be a " + p_type);
- // Make sure to not lost any eventual opacity.
- return val->Value();
-}
-
-Ref<StandardMaterial3D> FBXMaterial::import_material(ImportState &state) {
- ERR_FAIL_COND_V(material == nullptr, nullptr);
-
- const String p_fbx_current_directory = state.path;
-
- Ref<StandardMaterial3D> spatial_material;
- spatial_material.instantiate();
-
- // read the material file
- // is material two sided
- // read material name
- print_verbose("[material] material name: " + ImportUtils::FBXNodeToName(material->Name()));
-
- material_name = ImportUtils::FBXNodeToName(material->Name());
-
- for (const std::pair<std::string, const FBXDocParser::Texture *> iter : material->Textures()) {
- const uint64_t texture_id = iter.second->ID();
- const std::string &fbx_mapping_name = iter.first;
- const FBXDocParser::Texture *fbx_texture_data = iter.second;
- const String absolute_texture_path = iter.second->FileName().c_str();
- const String texture_name = absolute_texture_path.get_file();
- const String file_extension = absolute_texture_path.get_extension().to_upper();
-
- const String debug_string = "texture id: " + itos(texture_id) + " texture name: " + String(iter.second->Name().c_str()) + " mapping name: " + String(fbx_mapping_name.c_str());
- // remember errors STILL need this string at the end for when you aren't in verbose debug mode :) they need context for when you're not verbose-ing.
- print_verbose(debug_string);
-
- const String file_extension_uppercase = file_extension.to_upper();
-
- if (fbx_transparency_flags.count(fbx_mapping_name) > 0) {
- // just enable it later let's make this fine-tuned.
- spatial_material->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA);
- }
-
- ERR_CONTINUE_MSG(file_extension.is_empty(), "your texture has no file extension so we had to ignore it, let us know if you think this is wrong file an issue on github! " + debug_string);
- ERR_CONTINUE_MSG(fbx_texture_map.count(fbx_mapping_name) <= 0, "This material has a texture with mapping name: " + String(fbx_mapping_name.c_str()) + " which is not yet supported by this importer. Consider opening an issue so we can support it.");
- ERR_CONTINUE_MSG(
- file_extension_uppercase != "PNG" &&
- file_extension_uppercase != "JPEG" &&
- file_extension_uppercase != "JPG" &&
- file_extension_uppercase != "TGA" &&
- file_extension_uppercase != "WEBP" &&
- file_extension_uppercase != "DDS",
- "The FBX file contains a texture with an unrecognized extension: " + file_extension_uppercase);
-
- print_verbose("Getting FBX mapping mode for " + String(fbx_mapping_name.c_str()));
- // get the texture map type
- const StandardMaterial3D::TextureParam mapping_mode = fbx_texture_map.at(fbx_mapping_name);
- print_verbose("Set FBX mapping mode to " + get_texture_param_name(mapping_mode));
-
- Ref<Texture> texture;
- print_verbose("texture mapping name: " + texture_name);
-
- if (state.cached_image_searches.has(texture_name)) {
- texture = state.cached_image_searches[texture_name];
- } else {
- String path = find_texture_path_by_filename(texture_name, p_fbx_current_directory);
- if (!path.is_empty()) {
- Ref<Texture2D> image_texture = ResourceLoader::load(path);
-
- ERR_CONTINUE(image_texture.is_null());
-
- texture = image_texture;
- state.cached_image_searches.insert(texture_name, texture);
- print_verbose("Created texture from loaded image file.");
-
- } else if (fbx_texture_data != nullptr && fbx_texture_data->Media() != nullptr && fbx_texture_data->Media()->IsEmbedded()) {
- // This is an embedded texture. Extract it.
- Ref<Image> image;
- //image.instantiate(); // oooo double instance bug? why make Image::_png_blah call
-
- const String extension = texture_name.get_extension().to_upper();
- if (extension == "PNG") {
- // The stored file is a PNG.
- image = Image::_png_mem_loader_func(fbx_texture_data->Media()->Content(), fbx_texture_data->Media()->ContentLength());
- ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded PNG image load fail.");
-
- } else if (
- extension == "JPEG" ||
- extension == "JPG") {
- // The stored file is a JPEG.
- image = Image::_jpg_mem_loader_func(fbx_texture_data->Media()->Content(), fbx_texture_data->Media()->ContentLength());
- ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded JPEG image load fail.");
-
- } else if (extension == "TGA") {
- // The stored file is a TGA.
- image = Image::_tga_mem_loader_func(fbx_texture_data->Media()->Content(), fbx_texture_data->Media()->ContentLength());
- ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded TGA image load fail.");
-
- } else if (extension == "WEBP") {
- // The stored file is a WEBP.
- image = Image::_webp_mem_loader_func(fbx_texture_data->Media()->Content(), fbx_texture_data->Media()->ContentLength());
- ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded WEBP image load fail.");
-
- // } else if (extension == "DDS") {
- // // In this moment is not possible to extract a DDS from a buffer, TODO consider add it to godot. See `textureloader_dds.cpp::load().
- // // The stored file is a DDS.
- } else {
- ERR_CONTINUE_MSG(true, "The embedded image with extension: " + extension + " is not yet supported. Open an issue please.");
- }
-
- Ref<ImageTexture> image_texture;
- image_texture.instantiate();
- image_texture->create_from_image(image);
-
- texture = image_texture;
-
- // TODO: this is potentially making something with the same name have a match incorrectly USE FBX ID as Hash. #fuck it later.
- state.cached_image_searches[texture_name] = texture;
- print_verbose("Created texture from embedded image.");
- } else {
- ERR_CONTINUE_MSG(true, "The FBX texture, with name: `" + texture_name + "`, is not found into the project nor is stored as embedded file. Make sure to insert the texture as embedded file or into the project, then reimport.");
- }
- }
-
- spatial_material->set_texture(mapping_mode, texture);
- }
-
- if (spatial_material.is_valid()) {
- spatial_material->set_name(material_name);
- }
-
- /// ALL below is related to properties
- for (FBXDocParser::LazyPropertyMap::value_type iter : material->GetLazyProperties()) {
- const std::string name = iter.first;
-
- if (name.empty()) {
- continue;
- }
-
- PropertyDesc desc = PROPERTY_DESC_NOT_FOUND;
- if (fbx_properties_desc.count(name) > 0) {
- desc = fbx_properties_desc.at(name);
- }
-
- // check if we can ignore this it will be done at the next phase
- if (desc == PROPERTY_DESC_NOT_FOUND || desc == PROPERTY_DESC_IGNORE) {
- // count the texture mapping references. Skip this one if it's found and we can't look up a property value.
- if (fbx_texture_map.count(name) > 0) {
- continue; // safe to ignore it's a texture mapping.
- }
- }
-
- if (desc == PROPERTY_DESC_IGNORE) {
- //WARN_PRINT("[Ignored] The FBX material parameter: `" + String(name.c_str()) + "` is ignored.");
- continue;
- } else {
- print_verbose("FBX Material parameter: " + String(name.c_str()));
-
- // Check for Diffuse material system / lambert materials / legacy basically
- if (name == "Diffuse" && !warning_non_pbr_material) {
- ValidationTracker::get_singleton()->add_validation_error(state.path, "Invalid material settings change to Ai Standard Surface shader, mat name: " + material_name.c_escape());
- warning_non_pbr_material = true;
- }
- }
-
- // DISABLE when adding support for all weird and wonderful material formats
- if (desc == PROPERTY_DESC_NOT_FOUND) {
- continue;
- }
-
- ERR_CONTINUE_MSG(desc == PROPERTY_DESC_NOT_FOUND, "The FBX material parameter: `" + String(name.c_str()) + "` was not recognized. Please open an issue so we can add the support to it.");
-
- const FBXDocParser::PropertyTable *tbl = material;
- FBXDocParser::PropertyPtr prop = tbl->Get(name);
-
- ERR_CONTINUE_MSG(prop == nullptr, "This file may be corrupted because is not possible to extract the material parameter: " + String(name.c_str()));
-
- if (spatial_material.is_null()) {
- // Done here so if no data no material is created.
- spatial_material.instantiate();
- }
-
- const FBXDocParser::TypedProperty<real_t> *real_value = dynamic_cast<const FBXDocParser::TypedProperty<real_t> *>(prop);
- const FBXDocParser::TypedProperty<Vector3> *vector_value = dynamic_cast<const FBXDocParser::TypedProperty<Vector3> *>(prop);
-
- if (!real_value && !vector_value) {
- //WARN_PRINT("unsupported datatype in property: " + String(name.c_str()));
- continue;
- }
-
- if (vector_value && !real_value) {
- if (vector_value->Value() == Vector3(0, 0, 0) && !real_value) {
- continue;
- }
- }
-
- switch (desc) {
- case PROPERTY_DESC_ALBEDO_COLOR: {
- if (vector_value) {
- const Vector3 &color = vector_value->Value();
- // Make sure to not lost any eventual opacity.
- if (color != Vector3(0, 0, 0)) {
- Color c = Color();
- c[0] = color[0];
- c[1] = color[1];
- c[2] = color[2];
- spatial_material->set_albedo(c);
- }
-
- } else if (real_value) {
- print_error("albedo is unsupported format?");
- }
- } break;
- case PROPERTY_DESC_TRANSPARENT: {
- if (real_value) {
- const real_t opacity = real_value->Value();
- if (opacity < (1.0 - CMP_EPSILON)) {
- Color c = spatial_material->get_albedo();
- c.a = opacity;
- spatial_material->set_albedo(c);
-
- spatial_material->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA);
- spatial_material->set_depth_draw_mode(BaseMaterial3D::DEPTH_DRAW_OPAQUE_ONLY);
- }
- } else if (vector_value) {
- print_error("unsupported transparent desc type vector!");
- }
- } break;
- case PROPERTY_DESC_SPECULAR: {
- if (real_value) {
- print_verbose("specular real value: " + rtos(real_value->Value()));
- spatial_material->set_specular(MIN(1.0, real_value->Value()));
- }
-
- if (vector_value) {
- print_error("unsupported specular vector value: " + vector_value->Value());
- }
- } break;
-
- case PROPERTY_DESC_SPECULAR_COLOR: {
- if (vector_value) {
- print_error("unsupported specular color: " + vector_value->Value());
- }
- } break;
- case PROPERTY_DESC_SHINYNESS: {
- if (real_value) {
- print_error("unsupported shinyness:" + rtos(real_value->Value()));
- }
- } break;
- case PROPERTY_DESC_METALLIC: {
- if (real_value) {
- print_verbose("metallic real value: " + rtos(real_value->Value()));
- spatial_material->set_metallic(MIN(1.0f, real_value->Value()));
- } else {
- print_error("unsupported value type for metallic");
- }
- } break;
- case PROPERTY_DESC_ROUGHNESS: {
- if (real_value) {
- print_verbose("roughness real value: " + rtos(real_value->Value()));
- spatial_material->set_roughness(MIN(1.0f, real_value->Value()));
- } else {
- print_error("unsupported value type for roughness");
- }
- } break;
- case PROPERTY_DESC_COAT: {
- if (real_value) {
- print_verbose("clearcoat real value: " + rtos(real_value->Value()));
- spatial_material->set_clearcoat(MIN(1.0f, real_value->Value()));
- } else {
- print_error("unsupported value type for clearcoat");
- }
- } break;
- case PROPERTY_DESC_COAT_ROUGHNESS: {
- // meaning is that approx equal to zero is disabled not actually zero. ;)
- if (real_value && Math::is_zero_approx(real_value->Value())) {
- print_verbose("clearcoat real value: " + rtos(real_value->Value()));
- spatial_material->set_clearcoat_roughness(real_value->Value());
- } else {
- print_error("unsupported value type for clearcoat gloss");
- }
- } break;
- case PROPERTY_DESC_EMISSIVE: {
- if (real_value && Math::is_zero_approx(real_value->Value())) {
- print_verbose("Emissive real value: " + rtos(real_value->Value()));
- spatial_material->set_emission_energy(real_value->Value());
- } else if (vector_value && !vector_value->Value().is_equal_approx(Vector3(0, 0, 0))) {
- const Vector3 &color = vector_value->Value();
- Color c;
- c[0] = color[0];
- c[1] = color[1];
- c[2] = color[2];
- spatial_material->set_emission(c);
- }
- } break;
- case PROPERTY_DESC_EMISSIVE_COLOR: {
- if (vector_value && !vector_value->Value().is_equal_approx(Vector3(0, 0, 0))) {
- const Vector3 &color = vector_value->Value();
- Color c;
- c[0] = color[0];
- c[1] = color[1];
- c[2] = color[2];
- spatial_material->set_emission(c);
- } else {
- print_error("unsupported value type for emissive color");
- }
- } break;
- case PROPERTY_DESC_NOT_FOUND:
- case PROPERTY_DESC_IGNORE:
- break;
- default:
- break;
- }
- }
-
- return spatial_material;
-}
diff --git a/modules/fbx/data/fbx_material.h b/modules/fbx/data/fbx_material.h
deleted file mode 100644
index e20b43561b..0000000000
--- a/modules/fbx/data/fbx_material.h
+++ /dev/null
@@ -1,285 +0,0 @@
-/*************************************************************************/
-/* fbx_material.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef FBX_MATERIAL_H
-#define FBX_MATERIAL_H
-
-#include "tools/import_utils.h"
-
-#include "core/object/ref_counted.h"
-#include "core/string/ustring.h"
-
-struct FBXMaterial : public RefCounted {
- String material_name = String();
- bool warning_non_pbr_material = false;
- FBXDocParser::Material *material = nullptr;
-
- /* Godot materials
- *** Texture Maps:
- * Albedo - color, texture
- * Metallic - specular, metallic, texture
- * Roughness - roughness, texture
- * Emission - color, texture
- * Normal Map - scale, texture
- * Ambient Occlusion - texture
- * Refraction - scale, texture
- *** Has Settings for:
- * UV1 - SCALE, OFFSET
- * UV2 - SCALE, OFFSET
- *** Flags for
- * Transparent
- * Cull Mode
- */
-
- enum class MapMode {
- AlbedoM = 0,
- MetallicM,
- SpecularM,
- EmissionM,
- RoughnessM,
- NormalM,
- AmbientOcclusionM,
- RefractionM,
- ReflectionM,
- };
-
- /* Returns the string representation of the TextureParam enum */
- static String get_texture_param_name(StandardMaterial3D::TextureParam param) {
- switch (param) {
- case StandardMaterial3D::TEXTURE_ALBEDO:
- return "TEXTURE_ALBEDO";
- case StandardMaterial3D::TEXTURE_METALLIC:
- return "TEXTURE_METALLIC";
- case StandardMaterial3D::TEXTURE_ROUGHNESS:
- return "TEXTURE_ROUGHNESS";
- case StandardMaterial3D::TEXTURE_EMISSION:
- return "TEXTURE_EMISSION";
- case StandardMaterial3D::TEXTURE_NORMAL:
- return "TEXTURE_NORMAL";
- case StandardMaterial3D::TEXTURE_RIM:
- return "TEXTURE_RIM";
- case StandardMaterial3D::TEXTURE_CLEARCOAT:
- return "TEXTURE_CLEARCOAT";
- case StandardMaterial3D::TEXTURE_FLOWMAP:
- return "TEXTURE_FLOWMAP";
- case StandardMaterial3D::TEXTURE_AMBIENT_OCCLUSION:
- return "TEXTURE_AMBIENT_OCCLUSION";
- // case StandardMaterial3D::TEXTURE_DEPTH: // TODO: work out how to make this function again!
- // return "TEXTURE_DEPTH";
- case StandardMaterial3D::TEXTURE_SUBSURFACE_SCATTERING:
- return "TEXTURE_SUBSURFACE_SCATTERING";
- // case StandardMaterial3D::TEXTURE_TRANSMISSION: // TODO: work out how to make this function again!
- // return "TEXTURE_TRANSMISSION";
- case StandardMaterial3D::TEXTURE_REFRACTION:
- return "TEXTURE_REFRACTION";
- case StandardMaterial3D::TEXTURE_DETAIL_MASK:
- return "TEXTURE_DETAIL_MASK";
- case StandardMaterial3D::TEXTURE_DETAIL_ALBEDO:
- return "TEXTURE_DETAIL_ALBEDO";
- case StandardMaterial3D::TEXTURE_DETAIL_NORMAL:
- return "TEXTURE_DETAIL_NORMAL";
- case StandardMaterial3D::TEXTURE_MAX:
- return "TEXTURE_MAX";
- default:
- return "broken horribly";
- }
- };
-
- // TODO make this static?
- const std::map<std::string, bool> fbx_transparency_flags = {
- /* Transparent */
- { "TransparentColor", true },
- { "Maya|opacity", true }
- };
-
- // TODO make this static?
- const std::map<std::string, StandardMaterial3D::TextureParam> fbx_texture_map = {
- /* Diffuse */
- { "Maya|base", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO },
- { "DiffuseColor", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO },
- { "Maya|DiffuseTexture", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO },
- { "Maya|baseColor", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO },
- { "Maya|baseColor|file", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO },
- { "3dsMax|Parameters|base_color_map", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO },
- { "Maya|TEX_color_map|file", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO },
- { "Maya|TEX_color_map", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO },
- /* Emission */
- { "EmissiveColor", StandardMaterial3D::TextureParam::TEXTURE_EMISSION },
- { "EmissiveFactor", StandardMaterial3D::TextureParam::TEXTURE_EMISSION },
- { "Maya|emissionColor", StandardMaterial3D::TextureParam::TEXTURE_EMISSION },
- { "Maya|emissionColor|file", StandardMaterial3D::TextureParam::TEXTURE_EMISSION },
- { "3dsMax|Parameters|emission_map", StandardMaterial3D::TextureParam::TEXTURE_EMISSION },
- { "Maya|TEX_emissive_map", StandardMaterial3D::TextureParam::TEXTURE_EMISSION },
- { "Maya|TEX_emissive_map|file", StandardMaterial3D::TextureParam::TEXTURE_EMISSION },
- /* Metallic */
- { "Maya|metalness", StandardMaterial3D::TextureParam::TEXTURE_METALLIC },
- { "Maya|metalness|file", StandardMaterial3D::TextureParam::TEXTURE_METALLIC },
- { "3dsMax|Parameters|metalness_map", StandardMaterial3D::TextureParam::TEXTURE_METALLIC },
- { "Maya|TEX_metallic_map", StandardMaterial3D::TextureParam::TEXTURE_METALLIC },
- { "Maya|TEX_metallic_map|file", StandardMaterial3D::TextureParam::TEXTURE_METALLIC },
-
- /* Roughness */
- // Arnold Roughness Map
- { "Maya|specularRoughness", StandardMaterial3D::TextureParam::TEXTURE_ROUGHNESS },
-
- { "3dsMax|Parameters|roughness_map", StandardMaterial3D::TextureParam::TEXTURE_ROUGHNESS },
- { "Maya|TEX_roughness_map", StandardMaterial3D::TextureParam::TEXTURE_ROUGHNESS },
- { "Maya|TEX_roughness_map|file", StandardMaterial3D::TextureParam::TEXTURE_ROUGHNESS },
-
- /* Normal */
- { "NormalMap", StandardMaterial3D::TextureParam::TEXTURE_NORMAL },
- //{ "Bump", Material::TextureParam::TEXTURE_NORMAL },
- //{ "3dsMax|Parameters|bump_map", Material::TextureParam::TEXTURE_NORMAL },
- { "Maya|NormalTexture", StandardMaterial3D::TextureParam::TEXTURE_NORMAL },
- //{ "Maya|normalCamera", Material::TextureParam::TEXTURE_NORMAL },
- //{ "Maya|normalCamera|file", Material::TextureParam::TEXTURE_NORMAL },
- { "Maya|TEX_normal_map", StandardMaterial3D::TextureParam::TEXTURE_NORMAL },
- { "Maya|TEX_normal_map|file", StandardMaterial3D::TextureParam::TEXTURE_NORMAL },
- /* AO */
- { "Maya|TEX_ao_map", StandardMaterial3D::TextureParam::TEXTURE_AMBIENT_OCCLUSION },
- { "Maya|TEX_ao_map|file", StandardMaterial3D::TextureParam::TEXTURE_AMBIENT_OCCLUSION },
-
- // TODO: specular workflow conversion
- // { "SpecularColor", StandardMaterial3D::TextureParam::TEXTURE_METALLIC },
- // { "Maya|specularColor", StandardMaterial3D::TextureParam::TEXTURE_METALLIC },
- // { "Maya|SpecularTexture", StandardMaterial3D::TextureParam::TEXTURE_METALLIC },
- // { "Maya|SpecularTexture|file", StandardMaterial3D::TextureParam::TEXTURE_METALLIC },
- // { "ShininessExponent", SpatialMaterial::TextureParam::UNSUPPORTED },
- // { "ReflectionFactor", SpatialMaterial::TextureParam::UNSUPPORTED },
-
- //{ "TransparentColor",SpatialMaterial::TextureParam::TEXTURE_CHANNEL_ALPHA },
- //{ "TransparencyFactor",SpatialMaterial::TextureParam::TEXTURE_CHANNEL_ALPHA }
-
- // TODO: diffuse roughness
- //{ "Maya|diffuseRoughness", SpatialMaterial::TextureParam::UNSUPPORTED },
- //{ "Maya|diffuseRoughness|file", SpatialMaterial::TextureParam::UNSUPPORTED },
-
- };
-
- // TODO make this static?
- enum PropertyDesc {
- PROPERTY_DESC_NOT_FOUND,
- PROPERTY_DESC_ALBEDO_COLOR,
- PROPERTY_DESC_TRANSPARENT,
- PROPERTY_DESC_METALLIC,
- PROPERTY_DESC_ROUGHNESS,
- PROPERTY_DESC_SPECULAR,
- PROPERTY_DESC_SPECULAR_COLOR,
- PROPERTY_DESC_SHINYNESS,
- PROPERTY_DESC_COAT,
- PROPERTY_DESC_COAT_ROUGHNESS,
- PROPERTY_DESC_EMISSIVE,
- PROPERTY_DESC_EMISSIVE_COLOR,
- PROPERTY_DESC_IGNORE
- };
-
- const std::map<std::string, PropertyDesc> fbx_properties_desc = {
- /* Albedo */
- { "DiffuseColor", PROPERTY_DESC_ALBEDO_COLOR },
- { "Maya|baseColor", PROPERTY_DESC_ALBEDO_COLOR },
-
- /* Specular */
- { "Maya|specular", PROPERTY_DESC_SPECULAR },
- { "Maya|specularColor", PROPERTY_DESC_SPECULAR_COLOR },
-
- /* Specular roughness - arnold roughness map */
- { "Maya|specularRoughness", PROPERTY_DESC_ROUGHNESS },
-
- /* Transparent */
- { "Opacity", PROPERTY_DESC_TRANSPARENT },
- { "TransparencyFactor", PROPERTY_DESC_TRANSPARENT },
- { "Maya|opacity", PROPERTY_DESC_TRANSPARENT },
-
- { "Maya|metalness", PROPERTY_DESC_METALLIC },
- { "Maya|metallic", PROPERTY_DESC_METALLIC },
-
- /* Roughness */
- { "Maya|roughness", PROPERTY_DESC_ROUGHNESS },
-
- /* Coat */
- //{ "Maya|coat", PROPERTY_DESC_COAT },
-
- /* Coat roughness */
- //{ "Maya|coatRoughness", PROPERTY_DESC_COAT_ROUGHNESS },
-
- /* Emissive */
- { "Maya|emission", PROPERTY_DESC_EMISSIVE },
- { "Maya|emissive", PROPERTY_DESC_EMISSIVE },
-
- /* Emissive color */
- { "EmissiveColor", PROPERTY_DESC_EMISSIVE_COLOR },
- { "Maya|emissionColor", PROPERTY_DESC_EMISSIVE_COLOR },
-
- /* Ignore */
- { "Shininess", PROPERTY_DESC_IGNORE },
- { "Reflectivity", PROPERTY_DESC_IGNORE },
- { "Maya|diffuseRoughness", PROPERTY_DESC_IGNORE },
- { "Maya", PROPERTY_DESC_IGNORE },
- { "Diffuse", PROPERTY_DESC_ALBEDO_COLOR },
- { "Maya|TypeId", PROPERTY_DESC_IGNORE },
- { "Ambient", PROPERTY_DESC_IGNORE },
- { "AmbientColor", PROPERTY_DESC_IGNORE },
- { "ShininessExponent", PROPERTY_DESC_IGNORE },
- { "Specular", PROPERTY_DESC_IGNORE },
- { "SpecularColor", PROPERTY_DESC_IGNORE },
- { "SpecularFactor", PROPERTY_DESC_IGNORE },
- //{ "BumpFactor", PROPERTY_DESC_IGNORE },
- { "Maya|exitToBackground", PROPERTY_DESC_IGNORE },
- { "Maya|indirectDiffuse", PROPERTY_DESC_IGNORE },
- { "Maya|indirectSpecular", PROPERTY_DESC_IGNORE },
- { "Maya|internalReflections", PROPERTY_DESC_IGNORE },
- { "DiffuseFactor", PROPERTY_DESC_IGNORE },
- { "AmbientFactor", PROPERTY_DESC_IGNORE },
- { "ReflectionColor", PROPERTY_DESC_IGNORE },
- { "Emissive", PROPERTY_DESC_IGNORE },
- { "Maya|coatColor", PROPERTY_DESC_IGNORE },
- { "Maya|coatNormal", PROPERTY_DESC_IGNORE },
- { "Maya|coatIOR", PROPERTY_DESC_IGNORE },
- };
-
- /* storing the texture properties like color */
- template <class T>
- struct TexturePropertyMapping : RefCounted {
- StandardMaterial3D::TextureParam map_mode = StandardMaterial3D::TextureParam::TEXTURE_ALBEDO;
- const T property = T();
- };
-
- static void add_search_string(String p_filename, String p_current_directory, String search_directory, Vector<String> &texture_search_paths);
-
- static String find_texture_path_by_filename(const String p_filename, const String p_current_directory);
-
- String get_material_name() const;
-
- void set_imported_material(FBXDocParser::Material *p_material);
-
- Ref<StandardMaterial3D> import_material(ImportState &state);
-};
-
-#endif // FBX_MATERIAL_H
diff --git a/modules/fbx/data/fbx_mesh_data.cpp b/modules/fbx/data/fbx_mesh_data.cpp
deleted file mode 100644
index 643a74f83e..0000000000
--- a/modules/fbx/data/fbx_mesh_data.cpp
+++ /dev/null
@@ -1,1435 +0,0 @@
-/*************************************************************************/
-/* fbx_mesh_data.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "fbx_mesh_data.h"
-
-#include "core/templates/local_vector.h"
-#include "scene/resources/importer_mesh.h"
-#include "scene/resources/mesh.h"
-#include "scene/resources/surface_tool.h"
-
-#include "thirdparty/misc/polypartition.h"
-
-template <class T>
-T collect_first(const Vector<VertexData<T>> *p_data, T p_fall_back) {
- if (p_data->is_empty()) {
- return p_fall_back;
- }
-
- return (*p_data)[0].data;
-}
-
-template <class T>
-HashMap<int, T> collect_all(const Vector<VertexData<T>> *p_data, HashMap<int, T> p_fall_back) {
- if (p_data->is_empty()) {
- return p_fall_back;
- }
-
- HashMap<int, T> collection;
- for (int i = 0; i < p_data->size(); i += 1) {
- const VertexData<T> &vd = (*p_data)[i];
- collection[vd.polygon_index] = vd.data;
- }
- return collection;
-}
-
-template <class T>
-T collect_average(const Vector<VertexData<T>> *p_data, T p_fall_back) {
- if (p_data->is_empty()) {
- return p_fall_back;
- }
-
- T combined = (*p_data)[0].data; // Make sure the data is always correctly initialized.
- print_verbose("size of data: " + itos(p_data->size()));
- for (int i = 1; i < p_data->size(); i += 1) {
- combined += (*p_data)[i].data;
- }
- combined = combined / real_t(p_data->size());
-
- return combined.normalized();
-}
-
-HashMap<int, Vector3> collect_normal(const Vector<VertexData<Vector3>> *p_data, HashMap<int, Vector3> p_fall_back) {
- if (p_data->is_empty()) {
- return p_fall_back;
- }
-
- HashMap<int, Vector3> collection;
- for (int i = 0; i < p_data->size(); i += 1) {
- const VertexData<Vector3> &vd = (*p_data)[i];
- collection[vd.polygon_index] = vd.data;
- }
- return collection;
-}
-
-HashMap<int, Vector2> collect_uv(const Vector<VertexData<Vector2>> *p_data, HashMap<int, Vector2> p_fall_back) {
- if (p_data->is_empty()) {
- return p_fall_back;
- }
-
- HashMap<int, Vector2> collection;
- for (int i = 0; i < p_data->size(); i += 1) {
- const VertexData<Vector2> &vd = (*p_data)[i];
- collection[vd.polygon_index] = vd.data;
- }
- return collection;
-}
-
-ImporterMeshInstance3D *FBXMeshData::create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression) {
- mesh_geometry = p_mesh_geometry;
- // todo: make this just use a uint64_t FBX ID this is a copy of our original materials unfortunately.
- const std::vector<const FBXDocParser::Material *> &material_lookup = model->GetMaterials();
-
- // TODO: perf hotspot on large files
- // this can be a very large copy
- std::vector<int> polygon_indices = mesh_geometry->get_polygon_indices();
- std::vector<Vector3> vertices = mesh_geometry->get_vertices();
-
- // Phase 1. Parse all FBX data.
- HashMap<int, Vector3> normals;
- HashMap<int, HashMap<int, Vector3>> normals_raw = extract_per_vertex_data(
- vertices.size(),
- mesh_geometry->get_edge_map(),
- polygon_indices,
- mesh_geometry->get_normals(),
- &collect_all,
- HashMap<int, Vector3>());
-
- HashMap<int, Vector2> uvs_0;
- HashMap<int, HashMap<int, Vector2>> uvs_0_raw = extract_per_vertex_data(
- vertices.size(),
- mesh_geometry->get_edge_map(),
- polygon_indices,
- mesh_geometry->get_uv_0(),
- &collect_all,
- HashMap<int, Vector2>());
-
- HashMap<int, Vector2> uvs_1;
- HashMap<int, HashMap<int, Vector2>> uvs_1_raw = extract_per_vertex_data(
- vertices.size(),
- mesh_geometry->get_edge_map(),
- polygon_indices,
- mesh_geometry->get_uv_1(),
- &collect_all,
- HashMap<int, Vector2>());
-
- HashMap<int, Color> colors;
- HashMap<int, HashMap<int, Color>> colors_raw = extract_per_vertex_data(
- vertices.size(),
- mesh_geometry->get_edge_map(),
- polygon_indices,
- mesh_geometry->get_colors(),
- &collect_all,
- HashMap<int, Color>());
-
- // TODO what about tangents?
- // TODO what about bi-nomials?
- // TODO there is other?
-
- HashMap<int, SurfaceId> polygon_surfaces = extract_per_polygon(
- vertices.size(),
- polygon_indices,
- mesh_geometry->get_material_allocation_id(),
- -1);
-
- HashMap<String, MorphVertexData> morphs;
- extract_morphs(mesh_geometry, morphs);
-
- // TODO please add skinning.
- //mesh_id = mesh_geometry->ID();
-
- sanitize_vertex_weights(state);
-
- // Reorganize polygon vertices to correctly take into account strange
- // UVs.
- reorganize_vertices(
- polygon_indices,
- vertices,
- normals,
- uvs_0,
- uvs_1,
- colors,
- morphs,
- normals_raw,
- colors_raw,
- uvs_0_raw,
- uvs_1_raw);
-
- const int color_count = colors.size();
- print_verbose("Vertex color count: " + itos(color_count));
-
- // Make sure that from this moment on the mesh_geometry is no used anymore.
- // This is a safety step, because the mesh_geometry data are no more valid
- // at this point.
-
- const int vertex_count = vertices.size();
-
- print_verbose("Vertex count: " + itos(vertex_count));
-
- // The map key is the material allocator id that is also used as surface id.
- HashMap<SurfaceId, SurfaceData> surfaces;
-
- // Phase 2. For each material create a surface tool (So a different mesh).
- {
- if (polygon_surfaces.is_empty()) {
- // No material, just use the default one with index -1.
- // Set -1 to all polygons.
- const int polygon_count = count_polygons(polygon_indices);
- for (int p = 0; p < polygon_count; p += 1) {
- polygon_surfaces[p] = -1;
- }
- }
-
- // Create the surface now.
- for (const int *polygon_id = polygon_surfaces.next(nullptr); polygon_id != nullptr; polygon_id = polygon_surfaces.next(polygon_id)) {
- const int surface_id = polygon_surfaces[*polygon_id];
- if (surfaces.has(surface_id) == false) {
- SurfaceData sd;
- sd.surface_tool.instantiate();
- sd.surface_tool->begin(Mesh::PRIMITIVE_TRIANGLES);
-
- if (surface_id < 0) {
- // nothing to do
- } else if (surface_id < (int)material_lookup.size()) {
- const FBXDocParser::Material *mat_mapping = material_lookup.at(surface_id);
- const uint64_t mapping_id = mat_mapping->ID();
- if (state.cached_materials.has(mapping_id)) {
- sd.material = state.cached_materials[mapping_id];
- }
- } else {
- WARN_PRINT("out of bounds surface detected, FBX file has corrupt material data");
- }
-
- surfaces.set(surface_id, sd);
- }
- }
- }
-
- // Phase 3. Map the vertices relative to each surface, in this way we can
- // just insert the vertices that we need per each surface.
- {
- PolygonId polygon_index = -1;
- SurfaceId surface_id = -1;
- SurfaceData *surface_data = nullptr;
-
- for (size_t polygon_vertex = 0; polygon_vertex < polygon_indices.size(); polygon_vertex += 1) {
- if (is_start_of_polygon(polygon_indices, polygon_vertex)) {
- polygon_index += 1;
- ERR_FAIL_COND_V_MSG(polygon_surfaces.has(polygon_index) == false, nullptr, "The FBX file is corrupted, This surface_index is not expected.");
- surface_id = polygon_surfaces[polygon_index];
- surface_data = surfaces.getptr(surface_id);
- CRASH_COND(surface_data == nullptr); // Can't be null.
- }
-
- const int vertex = get_vertex_from_polygon_vertex(polygon_indices, polygon_vertex);
-
- // The vertex position in the surface
- // Uses a lookup table for speed with large scenes
- bool has_polygon_vertex_index = surface_data->lookup_table.has(vertex);
- int surface_polygon_vertex_index = -1;
-
- if (has_polygon_vertex_index) {
- surface_polygon_vertex_index = surface_data->lookup_table[vertex];
- } else {
- surface_polygon_vertex_index = surface_data->vertices_map.size();
- surface_data->lookup_table[vertex] = surface_polygon_vertex_index;
- surface_data->vertices_map.push_back(vertex);
- }
-
- surface_data->surface_polygon_vertex[polygon_index].push_back(surface_polygon_vertex_index);
- }
- }
-
- //print_verbose("[debug UV 1] UV1: " + itos(uvs_0.size()));
- //print_verbose("[debug UV 2] UV2: " + itos(uvs_1.size()));
-
- // Phase 4. Per each surface just insert the vertices and add the indices.
- for (const SurfaceId *surface_id = surfaces.next(nullptr); surface_id != nullptr; surface_id = surfaces.next(surface_id)) {
- SurfaceData *surface = surfaces.getptr(*surface_id);
-
- // Just add the vertices data.
- for (unsigned int i = 0; i < surface->vertices_map.size(); i += 1) {
- const Vertex vertex = surface->vertices_map[i];
-
- // This must be done before add_vertex because the surface tool is
- // expecting this before the st->add_vertex() call
- add_vertex(state,
- surface->surface_tool,
- state.scale,
- vertex,
- vertices,
- normals,
- uvs_0,
- uvs_1,
- colors);
- }
-
- // Triangulate the various polygons and add the indices.
- for (const PolygonId *polygon_id = surface->surface_polygon_vertex.next(nullptr); polygon_id != nullptr; polygon_id = surface->surface_polygon_vertex.next(polygon_id)) {
- const Vector<DataIndex> *indices = surface->surface_polygon_vertex.getptr(*polygon_id);
- triangulate_polygon(
- surface,
- *indices,
- vertices);
- }
- }
-
- // Phase 5. Compose the morphs if any.
- for (const SurfaceId *surface_id = surfaces.next(nullptr); surface_id != nullptr; surface_id = surfaces.next(surface_id)) {
- SurfaceData *surface = surfaces.getptr(*surface_id);
-
- for (const String *morph_name = morphs.next(nullptr); morph_name != nullptr; morph_name = morphs.next(morph_name)) {
- MorphVertexData *morph_data = morphs.getptr(*morph_name);
-
- // As said by the docs, this is not supposed to be different than
- // vertex_count.
- CRASH_COND(morph_data->vertices.size() != vertex_count);
- CRASH_COND(morph_data->normals.size() != vertex_count);
-
- Vector3 *vertices_ptr = morph_data->vertices.ptrw();
- Vector3 *normals_ptr = morph_data->normals.ptrw();
-
- Ref<SurfaceTool> morph_st;
- morph_st.instantiate();
- morph_st->begin(Mesh::PRIMITIVE_TRIANGLES);
-
- for (unsigned int vi = 0; vi < surface->vertices_map.size(); vi += 1) {
- const Vertex &vertex = surface->vertices_map[vi];
- add_vertex(
- state,
- morph_st,
- state.scale,
- vertex,
- vertices,
- normals,
- uvs_0,
- uvs_1,
- colors,
- vertices_ptr[vertex],
- normals_ptr[vertex]);
- }
-
- if (state.is_blender_fbx) {
- morph_st->generate_normals();
- }
- morph_st->generate_tangents();
- surface->morphs.push_back(morph_st->commit_to_arrays());
- }
- }
-
- // Phase 6. Compose the mesh and return it.
- Ref<ImporterMesh> mesh;
- mesh.instantiate();
-
- // Add blend shape info.
- for (const String *morph_name = morphs.next(nullptr); morph_name != nullptr; morph_name = morphs.next(morph_name)) {
- mesh->add_blend_shape(*morph_name);
- }
-
- // TODO always normalized, Why?
- mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED);
-
- // Add surfaces.
- for (const SurfaceId *surface_id = surfaces.next(nullptr); surface_id != nullptr; surface_id = surfaces.next(surface_id)) {
- SurfaceData *surface = surfaces.getptr(*surface_id);
-
- if (state.is_blender_fbx) {
- surface->surface_tool->generate_normals();
- }
- // you can't generate them without a valid uv map.
- if (uvs_0_raw.size() > 0) {
- surface->surface_tool->generate_tangents();
- }
-
- Array mesh_array = surface->surface_tool->commit_to_arrays();
- Array blend_shapes = surface->morphs;
-
- if (surface->material.is_valid()) {
- mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, mesh_array, blend_shapes, Dictionary(), surface->material, surface->material->get_name());
- } else {
- mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, mesh_array, blend_shapes);
- }
- }
-
- ImporterMeshInstance3D *godot_mesh = memnew(ImporterMeshInstance3D);
- godot_mesh->set_mesh(mesh);
- const String name = ImportUtils::FBXNodeToName(model->Name());
- godot_mesh->set_name(name); // hurry up compiling >.<
- mesh->set_name("mesh3d-" + name);
- return godot_mesh;
-}
-
-void FBXMeshData::sanitize_vertex_weights(const ImportState &state) {
- const int max_vertex_influence_count = RS::ARRAY_WEIGHTS_SIZE;
- Map<int, int> skeleton_to_skin_bind_id;
- // TODO: error's need added
- const FBXDocParser::Skin *fbx_skin = mesh_geometry->DeformerSkin();
-
- if (fbx_skin == nullptr || fbx_skin->Clusters().size() == 0) {
- return; // do nothing
- }
-
- //
- // Precalculate the skin cluster mapping
- //
-
- int bind_id = 0;
- for (const FBXDocParser::Cluster *cluster : fbx_skin->Clusters()) {
- ERR_CONTINUE_MSG(!state.fbx_bone_map.has(cluster->TargetNode()->ID()), "Missing bone map for cluster target node with id " + uitos(cluster->TargetNode()->ID()) + ".");
- Ref<FBXBone> bone = state.fbx_bone_map[cluster->TargetNode()->ID()];
- skeleton_to_skin_bind_id.insert(bone->godot_bone_id, bind_id);
- bind_id++;
- }
-
- for (const Vertex *v = vertex_weights.next(nullptr); v != nullptr; v = vertex_weights.next(v)) {
- VertexWeightMapping *vm = vertex_weights.getptr(*v);
- ERR_CONTINUE(vm->bones.size() != vm->weights.size()); // No message, already checked.
- ERR_CONTINUE(vm->bones_ref.size() != vm->weights.size()); // No message, already checked.
-
- const int initial_size = vm->weights.size();
- {
- // Init bone id
- int *bones_ptr = vm->bones.ptrw();
- Ref<FBXBone> *bones_ref_ptr = vm->bones_ref.ptrw();
-
- for (int i = 0; i < vm->weights.size(); i += 1) {
- // At this point this is not possible because the skeleton is already initialized.
- CRASH_COND(bones_ref_ptr[i]->godot_bone_id == -2);
- bones_ptr[i] = skeleton_to_skin_bind_id[bones_ref_ptr[i]->godot_bone_id];
- }
-
- // From this point on the data is no more valid.
- vm->bones_ref.clear();
- }
-
- {
- // Sort
- float *weights_ptr = vm->weights.ptrw();
- int *bones_ptr = vm->bones.ptrw();
- for (int i = 0; i < vm->weights.size(); i += 1) {
- for (int x = i + 1; x < vm->weights.size(); x += 1) {
- if (weights_ptr[i] < weights_ptr[x]) {
- SWAP(weights_ptr[i], weights_ptr[x]);
- SWAP(bones_ptr[i], bones_ptr[x]);
- }
- }
- }
- }
-
- {
- // Resize
- vm->weights.resize(max_vertex_influence_count);
- vm->bones.resize(max_vertex_influence_count);
- float *weights_ptr = vm->weights.ptrw();
- int *bones_ptr = vm->bones.ptrw();
- for (int i = initial_size; i < max_vertex_influence_count; i += 1) {
- weights_ptr[i] = 0.0;
- bones_ptr[i] = 0;
- }
-
- // Normalize
- real_t sum = 0.0;
- for (int i = 0; i < max_vertex_influence_count; i += 1) {
- sum += weights_ptr[i];
- }
- if (sum > 0.0) {
- for (int i = 0; i < vm->weights.size(); i += 1) {
- weights_ptr[i] = weights_ptr[i] / sum;
- }
- }
- }
- }
-}
-
-void FBXMeshData::reorganize_vertices(
- // TODO: perf hotspot on insane files
- std::vector<int> &r_polygon_indices,
- std::vector<Vector3> &r_vertices,
- HashMap<int, Vector3> &r_normals,
- HashMap<int, Vector2> &r_uv_1,
- HashMap<int, Vector2> &r_uv_2,
- HashMap<int, Color> &r_color,
- HashMap<String, MorphVertexData> &r_morphs,
- HashMap<int, HashMap<int, Vector3>> &r_normals_raw,
- HashMap<int, HashMap<int, Color>> &r_colors_raw,
- HashMap<int, HashMap<int, Vector2>> &r_uv_1_raw,
- HashMap<int, HashMap<int, Vector2>> &r_uv_2_raw) {
- // Key: OldVertex; Value: [New vertices];
- HashMap<int, Vector<int>> duplicated_vertices;
-
- PolygonId polygon_index = -1;
- for (int pv = 0; pv < (int)r_polygon_indices.size(); pv += 1) {
- if (is_start_of_polygon(r_polygon_indices, pv)) {
- polygon_index += 1;
- }
- const Vertex index = get_vertex_from_polygon_vertex(r_polygon_indices, pv);
-
- bool need_duplication = false;
- Vector2 this_vert_poly_uv1 = Vector2();
- Vector2 this_vert_poly_uv2 = Vector2();
- Vector3 this_vert_poly_normal = Vector3();
- Color this_vert_poly_color = Color();
-
- // Take the normal and see if we need to duplicate this polygon.
- if (r_normals_raw.has(index)) {
- const HashMap<PolygonId, Vector3> *nrml_arr = r_normals_raw.getptr(index);
-
- if (nrml_arr->has(polygon_index)) {
- this_vert_poly_normal = nrml_arr->get(polygon_index);
- } else if (nrml_arr->has(-1)) {
- this_vert_poly_normal = nrml_arr->get(-1);
- } else {
- print_error("invalid normal detected: " + itos(index) + " polygon index: " + itos(polygon_index));
- for (const PolygonId *pid = nrml_arr->next(nullptr); pid != nullptr; pid = nrml_arr->next(pid)) {
- print_verbose("debug contents key: " + itos(*pid));
-
- if (nrml_arr->has(*pid)) {
- print_verbose("contents valid: " + nrml_arr->get(*pid));
- }
- }
- }
-
- // Now, check if we need to duplicate it.
- for (const PolygonId *pid = nrml_arr->next(nullptr); pid != nullptr; pid = nrml_arr->next(pid)) {
- if (*pid == polygon_index) {
- continue;
- }
-
- const Vector3 vert_poly_normal = *nrml_arr->getptr(*pid);
- if (!vert_poly_normal.is_equal_approx(this_vert_poly_normal)) {
- // Yes this polygon need duplication.
- need_duplication = true;
- break;
- }
- }
- }
-
- // TODO: make me vertex color
- // Take the normal and see if we need to duplicate this polygon.
- if (r_colors_raw.has(index)) {
- const HashMap<PolygonId, Color> *color_arr = r_colors_raw.getptr(index);
-
- if (color_arr->has(polygon_index)) {
- this_vert_poly_color = color_arr->get(polygon_index);
- } else if (color_arr->has(-1)) {
- this_vert_poly_color = color_arr->get(-1);
- } else {
- print_error("invalid color detected: " + itos(index) + " polygon index: " + itos(polygon_index));
- for (const PolygonId *pid = color_arr->next(nullptr); pid != nullptr; pid = color_arr->next(pid)) {
- print_verbose("debug contents key: " + itos(*pid));
-
- if (color_arr->has(*pid)) {
- print_verbose("contents valid: " + color_arr->get(*pid));
- }
- }
- }
-
- // Now, check if we need to duplicate it.
- for (const PolygonId *pid = color_arr->next(nullptr); pid != nullptr; pid = color_arr->next(pid)) {
- if (*pid == polygon_index) {
- continue;
- }
-
- const Color vert_poly_color = *color_arr->getptr(*pid);
- if (!this_vert_poly_color.is_equal_approx(vert_poly_color)) {
- // Yes this polygon need duplication.
- need_duplication = true;
- break;
- }
- }
- }
-
- // Take the UV1 and UV2 and see if we need to duplicate this polygon.
- {
- HashMap<int, HashMap<int, Vector2>> *uv_raw = &r_uv_1_raw;
- Vector2 *this_vert_poly_uv = &this_vert_poly_uv1;
- for (int kk = 0; kk < 2; kk++) {
- if (uv_raw->has(index)) {
- const HashMap<PolygonId, Vector2> *uvs = uv_raw->getptr(index);
-
- if (uvs->has(polygon_index)) {
- // This Polygon has its own uv.
- (*this_vert_poly_uv) = *uvs->getptr(polygon_index);
-
- // Check if we need to duplicate it.
- for (const PolygonId *pid = uvs->next(nullptr); pid != nullptr; pid = uvs->next(pid)) {
- if (*pid == polygon_index) {
- continue;
- }
- const Vector2 vert_poly_uv = *uvs->getptr(*pid);
- if (!vert_poly_uv.is_equal_approx(*this_vert_poly_uv)) {
- // Yes this polygon need duplication.
- need_duplication = true;
- break;
- }
- }
- } else if (uvs->has(-1)) {
- // It has the default UV.
- (*this_vert_poly_uv) = *uvs->getptr(-1);
- } else if (uvs->size() > 0) {
- // No uv, this is strange, just take the first and duplicate.
- (*this_vert_poly_uv) = *uvs->getptr(*uvs->next(nullptr));
- WARN_PRINT("No UVs for this polygon, while there is no default and some other polygons have it. This FBX file may be corrupted.");
- }
- }
- uv_raw = &r_uv_2_raw;
- this_vert_poly_uv = &this_vert_poly_uv2;
- }
- }
-
- // If we want to duplicate it, Let's see if we already duplicated this
- // vertex.
- if (need_duplication) {
- if (duplicated_vertices.has(index)) {
- Vertex similar_vertex = -1;
- // Let's see if one of the new vertices has the same data of this.
- const Vector<int> *new_vertices = duplicated_vertices.getptr(index);
- for (int j = 0; j < new_vertices->size(); j += 1) {
- const Vertex new_vertex = (*new_vertices)[j];
- bool same_uv1 = false;
- bool same_uv2 = false;
- bool same_normal = false;
- bool same_color = false;
-
- if (r_uv_1.has(new_vertex)) {
- if ((this_vert_poly_uv1 - (*r_uv_1.getptr(new_vertex))).length_squared() <= CMP_EPSILON) {
- same_uv1 = true;
- }
- }
-
- if (r_uv_2.has(new_vertex)) {
- if ((this_vert_poly_uv2 - (*r_uv_2.getptr(new_vertex))).length_squared() <= CMP_EPSILON) {
- same_uv2 = true;
- }
- }
-
- if (r_color.has(new_vertex)) {
- if (this_vert_poly_color.is_equal_approx((*r_color.getptr(new_vertex)))) {
- same_color = true;
- }
- }
-
- if (r_normals.has(new_vertex)) {
- if ((this_vert_poly_normal - (*r_normals.getptr(new_vertex))).length_squared() <= CMP_EPSILON) {
- same_uv2 = true;
- }
- }
-
- if (same_uv1 && same_uv2 && same_normal && same_color) {
- similar_vertex = new_vertex;
- break;
- }
- }
-
- if (similar_vertex != -1) {
- // Update polygon.
- if (is_end_of_polygon(r_polygon_indices, pv)) {
- r_polygon_indices[pv] = ~similar_vertex;
- } else {
- r_polygon_indices[pv] = similar_vertex;
- }
- need_duplication = false;
- }
- }
- }
-
- if (need_duplication) {
- const Vertex old_index = index;
- const Vertex new_index = r_vertices.size();
-
- // Polygon index.
- if (is_end_of_polygon(r_polygon_indices, pv)) {
- r_polygon_indices[pv] = ~new_index;
- } else {
- r_polygon_indices[pv] = new_index;
- }
-
- // Vertex position.
- r_vertices.push_back(r_vertices[old_index]);
-
- // Normals
- if (r_normals_raw.has(old_index)) {
- r_normals.set(new_index, this_vert_poly_normal);
- r_normals_raw.getptr(old_index)->erase(polygon_index);
- r_normals_raw[new_index][polygon_index] = this_vert_poly_normal;
- }
-
- // Vertex Color
- if (r_colors_raw.has(old_index)) {
- r_color.set(new_index, this_vert_poly_color);
- r_colors_raw.getptr(old_index)->erase(polygon_index);
- r_colors_raw[new_index][polygon_index] = this_vert_poly_color;
- }
-
- // UV 0
- if (r_uv_1_raw.has(old_index)) {
- r_uv_1.set(new_index, this_vert_poly_uv1);
- r_uv_1_raw.getptr(old_index)->erase(polygon_index);
- r_uv_1_raw[new_index][polygon_index] = this_vert_poly_uv1;
- }
-
- // UV 1
- if (r_uv_2_raw.has(old_index)) {
- r_uv_2.set(new_index, this_vert_poly_uv2);
- r_uv_2_raw.getptr(old_index)->erase(polygon_index);
- r_uv_2_raw[new_index][polygon_index] = this_vert_poly_uv2;
- }
-
- // Morphs
- for (const String *mname = r_morphs.next(nullptr); mname != nullptr; mname = r_morphs.next(mname)) {
- MorphVertexData *d = r_morphs.getptr(*mname);
- // This can't never happen.
- CRASH_COND(d == nullptr);
- if (d->vertices.size() > old_index) {
- d->vertices.push_back(d->vertices[old_index]);
- }
- if (d->normals.size() > old_index) {
- d->normals.push_back(d->normals[old_index]);
- }
- }
-
- if (vertex_weights.has(old_index)) {
- vertex_weights.set(new_index, vertex_weights[old_index]);
- }
-
- duplicated_vertices[old_index].push_back(new_index);
- } else {
- if (r_normals_raw.has(index) &&
- r_normals.has(index) == false) {
- r_normals.set(index, this_vert_poly_normal);
- }
-
- if (r_colors_raw.has(index) && r_color.has(index) == false) {
- r_color.set(index, this_vert_poly_color);
- }
-
- if (r_uv_1_raw.has(index) &&
- r_uv_1.has(index) == false) {
- r_uv_1.set(index, this_vert_poly_uv1);
- }
-
- if (r_uv_2_raw.has(index) &&
- r_uv_2.has(index) == false) {
- r_uv_2.set(index, this_vert_poly_uv2);
- }
- }
- }
-}
-
-void FBXMeshData::add_vertex(
- const ImportState &state,
- Ref<SurfaceTool> p_surface_tool,
- real_t p_scale,
- Vertex p_vertex,
- const std::vector<Vector3> &p_vertices_position,
- const HashMap<int, Vector3> &p_normals,
- const HashMap<int, Vector2> &p_uvs_0,
- const HashMap<int, Vector2> &p_uvs_1,
- const HashMap<int, Color> &p_colors,
- const Vector3 &p_morph_value,
- const Vector3 &p_morph_normal) {
- ERR_FAIL_INDEX_MSG(p_vertex, (Vertex)p_vertices_position.size(), "FBX file is corrupted, the position of the vertex can't be retrieved.");
-
- if (p_normals.has(p_vertex) && !state.is_blender_fbx) {
- p_surface_tool->set_normal(p_normals[p_vertex] + p_morph_normal);
- }
-
- if (p_uvs_0.has(p_vertex)) {
- //print_verbose("uv1: [" + itos(p_vertex) + "] " + p_uvs_0[p_vertex]);
- // Inverts Y UV.
- p_surface_tool->set_uv(Vector2(p_uvs_0[p_vertex].x, 1 - p_uvs_0[p_vertex].y));
- }
-
- if (p_uvs_1.has(p_vertex)) {
- //print_verbose("uv2: [" + itos(p_vertex) + "] " + p_uvs_1[p_vertex]);
- // Inverts Y UV.
- p_surface_tool->set_uv2(Vector2(p_uvs_1[p_vertex].x, 1 - p_uvs_1[p_vertex].y));
- }
-
- if (p_colors.has(p_vertex)) {
- p_surface_tool->set_color(p_colors[p_vertex]);
- }
-
- // TODO what about binormals?
- // TODO there is other?
-
- if (vertex_weights.has(p_vertex)) {
- // Let's extract the weight info.
- const VertexWeightMapping *vm = vertex_weights.getptr(p_vertex);
- const Vector<int> &bones = vm->bones;
-
- // the bug is that the bone idx is wrong because it is not ref'ing the skin.
-
- if (bones.size() > RS::ARRAY_WEIGHTS_SIZE) {
- print_error("[weight overflow detected]");
- }
-
- p_surface_tool->set_weights(vm->weights);
- // 0 1 2 3 4 5 6 7 < local skeleton / skin for mesh
- // 0 1 2 3 4 5 6 7 8 9 10 < actual skeleton with all joints
- p_surface_tool->set_bones(bones);
- }
-
- // The surface tool want the vertex position as last thing.
- p_surface_tool->add_vertex((p_vertices_position[p_vertex] + p_morph_value) * p_scale);
-}
-
-void FBXMeshData::triangulate_polygon(SurfaceData *surface, const Vector<int> &p_polygon_vertex, const std::vector<Vector3> &p_vertices) const {
- Ref<SurfaceTool> st(surface->surface_tool);
- const int polygon_vertex_count = p_polygon_vertex.size();
- //const Vector<Vertex>& p_surface_vertex_map
- if (polygon_vertex_count == 1) {
- // point to triangle
- st->add_index(p_polygon_vertex[0]);
- st->add_index(p_polygon_vertex[0]);
- st->add_index(p_polygon_vertex[0]);
- return;
- } else if (polygon_vertex_count == 2) {
- // line to triangle
- st->add_index(p_polygon_vertex[1]);
- st->add_index(p_polygon_vertex[1]);
- st->add_index(p_polygon_vertex[0]);
- return;
- } else if (polygon_vertex_count == 3) {
- // triangle to triangle
- st->add_index(p_polygon_vertex[0]);
- st->add_index(p_polygon_vertex[2]);
- st->add_index(p_polygon_vertex[1]);
- return;
- } else if (polygon_vertex_count == 4) {
- // quad to triangle - this code is awesome for import times
- // it prevents triangles being generated slowly
- st->add_index(p_polygon_vertex[0]);
- st->add_index(p_polygon_vertex[2]);
- st->add_index(p_polygon_vertex[1]);
- st->add_index(p_polygon_vertex[2]);
- st->add_index(p_polygon_vertex[0]);
- st->add_index(p_polygon_vertex[3]);
- return;
- } else {
- // non triangulated - we must run the triangulation algorithm
- bool is_simple_convex = false;
- // this code is 'slow' but required it triangulates all the unsupported geometry.
- // Doesn't allow for bigger polygons because those are unlikely be convex
- if (polygon_vertex_count <= 6) {
- // Start from true, check if it's false.
- is_simple_convex = true;
- Vector3 first_vec;
- for (int i = 0; i < polygon_vertex_count; i += 1) {
- const Vector3 p1 = p_vertices[surface->vertices_map[p_polygon_vertex[i]]];
- const Vector3 p2 = p_vertices[surface->vertices_map[p_polygon_vertex[(i + 1) % polygon_vertex_count]]];
- const Vector3 p3 = p_vertices[surface->vertices_map[p_polygon_vertex[(i + 2) % polygon_vertex_count]]];
-
- const Vector3 edge1 = p1 - p2;
- const Vector3 edge2 = p3 - p2;
-
- const Vector3 res = edge1.normalized().cross(edge2.normalized()).normalized();
- if (i == 0) {
- first_vec = res;
- } else {
- if (first_vec.dot(res) < 0.0) {
- // Ok we found an angle that is not the same dir of the
- // others.
- is_simple_convex = false;
- break;
- }
- }
- }
- }
-
- if (is_simple_convex) {
- // This is a convex polygon, so just triangulate it.
- for (int i = 0; i < (polygon_vertex_count - 2); i += 1) {
- st->add_index(p_polygon_vertex[2 + i]);
- st->add_index(p_polygon_vertex[1 + i]);
- st->add_index(p_polygon_vertex[0]);
- }
- return;
- }
- }
-
- {
- // This is a concave polygon.
-
- std::vector<Vector3> poly_vertices(polygon_vertex_count);
- for (int i = 0; i < polygon_vertex_count; i += 1) {
- poly_vertices[i] = p_vertices[surface->vertices_map[p_polygon_vertex[i]]];
- }
-
- const Vector3 poly_norm = get_poly_normal(poly_vertices);
- if (poly_norm.length_squared() <= CMP_EPSILON) {
- ERR_FAIL_COND_MSG(poly_norm.length_squared() <= CMP_EPSILON, "The normal of this poly was not computed. Is this FBX file corrupted.");
- }
-
- // Select the plan coordinate.
- int axis_1_coord = 0;
- int axis_2_coord = 1;
- {
- real_t inv = poly_norm.z;
-
- const real_t axis_x = ABS(poly_norm.x);
- const real_t axis_y = ABS(poly_norm.y);
- const real_t axis_z = ABS(poly_norm.z);
-
- if (axis_x > axis_y) {
- if (axis_x > axis_z) {
- // For the most part the normal point toward X.
- axis_1_coord = 1;
- axis_2_coord = 2;
- inv = poly_norm.x;
- }
- } else if (axis_y > axis_z) {
- // For the most part the normal point toward Y.
- axis_1_coord = 2;
- axis_2_coord = 0;
- inv = poly_norm.y;
- }
-
- // Swap projection axes to take the negated projection vector into account
- if (inv < 0.0f) {
- SWAP(axis_1_coord, axis_2_coord);
- }
- }
-
- TPPLPoly tppl_poly;
- tppl_poly.Init(polygon_vertex_count);
- std::vector<Vector2> projected_vertices(polygon_vertex_count);
- for (int i = 0; i < polygon_vertex_count; i += 1) {
- const Vector2 pv(poly_vertices[i][axis_1_coord], poly_vertices[i][axis_2_coord]);
- projected_vertices[i] = pv;
- tppl_poly.GetPoint(i) = pv;
- }
- tppl_poly.SetOrientation(TPPL_ORIENTATION_CCW);
-
- List<TPPLPoly> out_poly;
-
- TPPLPartition tppl_partition;
- if (tppl_partition.Triangulate_OPT(&tppl_poly, &out_poly) == 0) { // Good result.
- if (tppl_partition.Triangulate_EC(&tppl_poly, &out_poly) == 0) { // Medium result.
- if (tppl_partition.Triangulate_MONO(&tppl_poly, &out_poly) == 0) { // Really poor result.
- ERR_FAIL_MSG("The triangulation of this polygon failed, please try to triangulate your mesh or check if it has broken polygons.");
- }
- }
- }
-
- std::vector<Vector2> tris(out_poly.size());
- for (List<TPPLPoly>::Element *I = out_poly.front(); I; I = I->next()) {
- TPPLPoly &tp = I->get();
-
- ERR_FAIL_COND_MSG(tp.GetNumPoints() != 3, "The triangulator returned more points, how this is possible?");
- // Find Index
- for (int i = 2; i >= 0; i -= 1) {
- const Vector2 vertex = tp.GetPoint(i);
- bool done = false;
- // Find Index
- for (int y = 0; y < polygon_vertex_count; y += 1) {
- if ((projected_vertices[y] - vertex).length_squared() <= CMP_EPSILON) {
- // This seems the right vertex
- st->add_index(p_polygon_vertex[y]);
- done = true;
- break;
- }
- }
- ERR_FAIL_COND(done == false);
- }
- }
- }
-}
-
-void FBXMeshData::gen_weight_info(Ref<SurfaceTool> st, Vertex vertex_id) const {
- if (vertex_weights.is_empty()) {
- return;
- }
-
- if (vertex_weights.has(vertex_id)) {
- // Let's extract the weight info.
- const VertexWeightMapping *vm = vertex_weights.getptr(vertex_id);
- st->set_weights(vm->weights);
- st->set_bones(vm->bones);
- }
-}
-
-int FBXMeshData::get_vertex_from_polygon_vertex(const std::vector<int> &p_polygon_indices, int p_index) const {
- if (p_index < 0 || p_index >= (int)p_polygon_indices.size()) {
- return -1;
- }
-
- const int vertex = p_polygon_indices[p_index];
- if (vertex >= 0) {
- return vertex;
- } else {
- // Negative numbers are the end of the face, reversing the bits is
- // possible to obtain the positive correct vertex number.
- return ~vertex;
- }
-}
-
-bool FBXMeshData::is_end_of_polygon(const std::vector<int> &p_polygon_indices, int p_index) const {
- if (p_index < 0 || p_index >= (int)p_polygon_indices.size()) {
- return false;
- }
-
- const int vertex = p_polygon_indices[p_index];
-
- // If the index is negative this is the end of the Polygon.
- return vertex < 0;
-}
-
-bool FBXMeshData::is_start_of_polygon(const std::vector<int> &p_polygon_indices, int p_index) const {
- if (p_index < 0 || p_index >= (int)p_polygon_indices.size()) {
- return false;
- }
-
- if (p_index == 0) {
- return true;
- }
-
- // If the previous indices is negative this is the begin of a new Polygon.
- return p_polygon_indices[p_index - 1] < 0;
-}
-
-int FBXMeshData::count_polygons(const std::vector<int> &p_polygon_indices) const {
- // The negative numbers define the end of the polygon. Counting the amount of
- // negatives the numbers of polygons are obtained.
- int count = 0;
- for (size_t i = 0; i < p_polygon_indices.size(); i += 1) {
- if (p_polygon_indices[i] < 0) {
- count += 1;
- }
- }
- return count;
-}
-
-template <class R, class T>
-HashMap<int, R> FBXMeshData::extract_per_vertex_data(
- int p_vertex_count,
- const std::vector<FBXDocParser::MeshGeometry::Edge> &p_edge_map,
- const std::vector<int> &p_mesh_indices,
- const FBXDocParser::MeshGeometry::MappingData<T> &p_mapping_data,
- R (*collector_function)(const Vector<VertexData<T>> *p_vertex_data, R p_fall_back),
- R p_fall_back) const {
- /* When index_to_direct is set
- * index size is 184 ( contains index for the data array [values 0, 96] )
- * data size is 96 (contains uv coordinates)
- * this means index is simple data reduction basically
- */
- ////
- if (p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index_to_direct && p_mapping_data.index.size() == 0) {
- print_verbose("debug count: index size: " + itos(p_mapping_data.index.size()) + ", data size: " + itos(p_mapping_data.data.size()));
- print_verbose("vertex indices count: " + itos(p_mesh_indices.size()));
- print_verbose("Edge map size: " + itos(p_edge_map.size()));
- }
-
- ERR_FAIL_COND_V_MSG(p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index_to_direct && p_mapping_data.index.size() == 0, (HashMap<int, R>()), "FBX importer needs to map correctly to this field, please specify the override index name to fix this problem!");
- ERR_FAIL_COND_V_MSG(p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index && p_mapping_data.index.size() == 0, (HashMap<int, R>()), "The FBX seems corrupted");
-
- // Aggregate vertex data.
- HashMap<Vertex, Vector<VertexData<T>>> aggregate_vertex_data;
-
- switch (p_mapping_data.map_type) {
- case FBXDocParser::MeshGeometry::MapType::none: {
- // No data nothing to do.
- return (HashMap<int, R>());
- }
- case FBXDocParser::MeshGeometry::MapType::vertex: {
- ERR_FAIL_COND_V_MSG(p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index_to_direct, (HashMap<int, R>()), "We will support in future");
-
- if (p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::direct) {
- // The data is mapped per vertex directly.
- ERR_FAIL_COND_V_MSG((int)p_mapping_data.data.size() != p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR01");
- for (size_t vertex_index = 0; vertex_index < p_mapping_data.data.size(); vertex_index += 1) {
- aggregate_vertex_data[vertex_index].push_back({ -1, p_mapping_data.data[vertex_index] });
- }
- } else {
- // The data is mapped per vertex using a reference.
- // The indices array, contains a *reference_id for each vertex.
- // * Note that the reference_id is the id of data into the data array.
- //
- // https://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_layer_element_html
- ERR_FAIL_COND_V_MSG((int)p_mapping_data.index.size() != p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR02");
- for (size_t vertex_index = 0; vertex_index < p_mapping_data.index.size(); vertex_index += 1) {
- ERR_FAIL_INDEX_V_MSG(p_mapping_data.index[vertex_index], (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR03.");
- aggregate_vertex_data[vertex_index].push_back({ -1, p_mapping_data.data[p_mapping_data.index[vertex_index]] });
- }
- }
- } break;
- case FBXDocParser::MeshGeometry::MapType::polygon_vertex: {
- if (p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index_to_direct) {
- // The data is mapped using each index from the indexes array then direct to the data (data reduction algorithm)
- ERR_FAIL_COND_V_MSG((int)p_mesh_indices.size() != (int)p_mapping_data.index.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR04");
- int polygon_id = -1;
- for (size_t polygon_vertex_index = 0; polygon_vertex_index < p_mapping_data.index.size(); polygon_vertex_index += 1) {
- if (is_start_of_polygon(p_mesh_indices, polygon_vertex_index)) {
- polygon_id += 1;
- }
- const int vertex_index = get_vertex_from_polygon_vertex(p_mesh_indices, polygon_vertex_index);
- ERR_FAIL_COND_V_MSG(vertex_index < 0, (HashMap<int, R>()), "FBX file corrupted: #ERR05");
- ERR_FAIL_COND_V_MSG(vertex_index >= p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR06");
- const int index_to_direct = get_vertex_from_polygon_vertex(p_mapping_data.index, polygon_vertex_index);
- T value = p_mapping_data.data[index_to_direct];
- aggregate_vertex_data[vertex_index].push_back({ polygon_id, value });
- }
- } else if (p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::direct) {
- // The data are mapped per polygon vertex directly.
- ERR_FAIL_COND_V_MSG((int)p_mesh_indices.size() != (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR04");
- int polygon_id = -1;
- for (size_t polygon_vertex_index = 0; polygon_vertex_index < p_mapping_data.data.size(); polygon_vertex_index += 1) {
- if (is_start_of_polygon(p_mesh_indices, polygon_vertex_index)) {
- polygon_id += 1;
- }
- const int vertex_index = get_vertex_from_polygon_vertex(p_mesh_indices, polygon_vertex_index);
- ERR_FAIL_COND_V_MSG(vertex_index < 0, (HashMap<int, R>()), "FBX file corrupted: #ERR05");
- ERR_FAIL_COND_V_MSG(vertex_index >= p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR06");
-
- aggregate_vertex_data[vertex_index].push_back({ polygon_id, p_mapping_data.data[polygon_vertex_index] });
- }
- } else {
- // The data is mapped per polygon_vertex using a reference.
- // The indices array, contains a *reference_id for each polygon_vertex.
- // * Note that the reference_id is the id of data into the data array.
- //
- // https://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_layer_element_html
- ERR_FAIL_COND_V_MSG(p_mesh_indices.size() != p_mapping_data.index.size(), (HashMap<int, R>()), "FBX file corrupted: #ERR7");
- int polygon_id = -1;
- for (size_t polygon_vertex_index = 0; polygon_vertex_index < p_mapping_data.index.size(); polygon_vertex_index += 1) {
- if (is_start_of_polygon(p_mesh_indices, polygon_vertex_index)) {
- polygon_id += 1;
- }
- const int vertex_index = get_vertex_from_polygon_vertex(p_mesh_indices, polygon_vertex_index);
- ERR_FAIL_COND_V_MSG(vertex_index < 0, (HashMap<int, R>()), "FBX file corrupted: #ERR8");
- ERR_FAIL_COND_V_MSG(vertex_index >= p_vertex_count, (HashMap<int, R>()), "FBX file seems corrupted: #ERR9.");
- ERR_FAIL_COND_V_MSG(p_mapping_data.index[polygon_vertex_index] < 0, (HashMap<int, R>()), "FBX file seems corrupted: #ERR10.");
- ERR_FAIL_COND_V_MSG(p_mapping_data.index[polygon_vertex_index] >= (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR11.");
- aggregate_vertex_data[vertex_index].push_back({ polygon_id, p_mapping_data.data[p_mapping_data.index[polygon_vertex_index]] });
- }
- }
- } break;
- case FBXDocParser::MeshGeometry::MapType::polygon: {
- if (p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::direct) {
- // The data are mapped per polygon directly.
- const int polygon_count = count_polygons(p_mesh_indices);
- ERR_FAIL_COND_V_MSG(polygon_count != (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR12");
-
- // Advance each polygon vertex, each new polygon advance the polygon index.
- int polygon_index = -1;
- for (size_t polygon_vertex_index = 0;
- polygon_vertex_index < p_mesh_indices.size();
- polygon_vertex_index += 1) {
- if (is_start_of_polygon(p_mesh_indices, polygon_vertex_index)) {
- polygon_index += 1;
- ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR13");
- }
-
- const int vertex_index = get_vertex_from_polygon_vertex(p_mesh_indices, polygon_vertex_index);
- ERR_FAIL_INDEX_V_MSG(vertex_index, p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR14");
-
- aggregate_vertex_data[vertex_index].push_back({ polygon_index, p_mapping_data.data[polygon_index] });
- }
- ERR_FAIL_COND_V_MSG((polygon_index + 1) != polygon_count, (HashMap<int, R>()), "FBX file seems corrupted: #ERR16. Not all Polygons are present in the file.");
- } else {
- // The data is mapped per polygon using a reference.
- // The indices array, contains a *reference_id for each polygon.
- // * Note that the reference_id is the id of data into the data array.
- //
- // https://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_layer_element_html
- const int polygon_count = count_polygons(p_mesh_indices);
- ERR_FAIL_COND_V_MSG(polygon_count != (int)p_mapping_data.index.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR17");
-
- // Advance each polygon vertex, each new polygon advance the polygon index.
- int polygon_index = -1;
- for (size_t polygon_vertex_index = 0;
- polygon_vertex_index < p_mesh_indices.size();
- polygon_vertex_index += 1) {
- if (is_start_of_polygon(p_mesh_indices, polygon_vertex_index)) {
- polygon_index += 1;
- ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_mapping_data.index.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR18");
- ERR_FAIL_INDEX_V_MSG(p_mapping_data.index[polygon_index], (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR19");
- }
-
- const int vertex_index = get_vertex_from_polygon_vertex(p_mesh_indices, polygon_vertex_index);
- ERR_FAIL_INDEX_V_MSG(vertex_index, p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR20");
-
- aggregate_vertex_data[vertex_index].push_back({ polygon_index, p_mapping_data.data[p_mapping_data.index[polygon_index]] });
- }
- ERR_FAIL_COND_V_MSG((polygon_index + 1) != polygon_count, (HashMap<int, R>()), "FBX file seems corrupted: #ERR22. Not all Polygons are present in the file.");
- }
- } break;
- case FBXDocParser::MeshGeometry::MapType::edge: {
- if (p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::direct) {
- // The data are mapped per edge directly.
- ERR_FAIL_COND_V_MSG(p_edge_map.size() != p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR23");
- for (size_t edge_index = 0; edge_index < p_mapping_data.data.size(); edge_index += 1) {
- const FBXDocParser::MeshGeometry::Edge edge = FBXDocParser::MeshGeometry::get_edge(p_edge_map, edge_index);
- ERR_FAIL_INDEX_V_MSG(edge.vertex_0, p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR24");
- ERR_FAIL_INDEX_V_MSG(edge.vertex_1, p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR25");
- ERR_FAIL_INDEX_V_MSG(edge.vertex_0, (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file corrupted: #ERR26");
- ERR_FAIL_INDEX_V_MSG(edge.vertex_1, (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file corrupted: #ERR27");
- aggregate_vertex_data[edge.vertex_0].push_back({ -1, p_mapping_data.data[edge_index] });
- aggregate_vertex_data[edge.vertex_1].push_back({ -1, p_mapping_data.data[edge_index] });
- }
- } else {
- // The data is mapped per edge using a reference.
- // The indices array, contains a *reference_id for each polygon.
- // * Note that the reference_id is the id of data into the data array.
- //
- // https://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_layer_element_html
- ERR_FAIL_COND_V_MSG(p_edge_map.size() != p_mapping_data.index.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR28");
- for (size_t edge_index = 0; edge_index < p_mapping_data.data.size(); edge_index += 1) {
- const FBXDocParser::MeshGeometry::Edge edge = FBXDocParser::MeshGeometry::get_edge(p_edge_map, edge_index);
- ERR_FAIL_INDEX_V_MSG(edge.vertex_0, p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR29");
- ERR_FAIL_INDEX_V_MSG(edge.vertex_1, p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR30");
- ERR_FAIL_INDEX_V_MSG(edge.vertex_0, (int)p_mapping_data.index.size(), (HashMap<int, R>()), "FBX file corrupted: #ERR31");
- ERR_FAIL_INDEX_V_MSG(edge.vertex_1, (int)p_mapping_data.index.size(), (HashMap<int, R>()), "FBX file corrupted: #ERR32");
- ERR_FAIL_INDEX_V_MSG(p_mapping_data.index[edge.vertex_0], (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file corrupted: #ERR33");
- ERR_FAIL_INDEX_V_MSG(p_mapping_data.index[edge.vertex_1], (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file corrupted: #ERR34");
- aggregate_vertex_data[edge.vertex_0].push_back({ -1, p_mapping_data.data[p_mapping_data.index[edge_index]] });
- aggregate_vertex_data[edge.vertex_1].push_back({ -1, p_mapping_data.data[p_mapping_data.index[edge_index]] });
- }
- }
- } break;
- case FBXDocParser::MeshGeometry::MapType::all_the_same: {
- // No matter the mode, no matter the data size; The first always win
- // and is set to all the vertices.
- ERR_FAIL_COND_V_MSG(p_mapping_data.data.size() <= 0, (HashMap<int, R>()), "FBX file seems corrupted: #ERR35");
- if (p_mapping_data.data.size() > 0) {
- for (int vertex_index = 0; vertex_index < p_vertex_count; vertex_index += 1) {
- aggregate_vertex_data[vertex_index].push_back({ -1, p_mapping_data.data[0] });
- }
- }
- } break;
- }
-
- if (aggregate_vertex_data.size() == 0) {
- return (HashMap<int, R>());
- }
-
- // A map is used because turns out that the some FBX file are not well organized
- // with vertices well compacted. Using a map allows avoid those issues.
- HashMap<Vertex, R> result;
-
- // Aggregate the collected data.
- for (const Vertex *index = aggregate_vertex_data.next(nullptr); index != nullptr; index = aggregate_vertex_data.next(index)) {
- Vector<VertexData<T>> *aggregated_vertex = aggregate_vertex_data.getptr(*index);
- // This can't be null because we are just iterating.
- CRASH_COND(aggregated_vertex == nullptr);
-
- ERR_FAIL_INDEX_V_MSG(0, aggregated_vertex->size(), (HashMap<int, R>()), "The FBX file is corrupted, No valid data for this vertex index.");
- result[*index] = collector_function(aggregated_vertex, p_fall_back);
- }
-
- // Sanitize the data now, if the file is broken we can try import it anyway.
- bool problem_found = false;
- for (size_t i = 0; i < p_mesh_indices.size(); i += 1) {
- const Vertex vertex = get_vertex_from_polygon_vertex(p_mesh_indices, i);
- if (result.has(vertex) == false) {
- result[vertex] = p_fall_back;
- problem_found = true;
- }
- }
- if (problem_found) {
- WARN_PRINT("Some data is missing, this FBX file may be corrupted: #WARN0.");
- }
-
- return result;
-}
-
-template <class T>
-HashMap<int, T> FBXMeshData::extract_per_polygon(
- int p_vertex_count,
- const std::vector<int> &p_polygon_indices,
- const FBXDocParser::MeshGeometry::MappingData<T> &p_fbx_data,
- T p_fallback_value) const {
- ERR_FAIL_COND_V_MSG(p_fbx_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index_to_direct && p_fbx_data.data.size() == 0, (HashMap<int, T>()), "invalid index to direct array");
- ERR_FAIL_COND_V_MSG(p_fbx_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index && p_fbx_data.index.size() == 0, (HashMap<int, T>()), "The FBX seems corrupted");
-
- const int polygon_count = count_polygons(p_polygon_indices);
-
- // Aggregate vertex data.
- HashMap<int, Vector<T>> aggregate_polygon_data;
-
- switch (p_fbx_data.map_type) {
- case FBXDocParser::MeshGeometry::MapType::none: {
- // No data nothing to do.
- return (HashMap<int, T>());
- }
- case FBXDocParser::MeshGeometry::MapType::vertex: {
- ERR_FAIL_V_MSG((HashMap<int, T>()), "This data can't be extracted and organized per polygon, since into the FBX is mapped per vertex. This should not happen.");
- } break;
- case FBXDocParser::MeshGeometry::MapType::polygon_vertex: {
- ERR_FAIL_V_MSG((HashMap<int, T>()), "This data can't be extracted and organized per polygon, since into the FBX is mapped per polygon vertex. This should not happen.");
- } break;
- case FBXDocParser::MeshGeometry::MapType::polygon: {
- if (p_fbx_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index_to_direct) {
- // The data is stored efficiently index_to_direct allows less data in the FBX file.
- for (int polygon_index = 0;
- polygon_index < polygon_count;
- polygon_index += 1) {
- if (p_fbx_data.index.size() == 0) {
- ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_fbx_data.data.size(), (HashMap<int, T>()), "FBX file is corrupted: #ERR62");
- aggregate_polygon_data[polygon_index].push_back(p_fbx_data.data[polygon_index]);
- } else {
- ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_fbx_data.index.size(), (HashMap<int, T>()), "FBX file is corrupted: #ERR62");
-
- const int index_to_direct = get_vertex_from_polygon_vertex(p_fbx_data.index, polygon_index);
- T value = p_fbx_data.data[index_to_direct];
- aggregate_polygon_data[polygon_index].push_back(value);
- }
- }
- } else if (p_fbx_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::direct) {
- // The data are mapped per polygon directly.
- ERR_FAIL_COND_V_MSG(polygon_count != (int)p_fbx_data.data.size(), (HashMap<int, T>()), "FBX file is corrupted: #ERR51");
-
- // Advance each polygon vertex, each new polygon advance the polygon index.
- for (int polygon_index = 0;
- polygon_index < polygon_count;
- polygon_index += 1) {
- ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_fbx_data.data.size(), (HashMap<int, T>()), "FBX file is corrupted: #ERR52");
- aggregate_polygon_data[polygon_index].push_back(p_fbx_data.data[polygon_index]);
- }
- } else {
- // The data is mapped per polygon using a reference.
- // The indices array, contains a *reference_id for each polygon.
- // * Note that the reference_id is the id of data into the data array.
- //
- // https://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_layer_element_html
- ERR_FAIL_COND_V_MSG(polygon_count != (int)p_fbx_data.index.size(), (HashMap<int, T>()), "FBX file seems corrupted: #ERR52");
-
- // Advance each polygon vertex, each new polygon advance the polygon index.
- for (int polygon_index = 0;
- polygon_index < polygon_count;
- polygon_index += 1) {
- ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_fbx_data.index.size(), (HashMap<int, T>()), "FBX file is corrupted: #ERR53");
- ERR_FAIL_INDEX_V_MSG(p_fbx_data.index[polygon_index], (int)p_fbx_data.data.size(), (HashMap<int, T>()), "FBX file is corrupted: #ERR54");
- aggregate_polygon_data[polygon_index].push_back(p_fbx_data.data[p_fbx_data.index[polygon_index]]);
- }
- }
- } break;
- case FBXDocParser::MeshGeometry::MapType::edge: {
- ERR_FAIL_V_MSG((HashMap<int, T>()), "This data can't be extracted and organized per polygon, since into the FBX is mapped per edge. This should not happen.");
- } break;
- case FBXDocParser::MeshGeometry::MapType::all_the_same: {
- // No matter the mode, no matter the data size; The first always win
- // and is set to all the vertices.
- ERR_FAIL_COND_V_MSG(p_fbx_data.data.size() <= 0, (HashMap<int, T>()), "FBX file seems corrupted: #ERR55");
- if (p_fbx_data.data.size() > 0) {
- for (int polygon_index = 0; polygon_index < polygon_count; polygon_index += 1) {
- aggregate_polygon_data[polygon_index].push_back(p_fbx_data.data[0]);
- }
- }
- } break;
- }
-
- if (aggregate_polygon_data.size() == 0) {
- return (HashMap<int, T>());
- }
-
- // A map is used because turns out that the some FBX file are not well organized
- // with vertices well compacted. Using a map allows avoid those issues.
- HashMap<int, T> polygons;
-
- // Take the first value for each vertex.
- for (const Vertex *index = aggregate_polygon_data.next(nullptr); index != nullptr; index = aggregate_polygon_data.next(index)) {
- Vector<T> *aggregated_polygon = aggregate_polygon_data.getptr(*index);
- // This can't be null because we are just iterating.
- CRASH_COND(aggregated_polygon == nullptr);
-
- ERR_FAIL_INDEX_V_MSG(0, (int)aggregated_polygon->size(), (HashMap<int, T>()), "The FBX file is corrupted, No valid data for this polygon index.");
-
- // Validate the final value.
- polygons[*index] = (*aggregated_polygon)[0];
- }
-
- // Sanitize the data now, if the file is broken we can try import it anyway.
- bool problem_found = false;
- for (int polygon_i = 0; polygon_i < polygon_count; polygon_i += 1) {
- if (polygons.has(polygon_i) == false) {
- polygons[polygon_i] = p_fallback_value;
- problem_found = true;
- }
- }
- if (problem_found) {
- WARN_PRINT("Some data is missing, this FBX file may be corrupted: #WARN1.");
- }
-
- return polygons;
-}
-
-void FBXMeshData::extract_morphs(const FBXDocParser::MeshGeometry *mesh_geometry, HashMap<String, MorphVertexData> &r_data) {
- r_data.clear();
-
- const int vertex_count = mesh_geometry->get_vertices().size();
-
- for (const FBXDocParser::BlendShape *blend_shape : mesh_geometry->get_blend_shapes()) {
- for (const FBXDocParser::BlendShapeChannel *blend_shape_channel : blend_shape->BlendShapeChannels()) {
- const std::vector<const FBXDocParser::ShapeGeometry *> &shape_geometries = blend_shape_channel->GetShapeGeometries();
- for (const FBXDocParser::ShapeGeometry *shape_geometry : shape_geometries) {
- String morph_name = ImportUtils::FBXAnimMeshName(shape_geometry->Name()).c_str();
- if (morph_name.is_empty()) {
- morph_name = "morph";
- }
-
- // TODO we have only these??
- const std::vector<unsigned int> &morphs_vertex_indices = shape_geometry->GetIndices();
- const std::vector<Vector3> &morphs_vertices = shape_geometry->GetVertices();
- const std::vector<Vector3> &morphs_normals = shape_geometry->GetNormals();
-
- ERR_FAIL_COND_MSG((int)morphs_vertex_indices.size() > vertex_count, "The FBX file is corrupted: #ERR103");
- ERR_FAIL_COND_MSG(morphs_vertex_indices.size() != morphs_vertices.size(), "The FBX file is corrupted: #ERR104");
- ERR_FAIL_COND_MSG((int)morphs_vertices.size() > vertex_count, "The FBX file is corrupted: #ERR105");
- ERR_FAIL_COND_MSG(morphs_normals.size() != 0 && morphs_normals.size() != morphs_vertices.size(), "The FBX file is corrupted: #ERR106");
-
- if (r_data.has(morph_name) == false) {
- // This morph doesn't exist yet.
- // Create it.
- MorphVertexData md;
- md.vertices.resize(vertex_count);
- md.normals.resize(vertex_count);
- r_data.set(morph_name, md);
- }
-
- MorphVertexData *data = r_data.getptr(morph_name);
- Vector3 *data_vertices_ptr = data->vertices.ptrw();
- Vector3 *data_normals_ptr = data->normals.ptrw();
-
- for (int i = 0; i < (int)morphs_vertex_indices.size(); i += 1) {
- const Vertex vertex = morphs_vertex_indices[i];
-
- ERR_FAIL_INDEX_MSG(vertex, vertex_count, "The blend shapes of this FBX file are corrupted. It has a not valid vertex.");
-
- data_vertices_ptr[vertex] = morphs_vertices[i];
-
- if (morphs_normals.size() != 0) {
- data_normals_ptr[vertex] = morphs_normals[i];
- }
- }
- }
- }
- }
-}
diff --git a/modules/fbx/data/fbx_mesh_data.h b/modules/fbx/data/fbx_mesh_data.h
deleted file mode 100644
index 358d0c2cb6..0000000000
--- a/modules/fbx/data/fbx_mesh_data.h
+++ /dev/null
@@ -1,200 +0,0 @@
-/*************************************************************************/
-/* fbx_mesh_data.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef FBX_MESH_DATA_H
-#define FBX_MESH_DATA_H
-
-#include "core/templates/hash_map.h"
-#include "core/templates/local_vector.h"
-#include "core/templates/ordered_hash_map.h"
-#include "editor/import/resource_importer_scene.h"
-#include "scene/3d/importer_mesh_instance_3d.h"
-#include "scene/3d/mesh_instance_3d.h"
-#include "scene/resources/surface_tool.h"
-
-#include "fbx_bone.h"
-#include "fbx_parser/FBXMeshGeometry.h"
-#include "import_state.h"
-#include "tools/import_utils.h"
-
-struct FBXNode;
-struct FBXMeshData;
-struct FBXBone;
-struct ImportState;
-
-typedef int Vertex;
-typedef int SurfaceId;
-typedef int PolygonId;
-typedef int DataIndex;
-
-struct SurfaceData {
- Ref<SurfaceTool> surface_tool;
- OrderedHashMap<Vertex, int> lookup_table; // proposed fix is to replace lookup_table[vertex_id] to give the position of the vertices_map[int] index.
- LocalVector<Vertex> vertices_map; // this must be ordered the same as insertion <-- slow to do find() operation.
- Ref<Material> material;
- HashMap<PolygonId, Vector<DataIndex>> surface_polygon_vertex;
- Array morphs;
-};
-
-struct VertexWeightMapping {
- Vector<float> weights;
- Vector<int> bones;
- // This extra vector is used because the bone id is computed in a second step.
- // TODO Get rid of this extra step is a good idea.
- Vector<Ref<FBXBone>> bones_ref;
-};
-
-template <class T>
-struct VertexData {
- int polygon_index;
- T data;
-};
-
-// Caches mesh information and instantiates meshes for you using helper functions.
-struct FBXMeshData : RefCounted {
- struct MorphVertexData {
- // TODO we have only these??
- /// Each element is a vertex. Not supposed to be void.
- Vector<Vector3> vertices;
- /// Each element is a vertex. Not supposed to be void.
- Vector<Vector3> normals;
- };
-
- // FIXME: remove this is a hack for testing only
- mutable const FBXDocParser::MeshGeometry *mesh_geometry = nullptr;
-
- Ref<FBXNode> mesh_node = nullptr;
- /// vertex id, Weight Info
- /// later: perf we can use array here
- HashMap<int, VertexWeightMapping> vertex_weights;
-
- // translate fbx mesh data from document context to FBX Mesh Geometry Context
- bool valid_weight_indexes = false;
-
- ImporterMeshInstance3D *create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression);
-
- void gen_weight_info(Ref<SurfaceTool> st, int vertex_id) const;
-
- /* mesh maximum weight count */
- bool valid_weight_count = false;
- int max_weight_count = 0;
- uint64_t armature_id = 0;
- bool valid_armature_id = false;
- ImporterMeshInstance3D *godot_mesh_instance = nullptr;
-
-private:
- void sanitize_vertex_weights(const ImportState &state);
-
- /// Make sure to reorganize the vertices so that the correct UV is taken.
- /// This step is needed because differently from the normal, that can be
- /// combined, the UV may need its own triangle because sometimes they have
- /// really different UV for the same vertex but different polygon.
- /// This function make sure to add another vertex for those UVS.
- void reorganize_vertices(
- std::vector<int> &r_polygon_indices,
- std::vector<Vector3> &r_vertices,
- HashMap<int, Vector3> &r_normals,
- HashMap<int, Vector2> &r_uv_1,
- HashMap<int, Vector2> &r_uv_2,
- HashMap<int, Color> &r_color,
- HashMap<String, MorphVertexData> &r_morphs,
- HashMap<int, HashMap<int, Vector3>> &r_normals_raw,
- HashMap<int, HashMap<int, Color>> &r_colors_raw,
- HashMap<int, HashMap<int, Vector2>> &r_uv_1_raw,
- HashMap<int, HashMap<int, Vector2>> &r_uv_2_raw);
-
- void add_vertex(
- const ImportState &state,
- Ref<SurfaceTool> p_surface_tool,
- real_t p_scale,
- int p_vertex,
- const std::vector<Vector3> &p_vertices_position,
- const HashMap<int, Vector3> &p_normals,
- const HashMap<int, Vector2> &p_uvs_0,
- const HashMap<int, Vector2> &p_uvs_1,
- const HashMap<int, Color> &p_colors,
- const Vector3 &p_morph_value = Vector3(),
- const Vector3 &p_morph_normal = Vector3());
-
- void triangulate_polygon(SurfaceData *surface, const Vector<int> &p_polygon_vertex, const std::vector<Vector3> &p_vertices) const;
-
- /// This function is responsible to convert the FBX polygon vertex to
- /// vertex index.
- /// The polygon vertices are stored in an array with some negative
- /// values. The negative values define the last face index.
- /// For example the following `face_array` contains two faces, the former
- /// with 3 vertices and the latter with a line:
- /// [0,2,-2,3,-5]
- /// Parsed as:
- /// [0, 2, 1, 3, 4]
- /// The negative values are computed using this formula: `(-value) - 1`
- ///
- /// Returns the vertex index from the polygon vertex.
- /// Returns -1 if `p_index` is invalid.
- int get_vertex_from_polygon_vertex(const std::vector<int> &p_face_indices, int p_index) const;
-
- /// Returns true if this polygon_vertex_index is the end of a new polygon.
- bool is_end_of_polygon(const std::vector<int> &p_face_indices, int p_index) const;
-
- /// Returns true if this polygon_vertex_index is the begin of a new polygon.
- bool is_start_of_polygon(const std::vector<int> &p_face_indices, int p_index) const;
-
- /// Returns the number of polygons.
- int count_polygons(const std::vector<int> &p_face_indices) const;
-
- /// Used to extract data from the `MappingData` aligned with vertex.
- /// Useful to extract normal/uvs/colors/tangents/etc...
- /// If the function fails somehow, it returns an hollow vector and print an error.
- template <class R, class T>
- HashMap<int, R> extract_per_vertex_data(
- int p_vertex_count,
- const std::vector<FBXDocParser::MeshGeometry::Edge> &p_edges,
- const std::vector<int> &p_mesh_indices,
- const FBXDocParser::MeshGeometry::MappingData<T> &p_mapping_data,
- R (*collector_function)(const Vector<VertexData<T>> *p_vertex_data, R p_fall_back),
- R p_fall_back) const;
-
- /// Used to extract data from the `MappingData` organized per polygon.
- /// Useful to extract the material
- /// If the function fails somehow, it returns an hollow vector and print an error.
- template <class T>
- HashMap<int, T> extract_per_polygon(
- int p_vertex_count,
- const std::vector<int> &p_face_indices,
- const FBXDocParser::MeshGeometry::MappingData<T> &p_fbx_data,
- T p_fallback_value) const;
-
- /// Extracts the morph data and organizes it per vertices.
- /// The returned `MorphVertexData` arrays are never something different
- /// then the `vertex_count`.
- void extract_morphs(const FBXDocParser::MeshGeometry *mesh_geometry, HashMap<String, MorphVertexData> &r_data);
-};
-
-#endif // FBX_MESH_DATA_H
diff --git a/modules/fbx/data/fbx_skeleton.cpp b/modules/fbx/data/fbx_skeleton.cpp
deleted file mode 100644
index 0225df16af..0000000000
--- a/modules/fbx/data/fbx_skeleton.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-/*************************************************************************/
-/* fbx_skeleton.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "fbx_skeleton.h"
-
-#include "import_state.h"
-
-#include "tools/import_utils.h"
-
-void FBXSkeleton::init_skeleton(const ImportState &state) {
- int skeleton_bone_count = skeleton_bones.size();
-
- if (skeleton == nullptr && skeleton_bone_count > 0) {
- skeleton = memnew(Skeleton3D);
-
- if (fbx_node.is_valid()) {
- // cache skeleton attachment for later during node creation
- // can't be done until after node hierarchy is built
- if (fbx_node->godot_node != state.root) {
- fbx_node->skeleton_node = Ref<FBXSkeleton>(this);
- print_verbose("cached armature skeleton attachment for node " + fbx_node->node_name);
- } else {
- // root node must never be a skeleton to prevent cyclic skeletons from being allowed (skeleton in a skeleton)
- fbx_node->godot_node->add_child(skeleton);
- skeleton->set_owner(state.root_owner);
- skeleton->set_name("Skeleton3D");
- print_verbose("created armature skeleton for root");
- }
- } else {
- memfree(skeleton);
- skeleton = nullptr;
- print_error("[doc] skeleton has no valid node to parent nodes to - erasing");
- skeleton_bones.clear();
- return;
- }
- }
-
- // Make the bone name uniques.
- for (int x = 0; x < skeleton_bone_count; x++) {
- Ref<FBXBone> bone = skeleton_bones[x];
- if (bone.is_valid()) {
- // Make sure the bone name is unique.
- const String bone_name = bone->bone_name;
- int same_name_count = 0;
- for (int y = x + 1; y < skeleton_bone_count; y++) {
- Ref<FBXBone> other_bone = skeleton_bones[y];
- if (other_bone.is_valid()) {
- if (other_bone->bone_name == bone_name) {
- same_name_count += 1;
- other_bone->bone_name += "_" + itos(same_name_count);
- }
- }
- }
- }
- }
-
- Map<int, Ref<FBXBone>> bone_map;
- // implement fbx cluster skin logic here this is where it goes
- int bone_count = 0;
- for (int x = 0; x < skeleton_bone_count; x++) {
- Ref<FBXBone> bone = skeleton_bones[x];
- if (bone.is_valid()) {
- skeleton->add_bone(bone->bone_name);
- bone->godot_bone_id = bone_count;
- bone->fbx_skeleton = Ref<FBXSkeleton>(this);
- bone_map.insert(bone_count, bone);
- print_verbose("added bone " + itos(bone->bone_id) + " " + bone->bone_name);
- bone_count++;
- }
- }
-
- ERR_FAIL_COND_MSG(skeleton->get_bone_count() != bone_count, "Not all bones got added, is the file corrupted?");
-
- for (const KeyValue<int, Ref<FBXBone>> &bone_element : bone_map) {
- const Ref<FBXBone> bone = bone_element.value;
- int bone_index = bone_element.key;
- print_verbose("working on bone: " + itos(bone_index) + " bone name:" + bone->bone_name);
-
- skeleton->set_bone_rest(bone->godot_bone_id, get_unscaled_transform(bone->node->pivot_transform->LocalTransform, state.scale));
- {
- Transform3D base_xform = bone->node->pivot_transform->LocalTransform;
-
- skeleton->set_bone_pose_position(bone_index, base_xform.origin);
- skeleton->set_bone_pose_rotation(bone_index, base_xform.basis.get_rotation_quaternion());
- skeleton->set_bone_pose_scale(bone_index, base_xform.basis.get_scale());
- }
-
- // lookup parent ID
- if (bone->valid_parent && state.fbx_bone_map.has(bone->parent_bone_id)) {
- Ref<FBXBone> parent_bone = state.fbx_bone_map[bone->parent_bone_id];
- int bone_id = skeleton->find_bone(parent_bone->bone_name);
- if (bone_id != -1) {
- skeleton->set_bone_parent(bone_index, bone_id);
- } else {
- print_error("invalid bone parent: " + parent_bone->bone_name);
- }
- } else {
- if (bone->godot_bone_id != -1) {
- skeleton->set_bone_parent(bone_index, -1); // no parent for this bone
- }
- }
- }
-}
diff --git a/modules/fbx/data/import_state.h b/modules/fbx/data/import_state.h
deleted file mode 100644
index eff11e3bb8..0000000000
--- a/modules/fbx/data/import_state.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*************************************************************************/
-/* import_state.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef IMPORT_STATE_H
-#define IMPORT_STATE_H
-
-#include "fbx_mesh_data.h"
-#include "tools/import_utils.h"
-#include "tools/validation_tools.h"
-
-#include "pivot_transform.h"
-
-#include "core/io/resource_importer.h"
-#include "core/templates/vector.h"
-#include "editor/import/resource_importer_scene.h"
-#include "editor/project_settings_editor.h"
-#include "scene/3d/mesh_instance_3d.h"
-#include "scene/3d/node_3d.h"
-#include "scene/3d/skeleton_3d.h"
-#include "scene/animation/animation_player.h"
-#include "scene/resources/animation.h"
-#include "scene/resources/surface_tool.h"
-
-#include "modules/fbx/fbx_parser/FBXDocument.h"
-#include "modules/fbx/fbx_parser/FBXImportSettings.h"
-#include "modules/fbx/fbx_parser/FBXMeshGeometry.h"
-#include "modules/fbx/fbx_parser/FBXParser.h"
-#include "modules/fbx/fbx_parser/FBXTokenizer.h"
-#include "modules/fbx/fbx_parser/FBXUtil.h"
-
-struct FBXBone;
-struct FBXMeshData;
-struct FBXNode;
-struct FBXSkeleton;
-
-struct ImportState {
- bool enable_material_import = true;
- bool enable_animation_import = true;
- bool is_blender_fbx = false;
-
- Map<StringName, Ref<Texture>> cached_image_searches;
- Map<uint64_t, Ref<Material>> cached_materials;
-
- String path = String();
- Node3D *root_owner = nullptr;
- Node3D *root = nullptr;
- real_t scale = 0.01;
- Ref<FBXNode> fbx_root_node = Ref<FBXNode>();
- // skeleton map - merged automatically when they are on the same x node in the tree so we can merge them automatically.
- Map<uint64_t, Ref<FBXSkeleton>> skeleton_map = Map<uint64_t, Ref<FBXSkeleton>>();
-
- // nodes on the same level get merged automatically.
- //Map<uint64_t, Skeleton3D *> armature_map;
- AnimationPlayer *animation_player = nullptr;
-
- // Generation 4 - Raw document accessing for bone/skin/joint/kLocators
- // joints are not necessarily bones but must be merged into the skeleton
- // (bone id), bone
- Map<uint64_t, Ref<FBXBone>> fbx_bone_map = Map<uint64_t, Ref<FBXBone>>(); // this is the bone name and setup information required for joints
- // this will never contain joints only bones attached to a mesh.
-
- // Generation 4 - Raw document for creating the nodes transforms in the scene
- // this is a list of the nodes in the scene
- // (id, node)
- List<Ref<FBXNode>> fbx_node_list = List<Ref<FBXNode>>();
-
- // All nodes which have been created in the scene
- // this will not contain the root node of the scene
- Map<uint64_t, Ref<FBXNode>> fbx_target_map = Map<uint64_t, Ref<FBXNode>>();
-
- // mesh nodes which are created in node / mesh step - used for populating skin poses in MeshSkins
- Map<uint64_t, Ref<FBXNode>> MeshNodes = Map<uint64_t, Ref<FBXNode>>();
- // mesh skin map
- Map<uint64_t, Ref<Skin>> MeshSkins = Map<uint64_t, Ref<Skin>>();
-
- // this is the container for the mesh weight information and eventually
- // any mesh data
- // but not the skin, just stuff important for rendering
- // skin is applied to mesh instance so not really required to be in here yet.
- // maybe later
- // fbx mesh id, FBXMeshData
- Map<uint64_t, Ref<FBXMeshData>> renderer_mesh_data = Map<uint64_t, Ref<FBXMeshData>>();
-};
-
-#endif // IMPORT_STATE_H
diff --git a/modules/fbx/data/model_abstraction.h b/modules/fbx/data/model_abstraction.h
deleted file mode 100644
index 4c3f81b163..0000000000
--- a/modules/fbx/data/model_abstraction.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*************************************************************************/
-/* model_abstraction.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef MODEL_ABSTRACTION_H
-#define MODEL_ABSTRACTION_H
-
-#include "modules/fbx/fbx_parser/FBXDocument.h"
-
-struct ModelAbstraction {
- mutable const FBXDocParser::Model *fbx_model = nullptr;
-
- void set_model(const FBXDocParser::Model *p_model) {
- fbx_model = p_model;
- }
-
- bool has_model() const {
- return fbx_model != nullptr;
- }
-
- const FBXDocParser::Model *get_model() const {
- return fbx_model;
- }
-};
-
-#endif // MODEL_ABSTRACTION_H
diff --git a/modules/fbx/data/pivot_transform.cpp b/modules/fbx/data/pivot_transform.cpp
deleted file mode 100644
index 9457b19a7f..0000000000
--- a/modules/fbx/data/pivot_transform.cpp
+++ /dev/null
@@ -1,307 +0,0 @@
-/*************************************************************************/
-/* pivot_transform.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "pivot_transform.h"
-
-#include "tools/import_utils.h"
-
-void PivotTransform::ReadTransformChain() {
- const FBXDocParser::PropertyTable *props = fbx_model;
- const FBXDocParser::Model::RotOrder &rot = fbx_model->RotationOrder();
- const FBXDocParser::TransformInheritance &inheritType = fbx_model->InheritType();
- inherit_type = inheritType; // copy the inherit type we need it in the second step.
- print_verbose("Model: " + String(fbx_model->Name().c_str()) + " Has inherit type: " + itos(fbx_model->InheritType()));
- bool ok = false;
- raw_pre_rotation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "PreRotation", ok));
- if (ok) {
- pre_rotation = ImportUtils::EulerToQuaternion(rot, ImportUtils::deg2rad(raw_pre_rotation));
- print_verbose("valid pre_rotation: " + raw_pre_rotation + " euler conversion: " + (pre_rotation.get_euler() * (180 / Math_PI)));
- }
- raw_post_rotation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "PostRotation", ok));
- if (ok) {
- post_rotation = ImportUtils::EulerToQuaternion(FBXDocParser::Model::RotOrder_EulerXYZ, ImportUtils::deg2rad(raw_post_rotation));
- print_verbose("valid post_rotation: " + raw_post_rotation + " euler conversion: " + (pre_rotation.get_euler() * (180 / Math_PI)));
- }
- const Vector3 &RotationPivot = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "RotationPivot", ok));
- if (ok) {
- rotation_pivot = ImportUtils::FixAxisConversions(RotationPivot);
- }
- const Vector3 &RotationOffset = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "RotationOffset", ok));
- if (ok) {
- rotation_offset = ImportUtils::FixAxisConversions(RotationOffset);
- }
- const Vector3 &ScalingOffset = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "ScalingOffset", ok));
- if (ok) {
- scaling_offset = ImportUtils::FixAxisConversions(ScalingOffset);
- }
- const Vector3 &ScalingPivot = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "ScalingPivot", ok));
- if (ok) {
- scaling_pivot = ImportUtils::FixAxisConversions(ScalingPivot);
- }
- const Vector3 &Translation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "Lcl Translation", ok));
- if (ok) {
- translation = ImportUtils::FixAxisConversions(Translation);
- }
- raw_rotation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "Lcl Rotation", ok));
- if (ok) {
- rotation = ImportUtils::EulerToQuaternion(rot, ImportUtils::deg2rad(raw_rotation));
- }
- const Vector3 &Scaling = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "Lcl Scaling", ok));
- if (ok) {
- scaling = Scaling;
- } else {
- scaling = Vector3(1, 1, 1);
- }
- const Vector3 &GeometricScaling = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "GeometricScaling", ok));
- if (ok) {
- geometric_scaling = GeometricScaling;
- } else {
- geometric_scaling = Vector3(1, 1, 1);
- }
-
- const Vector3 &GeometricRotation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "GeometricRotation", ok));
- if (ok) {
- geometric_rotation = ImportUtils::EulerToQuaternion(rot, ImportUtils::deg2rad(GeometricRotation));
- } else {
- geometric_rotation = Quaternion();
- }
-
- const Vector3 &GeometricTranslation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "GeometricTranslation", ok));
- if (ok) {
- geometric_translation = ImportUtils::FixAxisConversions(GeometricTranslation);
- } else {
- geometric_translation = Vector3(0, 0, 0);
- }
-
- if (geometric_rotation != Quaternion()) {
- print_error("geometric rotation is unsupported!");
- //CRASH_COND(true);
- }
-
- if (!geometric_scaling.is_equal_approx(Vector3(1, 1, 1))) {
- print_error("geometric scaling is unsupported!");
- //CRASH_COND(true);
- }
-
- if (!geometric_translation.is_equal_approx(Vector3(0, 0, 0))) {
- print_error("geometric translation is unsupported.");
- //CRASH_COND(true);
- }
-}
-
-Transform3D PivotTransform::ComputeLocalTransform(Vector3 p_translation, Quaternion p_rotation, Vector3 p_scaling) const {
- Transform3D T, Roff, Rp, Soff, Sp, S;
-
- // Here I assume this is the operation which needs done.
- // Its WorldTransform * V
-
- // Origin pivots
- T.set_origin(p_translation);
- Roff.set_origin(rotation_offset);
- Rp.set_origin(rotation_pivot);
- Soff.set_origin(scaling_offset);
- Sp.set_origin(scaling_pivot);
-
- // Scaling node
- S.scale(p_scaling);
- // Rotation pivots
- Transform3D Rpre = Transform3D(pre_rotation);
- Transform3D R = Transform3D(p_rotation);
- Transform3D Rpost = Transform3D(post_rotation);
-
- return T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse();
-}
-
-Transform3D PivotTransform::ComputeGlobalTransform(Transform3D t) const {
- Vector3 pos = t.origin;
- Vector3 scale = t.basis.get_scale();
- Quaternion rot = t.basis.get_rotation_quaternion();
- return ComputeGlobalTransform(pos, rot, scale);
-}
-
-Transform3D PivotTransform::ComputeLocalTransform(Transform3D t) const {
- Vector3 pos = t.origin;
- Vector3 scale = t.basis.get_scale();
- Quaternion rot = t.basis.get_rotation_quaternion();
- return ComputeLocalTransform(pos, rot, scale);
-}
-
-Transform3D PivotTransform::ComputeGlobalTransform(Vector3 p_translation, Quaternion p_rotation, Vector3 p_scaling) const {
- Transform3D T, Roff, Rp, Soff, Sp, S;
-
- // Here I assume this is the operation which needs done.
- // Its WorldTransform * V
-
- // Origin pivots
- T.set_origin(p_translation);
- Roff.set_origin(rotation_offset);
- Rp.set_origin(rotation_pivot);
- Soff.set_origin(scaling_offset);
- Sp.set_origin(scaling_pivot);
-
- // Scaling node
- S.scale(p_scaling);
-
- // Rotation pivots
- Transform3D Rpre = Transform3D(pre_rotation);
- Transform3D R = Transform3D(p_rotation);
- Transform3D Rpost = Transform3D(post_rotation);
-
- Transform3D parent_global_xform;
- Transform3D parent_local_scaling_m;
-
- if (parent_transform.is_valid()) {
- parent_global_xform = parent_transform->GlobalTransform;
- parent_local_scaling_m = parent_transform->Local_Scaling_Matrix;
- }
-
- Transform3D local_rotation_m, parent_global_rotation_m;
- Quaternion parent_global_rotation = parent_global_xform.basis.get_rotation_quaternion();
- parent_global_rotation_m.basis.set_quaternion(parent_global_rotation);
- local_rotation_m = Rpre * R * Rpost;
-
- //Basis parent_global_rotation = Basis(parent_global_xform.get_basis().get_rotation_quaternion().normalized());
-
- Transform3D local_shear_scaling, parent_shear_scaling, parent_shear_rotation, parent_shear_translation;
- Vector3 parent_translation = parent_global_xform.get_origin();
- parent_shear_translation.origin = parent_translation;
- parent_shear_rotation = parent_shear_translation.affine_inverse() * parent_global_xform;
- parent_shear_scaling = parent_global_rotation_m.affine_inverse() * parent_shear_rotation;
- local_shear_scaling = S;
-
- // Inherit type handler - we don't care about T here, just reordering RSrs etc.
- Transform3D global_rotation_scale;
- if (inherit_type == FBXDocParser::Transform_RrSs) {
- global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_shear_scaling * local_shear_scaling;
- } else if (inherit_type == FBXDocParser::Transform_RSrs) {
- global_rotation_scale = parent_global_rotation_m * parent_shear_scaling * local_rotation_m * local_shear_scaling;
- } else if (inherit_type == FBXDocParser::Transform_Rrs) {
- Transform3D parent_global_shear_m_noLocal = parent_shear_scaling * parent_local_scaling_m.affine_inverse();
- global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_global_shear_m_noLocal * local_shear_scaling;
- }
- Transform3D local_transform = T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse();
- //Transform3D local_translation_pivoted = Transform3D(Basis(), LocalTransform.origin);
-
- ERR_FAIL_COND_V_MSG(local_transform.basis.determinant() == 0, Transform3D(), "Det == 0 prevented in scene file");
-
- // manual hack to force SSC not to be compensated for - until we can handle it properly with tests
- return parent_global_xform * local_transform;
-}
-
-void PivotTransform::ComputePivotTransform() {
- Transform3D T, Roff, Rp, Soff, Sp, S;
-
- // Here I assume this is the operation which needs done.
- // Its WorldTransform * V
-
- // Origin pivots
- T.set_origin(translation);
- Roff.set_origin(rotation_offset);
- Rp.set_origin(rotation_pivot);
- Soff.set_origin(scaling_offset);
- Sp.set_origin(scaling_pivot);
-
- // Scaling node
- if (!scaling.is_equal_approx(Vector3())) {
- S.scale(scaling);
- } else {
- S.scale(Vector3(1, 1, 1));
- }
- Local_Scaling_Matrix = S; // copy for when node / child is looking for the value of this.
-
- // Rotation pivots
- Transform3D Rpre = Transform3D(pre_rotation);
- Transform3D R = Transform3D(rotation);
- Transform3D Rpost = Transform3D(post_rotation);
-
- Transform3D parent_global_xform;
- Transform3D parent_local_scaling_m;
-
- if (parent_transform.is_valid()) {
- parent_global_xform = parent_transform->GlobalTransform;
- parent_local_scaling_m = parent_transform->Local_Scaling_Matrix;
- }
-
- Transform3D local_rotation_m, parent_global_rotation_m;
- Quaternion parent_global_rotation = parent_global_xform.basis.get_rotation_quaternion();
- parent_global_rotation_m.basis.set_quaternion(parent_global_rotation);
- local_rotation_m = Rpre * R * Rpost;
-
- //Basis parent_global_rotation = Basis(parent_global_xform.get_basis().get_rotation_quaternion().normalized());
-
- Transform3D local_shear_scaling, parent_shear_scaling, parent_shear_rotation, parent_shear_translation;
- Vector3 parent_translation = parent_global_xform.get_origin();
- parent_shear_translation.origin = parent_translation;
- parent_shear_rotation = parent_shear_translation.affine_inverse() * parent_global_xform;
- parent_shear_scaling = parent_global_rotation_m.affine_inverse() * parent_shear_rotation;
- local_shear_scaling = S;
-
- // Inherit type handler - we don't care about T here, just reordering RSrs etc.
- Transform3D global_rotation_scale;
- if (inherit_type == FBXDocParser::Transform_RrSs) {
- global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_shear_scaling * local_shear_scaling;
- } else if (inherit_type == FBXDocParser::Transform_RSrs) {
- global_rotation_scale = parent_global_rotation_m * parent_shear_scaling * local_rotation_m * local_shear_scaling;
- } else if (inherit_type == FBXDocParser::Transform_Rrs) {
- Transform3D parent_global_shear_m_noLocal = parent_shear_scaling * parent_local_scaling_m.inverse();
- global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_global_shear_m_noLocal * local_shear_scaling;
- }
- LocalTransform = Transform3D();
- LocalTransform = T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse();
-
- ERR_FAIL_COND_MSG(LocalTransform.basis.determinant() == 0, "invalid scale reset");
-
- Transform3D local_translation_pivoted = Transform3D(Basis(), LocalTransform.origin);
- GlobalTransform = Transform3D();
- //GlobalTransform = parent_global_xform * LocalTransform;
- Transform3D global_origin = Transform3D(Basis(), parent_translation);
- GlobalTransform = (global_origin * local_translation_pivoted) * global_rotation_scale;
-
- ImportUtils::debug_xform("local xform calculation", LocalTransform);
- print_verbose("scale of node: " + S.basis.get_scale_local());
- print_verbose("---------------------------------------------------------------");
-}
-
-void PivotTransform::Execute() {
- ReadTransformChain();
- ComputePivotTransform();
-
- ImportUtils::debug_xform("global xform: ", GlobalTransform);
-
- if (LocalTransform.basis.determinant() == 0) {
- print_error("Serious det == 0!");
- }
-
- if (GlobalTransform.basis.determinant() == 0) {
- print_error("Serious! node has det == 0!");
- }
-
- computed_global_xform = true;
-}
diff --git a/modules/fbx/data/pivot_transform.h b/modules/fbx/data/pivot_transform.h
deleted file mode 100644
index df97c8db57..0000000000
--- a/modules/fbx/data/pivot_transform.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*************************************************************************/
-/* pivot_transform.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef PIVOT_TRANSFORM_H
-#define PIVOT_TRANSFORM_H
-
-#include "core/math/transform_3d.h"
-#include "core/object/ref_counted.h"
-
-#include "model_abstraction.h"
-
-#include "fbx_parser/FBXDocument.h"
-#include "tools/import_utils.h"
-
-enum TransformationComp {
- TransformationComp_Translation,
- TransformationComp_Scaling,
- TransformationComp_Rotation,
- TransformationComp_RotationOffset,
- TransformationComp_RotationPivot,
- TransformationComp_PreRotation,
- TransformationComp_PostRotation,
- TransformationComp_ScalingOffset,
- TransformationComp_ScalingPivot,
- TransformationComp_GeometricTranslation,
- TransformationComp_GeometricRotation,
- TransformationComp_GeometricScaling,
- TransformationComp_MAXIMUM
-};
-// Abstract away pivot data so its simpler to handle
-struct PivotTransform : RefCounted, ModelAbstraction {
- // at the end we want to keep geometric_ everything, post and pre rotation
- // these are used during animation data processing / keyframe ingestion the rest can be simplified down / out.
- Quaternion pre_rotation = Quaternion();
- Quaternion post_rotation = Quaternion();
- Quaternion rotation = Quaternion();
- Quaternion geometric_rotation = Quaternion();
- Vector3 rotation_pivot = Vector3();
- Vector3 rotation_offset = Vector3();
- Vector3 scaling_offset = Vector3(1.0, 1.0, 1.0);
- Vector3 scaling_pivot = Vector3(1.0, 1.0, 1.0);
- Vector3 translation = Vector3();
- Vector3 scaling = Vector3(1.0, 1.0, 1.0);
- Vector3 geometric_scaling = Vector3(1.0, 1.0, 1.0);
- Vector3 geometric_translation = Vector3();
-
- Vector3 raw_rotation = Vector3();
- Vector3 raw_post_rotation = Vector3();
- Vector3 raw_pre_rotation = Vector3();
-
- /* Read pivots from the document */
- void ReadTransformChain();
-
- void debug_pivot_xform(String p_name) {
- print_verbose("debugging node name: " + p_name);
- print_verbose("raw rotation: " + raw_rotation * (180 / Math_PI));
- print_verbose("raw pre_rotation " + raw_pre_rotation * (180 / Math_PI));
- print_verbose("raw post_rotation " + raw_post_rotation * (180 / Math_PI));
- }
-
- Transform3D ComputeGlobalTransform(Transform3D t) const;
- Transform3D ComputeLocalTransform(Transform3D t) const;
- Transform3D ComputeGlobalTransform(Vector3 p_translation, Quaternion p_rotation, Vector3 p_scaling) const;
- Transform3D ComputeLocalTransform(Vector3 p_translation, Quaternion p_rotation, Vector3 p_scaling) const;
-
- /* Extract into xforms and calculate once */
- void ComputePivotTransform();
-
- /* Execute the command for the pivot generation */
- void Execute();
-
- void set_parent(Ref<PivotTransform> p_parent) {
- parent_transform = p_parent;
- }
-
- bool computed_global_xform = false;
- Ref<PivotTransform> parent_transform = Ref<PivotTransform>();
- //Transform chain[TransformationComp_MAXIMUM];
-
- // cached for later use
- Transform3D GlobalTransform = Transform3D();
- Transform3D LocalTransform = Transform3D();
- Transform3D Local_Scaling_Matrix = Transform3D(); // used for inherit type.
- Transform3D GeometricTransform = Transform3D(); // 3DS max only
- FBXDocParser::TransformInheritance inherit_type = FBXDocParser::TransformInheritance_MAX; // maya fbx requires this - sorry <3
-};
-
-#endif // PIVOT_TRANSFORM_H
diff --git a/modules/fbx/editor_scene_importer_fbx.cpp b/modules/fbx/editor_scene_importer_fbx.cpp
deleted file mode 100644
index 758c47eecc..0000000000
--- a/modules/fbx/editor_scene_importer_fbx.cpp
+++ /dev/null
@@ -1,1475 +0,0 @@
-/*************************************************************************/
-/* editor_scene_importer_fbx.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "editor_scene_importer_fbx.h"
-
-#include "data/fbx_anim_container.h"
-#include "data/fbx_material.h"
-#include "data/fbx_mesh_data.h"
-#include "data/fbx_skeleton.h"
-#include "tools/import_utils.h"
-
-#include "core/io/image_loader.h"
-#include "editor/editor_log.h"
-#include "editor/editor_node.h"
-#include "editor/import/resource_importer_scene.h"
-#include "scene/3d/bone_attachment_3d.h"
-#include "scene/3d/camera_3d.h"
-#include "scene/3d/importer_mesh_instance_3d.h"
-#include "scene/3d/light_3d.h"
-#include "scene/main/node.h"
-#include "scene/resources/material.h"
-
-#include "fbx_parser/FBXDocument.h"
-#include "fbx_parser/FBXImportSettings.h"
-#include "fbx_parser/FBXMeshGeometry.h"
-#include "fbx_parser/FBXParser.h"
-#include "fbx_parser/FBXProperties.h"
-#include "fbx_parser/FBXTokenizer.h"
-
-#include <string>
-
-void EditorSceneFormatImporterFBX::get_extensions(List<String> *r_extensions) const {
- // register FBX as the one and only format for FBX importing
- const String import_setting_string = "filesystem/import/fbx/";
- const String fbx_str = "fbx";
- Vector<String> exts;
- exts.push_back(fbx_str);
- _register_project_setting_import(fbx_str, import_setting_string, exts, r_extensions, true);
-}
-
-void EditorSceneFormatImporterFBX::_register_project_setting_import(const String generic,
- const String import_setting_string,
- const Vector<String> &exts,
- List<String> *r_extensions,
- const bool p_enabled) const {
- const String use_generic = "use_" + generic;
- _GLOBAL_DEF(import_setting_string + use_generic, p_enabled, true);
- if (ProjectSettings::get_singleton()->get(import_setting_string + use_generic)) {
- for (int32_t i = 0; i < exts.size(); i++) {
- r_extensions->push_back(exts[i]);
- }
- }
-}
-
-uint32_t EditorSceneFormatImporterFBX::get_import_flags() const {
- return IMPORT_SCENE;
-}
-
-Node3D *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps,
- List<String> *r_missing_deps, Error *r_err) {
- // done for performance when re-importing lots of files when testing importer in verbose only!
- if (OS::get_singleton()->is_stdout_verbose()) {
- EditorLog *log = EditorNode::get_log();
- log->clear();
- }
- Error err;
- FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err);
-
- ERR_FAIL_COND_V(!f, nullptr);
-
- {
- PackedByteArray data;
- // broadphase tokenizing pass in which we identify the core
- // syntax elements of FBX (brackets, commas, key:value mappings)
- FBXDocParser::TokenList tokens;
-
- bool is_binary = false;
- data.resize(f->get_length());
-
- ERR_FAIL_COND_V(data.size() < 64, nullptr);
-
- f->get_buffer(data.ptrw(), data.size());
- PackedByteArray fbx_header;
- fbx_header.resize(64);
- for (int32_t byte_i = 0; byte_i < 64; byte_i++) {
- fbx_header.ptrw()[byte_i] = data.ptr()[byte_i];
- }
-
- String fbx_header_string;
- if (fbx_header.size() >= 0) {
- fbx_header_string.parse_utf8((const char *)fbx_header.ptr(), fbx_header.size());
- }
-
- print_verbose("[doc] opening fbx file: " + p_path);
- print_verbose("[doc] fbx header: " + fbx_header_string);
- bool corrupt = false;
-
- // safer to check this way as there can be different formatted headers
- if (fbx_header_string.contains("Kaydara FBX Binary")) {
- is_binary = true;
- print_verbose("[doc] is binary");
-
- FBXDocParser::TokenizeBinary(tokens, (const char *)data.ptrw(), (size_t)data.size(), corrupt);
-
- } else {
- print_verbose("[doc] is ascii");
- FBXDocParser::Tokenize(tokens, (const char *)data.ptrw(), (size_t)data.size(), corrupt);
- }
-
- if (corrupt) {
- for (FBXDocParser::TokenPtr token : tokens) {
- delete token;
- }
- tokens.clear();
- ERR_PRINT(vformat("Cannot import FBX file: %s the file is corrupt so we safely exited parsing the file.", p_path));
- return memnew(Node3D);
- }
-
- // The import process explained:
- // 1. Tokens are made, these are then taken into the 'parser' below
- // 2. The parser constructs 'Elements' and all 'real' FBX Types.
- // 3. This creates a problem: shared_ptr ownership, should Elements later 'take ownership'
- // 4. No, it shouldn't so we should either a.) use weak ref for elements; but this is not correct.
-
- // use this information to construct a very rudimentary
- // parse-tree representing the FBX scope structure
- FBXDocParser::Parser parser(tokens, is_binary);
-
- if (parser.IsCorrupt()) {
- for (FBXDocParser::TokenPtr token : tokens) {
- delete token;
- }
- tokens.clear();
- ERR_PRINT(vformat("Cannot import FBX file: %s the file is corrupt so we safely exited parsing the file.", p_path));
- return memnew(Node3D);
- }
-
- FBXDocParser::ImportSettings settings;
- settings.strictMode = false;
-
- // this function leaks a lot
- FBXDocParser::Document doc(parser, settings);
-
- // yeah so closing the file is a good idea (prevents readonly states)
- f->close();
-
- // safety for version handling
- if (doc.IsSafeToImport()) {
- bool is_blender_fbx = false;
- const FBXDocParser::PropertyTable &import_props = doc.GetMetadataProperties();
- const FBXDocParser::PropertyPtr app_name = import_props.Get("Original|ApplicationName");
- const FBXDocParser::PropertyPtr app_vendor = import_props.Get("Original|ApplicationVendor");
- const FBXDocParser::PropertyPtr app_version = import_props.Get("Original|ApplicationVersion");
- //
- if (app_name) {
- const FBXDocParser::TypedProperty<std::string> *app_name_string = dynamic_cast<const FBXDocParser::TypedProperty<std::string> *>(app_name);
- if (app_name_string) {
- print_verbose("FBX App Name: " + String(app_name_string->Value().c_str()));
- }
- }
-
- if (app_vendor) {
- const FBXDocParser::TypedProperty<std::string> *app_vendor_string = dynamic_cast<const FBXDocParser::TypedProperty<std::string> *>(app_vendor);
- if (app_vendor_string) {
- print_verbose("FBX App Vendor: " + String(app_vendor_string->Value().c_str()));
- is_blender_fbx = app_vendor_string->Value().find("Blender") != std::string::npos;
- }
- }
-
- if (app_version) {
- const FBXDocParser::TypedProperty<std::string> *app_version_string = dynamic_cast<const FBXDocParser::TypedProperty<std::string> *>(app_version);
- if (app_version_string) {
- print_verbose("FBX App Version: " + String(app_version_string->Value().c_str()));
- }
- }
-
- if (is_blender_fbx) {
- WARN_PRINT("We don't officially support Blender FBX animations yet, due to issues with upstream Blender,\n"
- "so please wait for us to work around remaining issues. We will continue to import the file but it may be broken.\n"
- "For minimal breakage, please export FBX from Blender with -Z forward, and Y up.");
- }
-
- Node3D *spatial = _generate_scene(p_path, &doc, p_flags, p_bake_fps, 8, is_blender_fbx);
- // todo: move to document shutdown (will need to be validated after moving; this code has been validated already)
- for (FBXDocParser::TokenPtr token : tokens) {
- if (token) {
- delete token;
- token = nullptr;
- }
- }
-
- return spatial;
-
- } else {
- for (FBXDocParser::TokenPtr token : tokens) {
- delete token;
- }
- tokens.clear();
-
- ERR_PRINT(vformat("Cannot import FBX file: %s. It uses file format %d which is unsupported by Godot. Please re-export it or convert it to a newer format.", p_path, doc.FBXVersion()));
- }
- }
-
- return memnew(Node3D);
-}
-
-template <class T>
-struct EditorSceneFormatImporterAssetImportInterpolate {
- T lerp(const T &a, const T &b, float c) const {
- return a + (b - a) * c;
- }
-
- T catmull_rom(const T &p0, const T &p1, const T &p2, const T &p3, float t) {
- const float t2 = t * t;
- const float t3 = t2 * t;
-
- return 0.5f * ((2.0f * p1) + (-p0 + p2) * t + (2.0f * p0 - 5.0f * p1 + 4.0f * p2 - p3) * t2 + (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3);
- }
-
- T bezier(T start, T control_1, T control_2, T end, float t) {
- /* Formula from Wikipedia article on Bezier curves. */
- const real_t omt = (1.0 - t);
- const real_t omt2 = omt * omt;
- const real_t omt3 = omt2 * omt;
- const real_t t2 = t * t;
- const real_t t3 = t2 * t;
-
- return start * omt3 + control_1 * omt2 * t * 3.0 + control_2 * omt * t2 * 3.0 + end * t3;
- }
-};
-
-//thank you for existing, partial specialization
-template <>
-struct EditorSceneFormatImporterAssetImportInterpolate<Quaternion> {
- Quaternion lerp(const Quaternion &a, const Quaternion &b, float c) const {
- ERR_FAIL_COND_V(!a.is_normalized(), Quaternion());
- ERR_FAIL_COND_V(!b.is_normalized(), Quaternion());
-
- return a.slerp(b, c).normalized();
- }
-
- Quaternion catmull_rom(const Quaternion &p0, const Quaternion &p1, const Quaternion &p2, const Quaternion &p3, float c) {
- ERR_FAIL_COND_V(!p1.is_normalized(), Quaternion());
- ERR_FAIL_COND_V(!p2.is_normalized(), Quaternion());
-
- return p1.slerp(p2, c).normalized();
- }
-
- Quaternion bezier(Quaternion start, Quaternion control_1, Quaternion control_2, Quaternion end, float t) {
- ERR_FAIL_COND_V(!start.is_normalized(), Quaternion());
- ERR_FAIL_COND_V(!end.is_normalized(), Quaternion());
-
- return start.slerp(end, t).normalized();
- }
-};
-
-template <class T>
-T EditorSceneFormatImporterFBX::_interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, float p_time,
- AssetImportAnimation::Interpolation p_interp) {
- //could use binary search, worth it?
- int idx = -1;
- for (int i = 0; i < p_times.size(); i++) {
- if (p_times[i] > p_time) {
- break;
- }
- idx++;
- }
-
- EditorSceneFormatImporterAssetImportInterpolate<T> interp;
-
- switch (p_interp) {
- case AssetImportAnimation::INTERP_LINEAR: {
- if (idx == -1) {
- return p_values[0];
- } else if (idx >= p_times.size() - 1) {
- return p_values[p_times.size() - 1];
- }
-
- float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]);
-
- return interp.lerp(p_values[idx], p_values[idx + 1], c);
-
- } break;
- case AssetImportAnimation::INTERP_STEP: {
- if (idx == -1) {
- return p_values[0];
- } else if (idx >= p_times.size() - 1) {
- return p_values[p_times.size() - 1];
- }
-
- return p_values[idx];
-
- } break;
- case AssetImportAnimation::INTERP_CATMULLROMSPLINE: {
- if (idx == -1) {
- return p_values[1];
- } else if (idx >= p_times.size() - 1) {
- return p_values[1 + p_times.size() - 1];
- }
-
- float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]);
-
- return interp.catmull_rom(p_values[idx - 1], p_values[idx], p_values[idx + 1], p_values[idx + 3], c);
-
- } break;
- case AssetImportAnimation::INTERP_CUBIC_SPLINE: {
- if (idx == -1) {
- return p_values[1];
- } else if (idx >= p_times.size() - 1) {
- return p_values[(p_times.size() - 1) * 3 + 1];
- }
-
- float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]);
-
- T from = p_values[idx * 3 + 1];
- T c1 = from + p_values[idx * 3 + 2];
- T to = p_values[idx * 3 + 4];
- T c2 = to + p_values[idx * 3 + 3];
-
- return interp.bezier(from, c1, c2, to, c);
-
- } break;
- }
-
- ERR_FAIL_V(p_values[0]);
-}
-
-Node3D *EditorSceneFormatImporterFBX::_generate_scene(
- const String &p_path,
- const FBXDocParser::Document *p_document,
- const uint32_t p_flags,
- int p_bake_fps,
- const int32_t p_max_bone_weights,
- bool p_is_blender_fbx) {
- ImportState state;
- state.is_blender_fbx = p_is_blender_fbx;
- state.path = p_path;
- state.animation_player = nullptr;
-
- // create new root node for scene
- Node3D *scene_root = memnew(Node3D);
- state.root = memnew(Node3D);
- state.root_owner = scene_root; // the real scene root... sorry compatibility code is painful...
-
- state.root->set_name("RootNode");
- scene_root->add_child(state.root);
- state.root->set_owner(scene_root);
-
- state.fbx_root_node.instantiate();
- state.fbx_root_node->godot_node = state.root;
-
- // Size relative to cm.
- const real_t fbx_unit_scale = p_document->GlobalSettingsPtr()->UnitScaleFactor();
-
- print_verbose("FBX unit scale import value: " + rtos(fbx_unit_scale));
- // Set FBX file scale is relative to CM must be converted to M
- state.scale = fbx_unit_scale / 100.0;
- print_verbose("FBX unit scale is: " + rtos(state.scale));
-
- // Enabled by default.
- state.enable_material_import = true;
- // Enabled by default.
- state.enable_animation_import = true;
- Ref<FBXNode> root_node;
- root_node.instantiate();
-
- // make sure fake noFBXDocParser::PropertyPtr ptrde always has a transform too ;)
- Ref<PivotTransform> pivot_transform;
- pivot_transform.instantiate();
- root_node->pivot_transform = pivot_transform;
- root_node->node_name = "root node";
- root_node->current_node_id = 0;
- root_node->godot_node = state.root;
-
- // cache this node onto the fbx_target map.
- state.fbx_target_map.insert(0, root_node);
-
- // cache basic node information from FBX document
- // grabs all FBX bones
- BuildDocumentBones(Ref<FBXBone>(), state, p_document, 0L);
- BuildDocumentNodes(Ref<PivotTransform>(), state, p_document, 0L, nullptr);
-
- // Build document skinning information
-
- // Algorithm is this:
- // Get Deformer: object with "Skin" class.
- // Deformer:: has link to Geometry:: (correct mesh for skin)
- // Deformer:: has Source which is the SubDeformer:: (e.g. the Cluster)
- // Notes at the end it configures the vertex weight mapping.
-
- for (uint64_t skin_id : p_document->GetSkinIDs()) {
- // Validate the parser
- FBXDocParser::LazyObject *lazy_skin = p_document->GetObject(skin_id);
- ERR_CONTINUE_MSG(lazy_skin == nullptr, "invalid lazy object [serious parser bug]");
-
- // Validate the parser
- const FBXDocParser::Skin *skin = lazy_skin->Get<FBXDocParser::Skin>();
- ERR_CONTINUE_MSG(skin == nullptr, "invalid skin added to skin list [parser bug]");
-
- const std::vector<const FBXDocParser::Connection *> source_to_destination = p_document->GetConnectionsBySourceSequenced(skin_id);
- FBXDocParser::MeshGeometry *mesh = nullptr;
- uint64_t mesh_id = 0;
-
- // Most likely only contains the mesh link for the skin
- // The mesh geometry.
- for (const FBXDocParser::Connection *con : source_to_destination) {
- // do something
- print_verbose("src: " + itos(con->src));
- FBXDocParser::Object *ob = con->DestinationObject();
- mesh = dynamic_cast<FBXDocParser::MeshGeometry *>(ob);
-
- if (mesh) {
- mesh_id = mesh->ID();
- break;
- }
- }
-
- // Validate the mesh exists and was retrieved
- ERR_CONTINUE_MSG(mesh_id == 0, "mesh id is invalid");
- const std::vector<const FBXDocParser::Cluster *> clusters = skin->Clusters();
-
- // NOTE: this will ONLY work on skinned bones (it is by design.)
- // A cluster is a skinned bone so SKINS won't contain unskinned bones so we need to pre-add all bones and parent them in a step beforehand.
- for (const FBXDocParser::Cluster *cluster : clusters) {
- ERR_CONTINUE_MSG(cluster == nullptr, "invalid bone cluster");
- const uint64_t deformer_id = cluster->ID();
- std::vector<const FBXDocParser::Connection *> connections = p_document->GetConnectionsByDestinationSequenced(deformer_id);
-
- // Weight data always has a node in the scene lets grab the limb's node in the scene :) (reverse set to true since it's the opposite way around)
- const FBXDocParser::ModelLimbNode *limb_node = ProcessDOMConnection<FBXDocParser::ModelLimbNode>(p_document, deformer_id, true);
-
- ERR_CONTINUE_MSG(limb_node == nullptr, "unable to resolve model for skinned bone");
-
- const uint64_t model_id = limb_node->ID();
-
- // This will never happen, so if it does you know you fucked up.
- ERR_CONTINUE_MSG(!state.fbx_bone_map.has(model_id), "missing LimbNode detected");
-
- // new bone instance
- Ref<FBXBone> bone_element = state.fbx_bone_map[model_id];
-
- //
- // Bone Weight Information Configuration
- //
-
- // Cache Weight Information into bone for later usage if you want the raw data.
- const std::vector<unsigned int> &indexes = cluster->GetIndices();
- const std::vector<float> &weights = cluster->GetWeights();
- Ref<FBXMeshData> mesh_vertex_data;
-
- // this data will pre-exist if vertex weight information is found
- if (state.renderer_mesh_data.has(mesh_id)) {
- mesh_vertex_data = state.renderer_mesh_data[mesh_id];
- } else {
- mesh_vertex_data.instantiate();
- state.renderer_mesh_data.insert(mesh_id, mesh_vertex_data);
- }
-
- mesh_vertex_data->armature_id = bone_element->armature_id;
- mesh_vertex_data->valid_armature_id = true;
-
- //print_verbose("storing mesh vertex data for mesh to use later");
- ERR_CONTINUE_MSG(indexes.size() != weights.size(), "[doc] error mismatch between weight info");
-
- for (size_t idx = 0; idx < indexes.size(); idx++) {
- const size_t vertex_index = indexes[idx];
- const real_t influence_weight = weights[idx];
-
- VertexWeightMapping &vm = mesh_vertex_data->vertex_weights[vertex_index];
- vm.weights.push_back(influence_weight);
- vm.bones.push_back(0); // bone id is pushed on here during sanitization phase
- vm.bones_ref.push_back(bone_element);
- }
-
- for (const int *vertex_index = mesh_vertex_data->vertex_weights.next(nullptr);
- vertex_index != nullptr;
- vertex_index = mesh_vertex_data->vertex_weights.next(vertex_index)) {
- VertexWeightMapping *vm = mesh_vertex_data->vertex_weights.getptr(*vertex_index);
- const int influence_count = vm->weights.size();
- if (influence_count > mesh_vertex_data->max_weight_count) {
- mesh_vertex_data->max_weight_count = influence_count;
- mesh_vertex_data->valid_weight_count = true;
- }
- }
-
- if (mesh_vertex_data->max_weight_count > 4) {
- if (mesh_vertex_data->max_weight_count > 8) {
- ERR_PRINT("[doc] Serious: maximum bone influences is 8 in this branch.");
- }
- // Clamp to 8 bone vertex influences.
- mesh_vertex_data->max_weight_count = 8;
- print_verbose("[doc] Using 8 vertex bone influences configuration.");
- } else {
- mesh_vertex_data->max_weight_count = 4;
- print_verbose("[doc] Using 4 vertex bone influences configuration.");
- }
- }
- }
-
- // do we globally allow for import of materials
- // (prevents overwrite of materials; so you can handle them explicitly)
- if (state.enable_material_import) {
- const std::vector<uint64_t> &materials = p_document->GetMaterialIDs();
-
- for (uint64_t material_id : materials) {
- FBXDocParser::LazyObject *lazy_material = p_document->GetObject(material_id);
- FBXDocParser::Material *mat = (FBXDocParser::Material *)lazy_material->Get<FBXDocParser::Material>();
- ERR_CONTINUE_MSG(!mat, "Could not convert fbx material by id: " + itos(material_id));
-
- Ref<FBXMaterial> material;
- material.instantiate();
- material->set_imported_material(mat);
-
- Ref<StandardMaterial3D> godot_material = material->import_material(state);
-
- state.cached_materials.insert(material_id, godot_material);
- }
- }
-
- // build skin and skeleton information
- print_verbose("[doc] Skeleton3D Bone count: " + itos(state.fbx_bone_map.size()));
-
- // Importing bones using document based method from FBX directly
- // We do not use the assimp bone format to determine this information anymore.
- if (state.fbx_bone_map.size() > 0) {
- // We are using a single skeleton only method here
- // this is because we really have no concept of skeletons in FBX
- // their are bones in a scene but they have no specific armature
- // we can detect armatures but the issue lies in the complexity
- // we opted to merge the entire scene onto one skeleton for now
- // if we need to change this we have an archive of the old code.
-
- // bind pose normally only has 1 per mesh but can have more than one
- // this is the point of skins
- // in FBX first bind pose is the master for the first skin
-
- // In order to handle the FBX skeleton we must also inverse any parent transforms on the bones
- // just to rule out any parent node transforms in the bone data
- // this is trivial to do and allows us to use the single skeleton method and merge them
- // this means that the nodes from maya kLocators will be preserved as bones
- // in the same rig without having to match this across skeletons and merge by detection
- // we can just merge and undo any parent transforms
- for (KeyValue<uint64_t, Ref<FBXBone>> &bone_element : state.fbx_bone_map) {
- Ref<FBXBone> bone = bone_element.value;
- Ref<FBXSkeleton> fbx_skeleton_inst;
-
- uint64_t armature_id = bone->armature_id;
- if (state.skeleton_map.has(armature_id)) {
- fbx_skeleton_inst = state.skeleton_map[armature_id];
- } else {
- fbx_skeleton_inst.instantiate();
- state.skeleton_map.insert(armature_id, fbx_skeleton_inst);
- }
-
- print_verbose("populating skeleton with bone: " + bone->bone_name);
-
- //// populate bone skeleton - since fbx has no DOM for the skeleton just a node.
- //bone->bone_skeleton = fbx_skeleton_inst;
-
- // now populate bone on the armature node list
- fbx_skeleton_inst->skeleton_bones.push_back(bone);
-
- CRASH_COND_MSG(!state.fbx_target_map.has(armature_id), "invalid armature [serious]");
-
- Ref<FBXNode> node = state.fbx_target_map[armature_id];
-
- CRASH_COND_MSG(node.is_null(), "invalid node [serious]");
- CRASH_COND_MSG(node->pivot_transform.is_null(), "invalid pivot transform [serious]");
- fbx_skeleton_inst->fbx_node = node;
-
- ERR_CONTINUE_MSG(fbx_skeleton_inst->fbx_node.is_null(), "invalid skeleton node [serious]");
-
- // we need to have a valid armature id and the model configured for the bone to be assigned fully.
- // happens once per skeleton
-
- if (state.fbx_target_map.has(armature_id) && !fbx_skeleton_inst->fbx_node->has_model()) {
- print_verbose("allocated fbx skeleton primary / armature node for the level: " + fbx_skeleton_inst->fbx_node->node_name);
- } else if (!state.fbx_target_map.has(armature_id) && !fbx_skeleton_inst->fbx_node->has_model()) {
- print_error("bones are not mapped to an armature node for armature id: " + itos(armature_id) + " bone: " + bone->bone_name);
- // this means bone will be removed and not used, which is safe actually and no skeleton will be created.
- }
- }
-
- // setup skeleton instances if required :)
- for (KeyValue<uint64_t, Ref<FBXSkeleton>> &skeleton_node : state.skeleton_map) {
- Ref<FBXSkeleton> &skeleton = skeleton_node.value;
- skeleton->init_skeleton(state);
-
- ERR_CONTINUE_MSG(skeleton->fbx_node.is_null(), "invalid fbx target map, missing skeleton");
- }
-
- // This list is not populated
- for (Map<uint64_t, Ref<FBXNode>>::Element *skin_mesh = state.MeshNodes.front(); skin_mesh; skin_mesh = skin_mesh->next()) {
- }
- }
-
- // build godot node tree
- if (state.fbx_node_list.size() > 0) {
- for (List<Ref<FBXNode>>::Element *node_element = state.fbx_node_list.front();
- node_element;
- node_element = node_element->next()) {
- Ref<FBXNode> fbx_node = node_element->get();
- ImporterMeshInstance3D *mesh_node = nullptr;
- Ref<FBXMeshData> mesh_data_precached;
-
- // check for valid geometry
- if (fbx_node->fbx_model == nullptr) {
- print_error("[doc] fundamental flaw, submit bug immediately with full import log with verbose logging on");
- } else {
- const std::vector<const FBXDocParser::Geometry *> &geometry = fbx_node->fbx_model->GetGeometry();
- for (const FBXDocParser::Geometry *mesh : geometry) {
- print_verbose("[doc] [" + itos(mesh->ID()) + "] mesh: " + fbx_node->node_name);
-
- if (mesh == nullptr) {
- continue;
- }
-
- const FBXDocParser::MeshGeometry *mesh_geometry = dynamic_cast<const FBXDocParser::MeshGeometry *>(mesh);
- if (mesh_geometry) {
- uint64_t mesh_id = mesh_geometry->ID();
-
- // this data will pre-exist if vertex weight information is found
- if (state.renderer_mesh_data.has(mesh_id)) {
- mesh_data_precached = state.renderer_mesh_data[mesh_id];
- } else {
- mesh_data_precached.instantiate();
- state.renderer_mesh_data.insert(mesh_id, mesh_data_precached);
- }
-
- mesh_data_precached->mesh_node = fbx_node;
-
- // mesh node, mesh id
- mesh_node = mesh_data_precached->create_fbx_mesh(state, mesh_geometry, fbx_node->fbx_model, false);
- if (!state.MeshNodes.has(mesh_id)) {
- state.MeshNodes.insert(mesh_id, fbx_node);
- }
- }
-
- const FBXDocParser::ShapeGeometry *shape_geometry = dynamic_cast<const FBXDocParser::ShapeGeometry *>(mesh);
- if (shape_geometry != nullptr) {
- print_verbose("[doc] valid shape geometry converted");
- }
- }
- }
-
- Ref<FBXSkeleton> node_skeleton = fbx_node->skeleton_node;
-
- if (node_skeleton.is_valid()) {
- Skeleton3D *skel = node_skeleton->skeleton;
- fbx_node->godot_node = skel;
- } else if (mesh_node == nullptr) {
- fbx_node->godot_node = memnew(Node3D);
- } else {
- fbx_node->godot_node = mesh_node;
- }
-
- fbx_node->godot_node->set_name(fbx_node->node_name);
-
- // assign parent if valid
- if (fbx_node->fbx_parent.is_valid()) {
- fbx_node->fbx_parent->godot_node->add_child(fbx_node->godot_node);
- fbx_node->godot_node->set_owner(state.root_owner);
- }
-
- // Node Transform debug, set local xform data.
- fbx_node->godot_node->set_transform(get_unscaled_transform(fbx_node->pivot_transform->LocalTransform, state.scale));
-
- // populate our mesh node reference
- if (mesh_node != nullptr && mesh_data_precached.is_valid()) {
- mesh_data_precached->godot_mesh_instance = mesh_node;
- }
- }
- }
-
- for (KeyValue<uint64_t, Ref<FBXMeshData>> &mesh_data : state.renderer_mesh_data) {
- const uint64_t mesh_id = mesh_data.key;
- Ref<FBXMeshData> mesh = mesh_data.value;
-
- const FBXDocParser::MeshGeometry *mesh_geometry = p_document->GetObject(mesh_id)->Get<FBXDocParser::MeshGeometry>();
-
- ERR_CONTINUE_MSG(mesh->mesh_node.is_null(), "invalid mesh allocation");
-
- const FBXDocParser::Skin *mesh_skin = mesh_geometry->DeformerSkin();
-
- if (!mesh_skin) {
- continue; // safe to continue
- }
-
- //
- // Skin bone configuration
- //
-
- //
- // Get Mesh Node Xform only
- //
- //ERR_CONTINUE_MSG(!state.fbx_target_map.has(mesh_id), "invalid xform for the skin pose: " + itos(mesh_id));
- //Ref<FBXNode> mesh_node_xform_data = state.fbx_target_map[mesh_id];
-
- if (!mesh_skin) {
- continue; // not a deformer.
- }
-
- if (mesh_skin->Clusters().size() == 0) {
- continue; // possibly buggy mesh
- }
-
- // Lookup skin or create it if it's not found.
- Ref<Skin> skin;
- if (!state.MeshSkins.has(mesh_id)) {
- print_verbose("Created new skin");
- skin.instantiate();
- state.MeshSkins.insert(mesh_id, skin);
- } else {
- print_verbose("Grabbed skin");
- skin = state.MeshSkins[mesh_id];
- }
-
- for (const FBXDocParser::Cluster *cluster : mesh_skin->Clusters()) {
- // node or bone this cluster targets (in theory will only be a bone target)
- uint64_t skin_target_id = cluster->TargetNode()->ID();
-
- print_verbose("adding cluster [" + itos(cluster->ID()) + "] " + String(cluster->Name().c_str()) + " for target: [" + itos(skin_target_id) + "] " + String(cluster->TargetNode()->Name().c_str()));
- ERR_CONTINUE_MSG(!state.fbx_bone_map.has(skin_target_id), "no bone found by that ID? locator");
-
- const Ref<FBXBone> bone = state.fbx_bone_map[skin_target_id];
- const Ref<FBXSkeleton> skeleton = bone->fbx_skeleton;
- const Ref<FBXNode> skeleton_node = skeleton->fbx_node;
-
- skin->add_named_bind(
- bone->bone_name,
- get_unscaled_transform(
- skeleton_node->pivot_transform->GlobalTransform.affine_inverse() * cluster->TransformLink().affine_inverse(), state.scale));
- }
-
- print_verbose("cluster name / id: " + String(mesh_skin->Name().c_str()) + " [" + itos(mesh_skin->ID()) + "]");
- print_verbose("skeleton has " + itos(state.fbx_bone_map.size()) + " binds");
- print_verbose("fbx skin has " + itos(mesh_skin->Clusters().size()) + " binds");
- }
-
- // mesh data iteration for populating skeleton mapping
- for (KeyValue<uint64_t, Ref<FBXMeshData>> &mesh_data : state.renderer_mesh_data) {
- Ref<FBXMeshData> mesh = mesh_data.value;
- const uint64_t mesh_id = mesh_data.key;
- ImporterMeshInstance3D *mesh_instance = mesh->godot_mesh_instance;
- const int mesh_weights = mesh->max_weight_count;
- Ref<FBXSkeleton> skeleton;
- const bool valid_armature = mesh->valid_armature_id;
- const uint64_t armature = mesh->armature_id;
-
- if (mesh_weights > 0) {
- // this is a bug, it means the weights were found but the skeleton wasn't
- ERR_CONTINUE_MSG(!valid_armature, "[doc] fbx armature is missing");
- } else {
- continue; // safe to continue not a bug just a normal mesh
- }
-
- if (state.skeleton_map.has(armature)) {
- skeleton = state.skeleton_map[armature];
- print_verbose("[doc] armature mesh to skeleton mapping has been allocated");
- } else {
- print_error("[doc] unable to find armature mapping");
- }
-
- ERR_CONTINUE_MSG(!mesh_instance, "[doc] invalid mesh mapping for skeleton assignment");
- ERR_CONTINUE_MSG(skeleton.is_null(), "[doc] unable to resolve the correct skeleton but we have weights!");
-
- mesh_instance->set_skeleton_path(mesh_instance->get_path_to(skeleton->skeleton));
- print_verbose("[doc] allocated skeleton to mesh " + mesh_instance->get_name());
-
- // do we have a mesh skin for this mesh
- ERR_CONTINUE_MSG(!state.MeshSkins.has(mesh_id), "no skin found for mesh");
-
- Ref<Skin> mesh_skin = state.MeshSkins[mesh_id];
-
- ERR_CONTINUE_MSG(mesh_skin.is_null(), "invalid skin stored in map");
- print_verbose("[doc] allocated skin to mesh " + mesh_instance->get_name());
- mesh_instance->set_skin(mesh_skin);
- }
-
- // build skin and skeleton information
- print_verbose("[doc] Skeleton3D Bone count: " + itos(state.fbx_bone_map.size()));
- const FBXDocParser::FileGlobalSettings *FBXSettings = p_document->GlobalSettingsPtr();
-
- // Configure constraints
- // NOTE: constraints won't be added quite yet, we don't have a real need for them *yet*. (they can be supported later on)
- // const std::vector<uint64_t> fbx_constraints = p_document->GetConstraintStackIDs();
-
- // get the animation FPS
- float fps_setting = ImportUtils::get_fbx_fps(FBXSettings);
-
- // enable animation import, only if local animation is enabled
- if (state.enable_animation_import && (p_flags & IMPORT_ANIMATION)) {
- // document animation stack list - get by ID so we can unload any non used animation stack
- const std::vector<uint64_t> animation_stack = p_document->GetAnimationStackIDs();
-
- for (uint64_t anim_id : animation_stack) {
- FBXDocParser::LazyObject *lazyObject = p_document->GetObject(anim_id);
- const FBXDocParser::AnimationStack *stack = lazyObject->Get<FBXDocParser::AnimationStack>();
-
- if (stack != nullptr) {
- String animation_name = ImportUtils::FBXNodeToName(stack->Name());
- print_verbose("Valid animation stack has been found: " + animation_name);
- // ReferenceTime is the same for some animations?
- // LocalStop time is the start and end time
- float r_start = CONVERT_FBX_TIME(stack->ReferenceStart());
- float r_stop = CONVERT_FBX_TIME(stack->ReferenceStop());
- float start_time = CONVERT_FBX_TIME(stack->LocalStart());
- float end_time = CONVERT_FBX_TIME(stack->LocalStop());
- float duration = end_time - start_time;
-
- print_verbose("r_start " + rtos(r_start) + ", r_stop " + rtos(r_stop));
- print_verbose("start_time" + rtos(start_time) + " end_time " + rtos(end_time));
- print_verbose("anim duration : " + rtos(duration));
-
- // we can safely create the animation player
- if (state.animation_player == nullptr) {
- print_verbose("Creating animation player");
- state.animation_player = memnew(AnimationPlayer);
- state.root->add_child(state.animation_player, true);
- state.animation_player->set_owner(state.root_owner);
- }
-
- Ref<Animation> animation;
- animation.instantiate();
- animation->set_name(animation_name);
- animation->set_length(duration);
-
- print_verbose("Animation length: " + rtos(animation->get_length()) + " seconds");
-
- // i think assimp was duplicating things, this lets me know to just reference or ignore this to prevent duplicate information in tracks
- // this would mean that we would be doing three times as much work per track if my theory is correct.
- // this was not the case but this is a good sanity check for the animation handler from the document.
- // it also lets us know if the FBX specification massively changes the animation system, in theory such a change would make this show
- // an fbx specification error, so best keep it in
- // the overhead is tiny.
- Map<uint64_t, const FBXDocParser::AnimationCurve *> CheckForDuplication;
-
- const std::vector<const FBXDocParser::AnimationLayer *> &layers = stack->Layers();
- print_verbose("FBX Animation layers: " + itos(layers.size()));
- for (const FBXDocParser::AnimationLayer *layer : layers) {
- std::vector<const FBXDocParser::AnimationCurveNode *> node_list = layer->Nodes();
- print_verbose("Layer: " + ImportUtils::FBXNodeToName(layer->Name()) + ", " + " AnimCurveNode count " + itos(node_list.size()));
-
- // first thing to do here is that i need to first get the animcurvenode to a Vector3
- // we now need to put this into the track information for godot.
- // to do this we need to know which track is what?
-
- // target id, [ track name, [time index, vector] ]
- // new map needs to be [ track name, keyframe_data ]
- Map<uint64_t, Map<StringName, FBXTrack>> AnimCurveNodes;
-
- // struct AnimTrack {
- // // Animation track can be
- // // visible, T, R, S
- // Map<StringName, Map<uint64_t, Vector3> > animation_track;
- // };
-
- // Map<uint64_t, AnimTrack> AnimCurveNodes;
-
- // so really, what does this mean to make an animtion track.
- // we need to know what object the curves are for.
- // we need the target ID and the target name for the track reduction.
-
- FBXDocParser::Model::RotOrder quaternion_rotation_order = FBXDocParser::Model::RotOrder_EulerXYZ;
-
- // T:: R:: S:: Visible:: Custom::
- for (const FBXDocParser::AnimationCurveNode *curve_node : node_list) {
- // when Curves() is called the curves are actually read, we could replace this with our own ProcessDomConnection code here if required.
- // We may need to do this but ideally we use Curves
- // note: when you call this there might be a delay in opening it
- // uses mutable type to 'cache' the response until the AnimationCurveNode is cleaned up.
- std::map<std::string, const FBXDocParser::AnimationCurve *> curves = curve_node->Curves();
- const FBXDocParser::Object *object = curve_node->Target();
- const FBXDocParser::Model *target = curve_node->TargetAsModel();
- if (target == nullptr) {
- if (object != nullptr) {
- print_error("[doc] warning failed to find a target Model for curve: " + String(object->Name().c_str()));
- } else {
- //print_error("[doc] failed to resolve object");
- continue;
- }
-
- continue;
- } else {
- //print_verbose("[doc] applied rotation order: " + itos(target->RotationOrder()));
- quaternion_rotation_order = target->RotationOrder();
- }
-
- uint64_t target_id = target->ID();
- String target_name = ImportUtils::FBXNodeToName(target->Name());
-
- const FBXDocParser::PropertyTable *properties = curve_node;
- bool got_x = false, got_y = false, got_z = false;
- float offset_x = FBXDocParser::PropertyGet<float>(properties, "d|X", got_x);
- float offset_y = FBXDocParser::PropertyGet<float>(properties, "d|Y", got_y);
- float offset_z = FBXDocParser::PropertyGet<float>(properties, "d|Z", got_z);
-
- String curve_node_name = ImportUtils::FBXNodeToName(curve_node->Name());
-
- // Reduce all curves for this node into a single container
- // T, R, S is what we expect, although other tracks are possible
- // like for example visibility tracks.
-
- // We are not ordered here, we don't care about ordering, this happens automagically by godot when we insert with the
- // key time :), so order is unimportant because the insertion will happen at a time index
- // good to know: we do not need a list of these in another format :)
- //Map<String, Vector<const Assimp::FBX::AnimationCurve *> > unordered_track;
-
- // T
- // R
- // S
- // Map[String, List<VECTOR>]
-
- // So this is a reduction of the animation curve nodes
- // We build this as a lookup, this is essentially our 'animation track'
- //AnimCurveNodes.insert(curve_node_name, Map<uint64_t, Vector3>());
-
- // create the animation curve information with the target id
- // so the point of this makes a track with the name "T" for example
- // the target ID is also set here, this means we don't need to do anything extra when we are in the 'create all animation tracks' step
- FBXTrack &keyframe_map = AnimCurveNodes[target_id][StringName(curve_node_name)];
-
- if (got_x && got_y && got_z) {
- Vector3 default_value = Vector3(offset_x, offset_y, offset_z);
- keyframe_map.default_value = default_value;
- keyframe_map.has_default = true;
- //print_verbose("track name: " + curve_node_name);
- //print_verbose("xyz default: " + default_value);
- }
- // target id, [ track name, [time index, vector] ]
- // Map<uint64_t, Map<StringName, Map<uint64_t, Vector3> > > AnimCurveNodes;
-
- // we probably need the target id here.
- // so map[uint64_t map]...
- // Map<uint64_t, Vector3D> translation_keys, rotation_keys, scale_keys;
-
- // extra const required by C++11 colon/Range operator
- // note: do not use C++17 syntax here for dicts.
- // this is banned in Godot.
- for (std::pair<const std::string, const FBXDocParser::AnimationCurve *> &kvp : curves) {
- const String curve_element = ImportUtils::FBXNodeToName(kvp.first);
- const FBXDocParser::AnimationCurve *curve = kvp.second;
- String curve_name = ImportUtils::FBXNodeToName(curve->Name());
- uint64_t curve_id = curve->ID();
-
- if (CheckForDuplication.has(curve_id)) {
- print_error("(FBX spec changed?) We found a duplicate curve being used for an alternative node - report to godot issue tracker");
- } else {
- CheckForDuplication.insert(curve_id, curve);
- }
-
- // FBX has no name for AnimCurveNode::, most of the time, not seen any with valid name here.
- const std::map<int64_t, float> &track_time = curve->GetValueTimeTrack();
-
- if (track_time.size() > 0) {
- for (std::pair<int64_t, float> keyframe : track_time) {
- if (curve_element == "d|X") {
- keyframe_map.keyframes[keyframe.first].x = keyframe.second;
- } else if (curve_element == "d|Y") {
- keyframe_map.keyframes[keyframe.first].y = keyframe.second;
- } else if (curve_element == "d|Z") {
- keyframe_map.keyframes[keyframe.first].z = keyframe.second;
- } else {
- //print_error("FBX Unsupported element: " + curve_element);
- }
-
- //print_verbose("[" + itos(target_id) + "] Keyframe added: " + itos(keyframe_map.size()));
-
- //print_verbose("Keyframe t:" + rtos(animation_track_time) + " v: " + rtos(keyframe.second));
- }
- }
- }
- }
-
- // Map<uint64_t, Map<StringName, Map<uint64_t, Vector3> > > AnimCurveNodes;
- // add this animation track here
-
- // target id, [ track name, [time index, vector] ]
- //std::map<uint64_t, std::map<StringName, FBXTrack > > AnimCurveNodes;
- for (KeyValue<uint64_t, Map<StringName, FBXTrack>> &track : AnimCurveNodes) {
- // 5 tracks
- // current track index
- // track count is 5
- // track count is 5.
- // next track id is 5.
- const uint64_t target_id = track.key;
-
- Ref<FBXBone> bone;
-
- // note we must not run the below code if the entry doesn't exist, it will create dummy entries which is very bad.
- // remember that state.fbx_bone_map[target_id] will create a new entry EVEN if you only read.
- // this would break node animation targets, so if you change this be warned. :)
- if (state.fbx_bone_map.has(target_id)) {
- bone = state.fbx_bone_map[target_id];
- }
-
- Transform3D target_transform;
-
- if (state.fbx_target_map.has(target_id)) {
- Ref<FBXNode> node_ref = state.fbx_target_map[target_id];
- target_transform = node_ref->pivot_transform->GlobalTransform;
- //print_verbose("[doc] allocated animation node transform");
- }
-
- //int size_targets = state.fbx_target_map.size();
- //print_verbose("Target ID map: " + itos(size_targets));
- //print_verbose("[doc] debug bone map size: " + itos(state.fbx_bone_map.size()));
-
- // if this is a skeleton mapped track we can just set the path for the track.
- // todo: implement node paths here at some
- NodePath track_path;
- if (state.fbx_bone_map.size() > 0 && state.fbx_bone_map.has(target_id)) {
- if (bone->fbx_skeleton.is_valid() && bone.is_valid()) {
- Ref<FBXSkeleton> fbx_skeleton = bone->fbx_skeleton;
- String bone_path = state.root->get_path_to(fbx_skeleton->skeleton);
- bone_path += ":" + fbx_skeleton->skeleton->get_bone_name(bone->godot_bone_id);
- print_verbose("[doc] track bone path: " + bone_path);
- track_path = bone_path;
- }
- } else if (state.fbx_target_map.has(target_id)) {
- //print_verbose("[doc] we have a valid target for a node animation");
- Ref<FBXNode> target_node = state.fbx_target_map[target_id];
- if (target_node.is_valid() && target_node->godot_node != nullptr) {
- String node_path = state.root->get_path_to(target_node->godot_node);
- track_path = node_path;
- //print_verbose("[doc] node animation path: " + node_path);
- }
- } else {
- // note: this could actually be unsafe this means we should be careful about continuing here, if we see bizarre effects later we should disable this.
- // I am not sure if this is unsafe or not, testing will tell us this.
- print_error("[doc] invalid fbx target detected for this track");
- continue;
- }
-
- // everything in FBX and Maya is a node therefore if this happens something is seriously broken.
- if (!state.fbx_target_map.has(target_id)) {
- print_error("unable to resolve this to an FBX object.");
- continue;
- }
-
- Ref<FBXNode> target_node = state.fbx_target_map[target_id];
- const FBXDocParser::Model *model = target_node->fbx_model;
- const FBXDocParser::PropertyTable *props = dynamic_cast<const FBXDocParser::PropertyTable *>(model);
-
- Map<StringName, FBXTrack> &track_data = track.value;
- FBXTrack &translation_keys = track_data[StringName("T")];
- FBXTrack &rotation_keys = track_data[StringName("R")];
- FBXTrack &scale_keys = track_data[StringName("S")];
-
- double increment = 1.0f / fps_setting;
- double time = 0.0f;
-
- bool last = false;
-
- Vector<Vector3> pos_values;
- Vector<float> pos_times;
- Vector<Vector3> scale_values;
- Vector<float> scale_times;
- Vector<Quaternion> rot_values;
- Vector<float> rot_times;
-
- double max_duration = 0;
- double anim_length = animation->get_length();
-
- for (std::pair<int64_t, Vector3> position_key : translation_keys.keyframes) {
- pos_values.push_back(position_key.second * state.scale);
- double animation_track_time = CONVERT_FBX_TIME(position_key.first);
-
- if (animation_track_time > max_duration) {
- max_duration = animation_track_time;
- }
-
- //print_verbose("pos keyframe: t:" + rtos(animation_track_time) + " value " + position_key.second);
- pos_times.push_back(animation_track_time);
- }
-
- for (std::pair<int64_t, Vector3> scale_key : scale_keys.keyframes) {
- scale_values.push_back(scale_key.second);
- double animation_track_time = CONVERT_FBX_TIME(scale_key.first);
-
- if (animation_track_time > max_duration) {
- max_duration = animation_track_time;
- }
- //print_verbose("scale keyframe t:" + rtos(animation_track_time));
- scale_times.push_back(animation_track_time);
- }
-
- //
- // Pre and Post keyframe rotation handler
- // -- Required because Maya and Autodesk <3 the pain when it comes to implementing animation code! enjoy <3
-
- bool got_pre = false;
- bool got_post = false;
-
- Quaternion post_rotation;
- Quaternion pre_rotation;
-
- // Rotation matrix
- const Vector3 &PreRotation = FBXDocParser::PropertyGet<Vector3>(props, "PreRotation", got_pre);
- const Vector3 &PostRotation = FBXDocParser::PropertyGet<Vector3>(props, "PostRotation", got_post);
-
- FBXDocParser::Model::RotOrder rot_order = model->RotationOrder();
- if (got_pre) {
- pre_rotation = ImportUtils::EulerToQuaternion(rot_order, ImportUtils::deg2rad(PreRotation));
- }
- if (got_post) {
- post_rotation = ImportUtils::EulerToQuaternion(rot_order, ImportUtils::deg2rad(PostRotation));
- }
-
- Quaternion lastQuaternion = Quaternion();
-
- for (std::pair<int64_t, Vector3> rotation_key : rotation_keys.keyframes) {
- double animation_track_time = CONVERT_FBX_TIME(rotation_key.first);
-
- //print_verbose("euler rotation key: " + rotation_key.second);
- Quaternion rot_key_value = ImportUtils::EulerToQuaternion(quaternion_rotation_order, ImportUtils::deg2rad(rotation_key.second));
-
- if (lastQuaternion != Quaternion() && rot_key_value.dot(lastQuaternion) < 0) {
- rot_key_value.x = -rot_key_value.x;
- rot_key_value.y = -rot_key_value.y;
- rot_key_value.z = -rot_key_value.z;
- rot_key_value.w = -rot_key_value.w;
- }
- // pre_post rotation possibly could fix orientation
- Quaternion final_rotation = pre_rotation * rot_key_value * post_rotation;
-
- lastQuaternion = final_rotation;
-
- if (animation_track_time > max_duration) {
- max_duration = animation_track_time;
- }
-
- rot_values.push_back(final_rotation.normalized());
- rot_times.push_back(animation_track_time);
- }
-
- bool valid_rest = false;
- Transform3D bone_rest;
- int skeleton_bone = -1;
- if (state.fbx_bone_map.has(target_id)) {
- if (bone.is_valid() && bone->fbx_skeleton.is_valid()) {
- skeleton_bone = bone->godot_bone_id;
- if (skeleton_bone >= 0) {
- bone_rest = bone->fbx_skeleton->skeleton->get_bone_rest(skeleton_bone);
- valid_rest = true;
- }
- }
-
- if (!valid_rest) {
- print_verbose("invalid rest!");
- }
- }
-
- const Vector3 def_pos = translation_keys.has_default ? (translation_keys.default_value * state.scale) : bone_rest.origin;
- const Quaternion def_rot = rotation_keys.has_default ? ImportUtils::EulerToQuaternion(quaternion_rotation_order, ImportUtils::deg2rad(rotation_keys.default_value)) : bone_rest.basis.get_rotation_quaternion();
- const Vector3 def_scale = scale_keys.has_default ? scale_keys.default_value : bone_rest.basis.get_scale();
- print_verbose("track defaults: p(" + def_pos + ") s(" + def_scale + ") r(" + def_rot + ")");
-
- int position_idx = -1;
- if (pos_values.size()) {
- position_idx = animation->get_track_count();
- animation->add_track(Animation::TYPE_POSITION_3D);
- animation->track_set_path(position_idx, track_path);
- animation->track_set_imported(position_idx, true);
- }
-
- int rotation_idx = -1;
- if (pos_values.size()) {
- rotation_idx = animation->get_track_count();
- animation->add_track(Animation::TYPE_ROTATION_3D);
- animation->track_set_path(rotation_idx, track_path);
- animation->track_set_imported(rotation_idx, true);
- }
-
- int scale_idx = -1;
- if (pos_values.size()) {
- scale_idx = animation->get_track_count();
- animation->add_track(Animation::TYPE_SCALE_3D);
- animation->track_set_path(scale_idx, track_path);
- animation->track_set_imported(scale_idx, true);
- }
-
- while (true) {
- Vector3 pos = def_pos;
- Quaternion rot = def_rot;
- Vector3 scale = def_scale;
-
- if (pos_values.size()) {
- pos = _interpolate_track<Vector3>(pos_times, pos_values, time,
- AssetImportAnimation::INTERP_LINEAR);
- }
-
- if (rot_values.size()) {
- rot = _interpolate_track<Quaternion>(rot_times, rot_values, time,
- AssetImportAnimation::INTERP_LINEAR);
- }
-
- if (scale_values.size()) {
- scale = _interpolate_track<Vector3>(scale_times, scale_values, time,
- AssetImportAnimation::INTERP_LINEAR);
- }
-
- if (position_idx >= 0) {
- animation->position_track_insert_key(position_idx, time, pos);
- }
- if (rotation_idx >= 0) {
- animation->rotation_track_insert_key(rotation_idx, time, rot);
- }
- if (scale_idx >= 0) {
- animation->scale_track_insert_key(scale_idx, time, scale);
- }
-
- if (last) {
- break;
- }
-
- time += increment;
- if (time > anim_length) {
- last = true;
- time = anim_length;
- break;
- }
- }
- }
- }
- state.animation_player->add_animation(animation_name, animation);
- }
- }
-
- // AnimStack elements contain start stop time and name of animation
- // AnimLayer is the current active layer of the animation (multiple layers can be active we only support 1)
- // AnimCurveNode has a OP link back to the model which is the real node.
- // AnimCurveNode has a direct link to AnimationCurve (of which it may have more than one)
-
- // Store animation stack in list
- // iterate over all AnimStacks like the cache node algorithm recursively
- // this can then be used with ProcessDomConnection<> to link from
- // AnimStack:: <-- (OO) --> AnimLayer:: <-- (OO) --> AnimCurveNode:: (which can OP resolve) to Model::
- }
-
- //
- // Cleanup operations - explicit to prevent errors on shutdown - found that ref to ref does behave badly sometimes.
- //
-
- state.renderer_mesh_data.clear();
- state.MeshSkins.clear();
- state.fbx_target_map.clear();
- state.fbx_node_list.clear();
-
- for (KeyValue<uint64_t, Ref<FBXBone>> &element : state.fbx_bone_map) {
- Ref<FBXBone> bone = element.value;
- bone->parent_bone.unref();
- bone->node.unref();
- bone->fbx_skeleton.unref();
- }
-
- for (KeyValue<uint64_t, Ref<FBXSkeleton>> &element : state.skeleton_map) {
- Ref<FBXSkeleton> skel = element.value;
- skel->fbx_node.unref();
- skel->skeleton_bones.clear();
- }
-
- state.fbx_bone_map.clear();
- state.skeleton_map.clear();
- state.fbx_root_node.unref();
-
- return scene_root;
-}
-
-void EditorSceneFormatImporterFBX::BuildDocumentBones(Ref<FBXBone> p_parent_bone,
- ImportState &state, const FBXDocParser::Document *p_doc,
- uint64_t p_id) {
- const std::vector<const FBXDocParser::Connection *> &conns = p_doc->GetConnectionsByDestinationSequenced(p_id, "Model");
- // FBX can do an join like this
- // Model -> SubDeformer (bone) -> Deformer (skin pose)
- // This is important because we need to somehow link skin back to bone id in skeleton :)
- // The rules are:
- // A subdeformer will exist if 'limbnode' class tag present
- // The subdeformer will not necessarily have a deformer as joints do not have one
- for (const FBXDocParser::Connection *con : conns) {
- // goto: bone creation
- //print_verbose("con: " + String(con->PropertyName().c_str()));
-
- // ignore object-property links we want the object to object links nothing else
- if (con->PropertyName().length()) {
- continue;
- }
-
- // convert connection source object into Object base class
- const FBXDocParser::Object *const object = con->SourceObject();
-
- if (nullptr == object) {
- print_verbose("failed to convert source object for Model link");
- continue;
- }
-
- // FBX Model::Cube, Model::Bone001, etc elements
- // This detects if we can cast the object into this model structure.
- const FBXDocParser::Model *const model = dynamic_cast<const FBXDocParser::Model *>(object);
-
- // declare our bone element reference (invalid, unless we create a bone in this step)
- // this lets us pass valid armature information into children objects and this is why we moved this up here
- // previously this was created .instantiated() on the same line.
- Ref<FBXBone> bone_element;
-
- if (model != nullptr) {
- // model marked with limb node / casted.
- const FBXDocParser::ModelLimbNode *const limb_node = dynamic_cast<const FBXDocParser::ModelLimbNode *>(model);
- if (limb_node != nullptr) {
- // Write bone into bone list for FBX
-
- ERR_FAIL_COND_MSG(state.fbx_bone_map.has(limb_node->ID()), "[serious] duplicate LimbNode detected");
-
- bool parent_is_bone = state.fbx_bone_map.find(p_id);
- bone_element.instantiate();
-
- // used to build the bone hierarchy in the skeleton
- bone_element->parent_bone_id = parent_is_bone ? p_id : 0;
- bone_element->valid_parent = parent_is_bone;
- bone_element->limb_node = limb_node;
-
- // parent is a node and this is the first bone
- if (!parent_is_bone) {
- uint64_t armature_id = p_id;
- bone_element->valid_armature_id = true;
- bone_element->armature_id = armature_id;
- print_verbose("[doc] valid armature has been configured for first child: " + itos(armature_id));
- } else if (p_parent_bone.is_valid()) {
- if (p_parent_bone->valid_armature_id) {
- bone_element->valid_armature_id = true;
- bone_element->armature_id = p_parent_bone->armature_id;
- print_verbose("[doc] bone has valid armature id:" + itos(bone_element->armature_id));
- } else {
- print_error("[doc] unassigned armature id: " + String(limb_node->Name().c_str()));
- }
- } else {
- print_error("[doc] error is this a bone? " + String(limb_node->Name().c_str()));
- }
-
- if (!parent_is_bone) {
- print_verbose("[doc] Root bone: " + bone_element->bone_name);
- }
-
- uint64_t limb_id = limb_node->ID();
- bone_element->bone_id = limb_id;
- bone_element->bone_name = ImportUtils::FBXNodeToName(model->Name());
- bone_element->parent_bone = p_parent_bone;
-
- // insert limb by ID into list.
- state.fbx_bone_map.insert(limb_node->ID(), bone_element);
- }
-
- // recursion call - child nodes
- BuildDocumentBones(bone_element, state, p_doc, model->ID());
- }
- }
-}
-
-void EditorSceneFormatImporterFBX::BuildDocumentNodes(
- Ref<PivotTransform> parent_transform,
- ImportState &state,
- const FBXDocParser::Document *p_doc,
- uint64_t id,
- Ref<FBXNode> parent_node) {
- // tree
- // here we get the node 0 on the root by default
- const std::vector<const FBXDocParser::Connection *> &conns = p_doc->GetConnectionsByDestinationSequenced(id, "Model");
-
- // branch
- for (const FBXDocParser::Connection *con : conns) {
- // ignore object-property links
- if (con->PropertyName().length()) {
- // really important we document why this is ignored.
- print_verbose("ignoring property link - no docs on why this is ignored");
- continue;
- }
-
- // convert connection source object into Object base class
- // Source objects can exist with 'null connections' this means that we only for sure know the source exists.
- const FBXDocParser::Object *const source_object = con->SourceObject();
-
- if (nullptr == source_object) {
- print_verbose("failed to convert source object for Model link");
- continue;
- }
-
- // FBX Model::Cube, Model::Bone001, etc elements
- // This detects if we can cast the object into this model structure.
- const FBXDocParser::Model *const model = dynamic_cast<const FBXDocParser::Model *>(source_object);
- // model is the current node
- if (nullptr != model) {
- uint64_t current_node_id = model->ID();
-
- Ref<FBXNode> new_node;
- new_node.instantiate();
- new_node->current_node_id = current_node_id;
- new_node->node_name = ImportUtils::FBXNodeToName(model->Name());
-
- Ref<PivotTransform> fbx_transform;
- fbx_transform.instantiate();
- fbx_transform->set_parent(parent_transform);
- fbx_transform->set_model(model);
- fbx_transform->debug_pivot_xform("name: " + new_node->node_name);
- fbx_transform->Execute();
-
- new_node->set_pivot_transform(fbx_transform);
-
- // check if this node is a bone
- if (state.fbx_bone_map.has(current_node_id)) {
- Ref<FBXBone> bone = state.fbx_bone_map[current_node_id];
- if (bone.is_valid()) {
- bone->set_node(new_node);
- print_verbose("allocated bone data: " + bone->bone_name);
- }
- }
-
- // set the model, we can't just assign this safely
- new_node->set_model(model);
-
- if (parent_node.is_valid()) {
- new_node->set_parent(parent_node);
- } else {
- new_node->set_parent(state.fbx_root_node);
- }
-
- CRASH_COND_MSG(new_node->pivot_transform.is_null(), "invalid fbx target map pivot transform [serious]");
-
- // populate lookup tables with references
- // [fbx_node_id, fbx_node]
-
- state.fbx_node_list.push_back(new_node);
- if (!state.fbx_target_map.has(new_node->current_node_id)) {
- state.fbx_target_map[new_node->current_node_id] = new_node;
- }
-
- // print node name
- print_verbose("[doc] new node " + new_node->node_name);
-
- // sub branches
- BuildDocumentNodes(new_node->pivot_transform, state, p_doc, current_node_id, new_node);
- }
- }
-}
-Ref<Animation> EditorSceneFormatImporterFBX::import_animation(const String &p_path,
- uint32_t p_flags, const Map<StringName, Variant> &p_options,
- int p_bake_fps) {
- return Ref<Animation>();
-}
diff --git a/modules/fbx/editor_scene_importer_fbx.h b/modules/fbx/editor_scene_importer_fbx.h
deleted file mode 100644
index eebcb86409..0000000000
--- a/modules/fbx/editor_scene_importer_fbx.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/*************************************************************************/
-/* editor_scene_importer_fbx.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef EDITOR_SCENE_IMPORTER_FBX_H
-#define EDITOR_SCENE_IMPORTER_FBX_H
-
-#ifdef TOOLS_ENABLED
-
-#include "data/import_state.h"
-#include "tools/import_utils.h"
-
-#include "core/io/resource_importer.h"
-#include "core/string/ustring.h"
-#include "core/templates/local_vector.h"
-#include "core/templates/vector.h"
-#include "core/variant/dictionary.h"
-#include "editor/import/resource_importer_scene.h"
-#include "editor/project_settings_editor.h"
-#include "scene/3d/mesh_instance_3d.h"
-#include "scene/3d/node_3d.h"
-#include "scene/3d/skeleton_3d.h"
-#include "scene/animation/animation_player.h"
-#include "scene/resources/animation.h"
-#include "scene/resources/surface_tool.h"
-
-#include "fbx_parser/FBXDocument.h"
-#include "fbx_parser/FBXImportSettings.h"
-#include "fbx_parser/FBXMeshGeometry.h"
-#include "fbx_parser/FBXUtil.h"
-
-#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
-
-class EditorSceneFormatImporterFBX : public EditorSceneFormatImporter {
-private:
- GDCLASS(EditorSceneFormatImporterFBX, EditorSceneFormatImporter);
-
- struct AssetImportAnimation {
- enum Interpolation {
- INTERP_LINEAR,
- INTERP_STEP,
- INTERP_CATMULLROMSPLINE,
- INTERP_CUBIC_SPLINE
- };
- };
-
- // ------------------------------------------------------------------------------------------------
- template <typename T>
- const T *ProcessDOMConnection(
- const FBXDocParser::Document *doc,
- uint64_t current_element,
- bool reverse_lookup = false) {
- const std::vector<const FBXDocParser::Connection *> &conns = reverse_lookup ? doc->GetConnectionsByDestinationSequenced(current_element) : doc->GetConnectionsBySourceSequenced(current_element);
- //print_verbose("[doc] looking for " + String(element_to_find));
- // using the temp pattern here so we can debug before it returns
- // in some cases we return too early, with 'deformer object base class' in wrong place
- // in assimp this means we can accidentally return too early...
- const T *return_obj = nullptr;
-
- for (const FBXDocParser::Connection *con : conns) {
- const FBXDocParser::Object *source_object = con->SourceObject();
- const FBXDocParser::Object *dest_object = con->DestinationObject();
- if (source_object && dest_object != nullptr) {
- //print_verbose("[doc] connection name: " + String(source_object->Name().c_str()) + ", dest: " + String(dest_object->Name().c_str()));
- const T *temp = dynamic_cast<const T *>(reverse_lookup ? source_object : dest_object);
- if (temp) {
- return_obj = temp;
- }
- }
- }
-
- if (return_obj != nullptr) {
- //print_verbose("[doc] returned valid element");
- //print_verbose("Found object for bone");
- return return_obj;
- }
-
- // safe to return nothing, need to use nullptr here as nullptr is used internally for FBX document.
- return nullptr;
- }
-
- void BuildDocumentBones(Ref<FBXBone> p_parent_bone,
- ImportState &state, const FBXDocParser::Document *p_doc,
- uint64_t p_id);
-
- void BuildDocumentNodes(Ref<PivotTransform> parent_transform, ImportState &state, const FBXDocParser::Document *doc, uint64_t id, Ref<FBXNode> fbx_parent);
-
- Node3D *_generate_scene(const String &p_path, const FBXDocParser::Document *p_document,
- const uint32_t p_flags,
- int p_bake_fps,
- const int32_t p_max_bone_weights,
- bool p_is_blender_fbx);
-
- template <class T>
- T _interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, float p_time, AssetImportAnimation::Interpolation p_interp);
- void _register_project_setting_import(const String generic, const String import_setting_string, const Vector<String> &exts, List<String> *r_extensions, const bool p_enabled) const;
-
-public:
- EditorSceneFormatImporterFBX() {}
- ~EditorSceneFormatImporterFBX() {}
-
- virtual void get_extensions(List<String> *r_extensions) const override;
- virtual uint32_t get_import_flags() const override;
- virtual Node3D *import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override;
- virtual Ref<Animation> import_animation(const String &p_path,
- uint32_t p_flags, const Map<StringName, Variant> &p_options,
- int p_bake_fps) override;
-};
-
-#endif // TOOLS_ENABLED
-#endif // EDITOR_SCENE_IMPORTER_FBX_H
diff --git a/modules/fbx/fbx_parser/ByteSwapper.h b/modules/fbx/fbx_parser/ByteSwapper.h
deleted file mode 100644
index 21c5557001..0000000000
--- a/modules/fbx/fbx_parser/ByteSwapper.h
+++ /dev/null
@@ -1,283 +0,0 @@
-/*************************************************************************/
-/* ByteSwapper.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2020, assimp team
-
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
-
-* Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-
-/** @file Helper class tp perform various byte order swappings
- (e.g. little to big endian) */
-#ifndef BYTE_SWAPPER_H
-#define BYTE_SWAPPER_H
-
-#include <stdint.h>
-#include <algorithm>
-#include <locale>
-
-namespace FBXDocParser {
-// --------------------------------------------------------------------------------------
-/** Defines some useful byte order swap routines.
- *
- * This is required to read big-endian model formats on little-endian machines,
- * and vice versa. Direct use of this class is DEPRECATED. Use #StreamReader instead. */
-// --------------------------------------------------------------------------------------
-class ByteSwap {
- ByteSwap() {}
-
-public:
- // ----------------------------------------------------------------------
- /** Swap two bytes of data
- * @param[inout] _szOut A void* to save the reintcasts for the caller. */
- static inline void Swap2(void *_szOut) {
- uint8_t *const szOut = reinterpret_cast<uint8_t *>(_szOut);
- std::swap(szOut[0], szOut[1]);
- }
-
- // ----------------------------------------------------------------------
- /** Swap four bytes of data
- * @param[inout] _szOut A void* to save the reintcasts for the caller. */
- static inline void Swap4(void *_szOut) {
- uint8_t *const szOut = reinterpret_cast<uint8_t *>(_szOut);
- std::swap(szOut[0], szOut[3]);
- std::swap(szOut[1], szOut[2]);
- }
-
- // ----------------------------------------------------------------------
- /** Swap eight bytes of data
- * @param[inout] _szOut A void* to save the reintcasts for the caller. */
- static inline void Swap8(void *_szOut) {
- uint8_t *const szOut = reinterpret_cast<uint8_t *>(_szOut);
- std::swap(szOut[0], szOut[7]);
- std::swap(szOut[1], szOut[6]);
- std::swap(szOut[2], szOut[5]);
- std::swap(szOut[3], szOut[4]);
- }
-
- // ----------------------------------------------------------------------
- /** ByteSwap a float. Not a joke.
- * @param[inout] fOut ehm. .. */
- static inline void Swap(float *fOut) {
- Swap4(fOut);
- }
-
- // ----------------------------------------------------------------------
- /** ByteSwap a double. Not a joke.
- * @param[inout] fOut ehm. .. */
- static inline void Swap(double *fOut) {
- Swap8(fOut);
- }
-
- // ----------------------------------------------------------------------
- /** ByteSwap an int16t. Not a joke.
- * @param[inout] fOut ehm. .. */
- static inline void Swap(int16_t *fOut) {
- Swap2(fOut);
- }
-
- static inline void Swap(uint16_t *fOut) {
- Swap2(fOut);
- }
-
- // ----------------------------------------------------------------------
- /** ByteSwap an int32t. Not a joke.
- * @param[inout] fOut ehm. .. */
- static inline void Swap(int32_t *fOut) {
- Swap4(fOut);
- }
-
- static inline void Swap(uint32_t *fOut) {
- Swap4(fOut);
- }
-
- // ----------------------------------------------------------------------
- /** ByteSwap an int64t. Not a joke.
- * @param[inout] fOut ehm. .. */
- static inline void Swap(int64_t *fOut) {
- Swap8(fOut);
- }
-
- static inline void Swap(uint64_t *fOut) {
- Swap8(fOut);
- }
-
- // ----------------------------------------------------------------------
- //! Templatized ByteSwap
- //! \returns param tOut as swapped
- template <typename Type>
- static inline Type Swapped(Type tOut) {
- return _swapper<Type, sizeof(Type)>()(tOut);
- }
-
-private:
- template <typename T, size_t size>
- struct _swapper;
-};
-
-template <typename T>
-struct ByteSwap::_swapper<T, 2> {
- T operator()(T tOut) {
- Swap2(&tOut);
- return tOut;
- }
-};
-
-template <typename T>
-struct ByteSwap::_swapper<T, 4> {
- T operator()(T tOut) {
- Swap4(&tOut);
- return tOut;
- }
-};
-
-template <typename T>
-struct ByteSwap::_swapper<T, 8> {
- T operator()(T tOut) {
- Swap8(&tOut);
- return tOut;
- }
-};
-
-// --------------------------------------------------------------------------------------
-// ByteSwap macros for BigEndian/LittleEndian support
-// --------------------------------------------------------------------------------------
-#if (defined AI_BUILD_BIG_ENDIAN)
-#define AI_LE(t) (t)
-#define AI_BE(t) ByteSwap::Swapped(t)
-#define AI_LSWAP2(p)
-#define AI_LSWAP4(p)
-#define AI_LSWAP8(p)
-#define AI_LSWAP2P(p)
-#define AI_LSWAP4P(p)
-#define AI_LSWAP8P(p)
-#define LE_NCONST const
-#define AI_SWAP2(p) ByteSwap::Swap2(&(p))
-#define AI_SWAP4(p) ByteSwap::Swap4(&(p))
-#define AI_SWAP8(p) ByteSwap::Swap8(&(p))
-#define AI_SWAP2P(p) ByteSwap::Swap2((p))
-#define AI_SWAP4P(p) ByteSwap::Swap4((p))
-#define AI_SWAP8P(p) ByteSwap::Swap8((p))
-#define BE_NCONST
-#else
-#define AI_BE(t) (t)
-#define AI_LE(t) ByteSwap::Swapped(t)
-#define AI_SWAP2(p)
-#define AI_SWAP4(p)
-#define AI_SWAP8(p)
-#define AI_SWAP2P(p)
-#define AI_SWAP4P(p)
-#define AI_SWAP8P(p)
-#define BE_NCONST const
-#define AI_LSWAP2(p) ByteSwap::Swap2(&(p))
-#define AI_LSWAP4(p) ByteSwap::Swap4(&(p))
-#define AI_LSWAP8(p) ByteSwap::Swap8(&(p))
-#define AI_LSWAP2P(p) ByteSwap::Swap2((p))
-#define AI_LSWAP4P(p) ByteSwap::Swap4((p))
-#define AI_LSWAP8P(p) ByteSwap::Swap8((p))
-#define LE_NCONST
-#endif
-
-namespace Intern {
-
-// --------------------------------------------------------------------------------------------
-template <typename T, bool doit>
-struct ByteSwapper {
- void operator()(T *inout) {
- ByteSwap::Swap(inout);
- }
-};
-
-template <typename T>
-struct ByteSwapper<T, false> {
- void operator()(T *) {
- }
-};
-
-// --------------------------------------------------------------------------------------------
-template <bool SwapEndianess, typename T, bool RuntimeSwitch>
-struct Getter {
- void operator()(T *inout, bool le) {
- le = !le;
- if (le) {
- ByteSwapper<T, (sizeof(T) > 1 ? true : false)>()(inout);
- } else {
- ByteSwapper<T, false>()(inout);
- }
- }
-};
-
-template <bool SwapEndianess, typename T>
-struct Getter<SwapEndianess, T, false> {
- void operator()(T *inout, bool /*le*/) {
- // static branch
- ByteSwapper<T, (SwapEndianess && sizeof(T) > 1)>()(inout);
- }
-};
-} // namespace Intern
-} // namespace FBXDocParser
-
-#endif // BYTE_SWAPPER_H
diff --git a/modules/fbx/fbx_parser/CREDITS b/modules/fbx/fbx_parser/CREDITS
deleted file mode 100644
index 62b449614e..0000000000
--- a/modules/fbx/fbx_parser/CREDITS
+++ /dev/null
@@ -1,183 +0,0 @@
-===============================================================
-Open Asset Import Library (Assimp)
-Developers and Contributors
-===============================================================
-
-The following is a non-exhaustive list of all constributors over the years.
-If you think your name should be listed here, drop us a line and we'll add you.
-
-- Alexander Gessler,
-3DS-, BLEND-, ASE-, DXF-, HMP-, MDL-, MD2-, MD3-, MD5-, MDC-, NFF-, PLY-, STL-, RAW-, OFF-, MS3D-, Q3D- and LWO-Loader, Assimp-Viewer, assimp-cmd, -noboost, Website (Design).
-
-- Thomas Schulze,
-X-, Collada-, BVH-Loader, Postprocessing framework. Data structure & Interface design, documentation.
-
-- Kim Kulling,
-Obj-, Q3BSD-, OpenGEX-Loader, Logging system, CMake-build-environment, Linux-build, Website ( Admin ), Coverity ( Admin ), Glitter ( Admin ).
-
-- R.Schmidt,
-Linux build, eclipse support.
-
-- Matthias Gubisch,
-Assimp.net
-Visual Studio 9 support, bugfixes.
-
-- Mark Sibly
-B3D-Loader, Assimp testing
-
-- Jonathan Klein
-Ogre Loader, VC2010 fixes and CMake fixes.
-
-- Sebastian Hempel,
-PyAssimp (first version)
-Compile-Bugfixes for mingw, add environment for static library support in make.
-
-- Jonathan Pokrass
-Supplied a bugfix concerning the scaling in the md3 loader.
-
-- Andrew Galante,
-Submitted patches to make Assimp compile with GCC-4, a makefile and the xcode3 workspace.
-
-- Andreas Nagel
-First Assimp testing & verification under Windows Vista 64 Bit.
-
-- Marius Schr�der
-Allowed us to use many of his models for screenshots and testing.
-
-- Christian Schubert
-Supplied various XFiles for testing purposes.
-
-- Tizian Wieland
-Searched the web for hundreds of test models for internal use
-
-- John Connors
-Supplied patches for linux and SCons.
-
-- T. R.
-The GUY who performed some of the CSM mocaps.
-
-- Andy Maloney
-Contributed fixes for the documentation and the doxygen markup
-
-- Zhao Lei
-Contributed several bugfixes fixing memory leaks and improving float parsing
-
-- sueastside
-Updated PyAssimp to the latest Assimp data structures and provided a script to keep the Python binding up-to-date.
-
-- Tobias Rittig
-Collada testing with Cinema 4D
-
-- Brad Grantham
-Improvements in OpenGL-Sample.
-
-- Robert Ramirez
-Add group loading feature to Obj-Loader.
-
-- Chris Maiwald
-Many bugreports, improving Assimp's portability, regular testing & feedback.
-
-- Stepan Hrbek
-Bugreport and fix for a obj-materialloader crash.
-
-- David Nadlinger
-D bindings, CMake install support.
-
-- Dario Accornero
-Contributed several patches regarding Mac OS/XCode targets, bug reports.
-
-- Martin Walser (Samhayne)
-Contributed the 'SimpleTexturedOpenGl' sample.
-
-- Matthias Fauconneau
-Contributed a fix for the Q3-BSP loader.
-
-- Jørgen P. Tjernø
-Contributed updated and improved xcode workspaces
-
-- drparallax
-Contributed the /samples/SimpleAssimpViewX sample
-
-- Carsten Fuchs
-Contributed a fix for the Normalize method in aiQuaternion.
-
-- dbburgess
-Contributes a Android-specific build issue: log the hardware architecture for ARM.
-
-- alfiereinre7
-Contributes a obj-fileparser fix: missing tokens in the obj-token list.
-
-- Roman Kharitonov
-Contributes a fix for the configure script environment.
-
-- Ed Diana
-Contributed AssimpDelphi (/port/AssimpDelphi).
-
-- rdb
-Contributes a bundle of fixes and improvements for the bsp-importer.
-
-- Mick P
-For contributing the De-bone postprocessing step and filing various bug reports.
-
-- Rosen Diankov
-Contributed patches to build assimp debian packages using cmake.
-
-- Mark Page
-Contributed a patch to fix the VertexTriangleAdjacency postprocessing step.
-
-- IOhannes
-Contributed the Debian build fixes ( architecture macro ).
-
-- gellule
-Several LWO and LWS fixes (pivoting).
-
-- Marcel Metz
-GCC/Linux fixes for the SimpleOpenGL sample.
-
-- Brian Miller
-Bugfix for a compiler fix for iOS on arm.
-
-- Séverin Lemaignan
-Rewrite of PyAssimp, distutils and Python3 support
-
-- albert-wang
-Bugfixes for the collada parser
-
-- Ya ping Jin
-Bugfixes for uv-tanget calculation.
-
-- Jonne Nauha
-Ogre Binary format support
-
-- Filip Wasil, Tieto Poland Sp. z o.o.
-Android JNI asset extraction support
-
-- Richard Steffen
-Contributed ExportProperties interface
-Contributed X File exporter
-Contributed Step (stp) exporter
-
-- Thomas Iorns (mesilliac)
-Initial FBX Export support
-
-For a more detailed list just check: https://github.com/assimp/assimp/network/members
-
-
-========
-Patreons
-========
-
-Huge thanks to our Patreons!
-
-- migenius
-- Marcus
-- Cort
-- elect
-- Steffen
-
-
-===================
-Commercial Sponsors
-===================
-
-- MyDidimo (mydidimo.com): Sponsored development of FBX Export support
diff --git a/modules/fbx/fbx_parser/FBXAnimation.cpp b/modules/fbx/fbx_parser/FBXAnimation.cpp
deleted file mode 100644
index 8627c95012..0000000000
--- a/modules/fbx/fbx_parser/FBXAnimation.cpp
+++ /dev/null
@@ -1,273 +0,0 @@
-/*************************************************************************/
-/* FBXAnimation.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, assimp team
-
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
-
-* Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-
-/** @file FBXAnimation.cpp
- * @brief Assimp::FBX::AnimationCurve, Assimp::FBX::AnimationCurveNode,
- * Assimp::FBX::AnimationLayer, Assimp::FBX::AnimationStack
- */
-
-#include "FBXCommon.h"
-#include "FBXDocument.h"
-#include "FBXDocumentUtil.h"
-#include "FBXParser.h"
-
-namespace FBXDocParser {
-
-using namespace Util;
-
-// ------------------------------------------------------------------------------------------------
-AnimationCurve::AnimationCurve(uint64_t id, const ElementPtr element, const std::string &name, const Document & /*doc*/) :
- Object(id, element, name) {
- const ScopePtr sc = GetRequiredScope(element);
- const ElementPtr KeyTime = GetRequiredElement(sc, "KeyTime");
- const ElementPtr KeyValueFloat = GetRequiredElement(sc, "KeyValueFloat");
-
- // note preserved keys and values for legacy FBXConverter.cpp
- // we can remove this once the animation system is written
- // and clean up this code so we do not have copies everywhere.
- ParseVectorDataArray(keys, KeyTime);
- ParseVectorDataArray(values, KeyValueFloat);
-
- if (keys.size() != values.size()) {
- DOMError("the number of key times does not match the number of keyframe values", KeyTime);
- }
-
- // put the two lists into the map, underlying container is really just a dictionary
- // these will always match, if not an error will throw and the file will not import
- // this is useful because we then can report something and fix this later if it becomes an issue
- // at this point we do not need a different count of these elements so this makes the
- // most sense to do.
- for (size_t x = 0; x < keys.size(); x++) {
- keyvalues[keys[x]] = values[x];
- }
-
- const ElementPtr KeyAttrDataFloat = sc->GetElement("KeyAttrDataFloat");
- if (KeyAttrDataFloat) {
- ParseVectorDataArray(attributes, KeyAttrDataFloat);
- }
-
- const ElementPtr KeyAttrFlags = sc->GetElement("KeyAttrFlags");
- if (KeyAttrFlags) {
- ParseVectorDataArray(flags, KeyAttrFlags);
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-AnimationCurve::~AnimationCurve() {
- // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-AnimationCurveNode::AnimationCurveNode(uint64_t id, const ElementPtr element, const std::string &name,
- const Document &doc, const char *const *target_prop_whitelist /*= nullptr*/,
- size_t whitelist_size /*= 0*/) :
- Object(id, element, name), doc(doc) {
- // find target node
- const char *whitelist[] = { "Model", "NodeAttribute", "Deformer" };
- const std::vector<const Connection *> &conns = doc.GetConnectionsBySourceSequenced(ID(), whitelist, 3);
-
- for (const Connection *con : conns) {
- // link should go for a property
- if (!con->PropertyName().length()) {
- continue;
- }
-
- Object *object = con->DestinationObject();
-
- if (!object) {
- DOMWarning("failed to read destination object for AnimationCurveNode->Model link, ignoring", element);
- continue;
- }
-
- target = object;
- prop = con->PropertyName();
- break;
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-AnimationCurveNode::~AnimationCurveNode() {
- curves.clear();
-}
-
-// ------------------------------------------------------------------------------------------------
-const AnimationMap &AnimationCurveNode::Curves() const {
- /* Lazy loaded animation curves, will only load if required */
- if (curves.empty()) {
- // resolve attached animation curves
- const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationCurve");
-
- for (const Connection *con : conns) {
- // So the advantage of having this STL boilerplate is that it's dead simple once you get it.
- // The other advantage is casting is guaranteed to be safe and nullptr will be returned in the last step if it fails.
- Object *ob = con->SourceObject();
- AnimationCurve *anim_curve = dynamic_cast<AnimationCurve *>(ob);
- ERR_CONTINUE_MSG(!anim_curve, "Failed to convert animation curve from object");
-
- curves.insert(std::make_pair(con->PropertyName(), anim_curve));
- }
- }
-
- return curves;
-}
-
-// ------------------------------------------------------------------------------------------------
-AnimationLayer::AnimationLayer(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
- Object(id, element, name), doc(doc) {
-}
-
-// ------------------------------------------------------------------------------------------------
-AnimationLayer::~AnimationLayer() {
- // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-const AnimationCurveNodeList AnimationLayer::Nodes(const char *const *target_prop_whitelist,
- size_t whitelist_size /*= 0*/) const {
- AnimationCurveNodeList nodes;
-
- // resolve attached animation nodes
- const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationCurveNode");
- nodes.reserve(conns.size());
-
- for (const Connection *con : conns) {
- // link should not go to a property
- if (con->PropertyName().length()) {
- continue;
- }
-
- Object *ob = con->SourceObject();
-
- if (!ob) {
- DOMWarning("failed to read source object for AnimationCurveNode->AnimationLayer link, ignoring", element);
- continue;
- }
-
- const AnimationCurveNode *anim = dynamic_cast<AnimationCurveNode *>(ob);
- if (!anim) {
- DOMWarning("source object for ->AnimationLayer link is not an AnimationCurveNode", element);
- continue;
- }
-
- if (target_prop_whitelist) {
- const char *s = anim->TargetProperty().c_str();
- bool ok = false;
- for (size_t i = 0; i < whitelist_size; ++i) {
- if (!strcmp(s, target_prop_whitelist[i])) {
- ok = true;
- break;
- }
- }
- if (!ok) {
- continue;
- }
- }
- nodes.push_back(anim);
- }
-
- return nodes;
-}
-
-// ------------------------------------------------------------------------------------------------
-AnimationStack::AnimationStack(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
- Object(id, element, name) {
- // resolve attached animation layers
- const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationLayer");
- layers.reserve(conns.size());
-
- for (const Connection *con : conns) {
- // link should not go to a property
- if (con->PropertyName().length()) {
- continue;
- }
-
- Object *ob = con->SourceObject();
- if (!ob) {
- DOMWarning("failed to read source object for AnimationLayer->AnimationStack link, ignoring", element);
- continue;
- }
-
- const AnimationLayer *anim = dynamic_cast<const AnimationLayer *>(ob);
-
- if (!anim) {
- DOMWarning("source object for ->AnimationStack link is not an AnimationLayer", element);
- continue;
- }
-
- layers.push_back(anim);
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-AnimationStack::~AnimationStack() {
-}
-} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp b/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp
deleted file mode 100644
index f982e0ca4d..0000000000
--- a/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp
+++ /dev/null
@@ -1,442 +0,0 @@
-/*************************************************************************/
-/* FBXBinaryTokenizer.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, assimp team
-
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
-
-* Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-/** @file FBXBinaryTokenizer.cpp
- * @brief Implementation of a fake lexer for binary fbx files -
- * we emit tokens so the parser needs almost no special handling
- * for binary files.
- */
-
-#include "ByteSwapper.h"
-#include "FBXTokenizer.h"
-#include "core/string/print_string.h"
-
-#include <stdint.h>
-
-namespace FBXDocParser {
-// ------------------------------------------------------------------------------------------------
-Token::Token(const char *sbegin, const char *send, TokenType type, size_t offset) :
- sbegin(sbegin),
- send(send),
- type(type),
- line(offset),
- column(BINARY_MARKER) {
-#ifdef DEBUG_ENABLED
- // contents is bad.. :/
- contents = std::string(sbegin, static_cast<size_t>(send - sbegin));
-#endif
- // calc length
- // measure from sBegin to sEnd and validate?
-}
-
-namespace {
-
-// ------------------------------------------------------------------------------------------------
-// signal tokenization error
-void TokenizeError(const std::string &message, size_t offset) {
- print_error("[FBX-Tokenize] " + String(message.c_str()) + ", offset " + itos(offset));
-}
-
-// ------------------------------------------------------------------------------------------------
-size_t Offset(const char *begin, const char *cursor) {
- //ai_assert(begin <= cursor);
-
- return cursor - begin;
-}
-
-// ------------------------------------------------------------------------------------------------
-void TokenizeError(const std::string &message, const char *begin, const char *cursor) {
- TokenizeError(message, Offset(begin, cursor));
-}
-
-// ------------------------------------------------------------------------------------------------
-uint32_t ReadWord(const char *input, const char *&cursor, const char *end) {
- const size_t k_to_read = sizeof(uint32_t);
- if (Offset(cursor, end) < k_to_read) {
- TokenizeError("cannot ReadWord, out of bounds", input, cursor);
- }
-
- uint32_t word;
- ::memcpy(&word, cursor, 4);
- AI_SWAP4(word);
-
- cursor += k_to_read;
-
- return word;
-}
-
-// ------------------------------------------------------------------------------------------------
-uint64_t ReadDoubleWord(const char *input, const char *&cursor, const char *end) {
- const size_t k_to_read = sizeof(uint64_t);
- if (Offset(cursor, end) < k_to_read) {
- TokenizeError("cannot ReadDoubleWord, out of bounds", input, cursor);
- }
-
- uint64_t dword /*= *reinterpret_cast<const uint64_t*>(cursor)*/;
- ::memcpy(&dword, cursor, sizeof(uint64_t));
- AI_SWAP8(dword);
-
- cursor += k_to_read;
-
- return dword;
-}
-
-// ------------------------------------------------------------------------------------------------
-uint8_t ReadByte(const char *input, const char *&cursor, const char *end) {
- if (Offset(cursor, end) < sizeof(uint8_t)) {
- TokenizeError("cannot ReadByte, out of bounds", input, cursor);
- }
-
- uint8_t word; /* = *reinterpret_cast< const uint8_t* >( cursor )*/
- ::memcpy(&word, cursor, sizeof(uint8_t));
- ++cursor;
-
- return word;
-}
-
-// ------------------------------------------------------------------------------------------------
-unsigned int ReadString(const char *&sbegin_out, const char *&send_out, const char *input,
- const char *&cursor, const char *end, bool long_length = false, bool allow_null = false) {
- const uint32_t len_len = long_length ? 4 : 1;
- if (Offset(cursor, end) < len_len) {
- TokenizeError("cannot ReadString, out of bounds reading length", input, cursor);
- }
-
- const uint32_t length = long_length ? ReadWord(input, cursor, end) : ReadByte(input, cursor, end);
-
- if (Offset(cursor, end) < length) {
- TokenizeError("cannot ReadString, length is out of bounds", input, cursor);
- }
-
- sbegin_out = cursor;
- cursor += length;
-
- send_out = cursor;
-
- if (!allow_null) {
- for (unsigned int i = 0; i < length; ++i) {
- if (sbegin_out[i] == '\0') {
- TokenizeError("failed ReadString, unexpected NUL character in string", input, cursor);
- }
- }
- }
-
- return length;
-}
-
-// ------------------------------------------------------------------------------------------------
-void ReadData(const char *&sbegin_out, const char *&send_out, const char *input, const char *&cursor, const char *end, bool &corrupt) {
- if (Offset(cursor, end) < 1) {
- TokenizeError("cannot ReadData, out of bounds reading length", input, cursor);
- corrupt = true;
- return;
- }
-
- const char type = *cursor;
- sbegin_out = cursor++;
-
- switch (type) {
- // 16 bit int
- case 'Y':
- cursor += 2;
- break;
-
- // 1 bit bool flag (yes/no)
- case 'C':
- cursor += 1;
- break;
-
- // 32 bit int
- case 'I':
- // <- fall through
-
- // float
- case 'F':
- cursor += 4;
- break;
-
- // double
- case 'D':
- cursor += 8;
- break;
-
- // 64 bit int
- case 'L':
- cursor += 8;
- break;
-
- // note: do not write cursor += ReadWord(...cursor) as this would be UB
-
- // raw binary data
- case 'R': {
- const uint32_t length = ReadWord(input, cursor, end);
- cursor += length;
- break;
- }
-
- case 'b':
- // TODO: what is the 'b' type code? Right now we just skip over it /
- // take the full range we could get
- cursor = end;
- break;
-
- // array of *
- case 'f':
- case 'd':
- case 'l':
- case 'i':
- case 'c': {
- const uint32_t length = ReadWord(input, cursor, end);
- const uint32_t encoding = ReadWord(input, cursor, end);
-
- const uint32_t comp_len = ReadWord(input, cursor, end);
-
- // compute length based on type and check against the stored value
- if (encoding == 0) {
- uint32_t stride = 0;
- switch (type) {
- case 'f':
- case 'i':
- stride = 4;
- break;
-
- case 'd':
- case 'l':
- stride = 8;
- break;
-
- case 'c':
- stride = 1;
- break;
-
- default:
- break;
- };
- //ai_assert(stride > 0);
- if (length * stride != comp_len) {
- TokenizeError("cannot ReadData, calculated data stride differs from what the file claims", input, cursor);
- }
- }
- // zip/deflate algorithm (encoding==1)? take given length. anything else? die
- else if (encoding != 1) {
- TokenizeError("cannot ReadData, unknown encoding", input, cursor);
- }
- cursor += comp_len;
- break;
- } // string
- case 'S': {
- const char *sb, *se;
- // 0 characters can legally happen in such strings
- ReadString(sb, se, input, cursor, end, true, true);
- break;
- }
- default:
- corrupt = true; // must exit
- TokenizeError("cannot ReadData, unexpected type code: " + std::string(&type, 1), input, cursor);
- return;
- }
-
- if (cursor > end) {
- corrupt = true; // must exit
- TokenizeError("cannot ReadData, the remaining size is too small for the data type: " + std::string(&type, 1), input, cursor);
- return;
- }
-
- // the type code is contained in the returned range
- send_out = cursor;
-}
-
-// ------------------------------------------------------------------------------------------------
-bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, const char *end, bool const is64bits, bool &corrupt) {
- // the first word contains the offset at which this block ends
- const uint64_t end_offset = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
-
- // we may get 0 if reading reached the end of the file -
- // fbx files have a mysterious extra footer which I don't know
- // how to extract any information from, but at least it always
- // starts with a 0.
- if (!end_offset) {
- return false;
- }
-
- if (end_offset > Offset(input, end)) {
- TokenizeError("block offset is out of range", input, cursor);
- corrupt = true;
- return false;
- } else if (end_offset < Offset(input, cursor)) {
- TokenizeError("block offset is negative out of range", input, cursor);
- corrupt = true;
- return false;
- }
-
- // the second data word contains the number of properties in the scope
- const uint64_t prop_count = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
-
- // the third data word contains the length of the property list
- const uint64_t prop_length = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
-
- // now comes the name of the scope/key
- const char *sbeg = nullptr, *send = nullptr;
- ReadString(sbeg, send, input, cursor, end);
-
- output_tokens.push_back(new_Token(sbeg, send, TokenType_KEY, Offset(input, cursor)));
-
- // now come the individual properties
- const char *begin_cursor = cursor;
- for (unsigned int i = 0; i < prop_count; ++i) {
- ReadData(sbeg, send, input, cursor, begin_cursor + prop_length, corrupt);
- if (corrupt) {
- return false;
- }
-
- output_tokens.push_back(new_Token(sbeg, send, TokenType_DATA, Offset(input, cursor)));
-
- if (i != prop_count - 1) {
- output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_COMMA, Offset(input, cursor)));
- }
- }
-
- if (Offset(begin_cursor, cursor) != prop_length) {
- TokenizeError("property length not reached, something is wrong", input, cursor);
- corrupt = true;
- return false;
- }
-
- // at the end of each nested block, there is a NUL record to indicate
- // that the sub-scope exists (i.e. to distinguish between P: and P : {})
- // this NUL record is 13 bytes long on 32 bit version and 25 bytes long on 64 bit.
- const size_t sentinel_block_length = is64bits ? (sizeof(uint64_t) * 3 + 1) : (sizeof(uint32_t) * 3 + 1);
-
- if (Offset(input, cursor) < end_offset) {
- if (end_offset - Offset(input, cursor) < sentinel_block_length) {
- TokenizeError("insufficient padding bytes at block end", input, cursor);
- }
-
- output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_OPEN_BRACKET, Offset(input, cursor)));
-
- // XXX this is vulnerable to stack overflowing ..
- while (Offset(input, cursor) < end_offset - sentinel_block_length) {
- ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, is64bits, corrupt);
- if (corrupt) {
- return false;
- }
- }
- output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor)));
-
- for (unsigned int i = 0; i < sentinel_block_length; ++i) {
- if (cursor[i] != '\0') {
- TokenizeError("failed to read nested block sentinel, expected all bytes to be 0", input, cursor);
- corrupt = true;
- return false;
- }
- }
- cursor += sentinel_block_length;
- }
-
- if (Offset(input, cursor) != end_offset) {
- TokenizeError("scope length not reached, something is wrong", input, cursor);
- corrupt = true;
- return false;
- }
-
- return true;
-}
-} // anonymous namespace
-
-// ------------------------------------------------------------------------------------------------
-// TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent
-void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, bool &corrupt) {
- if (length < 0x1b) {
- //TokenizeError("file is too short",0);
- }
-
- if (strncmp(input, "Kaydara FBX Binary", 18)) {
- TokenizeError("magic bytes not found", 0);
- }
-
- const char *cursor = input + 18;
- /*Result ignored*/ ReadByte(input, cursor, input + length);
- /*Result ignored*/ ReadByte(input, cursor, input + length);
- /*Result ignored*/ ReadByte(input, cursor, input + length);
- /*Result ignored*/ ReadByte(input, cursor, input + length);
- /*Result ignored*/ ReadByte(input, cursor, input + length);
- const uint32_t version = ReadWord(input, cursor, input + length);
- print_verbose("FBX Version: " + itos(version));
- //ASSIMP_LOG_DEBUG_F("FBX version: ", version);
- const bool is64bits = version >= 7500;
- const char *end = input + length;
- while (cursor < end) {
- if (!ReadScope(output_tokens, input, cursor, input + length, is64bits, corrupt)) {
- break;
- }
- }
-}
-} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXCommon.h b/modules/fbx/fbx_parser/FBXCommon.h
deleted file mode 100644
index d0d4790ba8..0000000000
--- a/modules/fbx/fbx_parser/FBXCommon.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*************************************************************************/
-/* FBXCommon.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, assimp team
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
-copyright notice, this list of conditions and the
-following disclaimer.
-
-* Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the
-following disclaimer in the documentation and/or other
-materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
-contributors may be used to endorse or promote products
-derived from this software without specific prior
-written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-
-/** @file FBXCommon.h
- * Some useful constants and enums for dealing with FBX files.
- */
-#ifndef FBX_COMMON_H
-#define FBX_COMMON_H
-
-#include <string>
-
-namespace FBXDocParser {
-const std::string NULL_RECORD = { // 13 null bytes
- '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'
-}; // who knows why
-const std::string SEPARATOR = { '\x00', '\x01' }; // for use inside strings
-const std::string MAGIC_NODE_TAG = "_$AssimpFbx$"; // from import
-const int64_t SECOND = 46186158000; // FBX's kTime unit
-
-// rotation order. We'll probably use EulerXYZ for everything
-enum RotOrder {
- RotOrder_EulerXYZ = 0,
- RotOrder_EulerXZY,
- RotOrder_EulerYZX,
- RotOrder_EulerYXZ,
- RotOrder_EulerZXY,
- RotOrder_EulerZYX,
-
- RotOrder_SphericXYZ,
-
- RotOrder_MAX // end-of-enum sentinel
-};
-
-enum TransformInheritance {
- Transform_RrSs = 0,
- Transform_RSrs = 1,
- Transform_Rrs = 2,
- TransformInheritance_MAX // end-of-enum sentinel
-};
-} // namespace FBXDocParser
-
-#endif // FBX_COMMON_H
diff --git a/modules/fbx/fbx_parser/FBXDeformer.cpp b/modules/fbx/fbx_parser/FBXDeformer.cpp
deleted file mode 100644
index a2b216ab09..0000000000
--- a/modules/fbx/fbx_parser/FBXDeformer.cpp
+++ /dev/null
@@ -1,271 +0,0 @@
-/*************************************************************************/
-/* FBXDeformer.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, assimp team
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
-
-* Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-
-/** @file FBXNoteAttribute.cpp
- * @brief Assimp::FBX::NodeAttribute (and subclasses) implementation
- */
-
-#include "FBXDocument.h"
-#include "FBXDocumentUtil.h"
-#include "FBXMeshGeometry.h"
-#include "FBXParser.h"
-#include "core/math/math_funcs.h"
-#include "core/math/transform_3d.h"
-
-#include <iostream>
-
-namespace FBXDocParser {
-
-using namespace Util;
-
-// ------------------------------------------------------------------------------------------------
-Deformer::Deformer(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
- Object(id, element, name) {
-}
-
-// ------------------------------------------------------------------------------------------------
-Deformer::~Deformer() {
-}
-
-Constraint::Constraint(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
- Object(id, element, name) {
-}
-
-Constraint::~Constraint() {
-}
-
-// ------------------------------------------------------------------------------------------------
-Cluster::Cluster(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
- Deformer(id, element, doc, name) {
- const ScopePtr sc = GetRequiredScope(element);
- // for( auto element : sc.Elements())
- // {
- // std::cout << "cluster element: " << element.first << std::endl;
- // }
- //
- // element: Indexes
- // element: Transform
- // element: TransformAssociateModel
- // element: TransformLink
- // element: UserData
- // element: Version
- // element: Weights
-
- const ElementPtr Indexes = sc->GetElement("Indexes");
- const ElementPtr Weights = sc->GetElement("Weights");
-
- const ElementPtr TransformAssociateModel = sc->GetElement("TransformAssociateModel");
- if (TransformAssociateModel != nullptr) {
- //Transform t = ReadMatrix(*TransformAssociateModel);
- link_mode = SkinLinkMode_Additive;
- valid_transformAssociateModel = true;
- } else {
- link_mode = SkinLinkMode_Normalized;
- valid_transformAssociateModel = false;
- }
-
- const ElementPtr Transform = GetRequiredElement(sc, "Transform", element);
- const ElementPtr TransformLink = GetRequiredElement(sc, "TransformLink", element);
-
- // todo: check if we need this
- //const Element& TransformAssociateModel = GetRequiredElement(sc, "TransformAssociateModel", &element);
-
- transform = ReadMatrix(Transform);
- transformLink = ReadMatrix(TransformLink);
-
- // it is actually possible that there be Deformer's with no weights
- if (!!Indexes != !!Weights) {
- DOMError("either Indexes or Weights are missing from Cluster", element);
- }
-
- if (Indexes) {
- ParseVectorDataArray(indices, Indexes);
- ParseVectorDataArray(weights, Weights);
- }
-
- if (indices.size() != weights.size()) {
- DOMError("sizes of index and weight array don't match up", element);
- }
-
- // read assigned node
- const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Model");
- for (const Connection *con : conns) {
- const Model *mod = ProcessSimpleConnection<Model>(*con, false, "Model -> Cluster", element);
- if (mod) {
- node = mod;
- break;
- }
- }
-
- if (!node) {
- DOMError("failed to read target Node for Cluster", element);
- node = nullptr;
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-Cluster::~Cluster() {
-}
-
-// ------------------------------------------------------------------------------------------------
-Skin::Skin(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
- Deformer(id, element, doc, name) {
- const ScopePtr sc = GetRequiredScope(element);
-
- // keep this it is used for debugging and any FBX format changes
- // for (auto element : sc.Elements()) {
- // std::cout << "skin element: " << element.first << std::endl;
- // }
-
- const ElementPtr Link_DeformAcuracy = sc->GetElement("Link_DeformAcuracy");
- if (Link_DeformAcuracy) {
- accuracy = ParseTokenAsFloat(GetRequiredToken(Link_DeformAcuracy, 0));
- }
-
- const ElementPtr SkinType = sc->GetElement("SkinningType");
-
- if (SkinType) {
- std::string skin_type = ParseTokenAsString(GetRequiredToken(SkinType, 0));
-
- if (skin_type == "Linear") {
- skinType = Skin_Linear;
- } else if (skin_type == "Rigid") {
- skinType = Skin_Rigid;
- } else if (skin_type == "DualQuaternion") {
- skinType = Skin_DualQuaternion;
- } else if (skin_type == "Blend") {
- skinType = Skin_Blend;
- } else {
- print_error("[doc:skin] could not find valid skin type: " + String(skin_type.c_str()));
- }
- }
-
- // resolve assigned clusters
- const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer");
-
- //
-
- clusters.reserve(conns.size());
- for (const Connection *con : conns) {
- const Cluster *cluster = ProcessSimpleConnection<Cluster>(*con, false, "Cluster -> Skin", element);
- if (cluster) {
- clusters.push_back(cluster);
- continue;
- }
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-Skin::~Skin() {
-}
-// ------------------------------------------------------------------------------------------------
-BlendShape::BlendShape(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
- Deformer(id, element, doc, name) {
- const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer");
- blendShapeChannels.reserve(conns.size());
- for (const Connection *con : conns) {
- const BlendShapeChannel *bspc = ProcessSimpleConnection<BlendShapeChannel>(*con, false, "BlendShapeChannel -> BlendShape", element);
- if (bspc) {
- blendShapeChannels.push_back(bspc);
- continue;
- }
- }
-}
-// ------------------------------------------------------------------------------------------------
-BlendShape::~BlendShape() {
-}
-// ------------------------------------------------------------------------------------------------
-BlendShapeChannel::BlendShapeChannel(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
- Deformer(id, element, doc, name) {
- const ScopePtr sc = GetRequiredScope(element);
- const ElementPtr DeformPercent = sc->GetElement("DeformPercent");
- if (DeformPercent) {
- percent = ParseTokenAsFloat(GetRequiredToken(DeformPercent, 0));
- }
- const ElementPtr FullWeights = sc->GetElement("FullWeights");
- if (FullWeights) {
- ParseVectorDataArray(fullWeights, FullWeights);
- }
- const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Geometry");
- shapeGeometries.reserve(conns.size());
- for (const Connection *con : conns) {
- const ShapeGeometry *const sg = ProcessSimpleConnection<ShapeGeometry>(*con, false, "Shape -> BlendShapeChannel", element);
- if (sg) {
- shapeGeometries.push_back(sg);
- continue;
- }
- }
-}
-// ------------------------------------------------------------------------------------------------
-BlendShapeChannel::~BlendShapeChannel() {
-}
-// ------------------------------------------------------------------------------------------------
-} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXDocument.cpp b/modules/fbx/fbx_parser/FBXDocument.cpp
deleted file mode 100644
index 929272c972..0000000000
--- a/modules/fbx/fbx_parser/FBXDocument.cpp
+++ /dev/null
@@ -1,636 +0,0 @@
-/*************************************************************************/
-/* FBXDocument.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, assimp team
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
-
-* Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the*
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-
-/** @file FBXDocument.cpp
- * @brief Implementation of the FBX DOM classes
- */
-
-#include "FBXDocument.h"
-#include "FBXDocumentUtil.h"
-#include "FBXImportSettings.h"
-#include "FBXMeshGeometry.h"
-#include "FBXParser.h"
-#include "FBXProperties.h"
-#include "FBXUtil.h"
-
-#include <algorithm>
-#include <functional>
-#include <iostream>
-#include <map>
-#include <memory>
-
-namespace FBXDocParser {
-
-using namespace Util;
-
-// ------------------------------------------------------------------------------------------------
-LazyObject::LazyObject(uint64_t id, const ElementPtr element, const Document &doc) :
- doc(doc), element(element), id(id) {
- // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-LazyObject::~LazyObject() {
- object.reset();
-}
-
-ObjectPtr LazyObject::LoadObject() {
- if (IsBeingConstructed() || FailedToConstruct()) {
- return nullptr;
- }
-
- if (object) {
- return object.get();
- }
-
- TokenPtr key = element->KeyToken();
- ERR_FAIL_COND_V(!key, nullptr);
- const TokenList &tokens = element->Tokens();
-
- if (tokens.size() < 3) {
- //DOMError("expected at least 3 tokens: id, name and class tag",&element);
- return nullptr;
- }
-
- const char *err = nullptr;
- std::string name = ParseTokenAsString(tokens[1], err);
- if (err) {
- DOMError(err, element);
- }
-
- // small fix for binary reading: binary fbx files don't use
- // prefixes such as Model:: in front of their names. The
- // loading code expects this at many places, though!
- // so convert the binary representation (a 0x0001) to the
- // double colon notation.
- if (tokens[1]->IsBinary()) {
- for (size_t i = 0; i < name.length(); ++i) {
- if (name[i] == 0x0 && name[i + 1] == 0x1) {
- name = name.substr(i + 2) + "::" + name.substr(0, i);
- }
- }
- }
-
- const std::string classtag = ParseTokenAsString(tokens[2], err);
- if (err) {
- DOMError(err, element);
- }
-
- // prevent recursive calls
- flags |= BEING_CONSTRUCTED;
-
- // this needs to be relatively fast since it happens a lot,
- // so avoid constructing strings all the time.
- const char *obtype = key->begin();
- const size_t length = static_cast<size_t>(key->end() - key->begin());
-
- if (!strncmp(obtype, "Pose", length)) {
- object.reset(new FbxPose(id, element, doc, name));
- } else if (!strncmp(obtype, "Geometry", length)) {
- if (!strcmp(classtag.c_str(), "Mesh")) {
- object.reset(new MeshGeometry(id, element, name, doc));
- }
- if (!strcmp(classtag.c_str(), "Shape")) {
- object.reset(new ShapeGeometry(id, element, name, doc));
- }
- if (!strcmp(classtag.c_str(), "Line")) {
- object.reset(new LineGeometry(id, element, name, doc));
- }
- } else if (!strncmp(obtype, "NodeAttribute", length)) {
- if (!strcmp(classtag.c_str(), "Camera")) {
- object.reset(new Camera(id, element, doc, name));
- } else if (!strcmp(classtag.c_str(), "CameraSwitcher")) {
- object.reset(new CameraSwitcher(id, element, doc, name));
- } else if (!strcmp(classtag.c_str(), "Light")) {
- object.reset(new Light(id, element, doc, name));
- } else if (!strcmp(classtag.c_str(), "Null")) {
- object.reset(new Null(id, element, doc, name));
- } else if (!strcmp(classtag.c_str(), "LimbNode")) {
- // This is an older format for bones
- // this is what blender uses I believe
- object.reset(new LimbNode(id, element, doc, name));
- }
- } else if (!strncmp(obtype, "Constraint", length)) {
- object.reset(new Constraint(id, element, doc, name));
- } else if (!strncmp(obtype, "Deformer", length)) {
- if (!strcmp(classtag.c_str(), "Cluster")) {
- object.reset(new Cluster(id, element, doc, name));
- } else if (!strcmp(classtag.c_str(), "Skin")) {
- object.reset(new Skin(id, element, doc, name));
- } else if (!strcmp(classtag.c_str(), "BlendShape")) {
- object.reset(new BlendShape(id, element, doc, name));
- } else if (!strcmp(classtag.c_str(), "BlendShapeChannel")) {
- object.reset(new BlendShapeChannel(id, element, doc, name));
- }
- } else if (!strncmp(obtype, "Model", length)) {
- // Model is normal node
-
- // LimbNode model is a 'bone' node.
- if (!strcmp(classtag.c_str(), "LimbNode")) {
- object.reset(new ModelLimbNode(id, element, doc, name));
-
- } else if (strcmp(classtag.c_str(), "IKEffector") && strcmp(classtag.c_str(), "FKEffector")) {
- // FK and IK effectors are not supported.
- object.reset(new Model(id, element, doc, name));
- }
- } else if (!strncmp(obtype, "Material", length)) {
- object.reset(new Material(id, element, doc, name));
- } else if (!strncmp(obtype, "Texture", length)) {
- object.reset(new Texture(id, element, doc, name));
- } else if (!strncmp(obtype, "LayeredTexture", length)) {
- object.reset(new LayeredTexture(id, element, doc, name));
- } else if (!strncmp(obtype, "Video", length)) {
- object.reset(new Video(id, element, doc, name));
- } else if (!strncmp(obtype, "AnimationStack", length)) {
- object.reset(new AnimationStack(id, element, name, doc));
- } else if (!strncmp(obtype, "AnimationLayer", length)) {
- object.reset(new AnimationLayer(id, element, name, doc));
- } else if (!strncmp(obtype, "AnimationCurve", length)) {
- object.reset(new AnimationCurve(id, element, name, doc));
- } else if (!strncmp(obtype, "AnimationCurveNode", length)) {
- object.reset(new AnimationCurveNode(id, element, name, doc));
- } else {
- ERR_FAIL_V_MSG(nullptr, "FBX contains unsupported object: " + String(obtype));
- }
-
- flags &= ~BEING_CONSTRUCTED;
-
- return object.get();
-}
-
-// ------------------------------------------------------------------------------------------------
-Object::Object(uint64_t id, const ElementPtr element, const std::string &name) :
- PropertyTable(element), element(element), name(name), id(id) {
-}
-
-// ------------------------------------------------------------------------------------------------
-Object::~Object() {
- // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-FileGlobalSettings::FileGlobalSettings(const Document &doc) :
- PropertyTable(), doc(doc) {
- // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-FileGlobalSettings::~FileGlobalSettings() {
-}
-
-// ------------------------------------------------------------------------------------------------
-Document::Document(const Parser &parser, const ImportSettings &settings) :
- settings(settings), parser(parser) {
- // Cannot use array default initialization syntax because vc8 fails on it
- for (unsigned int &timeStamp : creationTimeStamp) {
- timeStamp = 0;
- }
-
- // we must check if we can read the header version safely, if its outdated then drop it.
- if (ReadHeader()) {
- SafeToImport = true;
- ReadPropertyTemplates();
-
- ReadGlobalSettings();
-
- // This order is important, connections need parsed objects to check
- // whether connections are ok or not. Objects may not be evaluated yet,
- // though, since this may require valid connections.
- ReadObjects();
- ReadConnections();
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-Document::~Document() {
- for (PropertyTemplateMap::value_type v : templates) {
- delete v.second;
- }
-
- for (ObjectMap::value_type &v : objects) {
- delete v.second;
- }
-
- for (ConnectionMap::value_type &v : src_connections) {
- delete v.second;
- }
-
- // clear globals import pointer
- globals.reset();
-}
-
-// ------------------------------------------------------------------------------------------------
-static const unsigned int LowerSupportedVersion = 7100;
-static const unsigned int UpperSupportedVersion = 7700;
-
-bool Document::ReadHeader() {
- // Read ID objects from "Objects" section
- ScopePtr sc = parser.GetRootScope();
- ElementPtr ehead = sc->GetElement("FBXHeaderExtension");
- if (!ehead || !ehead->Compound()) {
- DOMError("no FBXHeaderExtension dictionary found");
- }
-
- if (parser.IsCorrupt()) {
- DOMError("File is corrupt");
- return false;
- }
-
- const ScopePtr shead = ehead->Compound();
- fbxVersion = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(shead, "FBXVersion", ehead), 0));
-
- // While we may have some success with newer files, we don't support
- // the older 6.n fbx format
- if (fbxVersion < LowerSupportedVersion) {
- DOMWarning("unsupported, old format version, FBX 2015-2020, you must re-export in a more modern version of your original modelling application");
- return false;
- }
- if (fbxVersion > UpperSupportedVersion) {
- DOMWarning("unsupported, newer format version, supported are only FBX 2015, up to FBX 2020"
- " trying to read it nevertheless");
- }
-
- const ElementPtr ecreator = shead->GetElement("Creator");
- if (ecreator) {
- creator = ParseTokenAsString(GetRequiredToken(ecreator, 0));
- }
-
- // Scene Info
- const ElementPtr scene_info = shead->GetElement("SceneInfo");
-
- if (scene_info) {
- metadata_properties.Setup(scene_info);
- }
-
- const ElementPtr etimestamp = shead->GetElement("CreationTimeStamp");
- if (etimestamp && etimestamp->Compound()) {
- const ScopePtr stimestamp = etimestamp->Compound();
- creationTimeStamp[0] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Year"), 0));
- creationTimeStamp[1] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Month"), 0));
- creationTimeStamp[2] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Day"), 0));
- creationTimeStamp[3] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Hour"), 0));
- creationTimeStamp[4] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Minute"), 0));
- creationTimeStamp[5] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Second"), 0));
- creationTimeStamp[6] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Millisecond"), 0));
- }
-
- return true;
-}
-
-// ------------------------------------------------------------------------------------------------
-void Document::ReadGlobalSettings() {
- ERR_FAIL_COND_MSG(globals != nullptr, "Global settings is already setup this is a serious error and should be reported");
-
- globals = std::make_shared<FileGlobalSettings>(*this);
-}
-
-// ------------------------------------------------------------------------------------------------
-void Document::ReadObjects() {
- // read ID objects from "Objects" section
- const ScopePtr sc = parser.GetRootScope();
- const ElementPtr eobjects = sc->GetElement("Objects");
- if (!eobjects || !eobjects->Compound()) {
- DOMError("no Objects dictionary found");
- }
-
- // add a dummy entry to represent the Model::RootNode object (id 0),
- // which is only indirectly defined in the input file
- objects[0] = new LazyObject(0L, eobjects, *this);
-
- const ScopePtr sobjects = eobjects->Compound();
- for (const ElementMap::value_type &iter : sobjects->Elements()) {
- // extract ID
- const TokenList &tok = iter.second->Tokens();
-
- if (tok.empty()) {
- DOMError("expected ID after object key", iter.second);
- }
-
- const char *err;
- const uint64_t id = ParseTokenAsID(tok[0], err);
- if (err) {
- DOMError(err, iter.second);
- }
-
- // id=0 is normally implicit
- if (id == 0L) {
- DOMError("encountered object with implicitly defined id 0", iter.second);
- }
-
- if (objects.find(id) != objects.end()) {
- DOMWarning("encountered duplicate object id, ignoring first occurrence", iter.second);
- }
-
- objects[id] = new LazyObject(id, iter.second, *this);
-
- // grab all animation stacks upfront since there is no listing of them
- if (!strcmp(iter.first.c_str(), "AnimationStack")) {
- animationStacks.push_back(id);
- } else if (!strcmp(iter.first.c_str(), "Constraint")) {
- constraints.push_back(id);
- } else if (!strcmp(iter.first.c_str(), "Pose")) {
- bind_poses.push_back(id);
- } else if (!strcmp(iter.first.c_str(), "Material")) {
- materials.push_back(id);
- } else if (!strcmp(iter.first.c_str(), "Deformer")) {
- TokenPtr key = iter.second->KeyToken();
- ERR_CONTINUE_MSG(!key, "[parser bug] invalid token key for deformer");
- const TokenList &tokens = iter.second->Tokens();
- const std::string class_tag = ParseTokenAsString(tokens[2], err);
-
- if (err) {
- DOMError(err, iter.second);
- }
-
- if (class_tag == "Skin") {
- //print_verbose("registered skin:" + itos(id));
- skins.push_back(id);
- }
- }
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-void Document::ReadPropertyTemplates() {
-}
-
-// ------------------------------------------------------------------------------------------------
-void Document::ReadConnections() {
- const ScopePtr sc = parser.GetRootScope();
-
- // read property templates from "Definitions" section
- const ElementPtr econns = sc->GetElement("Connections");
- if (!econns || !econns->Compound()) {
- DOMError("no Connections dictionary found");
- }
-
- uint64_t insertionOrder = 0l;
- const ScopePtr sconns = econns->Compound();
- const ElementCollection conns = sconns->GetCollection("C");
- for (ElementMap::const_iterator it = conns.first; it != conns.second; ++it) {
- const ElementPtr el = (*it).second;
- const std::string &type = ParseTokenAsString(GetRequiredToken(el, 0));
-
- // PP = property-property connection, ignored for now
- // (tokens: "PP", ID1, "Property1", ID2, "Property2")
- if (type == "PP") {
- continue;
- }
-
- const uint64_t src = ParseTokenAsID(GetRequiredToken(el, 1));
- const uint64_t dest = ParseTokenAsID(GetRequiredToken(el, 2));
-
- // OO = object-object connection
- // OP = object-property connection, in which case the destination property follows the object ID
- const std::string &prop = (type == "OP" ? ParseTokenAsString(GetRequiredToken(el, 3)) : "");
-
- if (objects.find(src) == objects.end()) {
- DOMWarning("source object for connection does not exist", el);
- continue;
- }
-
- // dest may be 0 (root node) but we added a dummy object before
- if (objects.find(dest) == objects.end()) {
- DOMWarning("destination object for connection does not exist", el);
- continue;
- }
-
- // add new connection
- const Connection *const c = new Connection(insertionOrder++, src, dest, prop, *this);
- src_connections.insert(ConnectionMap::value_type(src, c));
- dest_connections.insert(ConnectionMap::value_type(dest, c));
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-const std::vector<const AnimationStack *> &Document::AnimationStacks() const {
- if (!animationStacksResolved.empty() || animationStacks.empty()) {
- return animationStacksResolved;
- }
-
- animationStacksResolved.reserve(animationStacks.size());
- for (uint64_t id : animationStacks) {
- LazyObject *lazy = GetObject(id);
-
- // Two things happen here:
- // We cast internally an Object PTR to an Animation Stack PTR
- // We return invalid weak_ptrs for objects which are invalid
-
- const AnimationStack *stack = lazy->Get<AnimationStack>();
- ERR_CONTINUE_MSG(!stack, "invalid ptr to AnimationStack - conversion failure");
-
- // We push back the weak reference :) to keep things simple, as ownership is on the parser side so it won't be cleaned up.
- animationStacksResolved.push_back(stack);
- }
-
- return animationStacksResolved;
-}
-
-// ------------------------------------------------------------------------------------------------
-LazyObject *Document::GetObject(uint64_t id) const {
- ObjectMap::const_iterator it = objects.find(id);
- return it == objects.end() ? nullptr : (*it).second;
-}
-
-#define MAX_CLASSNAMES 6
-
-// ------------------------------------------------------------------------------------------------
-std::vector<const Connection *> Document::GetConnectionsSequenced(uint64_t id, const ConnectionMap &conns) const {
- std::vector<const Connection *> temp;
-
- const std::pair<ConnectionMap::const_iterator, ConnectionMap::const_iterator> range =
- conns.equal_range(id);
-
- temp.reserve(std::distance(range.first, range.second));
- for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) {
- temp.push_back((*it).second);
- }
-
- std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare));
-
- return temp; // NRVO should handle this
-}
-
-// ------------------------------------------------------------------------------------------------
-std::vector<const Connection *> Document::GetConnectionsSequenced(uint64_t id, bool is_src,
- const ConnectionMap &conns,
- const char *const *classnames,
- size_t count) const
-
-{
- size_t lengths[MAX_CLASSNAMES];
-
- const size_t c = count;
- for (size_t i = 0; i < c; ++i) {
- lengths[i] = strlen(classnames[i]);
- }
-
- std::vector<const Connection *> temp;
- const std::pair<ConnectionMap::const_iterator, ConnectionMap::const_iterator> range =
- conns.equal_range(id);
-
- temp.reserve(std::distance(range.first, range.second));
- for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) {
- TokenPtr key = (is_src ? (*it).second->LazyDestinationObject() : (*it).second->LazySourceObject())->GetElement()->KeyToken();
-
- const char *obtype = key->begin();
-
- for (size_t i = 0; i < c; ++i) {
- //ai_assert(classnames[i]);
- if (static_cast<size_t>(std::distance(key->begin(), key->end())) == lengths[i] && !strncmp(classnames[i], obtype, lengths[i])) {
- obtype = nullptr;
- break;
- }
- }
-
- if (obtype) {
- continue;
- }
-
- temp.push_back((*it).second);
- }
-
- std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare));
- return temp; // NRVO should handle this
-}
-
-// ------------------------------------------------------------------------------------------------
-std::vector<const Connection *> Document::GetConnectionsBySourceSequenced(uint64_t source) const {
- return GetConnectionsSequenced(source, ConnectionsBySource());
-}
-
-// ------------------------------------------------------------------------------------------------
-std::vector<const Connection *> Document::GetConnectionsBySourceSequenced(uint64_t src, const char *classname) const {
- const char *arr[] = { classname };
- return GetConnectionsBySourceSequenced(src, arr, 1);
-}
-
-// ------------------------------------------------------------------------------------------------
-std::vector<const Connection *> Document::GetConnectionsBySourceSequenced(uint64_t source,
- const char *const *classnames, size_t count) const {
- return GetConnectionsSequenced(source, true, ConnectionsBySource(), classnames, count);
-}
-
-// ------------------------------------------------------------------------------------------------
-std::vector<const Connection *> Document::GetConnectionsByDestinationSequenced(uint64_t dest,
- const char *classname) const {
- const char *arr[] = { classname };
- return GetConnectionsByDestinationSequenced(dest, arr, 1);
-}
-
-// ------------------------------------------------------------------------------------------------
-std::vector<const Connection *> Document::GetConnectionsByDestinationSequenced(uint64_t dest) const {
- return GetConnectionsSequenced(dest, ConnectionsByDestination());
-}
-
-// ------------------------------------------------------------------------------------------------
-std::vector<const Connection *> Document::GetConnectionsByDestinationSequenced(uint64_t dest,
- const char *const *classnames, size_t count) const {
- return GetConnectionsSequenced(dest, false, ConnectionsByDestination(), classnames, count);
-}
-
-// ------------------------------------------------------------------------------------------------
-Connection::Connection(uint64_t insertionOrder, uint64_t src, uint64_t dest, const std::string &prop,
- const Document &doc) :
- insertionOrder(insertionOrder), prop(prop), src(src), dest(dest), doc(doc) {
-}
-
-// ------------------------------------------------------------------------------------------------
-Connection::~Connection() {
- // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-LazyObject *Connection::LazySourceObject() const {
- LazyObject *const lazy = doc.GetObject(src);
- return lazy;
-}
-
-// ------------------------------------------------------------------------------------------------
-LazyObject *Connection::LazyDestinationObject() const {
- LazyObject *const lazy = doc.GetObject(dest);
- return lazy;
-}
-
-// ------------------------------------------------------------------------------------------------
-Object *Connection::SourceObject() const {
- LazyObject *lazy = doc.GetObject(src);
- //ai_assert(lazy);
- return lazy->LoadObject();
-}
-
-// ------------------------------------------------------------------------------------------------
-Object *Connection::DestinationObject() const {
- LazyObject *lazy = doc.GetObject(dest);
- //ai_assert(lazy);
- return lazy->LoadObject();
-}
-} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXDocument.h b/modules/fbx/fbx_parser/FBXDocument.h
deleted file mode 100644
index 5bf280a1dc..0000000000
--- a/modules/fbx/fbx_parser/FBXDocument.h
+++ /dev/null
@@ -1,1252 +0,0 @@
-/*************************************************************************/
-/* FBXDocument.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-/** @file FBXDocument.h
- * @brief FBX DOM
- */
-#ifndef FBX_DOCUMENT_H
-#define FBX_DOCUMENT_H
-
-#include "FBXCommon.h"
-#include "FBXParser.h"
-#include "FBXProperties.h"
-#include "core/math/transform_3d.h"
-#include "core/math/vector2.h"
-#include "core/math/vector3.h"
-#include "core/string/print_string.h"
-#include <stdint.h>
-#include <numeric>
-
-#define _AI_CONCAT(a, b) a##b
-#define AI_CONCAT(a, b) _AI_CONCAT(a, b)
-
-namespace FBXDocParser {
-
-class Parser;
-class Object;
-struct ImportSettings;
-class Connection;
-
-class PropertyTable;
-class Document;
-class Material;
-class ShapeGeometry;
-class LineGeometry;
-class Geometry;
-
-class Video;
-
-class AnimationCurve;
-class AnimationCurveNode;
-class AnimationLayer;
-class AnimationStack;
-
-class BlendShapeChannel;
-class BlendShape;
-class Skin;
-class Cluster;
-
-typedef Object *ObjectPtr;
-#define new_Object new Object
-
-/** Represents a delay-parsed FBX objects. Many objects in the scene
- * are not needed by assimp, so it makes no sense to parse them
- * upfront. */
-class LazyObject {
-public:
- LazyObject(uint64_t id, const ElementPtr element, const Document &doc);
- ~LazyObject();
-
- ObjectPtr LoadObject();
-
- /* Casting weak pointers to their templated type safely and preserving ref counting and safety
- * with lock() keyword to prevent leaking memory
- */
- template <typename T>
- const T *Get() {
- ObjectPtr ob = LoadObject();
- return dynamic_cast<const T *>(ob);
- }
-
- uint64_t ID() const {
- return id;
- }
-
- bool IsBeingConstructed() const {
- return (flags & BEING_CONSTRUCTED) != 0;
- }
-
- bool FailedToConstruct() const {
- return (flags & FAILED_TO_CONSTRUCT) != 0;
- }
-
- ElementPtr GetElement() const {
- return element;
- }
-
- const Document &GetDocument() const {
- return doc;
- }
-
-private:
- const Document &doc;
- ElementPtr element = nullptr;
- std::shared_ptr<Object> object = nullptr;
- const uint64_t id = 0;
-
- enum Flags {
- BEING_CONSTRUCTED = 0x1,
- FAILED_TO_CONSTRUCT = 0x2
- };
-
- unsigned int flags = 0;
-};
-
-/** Base class for in-memory (DOM) representations of FBX objects */
-class Object : public PropertyTable {
-public:
- Object(uint64_t id, const ElementPtr element, const std::string &name);
-
- virtual ~Object();
-
- ElementPtr SourceElement() const {
- return element;
- }
-
- const std::string &Name() const {
- return name;
- }
-
- uint64_t ID() const {
- return id;
- }
-
-protected:
- const ElementPtr element = nullptr;
- const std::string name;
- const uint64_t id;
-};
-
-/** DOM class for generic FBX NoteAttribute blocks. NoteAttribute's just hold a property table,
- * fixed members are added by deriving classes. */
-class NodeAttribute : public Object {
-public:
- NodeAttribute(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
- virtual ~NodeAttribute();
-};
-
-/** DOM base class for FBX camera settings attached to a node */
-class CameraSwitcher : public NodeAttribute {
-public:
- CameraSwitcher(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
- virtual ~CameraSwitcher();
-
- int CameraID() const {
- return cameraId;
- }
-
- const std::string &CameraName() const {
- return cameraName;
- }
-
- const std::string &CameraIndexName() const {
- return cameraIndexName;
- }
-
-private:
- int cameraId = 0;
- std::string cameraName;
- std::string cameraIndexName;
-};
-
-#define fbx_stringize(a) #a
-
-#define fbx_simple_property(name, type, default_value) \
- type name() const { \
- return PropertyGet<type>(this, fbx_stringize(name), (default_value)); \
- }
-
-// XXX improve logging
-#define fbx_simple_enum_property(name, type, default_value) \
- type name() const { \
- const int ival = PropertyGet<int>(this, fbx_stringize(name), static_cast<int>(default_value)); \
- if (ival < 0 || ival >= AI_CONCAT(type, _MAX)) { \
- return static_cast<type>(default_value); \
- } \
- return static_cast<type>(ival); \
- }
-
-class FbxPoseNode;
-class FbxPose : public Object {
-public:
- FbxPose(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
-
- const std::vector<FbxPoseNode *> &GetBindPoses() const {
- return pose_nodes;
- }
-
- virtual ~FbxPose();
-
-private:
- std::vector<FbxPoseNode *> pose_nodes;
-};
-
-class FbxPoseNode {
-public:
- FbxPoseNode(const ElementPtr element, const Document &doc, const std::string &name) {
- const ScopePtr sc = GetRequiredScope(element);
-
- // get pose node transform
- const ElementPtr Transform = GetRequiredElement(sc, "Matrix", element);
- transform = ReadMatrix(Transform);
-
- // get node id this pose node is for
- const ElementPtr NodeId = sc->GetElement("Node3D");
- if (NodeId) {
- target_id = ParseTokenAsInt64(GetRequiredToken(NodeId, 0));
- }
-
- print_verbose("added posenode " + itos(target_id) + " transform: " + transform);
- }
- virtual ~FbxPoseNode() {
- }
-
- uint64_t GetNodeID() const {
- return target_id;
- }
-
- Transform3D GetBindPose() const {
- return transform;
- }
-
-private:
- uint64_t target_id = 0;
- Transform3D transform;
-};
-
-/** DOM base class for FBX cameras attached to a node */
-class Camera : public NodeAttribute {
-public:
- Camera(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
- virtual ~Camera();
-
- fbx_simple_property(Position, Vector3, Vector3(0, 0, 0));
- fbx_simple_property(UpVector, Vector3, Vector3(0, 1, 0));
- fbx_simple_property(InterestPosition, Vector3, Vector3(0, 0, 0));
-
- fbx_simple_property(AspectWidth, float, 1.0f);
- fbx_simple_property(AspectHeight, float, 1.0f);
- fbx_simple_property(FilmWidth, float, 1.0f);
- fbx_simple_property(FilmHeight, float, 1.0f);
-
- fbx_simple_property(NearPlane, float, 0.1f);
- fbx_simple_property(FarPlane, float, 100.0f);
-
- fbx_simple_property(FilmAspectRatio, float, 1.0f);
- fbx_simple_property(ApertureMode, int, 0);
-
- fbx_simple_property(FieldOfView, float, 1.0f);
- fbx_simple_property(FocalLength, float, 1.0f);
-};
-
-/** DOM base class for FBX null markers attached to a node */
-class Null : public NodeAttribute {
-public:
- Null(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
- virtual ~Null();
-};
-
-/** DOM base class for FBX limb node markers attached to a node */
-class LimbNode : public NodeAttribute {
-public:
- LimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
- virtual ~LimbNode();
-};
-
-/** DOM base class for FBX lights attached to a node */
-class Light : public NodeAttribute {
-public:
- Light(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
- virtual ~Light();
-
- enum Type {
- Type_Point,
- Type_Directional,
- Type_Spot,
- Type_Area,
- Type_Volume,
-
- Type_MAX // end-of-enum sentinel
- };
-
- enum Decay {
- Decay_None,
- Decay_Linear,
- Decay_Quadratic,
- Decay_Cubic,
-
- Decay_MAX // end-of-enum sentinel
- };
-
- fbx_simple_property(Color, Vector3, Vector3(1, 1, 1));
- fbx_simple_enum_property(LightType, Type, 0);
- fbx_simple_property(CastLightOnObject, bool, false);
- fbx_simple_property(DrawVolumetricLight, bool, true);
- fbx_simple_property(DrawGroundProjection, bool, true);
- fbx_simple_property(DrawFrontFacingVolumetricLight, bool, false);
- fbx_simple_property(Intensity, float, 100.0f);
- fbx_simple_property(InnerAngle, float, 0.0f);
- fbx_simple_property(OuterAngle, float, 45.0f);
- fbx_simple_property(Fog, int, 50);
- fbx_simple_enum_property(DecayType, Decay, 2);
- fbx_simple_property(DecayStart, float, 1.0f);
- fbx_simple_property(FileName, std::string, "");
-
- fbx_simple_property(EnableNearAttenuation, bool, false);
- fbx_simple_property(NearAttenuationStart, float, 0.0f);
- fbx_simple_property(NearAttenuationEnd, float, 0.0f);
- fbx_simple_property(EnableFarAttenuation, bool, false);
- fbx_simple_property(FarAttenuationStart, float, 0.0f);
- fbx_simple_property(FarAttenuationEnd, float, 0.0f);
-
- fbx_simple_property(CastShadows, bool, true);
- fbx_simple_property(ShadowColor, Vector3, Vector3(0, 0, 0));
-
- fbx_simple_property(AreaLightShape, int, 0);
-
- fbx_simple_property(LeftBarnDoor, float, 20.0f);
- fbx_simple_property(RightBarnDoor, float, 20.0f);
- fbx_simple_property(TopBarnDoor, float, 20.0f);
- fbx_simple_property(BottomBarnDoor, float, 20.0f);
- fbx_simple_property(EnableBarnDoor, bool, true);
-};
-
-class Model;
-
-typedef Model *ModelPtr;
-#define new_Model new Model
-
-/** DOM base class for FBX models (even though its semantics are more "node" than "model" */
-class Model : public Object {
-public:
- enum RotOrder {
- RotOrder_EulerXYZ = 0,
- RotOrder_EulerXZY,
- RotOrder_EulerYZX,
- RotOrder_EulerYXZ,
- RotOrder_EulerZXY,
- RotOrder_EulerZYX,
-
- RotOrder_SphericXYZ,
-
- RotOrder_MAX // end-of-enum sentinel
- };
-
- Model(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
- virtual ~Model();
-
- fbx_simple_property(QuaternionInterpolate, int, 0);
-
- fbx_simple_property(RotationOffset, Vector3, Vector3());
- fbx_simple_property(RotationPivot, Vector3, Vector3());
- fbx_simple_property(ScalingOffset, Vector3, Vector3());
- fbx_simple_property(ScalingPivot, Vector3, Vector3());
- fbx_simple_property(TranslationActive, bool, false);
- fbx_simple_property(TranslationMin, Vector3, Vector3());
- fbx_simple_property(TranslationMax, Vector3, Vector3());
-
- fbx_simple_property(TranslationMinX, bool, false);
- fbx_simple_property(TranslationMaxX, bool, false);
- fbx_simple_property(TranslationMinY, bool, false);
- fbx_simple_property(TranslationMaxY, bool, false);
- fbx_simple_property(TranslationMinZ, bool, false);
- fbx_simple_property(TranslationMaxZ, bool, false);
-
- fbx_simple_enum_property(RotationOrder, RotOrder, 0);
- fbx_simple_property(RotationSpaceForLimitOnly, bool, false);
- fbx_simple_property(RotationStiffnessX, float, 0.0f);
- fbx_simple_property(RotationStiffnessY, float, 0.0f);
- fbx_simple_property(RotationStiffnessZ, float, 0.0f);
- fbx_simple_property(AxisLen, float, 0.0f);
-
- fbx_simple_property(PreRotation, Vector3, Vector3());
- fbx_simple_property(PostRotation, Vector3, Vector3());
- fbx_simple_property(RotationActive, bool, false);
-
- fbx_simple_property(RotationMin, Vector3, Vector3());
- fbx_simple_property(RotationMax, Vector3, Vector3());
-
- fbx_simple_property(RotationMinX, bool, false);
- fbx_simple_property(RotationMaxX, bool, false);
- fbx_simple_property(RotationMinY, bool, false);
- fbx_simple_property(RotationMaxY, bool, false);
- fbx_simple_property(RotationMinZ, bool, false);
- fbx_simple_property(RotationMaxZ, bool, false);
- fbx_simple_enum_property(InheritType, TransformInheritance, 0);
-
- fbx_simple_property(ScalingActive, bool, false);
- fbx_simple_property(ScalingMin, Vector3, Vector3());
- fbx_simple_property(ScalingMax, Vector3, Vector3(1, 1, 1));
- fbx_simple_property(ScalingMinX, bool, false);
- fbx_simple_property(ScalingMaxX, bool, false);
- fbx_simple_property(ScalingMinY, bool, false);
- fbx_simple_property(ScalingMaxY, bool, false);
- fbx_simple_property(ScalingMinZ, bool, false);
- fbx_simple_property(ScalingMaxZ, bool, false);
-
- fbx_simple_property(GeometricTranslation, Vector3, Vector3());
- fbx_simple_property(GeometricRotation, Vector3, Vector3());
- fbx_simple_property(GeometricScaling, Vector3, Vector3(1, 1, 1));
-
- fbx_simple_property(MinDampRangeX, float, 0.0f);
- fbx_simple_property(MinDampRangeY, float, 0.0f);
- fbx_simple_property(MinDampRangeZ, float, 0.0f);
- fbx_simple_property(MaxDampRangeX, float, 0.0f);
- fbx_simple_property(MaxDampRangeY, float, 0.0f);
- fbx_simple_property(MaxDampRangeZ, float, 0.0f);
-
- fbx_simple_property(MinDampStrengthX, float, 0.0f);
- fbx_simple_property(MinDampStrengthY, float, 0.0f);
- fbx_simple_property(MinDampStrengthZ, float, 0.0f);
- fbx_simple_property(MaxDampStrengthX, float, 0.0f);
- fbx_simple_property(MaxDampStrengthY, float, 0.0f);
- fbx_simple_property(MaxDampStrengthZ, float, 0.0f);
-
- fbx_simple_property(PreferredAngleX, float, 0.0f);
- fbx_simple_property(PreferredAngleY, float, 0.0f);
- fbx_simple_property(PreferredAngleZ, float, 0.0f);
-
- fbx_simple_property(Show, bool, true);
- fbx_simple_property(LODBox, bool, false);
- fbx_simple_property(Freeze, bool, false);
-
- const std::string &Shading() const {
- return shading;
- }
-
- const std::string &Culling() const {
- return culling;
- }
-
- /** Get material links */
- const std::vector<const Material *> &GetMaterials() const {
- return materials;
- }
-
- /** Get geometry links */
- const std::vector<const Geometry *> &GetGeometry() const {
- return geometry;
- }
-
- /** Get node attachments */
- const std::vector<const NodeAttribute *> &GetAttributes() const {
- return attributes;
- }
-
- /** convenience method to check if the node has a Null node marker */
- bool IsNull() const;
-
-private:
- void ResolveLinks(const ElementPtr element, const Document &doc);
-
-private:
- std::vector<const Material *> materials;
- std::vector<const Geometry *> geometry;
- std::vector<const NodeAttribute *> attributes;
-
- std::string shading;
- std::string culling;
-};
-
-class ModelLimbNode : public Model {
-public:
- ModelLimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
- virtual ~ModelLimbNode();
-};
-
-/** DOM class for generic FBX textures */
-class Texture : public Object {
-public:
- Texture(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
- virtual ~Texture();
-
- const std::string &Type() const {
- return type;
- }
-
- const std::string &FileName() const {
- return fileName;
- }
-
- const std::string &RelativeFilename() const {
- return relativeFileName;
- }
-
- const std::string &AlphaSource() const {
- return alphaSource;
- }
-
- const Vector2 &UVTranslation() const {
- return uvTrans;
- }
-
- const Vector2 &UVScaling() const {
- return uvScaling;
- }
-
- // return a 4-tuple
- const unsigned int *Crop() const {
- return crop;
- }
-
- const Video *Media() const {
- return media;
- }
-
-private:
- Vector2 uvTrans;
- Vector2 uvScaling;
-
- std::string type;
- std::string relativeFileName;
- std::string fileName;
- std::string alphaSource;
-
- unsigned int crop[4] = { 0 };
- const Video *media = nullptr;
-};
-
-/** DOM class for layered FBX textures */
-class LayeredTexture : public Object {
-public:
- LayeredTexture(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
- virtual ~LayeredTexture();
-
- // Can only be called after construction of the layered texture object due to construction flag.
- void fillTexture(const Document &doc);
-
- enum BlendMode {
- BlendMode_Translucent,
- BlendMode_Additive,
- BlendMode_Modulate,
- BlendMode_Modulate2,
- BlendMode_Over,
- BlendMode_Normal,
- BlendMode_Dissolve,
- BlendMode_Darken,
- BlendMode_ColorBurn,
- BlendMode_LinearBurn,
- BlendMode_DarkerColor,
- BlendMode_Lighten,
- BlendMode_Screen,
- BlendMode_ColorDodge,
- BlendMode_LinearDodge,
- BlendMode_LighterColor,
- BlendMode_SoftLight,
- BlendMode_HardLight,
- BlendMode_VividLight,
- BlendMode_LinearLight,
- BlendMode_PinLight,
- BlendMode_HardMix,
- BlendMode_Difference,
- BlendMode_Exclusion,
- BlendMode_Subtract,
- BlendMode_Divide,
- BlendMode_Hue,
- BlendMode_Saturation,
- BlendMode_Color,
- BlendMode_Luminosity,
- BlendMode_Overlay,
- BlendMode_BlendModeCount
- };
-
- const Texture *getTexture(int index = 0) const {
- return textures[index];
- }
- int textureCount() const {
- return static_cast<int>(textures.size());
- }
- BlendMode GetBlendMode() const {
- return blendMode;
- }
- float Alpha() {
- return alpha;
- }
-
-private:
- std::vector<const Texture *> textures;
- BlendMode blendMode = BlendMode::BlendMode_Additive;
- float alpha = 0;
-};
-
-typedef std::map<std::string, const Texture *> TextureMap;
-typedef std::map<std::string, const LayeredTexture *> LayeredTextureMap;
-
-/** DOM class for generic FBX videos */
-class Video : public Object {
-public:
- Video(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
-
- virtual ~Video();
-
- const std::string &Type() const {
- return type;
- }
-
- bool IsEmbedded() const {
- return contentLength > 0;
- }
-
- const std::string &FileName() const {
- return fileName;
- }
-
- const std::string &RelativeFilename() const {
- return relativeFileName;
- }
-
- const uint8_t *Content() const {
- return content;
- }
-
- uint64_t ContentLength() const {
- return contentLength;
- }
-
- uint8_t *RelinquishContent() {
- uint8_t *ptr = content;
- content = nullptr;
- return ptr;
- }
-
- bool operator==(const Video &other) const {
- return (
- type == other.type && relativeFileName == other.relativeFileName && fileName == other.fileName);
- }
-
- bool operator<(const Video &other) const {
- return std::tie(type, relativeFileName, fileName) < std::tie(other.type, other.relativeFileName, other.fileName);
- }
-
-private:
- std::string type;
- std::string relativeFileName;
- std::string fileName;
-
- uint64_t contentLength = 0;
- uint8_t *content = nullptr;
-};
-
-/** DOM class for generic FBX materials */
-class Material : public Object {
-public:
- Material(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
-
- virtual ~Material();
-
- const std::string &GetShadingModel() const {
- return shading;
- }
-
- bool IsMultilayer() const {
- return multilayer;
- }
-
- const TextureMap &Textures() const {
- return textures;
- }
-
- const LayeredTextureMap &LayeredTextures() const {
- return layeredTextures;
- }
-
-private:
- std::string shading;
- bool multilayer = false;
-
- TextureMap textures;
- LayeredTextureMap layeredTextures;
-};
-
-// signed int keys (this can happen!)
-typedef std::vector<int64_t> KeyTimeList;
-typedef std::vector<float> KeyValueList;
-
-/** Represents a FBX animation curve (i.e. a 1-dimensional set of keyframes and values therefore) */
-class AnimationCurve : public Object {
-public:
- AnimationCurve(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc);
- virtual ~AnimationCurve();
-
- /** get list of keyframe positions (time).
- * Invariant: |GetKeys()| > 0 */
- const KeyTimeList &GetKeys() const {
- return keys;
- }
-
- /** get list of keyframe values.
- * Invariant: |GetKeys()| == |GetValues()| && |GetKeys()| > 0*/
- const KeyValueList &GetValues() const {
- return values;
- }
-
- const std::map<int64_t, float> &GetValueTimeTrack() const {
- return keyvalues;
- }
-
- const std::vector<float> &GetAttributes() const {
- return attributes;
- }
-
- const std::vector<unsigned int> &GetFlags() const {
- return flags;
- }
-
-private:
- KeyTimeList keys;
- KeyValueList values;
- std::vector<float> attributes;
- std::map<int64_t, float> keyvalues;
- std::vector<unsigned int> flags;
-};
-
-/* Typedef for pointers for the animation handler */
-typedef std::shared_ptr<AnimationCurve> AnimationCurvePtr;
-typedef std::weak_ptr<AnimationCurve> AnimationCurveWeakPtr;
-typedef std::map<std::string, const AnimationCurve *> AnimationMap;
-
-/* Animation Curve node ptr */
-typedef std::shared_ptr<AnimationCurveNode> AnimationCurveNodePtr;
-typedef std::weak_ptr<AnimationCurveNode> AnimationCurveNodeWeakPtr;
-
-/** Represents a FBX animation curve (i.e. a mapping from single animation curves to nodes) */
-class AnimationCurveNode : public Object {
-public:
- /* the optional white list specifies a list of property names for which the caller
- wants animations for. If the curve node does not match one of these, std::range_error
- will be thrown. */
- AnimationCurveNode(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc,
- const char *const *target_prop_whitelist = nullptr, size_t whitelist_size = 0);
-
- virtual ~AnimationCurveNode();
-
- const AnimationMap &Curves() const;
-
- /** Object the curve is assigned to, this can be nullptr if the
- * target object has no DOM representation or could not
- * be read for other reasons.*/
- Object *Target() const {
- return target;
- }
-
- Model *TargetAsModel() const {
- return dynamic_cast<Model *>(target);
- }
-
- NodeAttribute *TargetAsNodeAttribute() const {
- return dynamic_cast<NodeAttribute *>(target);
- }
-
- /** Property of Target() that is being animated*/
- const std::string &TargetProperty() const {
- return prop;
- }
-
-private:
- Object *target = nullptr;
- mutable AnimationMap curves;
- std::string prop;
- const Document &doc;
-};
-
-typedef std::vector<const AnimationCurveNode *> AnimationCurveNodeList;
-
-typedef std::shared_ptr<AnimationLayer> AnimationLayerPtr;
-typedef std::weak_ptr<AnimationLayer> AnimationLayerWeakPtr;
-typedef std::vector<const AnimationLayer *> AnimationLayerList;
-
-/** Represents a FBX animation layer (i.e. a list of node animations) */
-class AnimationLayer : public Object {
-public:
- AnimationLayer(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc);
- virtual ~AnimationLayer();
-
- /* the optional white list specifies a list of property names for which the caller
- wants animations for. Curves not matching this list will not be added to the
- animation layer. */
- const AnimationCurveNodeList Nodes(const char *const *target_prop_whitelist = nullptr, size_t whitelist_size = 0) const;
-
-private:
- const Document &doc;
-};
-
-/** Represents a FBX animation stack (i.e. a list of animation layers) */
-class AnimationStack : public Object {
-public:
- AnimationStack(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc);
- virtual ~AnimationStack();
-
- fbx_simple_property(LocalStart, int64_t, 0L);
- fbx_simple_property(LocalStop, int64_t, 0L);
- fbx_simple_property(ReferenceStart, int64_t, 0L);
- fbx_simple_property(ReferenceStop, int64_t, 0L);
-
- const AnimationLayerList &Layers() const {
- return layers;
- }
-
-private:
- AnimationLayerList layers;
-};
-
-/** DOM class for deformers */
-class Deformer : public Object {
-public:
- Deformer(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
- virtual ~Deformer();
-};
-
-/** Constraints are from Maya they can help us with BoneAttachments :) **/
-class Constraint : public Object {
-public:
- Constraint(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
- virtual ~Constraint();
-};
-
-typedef std::vector<float> WeightArray;
-typedef std::vector<unsigned int> WeightIndexArray;
-
-/** DOM class for BlendShapeChannel deformers */
-class BlendShapeChannel : public Deformer {
-public:
- BlendShapeChannel(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
-
- virtual ~BlendShapeChannel();
-
- float DeformPercent() const {
- return percent;
- }
-
- const WeightArray &GetFullWeights() const {
- return fullWeights;
- }
-
- const std::vector<const ShapeGeometry *> &GetShapeGeometries() const {
- return shapeGeometries;
- }
-
-private:
- float percent = 0;
- WeightArray fullWeights;
- std::vector<const ShapeGeometry *> shapeGeometries;
-};
-
-/** DOM class for BlendShape deformers */
-class BlendShape : public Deformer {
-public:
- BlendShape(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
-
- virtual ~BlendShape();
-
- const std::vector<const BlendShapeChannel *> &BlendShapeChannels() const {
- return blendShapeChannels;
- }
-
-private:
- std::vector<const BlendShapeChannel *> blendShapeChannels;
-};
-
-/** DOM class for skin deformer clusters (aka sub-deformers) */
-class Cluster : public Deformer {
-public:
- Cluster(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
-
- virtual ~Cluster();
-
- /** get the list of deformer weights associated with this cluster.
- * Use #GetIndices() to get the associated vertices. Both arrays
- * have the same size (and may also be empty). */
- const std::vector<float> &GetWeights() const {
- return weights;
- }
-
- /** get indices into the vertex data of the geometry associated
- * with this cluster. Use #GetWeights() to get the associated weights.
- * Both arrays have the same size (and may also be empty). */
- const std::vector<unsigned int> &GetIndices() const {
- return indices;
- }
-
- /** */
- const Transform3D &GetTransform() const {
- return transform;
- }
-
- const Transform3D &TransformLink() const {
- return transformLink;
- }
-
- const Model *TargetNode() const {
- return node;
- }
-
- const Transform3D &TransformAssociateModel() const {
- return transformAssociateModel;
- }
-
- bool TransformAssociateModelValid() const {
- return valid_transformAssociateModel;
- }
-
- // property is not in the fbx file
- // if the cluster has an associate model
- // we then have an additive type
- enum SkinLinkMode {
- SkinLinkMode_Normalized = 0,
- SkinLinkMode_Additive = 1
- };
-
- SkinLinkMode GetLinkMode() {
- return link_mode;
- }
-
-private:
- std::vector<float> weights;
- std::vector<unsigned int> indices;
-
- Transform3D transform;
- Transform3D transformLink;
- Transform3D transformAssociateModel;
- SkinLinkMode link_mode;
- bool valid_transformAssociateModel = false;
- const Model *node = nullptr;
-};
-
-/** DOM class for skin deformers */
-class Skin : public Deformer {
-public:
- Skin(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
-
- virtual ~Skin();
-
- float DeformAccuracy() const {
- return accuracy;
- }
-
- const std::vector<const Cluster *> &Clusters() const {
- return clusters;
- }
-
- enum SkinType {
- Skin_Rigid = 0,
- Skin_Linear,
- Skin_DualQuaternion,
- Skin_Blend
- };
-
- const SkinType &GetSkinType() const {
- return skinType;
- }
-
-private:
- float accuracy = 0;
- SkinType skinType = SkinType::Skin_Linear;
- std::vector<const Cluster *> clusters;
-};
-
-/** Represents a link between two FBX objects. */
-class Connection {
-public:
- Connection(uint64_t insertionOrder, uint64_t src, uint64_t dest, const std::string &prop, const Document &doc);
- ~Connection();
-
- // note: a connection ensures that the source and dest objects exist, but
- // not that they have DOM representations, so the return value of one of
- // these functions can still be nullptr.
- Object *SourceObject() const;
- Object *DestinationObject() const;
-
- // these, however, are always guaranteed to be valid
- LazyObject *LazySourceObject() const;
- LazyObject *LazyDestinationObject() const;
-
- /** return the name of the property the connection is attached to.
- * this is an empty string for object to object (OO) connections. */
- const std::string &PropertyName() const {
- return prop;
- }
-
- uint64_t InsertionOrder() const {
- return insertionOrder;
- }
-
- int CompareTo(const Connection *c) const {
- //ai_assert(nullptr != c);
-
- // note: can't subtract because this would overflow uint64_t
- if (InsertionOrder() > c->InsertionOrder()) {
- return 1;
- } else if (InsertionOrder() < c->InsertionOrder()) {
- return -1;
- }
- return 0;
- }
-
- bool Compare(const Connection *c) const {
- //ai_assert(nullptr != c);
-
- return InsertionOrder() < c->InsertionOrder();
- }
-
-public:
- uint64_t insertionOrder = 0;
- const std::string prop;
-
- uint64_t src = 0, dest = 0;
- const Document &doc;
-};
-
-// XXX again, unique_ptr would be useful. shared_ptr is too
-// bloated since the objects have a well-defined single owner
-// during their entire lifetime (Document). FBX files have
-// up to many thousands of objects (most of which we never use),
-// so the memory overhead for them should be kept at a minimum.
-typedef std::map<uint64_t, LazyObject *> ObjectMap;
-typedef std::map<std::string, const PropertyTable *> PropertyTemplateMap;
-typedef std::multimap<uint64_t, const Connection *> ConnectionMap;
-
-/** DOM class for global document settings, a single instance per document can
- * be accessed via Document.Globals(). */
-class FileGlobalSettings : public PropertyTable {
-public:
- FileGlobalSettings(const Document &doc);
- virtual ~FileGlobalSettings();
-
- const Document &GetDocument() const {
- return doc;
- }
-
- fbx_simple_property(UpAxis, int, 1);
- fbx_simple_property(UpAxisSign, int, 1);
- fbx_simple_property(FrontAxis, int, 2);
- fbx_simple_property(FrontAxisSign, int, 1);
- fbx_simple_property(CoordAxis, int, 0);
- fbx_simple_property(CoordAxisSign, int, 1);
- fbx_simple_property(OriginalUpAxis, int, 0);
- fbx_simple_property(OriginalUpAxisSign, int, 1);
- fbx_simple_property(UnitScaleFactor, float, 1);
- fbx_simple_property(OriginalUnitScaleFactor, float, 1);
- fbx_simple_property(AmbientColor, Vector3, Vector3(0, 0, 0));
- fbx_simple_property(DefaultCamera, std::string, "");
-
- enum FrameRate {
- FrameRate_DEFAULT = 0,
- FrameRate_120 = 1,
- FrameRate_100 = 2,
- FrameRate_60 = 3,
- FrameRate_50 = 4,
- FrameRate_48 = 5,
- FrameRate_30 = 6,
- FrameRate_30_DROP = 7,
- FrameRate_NTSC_DROP_FRAME = 8,
- FrameRate_NTSC_FULL_FRAME = 9,
- FrameRate_PAL = 10,
- FrameRate_CINEMA = 11,
- FrameRate_1000 = 12,
- FrameRate_CINEMA_ND = 13,
- FrameRate_CUSTOM = 14,
-
- FrameRate_MAX // end-of-enum sentinel
- };
-
- fbx_simple_enum_property(TimeMode, FrameRate, FrameRate_DEFAULT);
- fbx_simple_property(TimeSpanStart, uint64_t, 0L);
- fbx_simple_property(TimeSpanStop, uint64_t, 0L);
- fbx_simple_property(CustomFrameRate, float, -1.0f);
-
-private:
- const Document &doc;
-};
-
-/** DOM root for a FBX file */
-class Document {
-public:
- Document(const Parser &parser, const ImportSettings &settings);
-
- ~Document();
-
- LazyObject *GetObject(uint64_t id) const;
-
- bool IsSafeToImport() const {
- return SafeToImport;
- }
-
- bool IsBinary() const {
- return parser.IsBinary();
- }
-
- unsigned int FBXVersion() const {
- return fbxVersion;
- }
-
- const std::string &Creator() const {
- return creator;
- }
-
- // elements (in this order): Year, Month, Day, Hour, Second, Millisecond
- const unsigned int *CreationTimeStamp() const {
- return creationTimeStamp;
- }
-
- const FileGlobalSettings *GlobalSettingsPtr() const {
- return globals.get();
- }
-
- const PropertyTable &GetMetadataProperties() const {
- return metadata_properties;
- }
-
- const PropertyTemplateMap &Templates() const {
- return templates;
- }
-
- const ObjectMap &Objects() const {
- return objects;
- }
-
- const ImportSettings &Settings() const {
- return settings;
- }
-
- const ConnectionMap &ConnectionsBySource() const {
- return src_connections;
- }
-
- const ConnectionMap &ConnectionsByDestination() const {
- return dest_connections;
- }
-
- // note: the implicit rule in all DOM classes is to always resolve
- // from destination to source (since the FBX object hierarchy is,
- // with very few exceptions, a DAG, this avoids cycles). In all
- // cases that may involve back-facing edges in the object graph,
- // use LazyObject::IsBeingConstructed() to check.
-
- std::vector<const Connection *> GetConnectionsBySourceSequenced(uint64_t source) const;
- std::vector<const Connection *> GetConnectionsByDestinationSequenced(uint64_t dest) const;
-
- std::vector<const Connection *> GetConnectionsBySourceSequenced(uint64_t source, const char *classname) const;
- std::vector<const Connection *> GetConnectionsByDestinationSequenced(uint64_t dest, const char *classname) const;
-
- std::vector<const Connection *> GetConnectionsBySourceSequenced(uint64_t source,
- const char *const *classnames, size_t count) const;
- std::vector<const Connection *> GetConnectionsByDestinationSequenced(uint64_t dest,
- const char *const *classnames,
- size_t count) const;
-
- const std::vector<const AnimationStack *> &AnimationStacks() const;
- const std::vector<uint64_t> &GetAnimationStackIDs() const {
- return animationStacks;
- }
-
- const std::vector<uint64_t> &GetConstraintStackIDs() const {
- return constraints;
- }
-
- const std::vector<uint64_t> &GetBindPoseIDs() const {
- return bind_poses;
- };
-
- const std::vector<uint64_t> &GetMaterialIDs() const {
- return materials;
- };
-
- const std::vector<uint64_t> &GetSkinIDs() const {
- return skins;
- }
-
-private:
- std::vector<const Connection *> GetConnectionsSequenced(uint64_t id, const ConnectionMap &) const;
- std::vector<const Connection *> GetConnectionsSequenced(uint64_t id, bool is_src,
- const ConnectionMap &,
- const char *const *classnames,
- size_t count) const;
- bool ReadHeader();
- void ReadObjects();
- void ReadPropertyTemplates();
- void ReadConnections();
- void ReadGlobalSettings();
-
-private:
- const ImportSettings &settings;
-
- ObjectMap objects;
- const Parser &parser;
- bool SafeToImport = false;
-
- PropertyTemplateMap templates;
- ConnectionMap src_connections;
- ConnectionMap dest_connections;
-
- unsigned int fbxVersion = 0;
- std::string creator;
- unsigned int creationTimeStamp[7] = { 0 };
-
- std::vector<uint64_t> animationStacks;
- std::vector<uint64_t> bind_poses;
- // constraints aren't in the tree / at least they are not easy to access.
- std::vector<uint64_t> constraints;
- std::vector<uint64_t> materials;
- std::vector<uint64_t> skins;
- mutable std::vector<const AnimationStack *> animationStacksResolved;
- PropertyTable metadata_properties;
- std::shared_ptr<FileGlobalSettings> globals = nullptr;
-};
-} // namespace FBXDocParser
-
-namespace std {
-template <>
-struct hash<const FBXDocParser::Video> {
- std::size_t operator()(const FBXDocParser::Video &video) const {
- using std::hash;
- using std::size_t;
- using std::string;
-
- size_t res = 17;
- res = res * 31 + hash<string>()(video.Name());
- res = res * 31 + hash<string>()(video.RelativeFilename());
- res = res * 31 + hash<string>()(video.Type());
-
- return res;
- }
-};
-} // namespace std
-
-#endif // FBX_DOCUMENT_H
diff --git a/modules/fbx/fbx_parser/FBXDocumentUtil.cpp b/modules/fbx/fbx_parser/FBXDocumentUtil.cpp
deleted file mode 100644
index 4ee8a42b33..0000000000
--- a/modules/fbx/fbx_parser/FBXDocumentUtil.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-/*************************************************************************/
-/* FBXDocumentUtil.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, assimp team
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
-
-* Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-
-/** @file FBXDocumentUtil.cpp
- * @brief Implementation of the FBX DOM utility functions declared in FBXDocumentUtil.h
- */
-
-#include "FBXDocumentUtil.h"
-#include "FBXDocument.h"
-#include "FBXParser.h"
-#include "FBXProperties.h"
-#include "FBXUtil.h"
-#include "core/string/print_string.h"
-
-namespace FBXDocParser {
-namespace Util {
-
-void DOMError(const std::string &message) {
- print_error("[FBX-DOM]" + String(message.c_str()));
-}
-
-void DOMError(const std::string &message, const Token *token) {
- print_error("[FBX-DOM]" + String(message.c_str()) + ";" + String(token->StringContents().c_str()));
-}
-
-void DOMError(const std::string &message, const std::shared_ptr<Token> token) {
- print_error("[FBX-DOM]" + String(message.c_str()) + ";" + String(token->StringContents().c_str()));
-}
-
-void DOMError(const std::string &message, const Element *element /*= nullptr*/) {
- if (element) {
- DOMError(message, element->KeyToken());
- }
- print_error("[FBX-DOM] " + String(message.c_str()));
-}
-
-void DOMError(const std::string &message, const std::shared_ptr<Element> element /*= nullptr*/) {
- if (element) {
- DOMError(message, element->KeyToken());
- }
- print_error("[FBX-DOM] " + String(message.c_str()));
-}
-
-void DOMWarning(const std::string &message) {
- print_verbose("[FBX-DOM] warning:" + String(message.c_str()));
-}
-
-void DOMWarning(const std::string &message, const Token *token) {
- print_verbose("[FBX-DOM] warning:" + String(message.c_str()) + ";" + String(token->StringContents().c_str()));
-}
-
-void DOMWarning(const std::string &message, const Element *element /*= nullptr*/) {
- if (element) {
- DOMWarning(message, element->KeyToken());
- return;
- }
- print_verbose("[FBX-DOM] warning:" + String(message.c_str()));
-}
-
-void DOMWarning(const std::string &message, const std::shared_ptr<Token> token) {
- print_verbose("[FBX-DOM] warning:" + String(message.c_str()) + ";" + String(token->StringContents().c_str()));
-}
-
-void DOMWarning(const std::string &message, const std::shared_ptr<Element> element /*= nullptr*/) {
- if (element) {
- DOMWarning(message, element->KeyToken());
- return;
- }
- print_verbose("[FBX-DOM] warning:" + String(message.c_str()));
-}
-
-} // namespace Util
-} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXDocumentUtil.h b/modules/fbx/fbx_parser/FBXDocumentUtil.h
deleted file mode 100644
index 61c92dbc83..0000000000
--- a/modules/fbx/fbx_parser/FBXDocumentUtil.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*************************************************************************/
-/* FBXDocumentUtil.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2012, assimp team
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
-
-* Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-
-/** @file FBXDocumentUtil.h
- * @brief FBX internal utilities used by the DOM reading code
- */
-#ifndef FBX_DOCUMENT_UTIL_H
-#define FBX_DOCUMENT_UTIL_H
-
-#include "FBXDocument.h"
-#include <memory>
-#include <string>
-
-struct Token;
-struct Element;
-
-namespace FBXDocParser {
-namespace Util {
-
-// Parser errors
-void DOMError(const std::string &message);
-void DOMError(const std::string &message, const Token *token);
-void DOMError(const std::string &message, const Element *element);
-void DOMError(const std::string &message, const std::shared_ptr<Element> element);
-void DOMError(const std::string &message, const std::shared_ptr<Token> token);
-
-// Parser warnings
-void DOMWarning(const std::string &message);
-void DOMWarning(const std::string &message, const Token *token);
-void DOMWarning(const std::string &message, const Element *element);
-void DOMWarning(const std::string &message, const std::shared_ptr<Token> token);
-void DOMWarning(const std::string &message, const std::shared_ptr<Element> element);
-
-// ------------------------------------------------------------------------------------------------
-template <typename T>
-const T *ProcessSimpleConnection(const Connection &con,
- bool is_object_property_conn,
- const char *name,
- const ElementPtr element,
- const char **propNameOut = nullptr) {
- if (is_object_property_conn && !con.PropertyName().length()) {
- DOMWarning("expected incoming " + std::string(name) +
- " link to be an object-object connection, ignoring",
- element);
- return nullptr;
- } else if (!is_object_property_conn && con.PropertyName().length()) {
- DOMWarning("expected incoming " + std::string(name) +
- " link to be an object-property connection, ignoring",
- element);
- return nullptr;
- }
-
- if (is_object_property_conn && propNameOut) {
- // note: this is ok, the return value of PropertyValue() is guaranteed to
- // remain valid and unchanged as long as the document exists.
- *propNameOut = con.PropertyName().c_str();
- }
-
- // Cast Object to AnimationPlayer for example using safe functions, which return nullptr etc
- Object *ob = con.SourceObject();
- ERR_FAIL_COND_V_MSG(!ob, nullptr, "Failed to load object from SourceObject ptr");
- return dynamic_cast<const T *>(ob);
-}
-} // namespace Util
-} // namespace FBXDocParser
-
-#endif // FBX_DOCUMENT_UTIL_H
diff --git a/modules/fbx/fbx_parser/FBXImportSettings.h b/modules/fbx/fbx_parser/FBXImportSettings.h
deleted file mode 100644
index fa93f275c2..0000000000
--- a/modules/fbx/fbx_parser/FBXImportSettings.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/*************************************************************************/
-/* FBXImportSettings.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, assimp team
-
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
-
-* Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-
-/** @file FBXImportSettings.h
- * @brief FBX importer runtime configuration
- */
-#ifndef FBX_IMPORT_SETTINGS_H
-#define FBX_IMPORT_SETTINGS_H
-
-namespace FBXDocParser {
-
-/** FBX import settings, parts of which are publicly accessible via their corresponding AI_CONFIG constants */
-struct ImportSettings {
- /** enable strict mode:
- * - only accept fbx 2012, 2013 files
- * - on the slightest error, give up.
- *
- * Basically, strict mode means that the fbx file will actually
- * be validated.*/
- bool strictMode = true;
-
- /** specifies whether all geometry layers are read and scanned for
- * usable data channels. The FBX spec indicates that many readers
- * will only read the first channel and that this is in some way
- * the recommended way- in reality, however, it happens a lot that
- * vertex data is spread among multiple layers.*/
- bool readAllLayers = true;
-
- /** specifies whether all materials are read, or only those that
- * are referenced by at least one mesh. Reading all materials
- * may make FBX reading a lot slower since all objects
- * need to be processed.
- * This bit is ignored unless readMaterials=true.*/
- bool readAllMaterials = true;
-
- /** import materials (true) or skip them and assign a default
- * material.*/
- bool readMaterials = true;
-
- /** import embedded textures?*/
- bool readTextures = true;
-
- /** import cameras?*/
- bool readCameras = true;
-
- /** import light sources?*/
- bool readLights = true;
-
- /** import animations (i.e. animation curves, the node
- * skeleton is always imported).*/
- bool readAnimations = true;
-
- /** read bones (vertex weights and deform info).*/
- bool readWeights = true;
-
- /** preserve transformation pivots and offsets. Since these can
- * not directly be represented in assimp, additional dummy
- * nodes will be generated. Note that settings this to false
- * can make animation import a lot slower.
- *
- * The naming scheme for the generated nodes is:
- * <OriginalName>_$AssimpFbx$_<TransformName>
- *
- * where <TransformName> is one of
- * RotationPivot
- * RotationOffset
- * PreRotation
- * PostRotation
- * ScalingPivot
- * ScalingOffset
- * Translation
- * Scaling
- * Rotation
- **/
- bool preservePivots = true;
-
- /** do not import animation curves that specify a constant
- * values matching the corresponding node transformation.*/
- bool optimizeEmptyAnimationCurves = true;
-
- /** use legacy naming for embedded textures eg: (*0, *1, *2).*/
- bool useLegacyEmbeddedTextureNaming = false;
-
- /** Empty bones shall be removed.*/
- bool removeEmptyBones = true;
-
- /** Set to true to perform a conversion from cm to meter after
- * the import.*/
- bool convertToMeters = false;
-};
-} // namespace FBXDocParser
-
-#endif // FBX_IMPORT_SETTINGS_H
diff --git a/modules/fbx/fbx_parser/FBXMaterial.cpp b/modules/fbx/fbx_parser/FBXMaterial.cpp
deleted file mode 100644
index e4ee77e850..0000000000
--- a/modules/fbx/fbx_parser/FBXMaterial.cpp
+++ /dev/null
@@ -1,388 +0,0 @@
-/*************************************************************************/
-/* FBXMaterial.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2020, assimp team
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
-
-* Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-
-/** @file FBXMaterial.cpp
- * @brief Assimp::FBX::Material and Assimp::FBX::Texture implementation
- */
-
-#include "ByteSwapper.h"
-#include "FBXDocument.h"
-#include "FBXDocumentUtil.h"
-#include "FBXImportSettings.h"
-#include "FBXParser.h"
-#include "FBXProperties.h"
-
-#include "FBXUtil.h"
-#include <algorithm> // std::transform
-
-namespace FBXDocParser {
-
-using namespace Util;
-
-// ------------------------------------------------------------------------------------------------
-Material::Material(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
- Object(id, element, name) {
- const ScopePtr sc = GetRequiredScope(element);
-
- const ElementPtr ShadingModel = sc->GetElement("ShadingModel");
- const ElementPtr MultiLayer = sc->GetElement("MultiLayer");
-
- if (MultiLayer) {
- multilayer = !!ParseTokenAsInt(GetRequiredToken(MultiLayer, 0));
- }
-
- if (ShadingModel) {
- shading = ParseTokenAsString(GetRequiredToken(ShadingModel, 0));
- } else {
- DOMWarning("shading mode not specified, assuming phong", element);
- shading = "phong";
- }
-
- std::string templateName;
-
- if (shading == "phong") {
- templateName = "Material.Phong";
- } else if (shading == "lambert") {
- templateName = "Material.Lambert";
- } else if (shading == "unknown") {
- templateName = "Material.StingRay";
- } else {
- DOMWarning("shading mode not recognized: " + shading, element);
- }
-
- // resolve texture links
- const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID());
- for (const Connection *con : conns) {
- // texture link to properties, not objects
- if (!con->PropertyName().length()) {
- continue;
- }
-
- Object *ob = con->SourceObject();
- if (!ob) {
- DOMWarning("failed to read source object for texture link, ignoring", element);
- continue;
- }
-
- const Texture *tex = dynamic_cast<const Texture *>(ob);
- if (!tex) {
- LayeredTexture *layeredTexture = dynamic_cast<LayeredTexture *>(ob);
-
- if (!layeredTexture) {
- DOMWarning("source object for texture link is not a texture or layered texture, ignoring", element);
- continue;
- }
-
- const std::string &prop = con->PropertyName();
- if (layeredTextures.find(prop) != layeredTextures.end()) {
- DOMWarning("duplicate layered texture link: " + prop, element);
- }
-
- layeredTextures[prop] = layeredTexture;
- layeredTexture->fillTexture(doc);
- } else {
- const std::string &prop = con->PropertyName();
- if (textures.find(prop) != textures.end()) {
- DOMWarning("duplicate texture link: " + prop, element);
- }
-
- textures[prop] = tex;
- }
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-Material::~Material() {
-}
-
-// ------------------------------------------------------------------------------------------------
-Texture::Texture(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
- Object(id, element, name), uvScaling(1.0f, 1.0f) {
- const ScopePtr sc = GetRequiredScope(element);
-
- const ElementPtr Type = sc->GetElement("Type");
- const ElementPtr FileName = sc->GetElement("FileName");
- const ElementPtr RelativeFilename = sc->GetElement("RelativeFilename");
- const ElementPtr ModelUVTranslation = sc->GetElement("ModelUVTranslation");
- const ElementPtr ModelUVScaling = sc->GetElement("ModelUVScaling");
- const ElementPtr Texture_Alpha_Source = sc->GetElement("Texture_Alpha_Source");
- const ElementPtr Cropping = sc->GetElement("Cropping");
-
- if (Type) {
- type = ParseTokenAsString(GetRequiredToken(Type, 0));
- }
-
- if (FileName) {
- fileName = ParseTokenAsString(GetRequiredToken(FileName, 0));
- }
-
- if (RelativeFilename) {
- relativeFileName = ParseTokenAsString(GetRequiredToken(RelativeFilename, 0));
- }
-
- if (ModelUVTranslation) {
- uvTrans = Vector2(ParseTokenAsFloat(GetRequiredToken(ModelUVTranslation, 0)),
- ParseTokenAsFloat(GetRequiredToken(ModelUVTranslation, 1)));
- }
-
- if (ModelUVScaling) {
- uvScaling = Vector2(ParseTokenAsFloat(GetRequiredToken(ModelUVScaling, 0)),
- ParseTokenAsFloat(GetRequiredToken(ModelUVScaling, 1)));
- }
-
- if (Cropping) {
- crop[0] = ParseTokenAsInt(GetRequiredToken(Cropping, 0));
- crop[1] = ParseTokenAsInt(GetRequiredToken(Cropping, 1));
- crop[2] = ParseTokenAsInt(GetRequiredToken(Cropping, 2));
- crop[3] = ParseTokenAsInt(GetRequiredToken(Cropping, 3));
- } else {
- // vc8 doesn't support the crop() syntax in initialization lists
- // (and vc9 WARNS about the new (i.e. compliant) behaviour).
- crop[0] = crop[1] = crop[2] = crop[3] = 0;
- }
-
- if (Texture_Alpha_Source) {
- alphaSource = ParseTokenAsString(GetRequiredToken(Texture_Alpha_Source, 0));
- }
-
- // 3DS Max and FBX SDK use "Scaling" and "Translation" instead of "ModelUVScaling" and "ModelUVTranslation". Use these properties if available.
- bool ok = true;
- const Vector3 &scaling = PropertyGet<Vector3>(this, "Scaling", ok);
- if (ok) {
- uvScaling.x = scaling.x;
- uvScaling.y = scaling.y;
- }
-
- const Vector3 &trans = PropertyGet<Vector3>(this, "Translation", ok);
- if (ok) {
- uvTrans.x = trans.x;
- uvTrans.y = trans.y;
- }
-
- // resolve video links
- if (doc.Settings().readTextures) {
- const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID());
- for (const Connection *con : conns) {
- const Object *const ob = con->SourceObject();
- if (!ob) {
- DOMWarning("failed to read source object for texture link, ignoring", element);
- continue;
- }
-
- const Video *const video = dynamic_cast<const Video *>(ob);
- if (video) {
- media = video;
- }
- }
- }
-}
-
-Texture::~Texture() {
-}
-
-LayeredTexture::LayeredTexture(uint64_t id, const ElementPtr element, const Document & /*doc*/, const std::string &name) :
- Object(id, element, name), blendMode(BlendMode_Modulate), alpha(1) {
- const ScopePtr sc = GetRequiredScope(element);
-
- ElementPtr BlendModes = sc->GetElement("BlendModes");
- ElementPtr Alphas = sc->GetElement("Alphas");
-
- if (BlendModes != nullptr) {
- blendMode = (BlendMode)ParseTokenAsInt(GetRequiredToken(BlendModes, 0));
- }
- if (Alphas != nullptr) {
- alpha = ParseTokenAsFloat(GetRequiredToken(Alphas, 0));
- }
-}
-
-LayeredTexture::~LayeredTexture() {
-}
-
-void LayeredTexture::fillTexture(const Document &doc) {
- const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID());
- for (size_t i = 0; i < conns.size(); ++i) {
- const Connection *con = conns.at(i);
-
- const Object *const ob = con->SourceObject();
- if (!ob) {
- DOMWarning("failed to read source object for texture link, ignoring", element);
- continue;
- }
-
- const Texture *const tex = dynamic_cast<const Texture *>(ob);
-
- textures.push_back(tex);
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-Video::Video(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
- Object(id, element, name) {
- const ScopePtr sc = GetRequiredScope(element);
-
- const ElementPtr Type = sc->GetElement("Type");
- // File Version 7500 Crashes if this is not checked fully.
- // As of writing this comment 7700 exists, in August 2020
- ElementPtr FileName = nullptr;
- if (HasElement(sc, "Filename")) {
- FileName = (ElementPtr)sc->GetElement("Filename");
- } else if (HasElement(sc, "FileName")) {
- FileName = (ElementPtr)sc->GetElement("FileName");
- } else {
- print_error("file has invalid video material returning...");
- return;
- }
- const ElementPtr RelativeFilename = sc->GetElement("RelativeFilename");
- const ElementPtr Content = sc->GetElement("Content");
-
- if (Type) {
- type = ParseTokenAsString(GetRequiredToken(Type, 0));
- }
-
- if (FileName) {
- fileName = ParseTokenAsString(GetRequiredToken(FileName, 0));
- }
-
- if (RelativeFilename) {
- relativeFileName = ParseTokenAsString(GetRequiredToken(RelativeFilename, 0));
- }
-
- if (Content && !Content->Tokens().empty()) {
- //this field is omitted when the embedded texture is already loaded, let's ignore if it's not found
- try {
- const Token *token = GetRequiredToken(Content, 0);
- const char *data = token->begin();
- if (!token->IsBinary()) {
- if (*data != '"') {
- DOMError("embedded content is not surrounded by quotation marks", element);
- } else {
- size_t targetLength = 0;
- const size_t numTokens = Content->Tokens().size();
- // First time compute size (it could be large like 64Gb and it is good to allocate it once)
- for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx) {
- const Token *dataToken = GetRequiredToken(Content, tokenIdx);
- size_t tokenLength = dataToken->end() - dataToken->begin() - 2; // ignore double quotes
- const char *base64data = dataToken->begin() + 1;
- const size_t outLength = Util::ComputeDecodedSizeBase64(base64data, tokenLength);
- if (outLength == 0) {
- DOMError("Corrupted embedded content found", element);
- }
- targetLength += outLength;
- }
- if (targetLength == 0) {
- DOMError("Corrupted embedded content found", element);
- } else {
- content = new uint8_t[targetLength];
- contentLength = static_cast<uint64_t>(targetLength);
- size_t dst_offset = 0;
- for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx) {
- const Token *dataToken = GetRequiredToken(Content, tokenIdx);
- ERR_FAIL_COND(!dataToken);
- size_t tokenLength = dataToken->end() - dataToken->begin() - 2; // ignore double quotes
- const char *base64data = dataToken->begin() + 1;
- dst_offset += Util::DecodeBase64(base64data, tokenLength, content + dst_offset, targetLength - dst_offset);
- }
- if (targetLength != dst_offset) {
- delete[] content;
- contentLength = 0;
- DOMError("Corrupted embedded content found", element);
- }
- }
- }
- } else if (static_cast<size_t>(token->end() - data) < 5) {
- DOMError("binary data array is too short, need five (5) bytes for type signature and element count", element);
- } else if (*data != 'R') {
- DOMWarning("video content is not raw binary data, ignoring", element);
- } else {
- // read number of elements
- uint32_t len = 0;
- ::memcpy(&len, data + 1, sizeof(len));
- AI_SWAP4(len);
-
- contentLength = len;
-
- content = new uint8_t[len];
- ::memcpy(content, data + 5, len);
- }
- } catch (...) {
- // //we don't need the content data for contents that has already been loaded
- // ASSIMP_LOG_VERBOSE_DEBUG_F("Caught exception in FBXMaterial (likely because content was already loaded): ",
- // runtimeError.what());
- }
- }
-}
-
-Video::~Video() {
- if (content) {
- delete[] content;
- }
-}
-} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXMeshGeometry.cpp b/modules/fbx/fbx_parser/FBXMeshGeometry.cpp
deleted file mode 100644
index 591f2e5503..0000000000
--- a/modules/fbx/fbx_parser/FBXMeshGeometry.cpp
+++ /dev/null
@@ -1,459 +0,0 @@
-/*************************************************************************/
-/* FBXMeshGeometry.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, assimp team
-
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
-
-* Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-
-/** @file FBXMeshGeometry.cpp
- * @brief Assimp::FBX::MeshGeometry implementation
- */
-
-#include <functional>
-
-#include "FBXDocument.h"
-#include "FBXDocumentUtil.h"
-#include "FBXImportSettings.h"
-#include "FBXMeshGeometry.h"
-#include "core/math/vector3.h"
-
-namespace FBXDocParser {
-
-using namespace Util;
-
-// ------------------------------------------------------------------------------------------------
-Geometry::Geometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
- Object(id, element, name) {
- const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer");
- for (const Connection *con : conns) {
- const Skin *sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
- if (sk) {
- skin = sk;
- }
- const BlendShape *bsp = ProcessSimpleConnection<BlendShape>(*con, false, "BlendShape -> Geometry",
- element);
- if (bsp) {
- blendShapes.push_back(bsp);
- }
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-Geometry::~Geometry() {
- // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-const std::vector<const BlendShape *> &Geometry::get_blend_shapes() const {
- return blendShapes;
-}
-
-// ------------------------------------------------------------------------------------------------
-const Skin *Geometry::DeformerSkin() const {
- return skin;
-}
-
-// ------------------------------------------------------------------------------------------------
-MeshGeometry::MeshGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
- Geometry(id, element, name, doc) {
- print_verbose("mesh name: " + String(name.c_str()));
-
- ScopePtr sc = element->Compound();
- ERR_FAIL_COND_MSG(sc == nullptr, "failed to read geometry, prevented crash");
- ERR_FAIL_COND_MSG(!HasElement(sc, "Vertices"), "Detected mesh with no vertices, didn't populate the mesh");
-
- // must have Mesh elements:
- const ElementPtr Vertices = GetRequiredElement(sc, "Vertices", element);
- const ElementPtr PolygonVertexIndex = GetRequiredElement(sc, "PolygonVertexIndex", element);
-
- if (HasElement(sc, "Edges")) {
- const ElementPtr element_edges = GetRequiredElement(sc, "Edges", element);
- ParseVectorDataArray(m_edges, element_edges);
- }
-
- // read mesh data into arrays
- ParseVectorDataArray(m_vertices, Vertices);
- ParseVectorDataArray(m_face_indices, PolygonVertexIndex);
-
- ERR_FAIL_COND_MSG(m_vertices.empty(), "mesh with no vertices in FBX file, did you mean to delete it?");
- ERR_FAIL_COND_MSG(m_face_indices.empty(), "mesh has no faces, was this intended?");
-
- // Retrieve layer elements, for all of the mesh
- const ElementCollection &Layer = sc->GetCollection("Layer");
-
- // Store all layers
- std::vector<std::tuple<int, std::string>> valid_layers;
-
- // now read the sub mesh information from the geometry (normals, uvs, etc)
- for (ElementMap::const_iterator it = Layer.first; it != Layer.second; ++it) {
- const ScopePtr layer = GetRequiredScope(it->second);
- const ElementCollection &LayerElement = layer->GetCollection("LayerElement");
- for (ElementMap::const_iterator eit = LayerElement.first; eit != LayerElement.second; ++eit) {
- std::string layer_name = eit->first;
- ElementPtr element_layer = eit->second;
- const ScopePtr layer_element = GetRequiredScope(element_layer);
-
- // Actual usable 'type' LayerElementUV, LayerElementNormal, etc
- const ElementPtr Type = GetRequiredElement(layer_element, "Type");
- const ElementPtr TypedIndex = GetRequiredElement(layer_element, "TypedIndex");
- const std::string &type = ParseTokenAsString(GetRequiredToken(Type, 0));
- const int typedIndex = ParseTokenAsInt(GetRequiredToken(TypedIndex, 0));
-
- // we only need the layer name and the typed index.
- valid_layers.push_back(std::tuple<int, std::string>(typedIndex, type));
- }
- }
-
- // get object / mesh directly from the FBX by the element ID.
- const ScopePtr top = GetRequiredScope(element);
-
- // iterate over all layers for the mesh (uvs, normals, smoothing groups, colors, etc)
- for (size_t x = 0; x < valid_layers.size(); x++) {
- const int layer_id = std::get<0>(valid_layers[x]);
- const std::string &layer_type_name = std::get<1>(valid_layers[x]);
-
- // Get collection of elements from the XLayerMap (example: LayerElementUV)
- // this must contain our proper elements.
-
- // This is stupid, because it means we select them ALL not just the one we want.
- // but it's fine we can match by id.
-
- const ElementCollection &candidates = top->GetCollection(layer_type_name);
-
- ElementMap::const_iterator iter;
- for (iter = candidates.first; iter != candidates.second; ++iter) {
- const ScopePtr layer_scope = GetRequiredScope(iter->second);
- TokenPtr layer_token = GetRequiredToken(iter->second, 0);
- const int index = ParseTokenAsInt(layer_token);
-
- ERR_FAIL_COND_MSG(layer_scope == nullptr, "prevented crash, layer scope is invalid");
-
- if (index == layer_id) {
- const std::string &MappingInformationType = ParseTokenAsString(GetRequiredToken(
- GetRequiredElement(layer_scope, "MappingInformationType"), 0));
-
- const std::string &ReferenceInformationType = ParseTokenAsString(GetRequiredToken(
- GetRequiredElement(layer_scope, "ReferenceInformationType"), 0));
-
- if (layer_type_name == "LayerElementUV") {
- if (index == 0) {
- m_uv_0 = resolve_vertex_data_array<Vector2>(layer_scope, MappingInformationType, ReferenceInformationType, "UV");
- } else if (index == 1) {
- m_uv_1 = resolve_vertex_data_array<Vector2>(layer_scope, MappingInformationType, ReferenceInformationType, "UV");
- }
- } else if (layer_type_name == "LayerElementMaterial") {
- m_material_allocation_ids = resolve_vertex_data_array<int>(layer_scope, MappingInformationType, ReferenceInformationType, "Materials");
- } else if (layer_type_name == "LayerElementNormal") {
- m_normals = resolve_vertex_data_array<Vector3>(layer_scope, MappingInformationType, ReferenceInformationType, "Normals");
- } else if (layer_type_name == "LayerElementColor") {
- m_colors = resolve_vertex_data_array<Color>(layer_scope, MappingInformationType, ReferenceInformationType, "Colors", "ColorIndex");
- }
- }
- }
- }
-
- print_verbose("Mesh statistics \nuv_0: " + m_uv_0.debug_info() + "\nuv_1: " + m_uv_1.debug_info() + "\nvertices: " + itos(m_vertices.size()));
-
- // Compose the edge of the mesh.
- // You can see how the edges are stored into the FBX here: https://gist.github.com/AndreaCatania/da81840f5aa3b2feedf189e26c5a87e6
- for (size_t i = 0; i < m_edges.size(); i += 1) {
- ERR_FAIL_INDEX_MSG((size_t)m_edges[i], m_face_indices.size(), "The edge is pointing to a weird location in the face indices. The FBX is corrupted.");
- int polygon_vertex_0 = m_face_indices[m_edges[i]];
- int polygon_vertex_1;
- if (polygon_vertex_0 < 0) {
- // The polygon_vertex_0 points to the end of a polygon, so it's
- // connected with the beginning of polygon in the edge list.
-
- // Fist invert the vertex.
- polygon_vertex_0 = ~polygon_vertex_0;
-
- // Search the start vertex of the polygon.
- // Iterate from the polygon_vertex_index backward till the start of
- // the polygon is found.
- ERR_FAIL_COND_MSG(m_edges[i] - 1 < 0, "The polygon is not yet started and we already need the final vertex. This FBX is corrupted.");
- bool found_it = false;
- for (int x = m_edges[i] - 1; x >= 0; x -= 1) {
- if (x == 0) {
- // This for sure is the start.
- polygon_vertex_1 = m_face_indices[x];
- found_it = true;
- break;
- } else if (m_face_indices[x] < 0) {
- // This is the end of the previous polygon, so the next is
- // the start of the polygon we need.
- polygon_vertex_1 = m_face_indices[x + 1];
- found_it = true;
- break;
- }
- }
- // As the algorithm above, this check is useless. Because the first
- // ever vertex is always considered the beginning of a polygon.
- ERR_FAIL_COND_MSG(found_it == false, "Was not possible to find the first vertex of this polygon. FBX file is corrupted.");
-
- } else {
- ERR_FAIL_INDEX_MSG((size_t)(m_edges[i] + 1), m_face_indices.size(), "FBX The other FBX edge seems to point to an invalid vertices. This FBX file is corrupted.");
- // Take the next vertex
- polygon_vertex_1 = m_face_indices[m_edges[i] + 1];
- }
-
- if (polygon_vertex_1 < 0) {
- // We don't care if the `polygon_vertex_1` is the end of the polygon,
- // for `polygon_vertex_1` so we can just invert it.
- polygon_vertex_1 = ~polygon_vertex_1;
- }
-
- ERR_FAIL_COND_MSG(polygon_vertex_0 == polygon_vertex_1, "The vertices of this edge can't be the same, Is this a point???. This FBX file is corrupted.");
-
- // Just create the edge.
- edge_map.push_back({ polygon_vertex_0, polygon_vertex_1 });
- }
-}
-
-MeshGeometry::~MeshGeometry() {
- // empty
-}
-
-const std::vector<Vector3> &MeshGeometry::get_vertices() const {
- return m_vertices;
-}
-
-const std::vector<MeshGeometry::Edge> &MeshGeometry::get_edge_map() const {
- return edge_map;
-}
-
-const std::vector<int> &MeshGeometry::get_polygon_indices() const {
- return m_face_indices;
-}
-
-const std::vector<int> &MeshGeometry::get_edges() const {
- return m_edges;
-}
-
-const MeshGeometry::MappingData<Vector3> &MeshGeometry::get_normals() const {
- return m_normals;
-}
-
-const MeshGeometry::MappingData<Vector2> &MeshGeometry::get_uv_0() const {
- //print_verbose("get uv_0 " + m_uv_0.debug_info() );
- return m_uv_0;
-}
-
-const MeshGeometry::MappingData<Vector2> &MeshGeometry::get_uv_1() const {
- //print_verbose("get uv_1 " + m_uv_1.debug_info() );
- return m_uv_1;
-}
-
-const MeshGeometry::MappingData<Color> &MeshGeometry::get_colors() const {
- return m_colors;
-}
-
-const MeshGeometry::MappingData<int> &MeshGeometry::get_material_allocation_id() const {
- return m_material_allocation_ids;
-}
-
-int MeshGeometry::get_edge_id(const std::vector<Edge> &p_map, int p_vertex_a, int p_vertex_b) {
- for (size_t i = 0; i < p_map.size(); i += 1) {
- if ((p_map[i].vertex_0 == p_vertex_a && p_map[i].vertex_1 == p_vertex_b) || (p_map[i].vertex_1 == p_vertex_a && p_map[i].vertex_0 == p_vertex_b)) {
- return i;
- }
- }
- return -1;
-}
-
-MeshGeometry::Edge MeshGeometry::get_edge(const std::vector<Edge> &p_map, int p_id) {
- ERR_FAIL_INDEX_V_MSG((size_t)p_id, p_map.size(), Edge({ -1, -1 }), "ID not found.");
- return p_map[p_id];
-}
-
-template <class T>
-MeshGeometry::MappingData<T> MeshGeometry::resolve_vertex_data_array(
- const ScopePtr source,
- const std::string &MappingInformationType,
- const std::string &ReferenceInformationType,
- const std::string &dataElementName,
- const std::string &indexOverride) {
- ERR_FAIL_COND_V_MSG(source == nullptr, MappingData<T>(), "Invalid scope operator preventing memory corruption");
-
- // UVIndex, MaterialIndex, NormalIndex, etc..
- std::string indexDataElementName;
-
- if (!indexOverride.empty()) {
- // Colors should become ColorIndex
- indexDataElementName = indexOverride;
- } else {
- // Some indexes will exist.
- indexDataElementName = dataElementName + "Index";
- }
-
- // goal: expand everything to be per vertex
-
- ReferenceType l_ref_type = ReferenceType::direct;
-
- // Read the reference type into the enumeration
- if (ReferenceInformationType == "IndexToDirect") {
- l_ref_type = ReferenceType::index_to_direct;
- } else if (ReferenceInformationType == "Index") {
- // set non legacy index to direct mapping
- l_ref_type = ReferenceType::index;
- } else if (ReferenceInformationType == "Direct") {
- l_ref_type = ReferenceType::direct;
- } else {
- ERR_FAIL_V_MSG(MappingData<T>(), "invalid reference type has the FBX format changed?");
- }
-
- MapType l_map_type = MapType::none;
-
- if (MappingInformationType == "None") {
- l_map_type = MapType::none;
- } else if (MappingInformationType == "ByVertice") {
- l_map_type = MapType::vertex;
- } else if (MappingInformationType == "ByPolygonVertex") {
- l_map_type = MapType::polygon_vertex;
- } else if (MappingInformationType == "ByPolygon") {
- l_map_type = MapType::polygon;
- } else if (MappingInformationType == "ByEdge") {
- l_map_type = MapType::edge;
- } else if (MappingInformationType == "AllSame") {
- l_map_type = MapType::all_the_same;
- } else {
- print_error("invalid mapping type: " + String(MappingInformationType.c_str()));
- }
-
- // create mapping data
- MeshGeometry::MappingData<T> tempData;
- tempData.map_type = l_map_type;
- tempData.ref_type = l_ref_type;
-
- // parse data into array
- ParseVectorDataArray(tempData.data, GetRequiredElement(source, dataElementName));
-
- // index array won't always exist
- const ElementPtr element = GetOptionalElement(source, indexDataElementName);
- if (element) {
- ParseVectorDataArray(tempData.index, element);
- }
-
- return tempData;
-}
-// ------------------------------------------------------------------------------------------------
-ShapeGeometry::ShapeGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
- Geometry(id, element, name, doc) {
- const ScopePtr sc = element->Compound();
- if (nullptr == sc) {
- DOMError("failed to read Geometry object (class: Shape), no data scope found");
- }
- const ElementPtr Indexes = GetRequiredElement(sc, "Indexes", element);
- const ElementPtr Normals = GetRequiredElement(sc, "Normals", element);
- const ElementPtr Vertices = GetRequiredElement(sc, "Vertices", element);
- ParseVectorDataArray(m_indices, Indexes);
- ParseVectorDataArray(m_vertices, Vertices);
- ParseVectorDataArray(m_normals, Normals);
-}
-
-// ------------------------------------------------------------------------------------------------
-ShapeGeometry::~ShapeGeometry() {
- // empty
-}
-// ------------------------------------------------------------------------------------------------
-const std::vector<Vector3> &ShapeGeometry::GetVertices() const {
- return m_vertices;
-}
-// ------------------------------------------------------------------------------------------------
-const std::vector<Vector3> &ShapeGeometry::GetNormals() const {
- return m_normals;
-}
-// ------------------------------------------------------------------------------------------------
-const std::vector<unsigned int> &ShapeGeometry::GetIndices() const {
- return m_indices;
-}
-// ------------------------------------------------------------------------------------------------
-LineGeometry::LineGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
- Geometry(id, element, name, doc) {
- const ScopePtr sc = element->Compound();
- if (!sc) {
- DOMError("failed to read Geometry object (class: Line), no data scope found");
- }
- const ElementPtr Points = GetRequiredElement(sc, "Points", element);
- const ElementPtr PointsIndex = GetRequiredElement(sc, "PointsIndex", element);
- ParseVectorDataArray(m_vertices, Points);
- ParseVectorDataArray(m_indices, PointsIndex);
-}
-
-// ------------------------------------------------------------------------------------------------
-LineGeometry::~LineGeometry() {
- // empty
-}
-// ------------------------------------------------------------------------------------------------
-const std::vector<Vector3> &LineGeometry::GetVertices() const {
- return m_vertices;
-}
-// ------------------------------------------------------------------------------------------------
-const std::vector<int> &LineGeometry::GetIndices() const {
- return m_indices;
-}
-} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXMeshGeometry.h b/modules/fbx/fbx_parser/FBXMeshGeometry.h
deleted file mode 100644
index 9f0242d233..0000000000
--- a/modules/fbx/fbx_parser/FBXMeshGeometry.h
+++ /dev/null
@@ -1,263 +0,0 @@
-/*************************************************************************/
-/* FBXMeshGeometry.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, assimp team
-
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
-copyright notice, this list of conditions and the
-following disclaimer.
-
-* Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the
-following disclaimer in the documentation and/or other
-materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
-contributors may be used to endorse or promote products
-derived from this software without specific prior
-written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-
-#ifndef FBX_MESH_GEOMETRY_H
-#define FBX_MESH_GEOMETRY_H
-
-#include "core/math/color.h"
-#include "core/math/vector2.h"
-#include "core/math/vector3.h"
-#include "core/templates/vector.h"
-
-#include "FBXDocument.h"
-#include "FBXParser.h"
-
-#include <iostream>
-
-#define AI_MAX_NUMBER_OF_TEXTURECOORDS 4
-#define AI_MAX_NUMBER_OF_COLOR_SETS 8
-
-namespace FBXDocParser {
-
-/*
- * DOM base class for all kinds of FBX geometry
- */
-class Geometry : public Object {
-public:
- Geometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc);
- virtual ~Geometry();
-
- /** Get the Skin attached to this geometry or nullptr */
- const Skin *DeformerSkin() const;
-
- const std::vector<const BlendShape *> &get_blend_shapes() const;
-
- size_t get_blend_shape_count() const {
- return blendShapes.size();
- }
-
-private:
- const Skin *skin = nullptr;
- std::vector<const BlendShape *> blendShapes;
-};
-
-typedef std::vector<int> MatIndexArray;
-
-/// Map Geometry stores the FBX file information.
-///
-/// # FBX doc.
-/// ## Reference type declared:
-/// - Direct (directly related to the mapping information type)
-/// - IndexToDirect (Map with key value, meaning depends on the MappingInformationType)
-///
-/// ## Map Type:
-/// * None The mapping is undetermined.
-/// * ByVertex There will be one mapping coordinate for each surface control point/vertex (ControlPoint is a vertex).
-/// * If you have direct reference type vertices[x]
-/// * If you have IndexToDirect reference type the UV
-/// * ByPolygonVertex There will be one mapping coordinate for each vertex, for every polygon of which it is a part. This means that a vertex will have as many mapping coordinates as polygons of which it is a part. (Sorted by polygon, referencing vertex)
-/// * ByPolygon There can be only one mapping coordinate for the whole polygon.
-/// * One mapping per polygon polygon x has this normal x
-/// * For each vertex of the polygon then set the normal to x
-/// * ByEdge There will be one mapping coordinate for each unique edge in the mesh. This is meant to be used with smoothing layer elements. (Mapping is referencing the edge id)
-/// * AllSame There can be only one mapping coordinate for the whole surface.
-class MeshGeometry : public Geometry {
-public:
- enum class MapType {
- none = 0, // No mapping type. Stored as "None".
- vertex, // Maps per vertex. Stored as "ByVertice".
- polygon_vertex, // Maps per polygon vertex. Stored as "ByPolygonVertex".
- polygon, // Maps per polygon. Stored as "ByPolygon".
- edge, // Maps per edge. Stored as "ByEdge".
- all_the_same // Uaps to everything. Stored as "AllSame".
- };
-
- enum class ReferenceType {
- direct = 0,
- index = 1,
- index_to_direct = 2
- };
-
- template <class T>
- struct MappingData {
- MapType map_type = MapType::none;
- ReferenceType ref_type = ReferenceType::direct;
- std::vector<T> data;
- /// The meaning of the indices depends from the `MapType`.
- /// If `ref_type` is `direct` this map is hollow.
- std::vector<int> index;
-
- String debug_info() const {
- return "indexes: " + itos(index.size()) + " data: " + itos(data.size());
- }
- };
-
- struct Edge {
- int vertex_0 = 0, vertex_1 = 0;
- Edge(int v0, int v1) :
- vertex_0(v0), vertex_1(v1) {}
- Edge() {}
- };
-
-public:
- MeshGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc);
-
- virtual ~MeshGeometry();
-
- const std::vector<Vector3> &get_vertices() const;
- const std::vector<Edge> &get_edge_map() const;
- const std::vector<int> &get_polygon_indices() const;
- const std::vector<int> &get_edges() const;
- const MappingData<Vector3> &get_normals() const;
- const MappingData<Vector2> &get_uv_0() const;
- const MappingData<Vector2> &get_uv_1() const;
- const MappingData<Color> &get_colors() const;
- const MappingData<int> &get_material_allocation_id() const;
-
- /// Returns -1 if the vertices doesn't form an edge. Vertex order, doesn't
- // matter.
- static int get_edge_id(const std::vector<Edge> &p_map, int p_vertex_a, int p_vertex_b);
- // Returns the edge point bu that ID, or the edge with -1 vertices if the
- // id is not valid.
- static Edge get_edge(const std::vector<Edge> &p_map, int p_id);
-
-private:
- // Read directly from the FBX file.
- std::vector<Vector3> m_vertices;
- std::vector<Edge> edge_map;
- std::vector<int> m_face_indices;
- std::vector<int> m_edges;
- MappingData<Vector3> m_normals;
- MappingData<Vector2> m_uv_0; // first uv coordinates
- MappingData<Vector2> m_uv_1; // second uv coordinates
- MappingData<Color> m_colors; // colors for the mesh
- MappingData<int> m_material_allocation_ids; // slot of material used
-
- template <class T>
- MappingData<T> resolve_vertex_data_array(
- const ScopePtr source,
- const std::string &MappingInformationType,
- const std::string &ReferenceInformationType,
- const std::string &dataElementName,
- const std::string &indexOverride = "");
-};
-
-/*
- * DOM class for FBX geometry of type "Shape"
- */
-class ShapeGeometry : public Geometry {
-public:
- /** The class constructor */
- ShapeGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc);
-
- /** The class destructor */
- virtual ~ShapeGeometry();
-
- /** Get a list of all vertex points, non-unique*/
- const std::vector<Vector3> &GetVertices() const;
-
- /** Get a list of all vertex normals or an empty array if
- * no normals are specified. */
- const std::vector<Vector3> &GetNormals() const;
-
- /** Return list of vertex indices. */
- const std::vector<unsigned int> &GetIndices() const;
-
-private:
- std::vector<Vector3> m_vertices;
- std::vector<Vector3> m_normals;
- std::vector<unsigned int> m_indices;
-};
-/**
- * DOM class for FBX geometry of type "Line"
- */
-class LineGeometry : public Geometry {
-public:
- /** The class constructor */
- LineGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc);
-
- /** The class destructor */
- virtual ~LineGeometry();
-
- /** Get a list of all vertex points, non-unique*/
- const std::vector<Vector3> &GetVertices() const;
-
- /** Return list of vertex indices. */
- const std::vector<int> &GetIndices() const;
-
-private:
- std::vector<Vector3> m_vertices;
- std::vector<int> m_indices;
-};
-} // namespace FBXDocParser
-
-#endif // FBX_MESH_GEOMETRY_H
diff --git a/modules/fbx/fbx_parser/FBXModel.cpp b/modules/fbx/fbx_parser/FBXModel.cpp
deleted file mode 100644
index 625ee6237b..0000000000
--- a/modules/fbx/fbx_parser/FBXModel.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-/*************************************************************************/
-/* FBXModel.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, assimp team
-
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
-
-* Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-
-/** @file FBXModel.cpp
- * @brief Assimp::FBX::Model implementation
- */
-
-#include "FBXDocument.h"
-#include "FBXDocumentUtil.h"
-#include "FBXMeshGeometry.h"
-#include "FBXParser.h"
-
-namespace FBXDocParser {
-
-using namespace Util;
-
-// ------------------------------------------------------------------------------------------------
-Model::Model(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
- Object(id, element, name), shading("Y") {
- const ScopePtr sc = GetRequiredScope(element);
- const ElementPtr Shading = sc->GetElement("Shading");
- const ElementPtr Culling = sc->GetElement("Culling");
-
- if (Shading) {
- shading = GetRequiredToken(Shading, 0)->StringContents();
- }
-
- if (Culling) {
- culling = ParseTokenAsString(GetRequiredToken(Culling, 0));
- }
-
- ResolveLinks(element, doc);
-}
-
-// ------------------------------------------------------------------------------------------------
-Model::~Model() {
-}
-
-ModelLimbNode::ModelLimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
- Model(id, element, doc, name){};
-
-ModelLimbNode::~ModelLimbNode() {
-}
-
-// ------------------------------------------------------------------------------------------------
-void Model::ResolveLinks(const ElementPtr element, const Document &doc) {
- const char *const arr[] = { "Geometry", "Material", "NodeAttribute" };
-
- // resolve material
- const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), arr, 3);
-
- materials.reserve(conns.size());
- geometry.reserve(conns.size());
- attributes.reserve(conns.size());
- for (const Connection *con : conns) {
- // material and geometry links should be Object-Object connections
- if (con->PropertyName().length()) {
- continue;
- }
-
- const Object *const ob = con->SourceObject();
- if (!ob) {
- //DOMWarning("failed to read source object for incoming Model link, ignoring",&element);
- continue;
- }
-
- const Material *const mat = dynamic_cast<const Material *>(ob);
- if (mat) {
- materials.push_back(mat);
- continue;
- }
-
- const Geometry *const geo = dynamic_cast<const Geometry *>(ob);
- if (geo) {
- geometry.push_back(geo);
- continue;
- }
-
- const NodeAttribute *const att = dynamic_cast<const NodeAttribute *>(ob);
- if (att) {
- attributes.push_back(att);
- continue;
- }
-
- DOMWarning("source object for model link is neither Material, NodeAttribute nor Geometry, ignoring", element);
- continue;
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-bool Model::IsNull() const {
- const std::vector<const NodeAttribute *> &attrs = GetAttributes();
- for (const NodeAttribute *att : attrs) {
- const Null *null_tag = dynamic_cast<const Null *>(att);
- if (null_tag) {
- return true;
- }
- }
-
- return false;
-}
-} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXNodeAttribute.cpp b/modules/fbx/fbx_parser/FBXNodeAttribute.cpp
deleted file mode 100644
index c8ea03adec..0000000000
--- a/modules/fbx/fbx_parser/FBXNodeAttribute.cpp
+++ /dev/null
@@ -1,174 +0,0 @@
-/*************************************************************************/
-/* FBXNodeAttribute.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, assimp team
-
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
-
-* Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-
-/** @file FBXNoteAttribute.cpp
- * @brief Assimp::FBX::NodeAttribute (and subclasses) implementation
- */
-
-#include "FBXDocument.h"
-#include "FBXDocumentUtil.h"
-#include "FBXParser.h"
-#include <iostream>
-
-namespace FBXDocParser {
-using namespace Util;
-
-// ------------------------------------------------------------------------------------------------
-NodeAttribute::NodeAttribute(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
- Object(id, element, name) {
-}
-
-// ------------------------------------------------------------------------------------------------
-NodeAttribute::~NodeAttribute() {
- // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-CameraSwitcher::CameraSwitcher(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
- NodeAttribute(id, element, doc, name) {
- const ScopePtr sc = GetRequiredScope(element);
- const ElementPtr CameraId = sc->GetElement("CameraId");
- const ElementPtr CameraName = sc->GetElement("CameraName");
- const ElementPtr CameraIndexName = sc->GetElement("CameraIndexName");
-
- if (CameraId) {
- cameraId = ParseTokenAsInt(GetRequiredToken(CameraId, 0));
- }
-
- if (CameraName) {
- cameraName = GetRequiredToken(CameraName, 0)->StringContents();
- }
-
- if (CameraIndexName && CameraIndexName->Tokens().size()) {
- cameraIndexName = GetRequiredToken(CameraIndexName, 0)->StringContents();
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-CameraSwitcher::~CameraSwitcher() {
- // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-Camera::Camera(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
- NodeAttribute(id, element, doc, name) {
- // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-Camera::~Camera() {
- // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-Light::Light(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
- NodeAttribute(id, element, doc, name) {
- // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-Light::~Light() {
-}
-
-// ------------------------------------------------------------------------------------------------
-Null::Null(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
- NodeAttribute(id, element, doc, name) {
-}
-
-// ------------------------------------------------------------------------------------------------
-Null::~Null() {
-}
-
-// ------------------------------------------------------------------------------------------------
-LimbNode::LimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
- NodeAttribute(id, element, doc, name) {
- //std::cout << "limb node: " << name << std::endl;
- //const Scope &sc = GetRequiredScope(element);
-
- //const ElementPtr const TypeFlag = sc["TypeFlags"];
-
- // keep this it can dump new properties for you
- // for( auto element : sc.Elements())
- // {
- // std::cout << "limbnode element: " << element.first << std::endl;
- // }
-
- // if(TypeFlag)
- // {
- // // std::cout << "type flag: " << GetRequiredToken(*TypeFlag, 0).StringContents() << std::endl;
- // }
-}
-
-// ------------------------------------------------------------------------------------------------
-LimbNode::~LimbNode() {
-}
-} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXParseTools.h b/modules/fbx/fbx_parser/FBXParseTools.h
deleted file mode 100644
index 37a7ccad2a..0000000000
--- a/modules/fbx/fbx_parser/FBXParseTools.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*************************************************************************/
-/* FBXParseTools.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef FBX_PARSE_TOOLS_H
-#define FBX_PARSE_TOOLS_H
-
-#include "core/error/error_macros.h"
-#include "core/string/ustring.h"
-
-#include <stdint.h>
-#include <algorithm>
-#include <locale>
-
-template <class char_t>
-inline bool IsNewLine(char_t c) {
- return c == '\n' || c == '\r';
-}
-template <class char_t>
-inline bool IsSpace(char_t c) {
- return (c == (char_t)' ' || c == (char_t)'\t');
-}
-
-template <class char_t>
-inline bool IsSpaceOrNewLine(char_t c) {
- return IsNewLine(c) || IsSpace(c);
-}
-
-template <class char_t>
-inline bool IsLineEnd(char_t c) {
- return (c == (char_t)'\r' || c == (char_t)'\n' || c == (char_t)'\0' || c == (char_t)'\f');
-}
-
-// ------------------------------------------------------------------------------------
-// Special version of the function, providing higher accuracy and safety
-// It is mainly used by fast_atof to prevent ugly and unwanted integer overflows.
-// ------------------------------------------------------------------------------------
-inline uint64_t strtoul10_64(const char *in, bool &errored, const char **out = nullptr, unsigned int *max_inout = nullptr) {
- unsigned int cur = 0;
- uint64_t value = 0;
-
- errored = *in < '0' || *in > '9';
- ERR_FAIL_COND_V_MSG(errored, 0, "The string cannot be converted parser error");
-
- for (;;) {
- if (*in < '0' || *in > '9') {
- break;
- }
-
- const uint64_t new_value = (value * (uint64_t)10) + ((uint64_t)(*in - '0'));
-
- // numeric overflow, we rely on you
- if (new_value < value) {
- //WARN_PRINT( "Converting the string \" " + in + " \" into a value resulted in overflow." );
- return 0;
- }
-
- value = new_value;
-
- ++in;
- ++cur;
-
- if (max_inout && *max_inout == cur) {
- if (out) { /* skip to end */
- while (*in >= '0' && *in <= '9') {
- ++in;
- }
- *out = in;
- }
-
- return value;
- }
- }
- if (out) {
- *out = in;
- }
-
- if (max_inout) {
- *max_inout = cur;
- }
-
- return value;
-}
-
-#endif // FBX_PARSE_TOOLS_H
diff --git a/modules/fbx/fbx_parser/FBXParser.cpp b/modules/fbx/fbx_parser/FBXParser.cpp
deleted file mode 100644
index e345b7fc18..0000000000
--- a/modules/fbx/fbx_parser/FBXParser.cpp
+++ /dev/null
@@ -1,1322 +0,0 @@
-/*************************************************************************/
-/* FBXParser.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, assimp team
-
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
-
-* Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-
-/** @file FBXParser.cpp
- * @brief Implementation of the FBX parser and the rudimentary DOM that we use
- */
-
-#include <stdlib.h> /* strtol */
-#include <zlib.h>
-
-#include "ByteSwapper.h"
-#include "FBXParseTools.h"
-#include "FBXParser.h"
-#include "FBXTokenizer.h"
-#include "core/math/math_defs.h"
-#include "core/math/transform_3d.h"
-#include "core/math/vector3.h"
-#include "core/string/print_string.h"
-
-using namespace FBXDocParser;
-namespace {
-
-// Initially, we did reinterpret_cast, breaking strict aliasing rules.
-// This actually caused trouble on Android, so let's be safe this time.
-// https://github.com/assimp/assimp/issues/24
-template <typename T>
-T SafeParse(const char *data, const char *end) {
- // Actual size validation happens during Tokenization so
- // this is valid as an assertion.
- (void)(end);
- //ai_assert(static_cast<size_t>(end - data) >= sizeof(T));
- T result = static_cast<T>(0);
- ::memcpy(&result, data, sizeof(T));
- return result;
-}
-} // namespace
-
-namespace FBXDocParser {
-
-// ------------------------------------------------------------------------------------------------
-Element::Element(const TokenPtr key_token, Parser &parser) :
- key_token(key_token) {
- TokenPtr n = nullptr;
- do {
- n = parser.AdvanceToNextToken();
- if (n == nullptr) {
- continue;
- }
-
- if (!n) {
- print_error("unexpected end of file, expected closing bracket" + String(parser.LastToken()->StringContents().c_str()));
- }
-
- if (n && n->Type() == TokenType_DATA) {
- tokens.push_back(n);
- TokenPtr prev = n;
- n = parser.AdvanceToNextToken();
-
- if (n == nullptr) {
- break;
- }
-
- if (!n) {
- print_error("unexpected end of file, expected bracket, comma or key" + String(parser.LastToken()->StringContents().c_str()));
- parser.corrupt = true;
- return;
- }
-
- const TokenType ty = n->Type();
-
- // some exporters are missing a comma on the next line
- if (ty == TokenType_DATA && prev->Type() == TokenType_DATA && (n->Line() == prev->Line() + 1)) {
- tokens.push_back(n);
- continue;
- }
-
- if (ty != TokenType_OPEN_BRACKET && ty != TokenType_CLOSE_BRACKET && ty != TokenType_COMMA && ty != TokenType_KEY) {
- print_error("unexpected token; expected bracket, comma or key" + String(n->StringContents().c_str()));
- parser.corrupt = true;
- return;
- }
- }
-
- if (n && n->Type() == TokenType_OPEN_BRACKET) {
- compound = new_Scope(parser);
- parser.scopes.push_back(compound);
-
- if (parser.corrupt) {
- return;
- }
-
- // current token should be a TOK_CLOSE_BRACKET
- n = parser.CurrentToken();
-
- if (n && n->Type() != TokenType_CLOSE_BRACKET) {
- print_error("expected closing bracket" + String(n->StringContents().c_str()));
- parser.corrupt = true;
- return;
- }
-
- parser.AdvanceToNextToken();
- return;
- }
- } while (n && n->Type() != TokenType_KEY && n->Type() != TokenType_CLOSE_BRACKET);
-}
-
-// ------------------------------------------------------------------------------------------------
-Element::~Element() {
-}
-
-// ------------------------------------------------------------------------------------------------
-Scope::Scope(Parser &parser, bool topLevel) {
- if (!topLevel) {
- TokenPtr t = parser.CurrentToken();
- if (t->Type() != TokenType_OPEN_BRACKET) {
- print_error("expected open bracket" + String(t->StringContents().c_str()));
- parser.corrupt = true;
- return;
- }
- }
-
- TokenPtr n = parser.AdvanceToNextToken();
- if (n == nullptr) {
- print_error("unexpected end of file");
- parser.corrupt = true;
- return;
- }
-
- // note: empty scopes are allowed
- while (n && n->Type() != TokenType_CLOSE_BRACKET) {
- if (n->Type() != TokenType_KEY) {
- print_error("unexpected token, expected TOK_KEY" + String(n->StringContents().c_str()));
- parser.corrupt = true;
- return;
- }
-
- const std::string str = n->StringContents();
-
- if (parser.corrupt) {
- return;
- }
- // std::multimap<std::string, ElementPtr> (key and value)
- elements.insert(ElementMap::value_type(str, new_Element(n, parser)));
-
- // Element() should stop at the next Key token (or right after a Close token)
- n = parser.CurrentToken();
- if (n == nullptr) {
- if (topLevel) {
- return;
- }
-
- //print_error("unexpected end of file" + String(parser.LastToken()->StringContents().c_str()));
- }
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-Scope::~Scope() {
- for (ElementMap::value_type &v : elements) {
- delete v.second;
- v.second = nullptr;
- }
-
- elements.clear();
-}
-
-// ------------------------------------------------------------------------------------------------
-Parser::Parser(const TokenList &tokens, bool is_binary) :
- tokens(tokens), cursor(tokens.begin()), is_binary(is_binary) {
- root = new_Scope(*this, true);
- scopes.push_back(root);
-}
-
-// ------------------------------------------------------------------------------------------------
-Parser::~Parser() {
- for (ScopePtr scope : scopes) {
- delete scope;
- scope = nullptr;
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-TokenPtr Parser::AdvanceToNextToken() {
- last = current;
- if (cursor == tokens.end()) {
- current = nullptr;
- } else {
- current = *cursor++;
- }
- return current;
-}
-
-// ------------------------------------------------------------------------------------------------
-TokenPtr Parser::CurrentToken() const {
- return current;
-}
-
-// ------------------------------------------------------------------------------------------------
-TokenPtr Parser::LastToken() const {
- return last;
-}
-
-// ------------------------------------------------------------------------------------------------
-uint64_t ParseTokenAsID(const TokenPtr t, const char *&err_out) {
- ERR_FAIL_COND_V_MSG(t == nullptr, 0L, "Invalid token passed to ParseTokenAsID");
- err_out = nullptr;
-
- if (t->Type() != TokenType_DATA) {
- err_out = "expected TOK_DATA token";
- return 0L;
- }
-
- if (t->IsBinary()) {
- const char *data = t->begin();
- if (data[0] != 'L') {
- err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)";
- return 0L;
- }
-
- uint64_t id = SafeParse<uint64_t>(data + 1, t->end());
- return id;
- }
-
- // XXX: should use size_t here
- unsigned int length = static_cast<unsigned int>(t->end() - t->begin());
- //ai_assert(length > 0);
-
- const char *out = nullptr;
- bool errored = false;
-
- const uint64_t id = strtoul10_64(t->begin(), errored, &out, &length);
- if (errored || out > t->end()) {
- err_out = "failed to parse ID (text)";
- return 0L;
- }
-
- return id;
-}
-
-// ------------------------------------------------------------------------------------------------
-// wrapper around ParseTokenAsID() with print_error handling
-uint64_t ParseTokenAsID(const TokenPtr t) {
- const char *err = nullptr;
- const uint64_t i = ParseTokenAsID(t, err);
- if (err) {
- print_error(String(err) + " " + String(t->StringContents().c_str()));
- }
- return i;
-}
-
-// ------------------------------------------------------------------------------------------------
-size_t ParseTokenAsDim(const TokenPtr t, const char *&err_out) {
- // same as ID parsing, except there is a trailing asterisk
- err_out = nullptr;
-
- if (t->Type() != TokenType_DATA) {
- err_out = "expected TOK_DATA token";
- return 0;
- }
-
- if (t->IsBinary()) {
- const char *data = t->begin();
- if (data[0] != 'L') {
- err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)";
- return 0;
- }
-
- uint64_t id = SafeParse<uint64_t>(data + 1, t->end());
- AI_SWAP8(id);
- return static_cast<size_t>(id);
- }
-
- if (*t->begin() != '*') {
- err_out = "expected asterisk before array dimension";
- return 0;
- }
-
- // XXX: should use size_t here
- unsigned int length = static_cast<unsigned int>(t->end() - t->begin());
- if (length == 0) {
- err_out = "expected valid integer number after asterisk";
- return 0;
- }
-
- const char *out = nullptr;
- bool errored = false;
- const size_t id = static_cast<size_t>(strtoul10_64(t->begin() + 1, errored, &out, &length));
- if (errored || out > t->end()) {
- print_error("failed to parse id");
- err_out = "failed to parse ID";
- return 0;
- }
-
- return id;
-}
-
-// ------------------------------------------------------------------------------------------------
-float ParseTokenAsFloat(const TokenPtr t, const char *&err_out) {
- err_out = nullptr;
-
- if (t->Type() != TokenType_DATA) {
- err_out = "expected TOK_DATA token";
- return 0.0f;
- }
-
- if (t->IsBinary()) {
- const char *data = t->begin();
- if (data[0] != 'F' && data[0] != 'D') {
- err_out = "failed to parse F(loat) or D(ouble), unexpected data type (binary)";
- return 0.0f;
- }
-
- if (data[0] == 'F') {
- return SafeParse<float>(data + 1, t->end());
- } else {
- return static_cast<float>(SafeParse<double>(data + 1, t->end()));
- }
- }
-
-// need to copy the input string to a temporary buffer
-// first - next in the fbx token stream comes ',',
-// which fast_atof could interpret as decimal point.
-#define MAX_FLOAT_LENGTH 31
- char temp[MAX_FLOAT_LENGTH + 1];
- const size_t length = static_cast<size_t>(t->end() - t->begin());
- std::copy(t->begin(), t->end(), temp);
- temp[std::min(static_cast<size_t>(MAX_FLOAT_LENGTH), length)] = '\0';
-
- return atof(temp);
-}
-
-// ------------------------------------------------------------------------------------------------
-int ParseTokenAsInt(const TokenPtr t, const char *&err_out) {
- err_out = nullptr;
-
- if (t->Type() != TokenType_DATA) {
- err_out = "expected TOK_DATA token";
- return 0;
- }
-
- // binary files are simple to parse
- if (t->IsBinary()) {
- const char *data = t->begin();
- if (data[0] != 'I') {
- err_out = "failed to parse I(nt), unexpected data type (binary)";
- return 0;
- }
-
- int32_t ival = SafeParse<int32_t>(data + 1, t->end());
- AI_SWAP4(ival);
- return static_cast<int>(ival);
- }
-
- // ASCII files are unsafe.
- const size_t length = static_cast<size_t>(t->end() - t->begin());
- if (length == 0) {
- err_out = "expected valid integer number after asterisk";
- ERR_FAIL_V_MSG(0, "expected valid integer number after asterisk");
- }
-
- // must not be null for strtol to work
- char *out = (char *)t->end();
- // string begin, end ptr ref, base 10
- const int value = strtol(t->begin(), &out, 10);
- if (out == nullptr || out != t->end()) {
- err_out = "failed to parse ID";
- ERR_FAIL_V_MSG(0, "failed to parse ID");
- }
-
- return value;
-}
-
-// ------------------------------------------------------------------------------------------------
-int64_t ParseTokenAsInt64(const TokenPtr t, const char *&err_out) {
- err_out = nullptr;
-
- if (t->Type() != TokenType_DATA) {
- err_out = "expected TOK_DATA token";
- return 0L;
- }
-
- if (t->IsBinary()) {
- const char *data = t->begin();
- if (data[0] != 'L') {
- err_out = "failed to parse Int64, unexpected data type";
- return 0L;
- }
-
- int64_t id = SafeParse<int64_t>(data + 1, t->end());
- AI_SWAP8(id);
- return id;
- }
-
- // XXX: should use size_t here
- unsigned int length = static_cast<unsigned int>(t->end() - t->begin());
- //ai_assert(length > 0);
-
- char *out = nullptr;
- const int64_t id = strtol(t->begin(), &out, length);
- if (out > t->end()) {
- err_out = "failed to parse Int64 (text)";
- return 0L;
- }
-
- return id;
-}
-
-// ------------------------------------------------------------------------------------------------
-std::string ParseTokenAsString(const TokenPtr t, const char *&err_out) {
- err_out = nullptr;
-
- if (t->Type() != TokenType_DATA) {
- err_out = "expected TOK_DATA token";
- return "";
- }
-
- if (t->IsBinary()) {
- const char *data = t->begin();
- if (data[0] != 'S') {
- err_out = "failed to parse String, unexpected data type (binary)";
- return "";
- }
-
- // read string length
- int32_t len = SafeParse<int32_t>(data + 1, t->end());
- AI_SWAP4(len);
-
- //ai_assert(t.end() - data == 5 + len);
- return std::string(data + 5, len);
- }
-
- const size_t length = static_cast<size_t>(t->end() - t->begin());
- if (length < 2) {
- err_out = "token is too short to hold a string";
- return "";
- }
-
- const char *s = t->begin(), *e = t->end() - 1;
- if (*s != '\"' || *e != '\"') {
- err_out = "expected double quoted string";
- return "";
- }
-
- return std::string(s + 1, length - 2);
-}
-
-namespace {
-
-// ------------------------------------------------------------------------------------------------
-// read the type code and element count of a binary data array and stop there
-void ReadBinaryDataArrayHead(const char *&data, const char *end, char &type, uint32_t &count,
- const ElementPtr el) {
- TokenPtr token = el->KeyToken();
- if (static_cast<size_t>(end - data) < 5) {
- print_error("binary data array is too short, need five (5) bytes for type signature and element count: " + String(token->StringContents().c_str()));
- }
-
- // data type
- type = *data;
-
- // read number of elements
- uint32_t len = SafeParse<uint32_t>(data + 1, end);
- AI_SWAP4(len);
-
- count = len;
- data += 5;
-}
-
-// ------------------------------------------------------------------------------------------------
-// read binary data array, assume cursor points to the 'compression mode' field (i.e. behind the header)
-void ReadBinaryDataArray(char type, uint32_t count, const char *&data, const char *end,
- std::vector<char> &buff,
- const ElementPtr /*el*/) {
- uint32_t encmode = SafeParse<uint32_t>(data, end);
- AI_SWAP4(encmode);
- data += 4;
-
- // next comes the compressed length
- uint32_t comp_len = SafeParse<uint32_t>(data, end);
- AI_SWAP4(comp_len);
- data += 4;
-
- //ai_assert(data + comp_len == end);
-
- // determine the length of the uncompressed data by looking at the type signature
- uint32_t stride = 0;
- switch (type) {
- case 'f':
- case 'i':
- stride = 4;
- break;
-
- case 'd':
- case 'l':
- stride = 8;
- break;
- }
-
- const uint32_t full_length = stride * count;
- buff.resize(full_length);
-
- if (encmode == 0) {
- //ai_assert(full_length == comp_len);
-
- // plain data, no compression
- std::copy(data, end, buff.begin());
- } else if (encmode == 1) {
- // zlib/deflate, next comes ZIP head (0x78 0x01)
- // see https://www.ietf.org/rfc/rfc1950.txt
-
- z_stream zstream;
- zstream.opaque = Z_NULL;
- zstream.zalloc = Z_NULL;
- zstream.zfree = Z_NULL;
- zstream.data_type = Z_BINARY;
-
- // http://hewgill.com/journal/entries/349-how-to-decompress-gzip-stream-with-zlib
- if (Z_OK != inflateInit(&zstream)) {
- print_error("failure initializing zlib");
- }
-
- zstream.next_in = reinterpret_cast<Bytef *>(const_cast<char *>(data));
- zstream.avail_in = comp_len;
-
- zstream.avail_out = static_cast<uInt>(buff.size());
- zstream.next_out = reinterpret_cast<Bytef *>(&*buff.begin());
- const int ret = inflate(&zstream, Z_FINISH);
-
- if (ret != Z_STREAM_END && ret != Z_OK) {
- print_error("failure decompressing compressed data section");
- }
-
- // terminate zlib
- inflateEnd(&zstream);
- }
-#ifdef ASSIMP_BUILD_DEBUG
- else {
- // runtime check for this happens at tokenization stage
- //ai_assert(false);
- }
-#endif
-
- data += comp_len;
- //ai_assert(data == end);
-}
-} // namespace
-
-// ------------------------------------------------------------------------------------------------
-// read an array of float3 tuples
-void ParseVectorDataArray(std::vector<Vector3> &out, const ElementPtr el) {
- out.resize(0);
-
- const TokenList &tok = el->Tokens();
- TokenPtr token = el->KeyToken();
- if (tok.empty()) {
- print_error("unexpected empty element" + String(token->StringContents().c_str()));
- }
-
- if (tok[0]->IsBinary()) {
- const char *data = tok[0]->begin(), *end = tok[0]->end();
-
- char type;
- uint32_t count;
- ReadBinaryDataArrayHead(data, end, type, count, el);
-
- if (count % 3 != 0) {
- print_error("number of floats is not a multiple of three (3) (binary)" + String(token->StringContents().c_str()));
- }
-
- if (!count) {
- return;
- }
-
- if (type != 'd' && type != 'f') {
- print_error("expected float or double array (binary)" + String(token->StringContents().c_str()));
- }
-
- std::vector<char> buff;
- ReadBinaryDataArray(type, count, data, end, buff, el);
-
- //ai_assert(data == end);
- //ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
-
- const uint32_t count3 = count / 3;
- out.reserve(count3);
-
- if (type == 'd') {
- const double *d = reinterpret_cast<const double *>(&buff[0]);
- for (unsigned int i = 0; i < count3; ++i, d += 3) {
- out.push_back(Vector3(static_cast<real_t>(d[0]),
- static_cast<real_t>(d[1]),
- static_cast<real_t>(d[2])));
- }
- } else if (type == 'f') {
- const float *f = reinterpret_cast<const float *>(&buff[0]);
- for (unsigned int i = 0; i < count3; ++i, f += 3) {
- out.push_back(Vector3(f[0], f[1], f[2]));
- }
- }
-
- return;
- }
-
- const size_t dim = ParseTokenAsDim(tok[0]);
-
- // may throw bad_alloc if the input is rubbish, but this need
- // not to be prevented - importing would fail but we wouldn't
- // crash since assimp handles this case properly.
- out.reserve(dim);
-
- const ScopePtr scope = GetRequiredScope(el);
- const ElementPtr a = GetRequiredElement(scope, "a", el);
-
- if (a->Tokens().size() % 3 != 0) {
- print_error("number of floats is not a multiple of three (3)" + String(token->StringContents().c_str()));
- } else {
- for (TokenList::const_iterator it = a->Tokens().begin(), end = a->Tokens().end(); it != end;) {
- Vector3 v;
- v.x = ParseTokenAsFloat(*it++);
- v.y = ParseTokenAsFloat(*it++);
- v.z = ParseTokenAsFloat(*it++);
-
- out.push_back(v);
- }
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-// read an array of color4 tuples
-void ParseVectorDataArray(std::vector<Color> &out, const ElementPtr el) {
- out.resize(0);
- const TokenList &tok = el->Tokens();
-
- TokenPtr token = el->KeyToken();
-
- if (tok.empty()) {
- print_error("unexpected empty element" + String(token->StringContents().c_str()));
- }
-
- if (tok[0]->IsBinary()) {
- const char *data = tok[0]->begin(), *end = tok[0]->end();
-
- char type;
- uint32_t count;
- ReadBinaryDataArrayHead(data, end, type, count, el);
-
- if (count % 4 != 0) {
- print_error("number of floats is not a multiple of four (4) (binary)" + String(token->StringContents().c_str()));
- }
-
- if (!count) {
- return;
- }
-
- if (type != 'd' && type != 'f') {
- print_error("expected float or double array (binary)" + String(token->StringContents().c_str()));
- }
-
- std::vector<char> buff;
- ReadBinaryDataArray(type, count, data, end, buff, el);
-
- //ai_assert(data == end);
- //ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
-
- const uint32_t count4 = count / 4;
- out.reserve(count4);
-
- if (type == 'd') {
- const double *d = reinterpret_cast<const double *>(&buff[0]);
- for (unsigned int i = 0; i < count4; ++i, d += 4) {
- out.push_back(Color(static_cast<float>(d[0]),
- static_cast<float>(d[1]),
- static_cast<float>(d[2]),
- static_cast<float>(d[3])));
- }
- } else if (type == 'f') {
- const float *f = reinterpret_cast<const float *>(&buff[0]);
- for (unsigned int i = 0; i < count4; ++i, f += 4) {
- out.push_back(Color(f[0], f[1], f[2], f[3]));
- }
- }
- return;
- }
-
- const size_t dim = ParseTokenAsDim(tok[0]);
-
- // see notes in ParseVectorDataArray() above
- out.reserve(dim);
-
- const ScopePtr scope = GetRequiredScope(el);
- const ElementPtr a = GetRequiredElement(scope, "a", el);
-
- if (a->Tokens().size() % 4 != 0) {
- print_error("number of floats is not a multiple of four (4)" + String(token->StringContents().c_str()));
- }
- for (TokenList::const_iterator it = a->Tokens().begin(), end = a->Tokens().end(); it != end;) {
- Color v;
- v.r = ParseTokenAsFloat(*it++);
- v.g = ParseTokenAsFloat(*it++);
- v.b = ParseTokenAsFloat(*it++);
- v.a = ParseTokenAsFloat(*it++);
-
- out.push_back(v);
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-// read an array of float2 tuples
-void ParseVectorDataArray(std::vector<Vector2> &out, const ElementPtr el) {
- out.resize(0);
- const TokenList &tok = el->Tokens();
- TokenPtr token = el->KeyToken();
- if (tok.empty()) {
- print_error("unexpected empty element" + String(token->StringContents().c_str()));
- }
-
- if (tok[0]->IsBinary()) {
- const char *data = tok[0]->begin(), *end = tok[0]->end();
-
- char type;
- uint32_t count;
- ReadBinaryDataArrayHead(data, end, type, count, el);
-
- if (count % 2 != 0) {
- print_error("number of floats is not a multiple of two (2) (binary)" + String(token->StringContents().c_str()));
- }
-
- if (!count) {
- return;
- }
-
- if (type != 'd' && type != 'f') {
- print_error("expected float or double array (binary)" + String(token->StringContents().c_str()));
- }
-
- std::vector<char> buff;
- ReadBinaryDataArray(type, count, data, end, buff, el);
-
- //ai_assert(data == end);
- //ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
-
- const uint32_t count2 = count / 2;
- out.reserve(count2);
-
- if (type == 'd') {
- const double *d = reinterpret_cast<const double *>(&buff[0]);
- for (unsigned int i = 0; i < count2; ++i, d += 2) {
- out.push_back(Vector2(static_cast<float>(d[0]),
- static_cast<float>(d[1])));
- }
- } else if (type == 'f') {
- const float *f = reinterpret_cast<const float *>(&buff[0]);
- for (unsigned int i = 0; i < count2; ++i, f += 2) {
- out.push_back(Vector2(f[0], f[1]));
- }
- }
-
- return;
- }
-
- const size_t dim = ParseTokenAsDim(tok[0]);
-
- // see notes in ParseVectorDataArray() above
- out.reserve(dim);
-
- const ScopePtr scope = GetRequiredScope(el);
- const ElementPtr a = GetRequiredElement(scope, "a", el);
-
- if (a->Tokens().size() % 2 != 0) {
- print_error("number of floats is not a multiple of two (2)" + String(token->StringContents().c_str()));
- } else {
- for (TokenList::const_iterator it = a->Tokens().begin(), end = a->Tokens().end(); it != end;) {
- Vector2 v;
- v.x = ParseTokenAsFloat(*it++);
- v.y = ParseTokenAsFloat(*it++);
- out.push_back(v);
- }
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-// read an array of ints
-void ParseVectorDataArray(std::vector<int> &out, const ElementPtr el) {
- out.resize(0);
- const TokenList &tok = el->Tokens();
- TokenPtr token = el->KeyToken();
- if (tok.empty()) {
- print_error("unexpected empty element" + String(token->StringContents().c_str()));
- }
-
- if (tok[0]->IsBinary()) {
- const char *data = tok[0]->begin(), *end = tok[0]->end();
-
- char type;
- uint32_t count;
- ReadBinaryDataArrayHead(data, end, type, count, el);
-
- if (!count) {
- return;
- }
-
- if (type != 'i') {
- print_error("expected int array (binary)" + String(token->StringContents().c_str()));
- }
-
- std::vector<char> buff;
- ReadBinaryDataArray(type, count, data, end, buff, el);
-
- //ai_assert(data == end);
- //ai_assert(buff.size() == count * 4);
-
- out.reserve(count);
-
- const int32_t *ip = reinterpret_cast<const int32_t *>(&buff[0]);
- for (unsigned int i = 0; i < count; ++i, ++ip) {
- int32_t val = *ip;
- AI_SWAP4(val);
- out.push_back(val);
- }
-
- return;
- }
-
- const size_t dim = ParseTokenAsDim(tok[0]);
-
- // see notes in ParseVectorDataArray()
- out.reserve(dim);
-
- const ScopePtr scope = GetRequiredScope(el);
- const ElementPtr a = GetRequiredElement(scope, "a", el);
-
- for (TokenList::const_iterator it = a->Tokens().begin(), end = a->Tokens().end(); it != end;) {
- const int ival = ParseTokenAsInt(*it++);
- out.push_back(ival);
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-// read an array of floats
-void ParseVectorDataArray(std::vector<float> &out, const ElementPtr el) {
- out.resize(0);
- const TokenList &tok = el->Tokens();
- TokenPtr token = el->KeyToken();
- if (tok.empty()) {
- print_error("unexpected empty element: " + String(token->StringContents().c_str()));
- }
-
- if (tok[0]->IsBinary()) {
- const char *data = tok[0]->begin(), *end = tok[0]->end();
-
- char type;
- uint32_t count;
- ReadBinaryDataArrayHead(data, end, type, count, el);
-
- if (!count) {
- return;
- }
-
- if (type != 'd' && type != 'f') {
- print_error("expected float or double array (binary) " + String(token->StringContents().c_str()));
- }
-
- std::vector<char> buff;
- ReadBinaryDataArray(type, count, data, end, buff, el);
-
- //ai_assert(data == end);
- //ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
-
- if (type == 'd') {
- const double *d = reinterpret_cast<const double *>(&buff[0]);
- for (unsigned int i = 0; i < count; ++i, ++d) {
- out.push_back(static_cast<float>(*d));
- }
- } else if (type == 'f') {
- const float *f = reinterpret_cast<const float *>(&buff[0]);
- for (unsigned int i = 0; i < count; ++i, ++f) {
- out.push_back(*f);
- }
- }
-
- return;
- }
-
- const size_t dim = ParseTokenAsDim(tok[0]);
-
- // see notes in ParseVectorDataArray()
- out.reserve(dim);
-
- const ScopePtr scope = GetRequiredScope(el);
- const ElementPtr a = GetRequiredElement(scope, "a", el);
-
- for (TokenList::const_iterator it = a->Tokens().begin(), end = a->Tokens().end(); it != end;) {
- const float ival = ParseTokenAsFloat(*it++);
- out.push_back(ival);
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-// read an array of uints
-void ParseVectorDataArray(std::vector<unsigned int> &out, const ElementPtr el) {
- out.resize(0);
- const TokenList &tok = el->Tokens();
- const TokenPtr token = el->KeyToken();
-
- ERR_FAIL_COND_MSG(!token, "invalid ParseVectorDataArrat token invalid");
-
- if (tok.empty()) {
- print_error("unexpected empty element: " + String(token->StringContents().c_str()));
- }
-
- if (tok[0]->IsBinary()) {
- const char *data = tok[0]->begin(), *end = tok[0]->end();
-
- char type;
- uint32_t count;
- ReadBinaryDataArrayHead(data, end, type, count, el);
-
- if (!count) {
- return;
- }
-
- if (type != 'i') {
- print_error("expected (u)int array (binary)" + String(token->StringContents().c_str()));
- }
-
- std::vector<char> buff;
- ReadBinaryDataArray(type, count, data, end, buff, el);
-
- //ai_assert(data == end);
- //ai_assert(buff.size() == count * 4);
-
- out.reserve(count);
-
- const int32_t *ip = reinterpret_cast<const int32_t *>(&buff[0]);
- for (unsigned int i = 0; i < count; ++i, ++ip) {
- int32_t val = *ip;
- if (val < 0) {
- print_error("encountered negative integer index (binary)");
- }
-
- out.push_back(val);
- }
-
- return;
- }
-
- const size_t dim = ParseTokenAsDim(tok[0]);
-
- // see notes in ParseVectorDataArray()
- out.reserve(dim);
-
- const ScopePtr scope = GetRequiredScope(el);
- const ElementPtr a = GetRequiredElement(scope, "a", el);
-
- for (TokenList::const_iterator it = a->Tokens().begin(), end = a->Tokens().end(); it != end;) {
- const int ival = ParseTokenAsInt(*it++);
- if (ival < 0) {
- print_error("encountered negative integer index");
- }
- out.push_back(static_cast<unsigned int>(ival));
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-// read an array of uint64_ts
-void ParseVectorDataArray(std::vector<uint64_t> &out, const ElementPtr el) {
- out.resize(0);
-
- const TokenList &tok = el->Tokens();
- TokenPtr token = el->KeyToken();
- ERR_FAIL_COND(!token);
-
- if (tok.empty()) {
- print_error("unexpected empty element " + String(token->StringContents().c_str()));
- }
-
- if (tok[0]->IsBinary()) {
- const char *data = tok[0]->begin(), *end = tok[0]->end();
-
- char type;
- uint32_t count;
- ReadBinaryDataArrayHead(data, end, type, count, el);
-
- if (!count) {
- return;
- }
-
- if (type != 'l') {
- print_error("expected long array (binary): " + String(token->StringContents().c_str()));
- }
-
- std::vector<char> buff;
- ReadBinaryDataArray(type, count, data, end, buff, el);
-
- //ai_assert(data == end);
- //ai_assert(buff.size() == count * 8);
-
- out.reserve(count);
-
- const uint64_t *ip = reinterpret_cast<const uint64_t *>(&buff[0]);
- for (unsigned int i = 0; i < count; ++i, ++ip) {
- uint64_t val = *ip;
- AI_SWAP8(val);
- out.push_back(val);
- }
-
- return;
- }
-
- const size_t dim = ParseTokenAsDim(tok[0]);
-
- // see notes in ParseVectorDataArray()
- out.reserve(dim);
-
- const ScopePtr scope = GetRequiredScope(el);
- const ElementPtr a = GetRequiredElement(scope, "a", el);
-
- for (TokenList::const_iterator it = a->Tokens().begin(), end = a->Tokens().end(); it != end;) {
- const uint64_t ival = ParseTokenAsID(*it++);
-
- out.push_back(ival);
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-// read an array of int64_ts
-void ParseVectorDataArray(std::vector<int64_t> &out, const ElementPtr el) {
- out.resize(0);
- const TokenList &tok = el->Tokens();
- TokenPtr token = el->KeyToken();
- ERR_FAIL_COND(!token);
- if (tok.empty()) {
- print_error("unexpected empty element: " + String(token->StringContents().c_str()));
- }
-
- if (tok[0]->IsBinary()) {
- const char *data = tok[0]->begin(), *end = tok[0]->end();
-
- char type;
- uint32_t count;
- ReadBinaryDataArrayHead(data, end, type, count, el);
-
- if (!count) {
- return;
- }
-
- if (type != 'l') {
- print_error("expected long array (binary) " + String(token->StringContents().c_str()));
- }
-
- std::vector<char> buff;
- ReadBinaryDataArray(type, count, data, end, buff, el);
-
- //ai_assert(data == end);
- //ai_assert(buff.size() == count * 8);
-
- out.reserve(count);
-
- const int64_t *ip = reinterpret_cast<const int64_t *>(&buff[0]);
- for (unsigned int i = 0; i < count; ++i, ++ip) {
- int64_t val = *ip;
- AI_SWAP8(val);
- out.push_back(val);
- }
-
- return;
- }
-
- const size_t dim = ParseTokenAsDim(tok[0]);
-
- // see notes in ParseVectorDataArray()
- out.reserve(dim);
-
- const ScopePtr scope = GetRequiredScope(el);
- const ElementPtr a = GetRequiredElement(scope, "a", el);
-
- for (TokenList::const_iterator it = a->Tokens().begin(), end = a->Tokens().end(); it != end;) {
- const int64_t val = ParseTokenAsInt64(*it++);
- out.push_back(val);
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-Transform3D ReadMatrix(const ElementPtr element) {
- std::vector<float> values;
- ParseVectorDataArray(values, element);
-
- if (values.size() != 16) {
- print_error("expected 16 matrix elements");
- }
-
- // clean values to prevent any IBM damage on inverse() / affine_inverse()
- for (float &value : values) {
- if (::Math::is_zero_approx(value)) {
- value = 0;
- }
- }
-
- Transform3D xform;
- Basis basis;
-
- basis.set(
- Vector3(values[0], values[1], values[2]),
- Vector3(values[4], values[5], values[6]),
- Vector3(values[8], values[9], values[10]));
-
- xform.basis = basis;
- xform.origin = Vector3(values[12], values[13], values[14]);
- // determine if we need to think about this with dynamic rotation order?
- // for example:
- // xform.basis = z_axis * y_axis * x_axis;
- //xform.basis.transpose();
-
- print_verbose("xform verbose basis: " + (xform.basis.get_euler() * (180 / Math_PI)) + " xform origin:" + xform.origin);
-
- return xform;
-}
-
-// ------------------------------------------------------------------------------------------------
-// wrapper around ParseTokenAsString() with print_error handling
-std::string ParseTokenAsString(const TokenPtr t) {
- ERR_FAIL_COND_V(!t, "");
- const char *err;
- const std::string &i = ParseTokenAsString(t, err);
- if (err) {
- print_error(String(err) + ", " + String(t->StringContents().c_str()));
- }
- return i;
-}
-
-// ------------------------------------------------------------------------------------------------
-// extract a required element from a scope, abort if the element cannot be found
-ElementPtr GetRequiredElement(const ScopePtr sc, const std::string &index, const ElementPtr element /*= nullptr*/) {
- const ElementPtr el = sc->GetElement(index);
- TokenPtr token = el->KeyToken();
- ERR_FAIL_COND_V(!token, nullptr);
- if (!el) {
- print_error("did not find required element \"" + String(index.c_str()) + "\" " + String(token->StringContents().c_str()));
- }
- return el;
-}
-
-bool HasElement(const ScopePtr sc, const std::string &index) {
- const ElementPtr el = sc->GetElement(index);
- if (nullptr == el) {
- return false;
- }
-
- return true;
-}
-
-// ------------------------------------------------------------------------------------------------
-// extract a required element from a scope, abort if the element cannot be found
-ElementPtr GetOptionalElement(const ScopePtr sc, const std::string &index, const ElementPtr element /*= nullptr*/) {
- const ElementPtr el = sc->GetElement(index);
- return el;
-}
-
-// ------------------------------------------------------------------------------------------------
-// extract required compound scope
-ScopePtr GetRequiredScope(const ElementPtr el) {
- if (el) {
- ScopePtr s = el->Compound();
- TokenPtr token = el->KeyToken();
- ERR_FAIL_COND_V(!token, nullptr);
- if (s) {
- return s;
- }
-
- ERR_FAIL_V_MSG(nullptr, "expected compound scope " + String(token->StringContents().c_str()));
- }
-
- ERR_FAIL_V_MSG(nullptr, "Invalid element supplied to parser");
-}
-
-// ------------------------------------------------------------------------------------------------
-// extract optional compound scope
-ScopePtr GetOptionalScope(const ElementPtr el) {
- if (el) {
- ScopePtr s = el->Compound();
- TokenPtr token = el->KeyToken();
-
- if (token && s) {
- return s;
- }
- }
-
- return nullptr;
-}
-
-// ------------------------------------------------------------------------------------------------
-// get token at a particular index
-TokenPtr GetRequiredToken(const ElementPtr el, unsigned int index) {
- if (el) {
- const TokenList &x = el->Tokens();
- TokenPtr token = el->KeyToken();
-
- ERR_FAIL_COND_V(!token, nullptr);
-
- if (index >= x.size()) {
- ERR_FAIL_V_MSG(nullptr, "missing token at index: " + itos(index) + " " + String(token->StringContents().c_str()));
- }
-
- return x[index];
- }
-
- return nullptr;
-}
-
-// ------------------------------------------------------------------------------------------------
-// wrapper around ParseTokenAsDim() with print_error handling
-size_t ParseTokenAsDim(const TokenPtr t) {
- const char *err;
- const size_t i = ParseTokenAsDim(t, err);
- if (err) {
- print_error(String(err) + " " + String(t->StringContents().c_str()));
- }
- return i;
-}
-
-// ------------------------------------------------------------------------------------------------
-// wrapper around ParseTokenAsFloat() with print_error handling
-float ParseTokenAsFloat(const TokenPtr t) {
- const char *err;
- const float i = ParseTokenAsFloat(t, err);
- if (err) {
- print_error(String(err) + " " + String(t->StringContents().c_str()));
- }
- return i;
-}
-
-// ------------------------------------------------------------------------------------------------
-// wrapper around ParseTokenAsInt() with print_error handling
-int ParseTokenAsInt(const TokenPtr t) {
- const char *err;
- const int i = ParseTokenAsInt(t, err);
- if (err) {
- print_error(String(err) + " " + String(t->StringContents().c_str()));
- }
- return i;
-}
-
-// ------------------------------------------------------------------------------------------------
-// wrapper around ParseTokenAsInt64() with print_error handling
-int64_t ParseTokenAsInt64(const TokenPtr t) {
- const char *err;
- const int64_t i = ParseTokenAsInt64(t, err);
- if (err) {
- print_error(String(err) + " " + String(t->StringContents().c_str()));
- }
- return i;
-}
-} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXParser.h b/modules/fbx/fbx_parser/FBXParser.h
deleted file mode 100644
index c5e3f5bf6b..0000000000
--- a/modules/fbx/fbx_parser/FBXParser.h
+++ /dev/null
@@ -1,270 +0,0 @@
-/*************************************************************************/
-/* FBXParser.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, assimp team
-
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
-
-* Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-
-/** @file FBXParser.h
- * @brief FBX parsing code
- */
-#ifndef FBX_PARSER_H
-#define FBX_PARSER_H
-
-#include <stdint.h>
-#include <map>
-#include <memory>
-
-#include "core/math/color.h"
-#include "core/math/transform_3d.h"
-#include "core/math/vector2.h"
-#include "core/math/vector3.h"
-
-#include "FBXTokenizer.h"
-
-namespace FBXDocParser {
-
-class Scope;
-class Parser;
-class Element;
-
-typedef Element *ElementPtr;
-typedef Scope *ScopePtr;
-
-typedef std::vector<ScopePtr> ScopeList;
-typedef std::multimap<std::string, ElementPtr> ElementMap;
-typedef std::pair<ElementMap::const_iterator, ElementMap::const_iterator> ElementCollection;
-
-#define new_Scope new Scope
-#define new_Element new Element
-
-/** FBX data entity that consists of a key:value tuple.
- *
- * Example:
- * @verbatim
- * AnimationCurve: 23, "AnimCurve::", "" {
- * [..]
- * }
- * @endverbatim
- *
- * As can be seen in this sample, elements can contain nested #Scope
- * as their trailing member. **/
-class Element {
-public:
- Element(TokenPtr key_token, Parser &parser);
- ~Element();
-
- ScopePtr Compound() const {
- return compound;
- }
-
- TokenPtr KeyToken() const {
- return key_token;
- }
-
- const TokenList &Tokens() const {
- return tokens;
- }
-
-private:
- TokenList tokens;
- ScopePtr compound = nullptr;
- std::vector<ScopePtr> compound_scope;
- TokenPtr key_token = nullptr;
-};
-
-/** FBX data entity that consists of a 'scope', a collection
- * of not necessarily unique #Element instances.
- *
- * Example:
- * @verbatim
- * GlobalSettings: {
- * Version: 1000
- * Properties70:
- * [...]
- * }
- * @endverbatim */
-class Scope {
-public:
- Scope(Parser &parser, bool topLevel = false);
- ~Scope();
-
- ElementPtr GetElement(const std::string &index) const {
- ElementMap::const_iterator it = elements.find(index);
- return it == elements.end() ? nullptr : (*it).second;
- }
-
- ElementPtr FindElementCaseInsensitive(const std::string &elementName) const {
- for (FBXDocParser::ElementMap::const_iterator element = elements.begin(); element != elements.end(); ++element) {
- if (element->first.compare(elementName)) {
- return element->second;
- }
- }
-
- // nothing to reference / expired.
- return nullptr;
- }
-
- ElementCollection GetCollection(const std::string &index) const {
- return elements.equal_range(index);
- }
-
- const ElementMap &Elements() const {
- return elements;
- }
-
-private:
- ElementMap elements;
-};
-
-/** FBX parsing class, takes a list of input tokens and generates a hierarchy
- * of nested #Scope instances, representing the fbx DOM.*/
-class Parser {
-public:
- /** Parse given a token list. Does not take ownership of the tokens -
- * the objects must persist during the entire parser lifetime */
- Parser(const TokenList &tokens, bool is_binary);
- ~Parser();
-
- ScopePtr GetRootScope() const {
- return root;
- }
-
- bool IsBinary() const {
- return is_binary;
- }
-
- bool IsCorrupt() const {
- return corrupt;
- }
-
-private:
- friend class Scope;
- friend class Element;
-
- TokenPtr AdvanceToNextToken();
- TokenPtr LastToken() const;
- TokenPtr CurrentToken() const;
-
-private:
- bool corrupt = false;
- ScopeList scopes;
- const TokenList &tokens;
-
- TokenPtr last = nullptr, current = nullptr;
- TokenList::const_iterator cursor;
- ScopePtr root = nullptr;
-
- const bool is_binary;
-};
-
-/* token parsing - this happens when building the DOM out of the parse-tree*/
-uint64_t ParseTokenAsID(const TokenPtr t, const char *&err_out);
-size_t ParseTokenAsDim(const TokenPtr t, const char *&err_out);
-float ParseTokenAsFloat(const TokenPtr t, const char *&err_out);
-int ParseTokenAsInt(const TokenPtr t, const char *&err_out);
-int64_t ParseTokenAsInt64(const TokenPtr t, const char *&err_out);
-std::string ParseTokenAsString(const TokenPtr t, const char *&err_out);
-
-/* wrapper around ParseTokenAsXXX() with DOMError handling */
-uint64_t ParseTokenAsID(const TokenPtr t);
-size_t ParseTokenAsDim(const TokenPtr t);
-float ParseTokenAsFloat(const TokenPtr t);
-int ParseTokenAsInt(const TokenPtr t);
-int64_t ParseTokenAsInt64(const TokenPtr t);
-std::string ParseTokenAsString(const TokenPtr t);
-
-/* read data arrays */
-void ParseVectorDataArray(std::vector<Vector3> &out, const ElementPtr el);
-void ParseVectorDataArray(std::vector<Color> &out, const ElementPtr el);
-void ParseVectorDataArray(std::vector<Vector2> &out, const ElementPtr el);
-void ParseVectorDataArray(std::vector<int> &out, const ElementPtr el);
-void ParseVectorDataArray(std::vector<float> &out, const ElementPtr el);
-void ParseVectorDataArray(std::vector<float> &out, const ElementPtr el);
-void ParseVectorDataArray(std::vector<unsigned int> &out, const ElementPtr el);
-void ParseVectorDataArray(std::vector<uint64_t> &out, const ElementPtr ep);
-void ParseVectorDataArray(std::vector<int64_t> &out, const ElementPtr el);
-bool HasElement(const ScopePtr sc, const std::string &index);
-
-// extract a required element from a scope, abort if the element cannot be found
-ElementPtr GetRequiredElement(const ScopePtr sc, const std::string &index, const ElementPtr element = nullptr);
-ScopePtr GetRequiredScope(const ElementPtr el); // New in 2020. (less likely to destroy application)
-ScopePtr GetOptionalScope(const ElementPtr el); // New in 2021. (even LESS likely to destroy application now)
-
-ElementPtr GetOptionalElement(const ScopePtr sc, const std::string &index, const ElementPtr element = nullptr);
-// extract required compound scope
-ScopePtr GetRequiredScope(const ElementPtr el);
-// get token at a particular index
-TokenPtr GetRequiredToken(const ElementPtr el, unsigned int index);
-
-// ------------------------------------------------------------------------------------------------
-// read a 4x4 matrix from an array of 16 floats
-Transform3D ReadMatrix(const ElementPtr element);
-} // namespace FBXDocParser
-
-#endif // FBX_PARSER_H
diff --git a/modules/fbx/fbx_parser/FBXPose.cpp b/modules/fbx/fbx_parser/FBXPose.cpp
deleted file mode 100644
index 738b9131b6..0000000000
--- a/modules/fbx/fbx_parser/FBXPose.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/*************************************************************************/
-/* FBXPose.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, assimp team
-
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
-
-* Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-
-/** @file FBXNoteAttribute.cpp
- * @brief Assimp::FBX::NodeAttribute (and subclasses) implementation
- */
-
-#include "FBXDocument.h"
-#include "FBXParser.h"
-#include <iostream>
-
-namespace FBXDocParser {
-
-class FbxPoseNode;
-// ------------------------------------------------------------------------------------------------
-FbxPose::FbxPose(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
- Object(id, element, name) {
- const ScopePtr sc = GetRequiredScope(element);
- //const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
-
- const ElementCollection &PoseNodes = sc->GetCollection("PoseNode");
- for (ElementMap::const_iterator it = PoseNodes.first; it != PoseNodes.second; ++it) {
- std::string entry_name = (*it).first;
- ElementPtr some_element = (*it).second;
- FbxPoseNode *pose_node = new FbxPoseNode(some_element, doc, entry_name);
- pose_nodes.push_back(pose_node);
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-FbxPose::~FbxPose() {
- pose_nodes.clear();
- // empty
-}
-} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXProperties.cpp b/modules/fbx/fbx_parser/FBXProperties.cpp
deleted file mode 100644
index 7cbb3a2eda..0000000000
--- a/modules/fbx/fbx_parser/FBXProperties.cpp
+++ /dev/null
@@ -1,245 +0,0 @@
-/*************************************************************************/
-/* FBXProperties.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, assimp team
-
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
-
-* Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-
-/** @file FBXProperties.cpp
- * @brief Implementation of the FBX dynamic properties system
- */
-
-#include "FBXProperties.h"
-#include "FBXDocumentUtil.h"
-#include "FBXParser.h"
-#include "FBXTokenizer.h"
-
-namespace FBXDocParser {
-
-using namespace Util;
-
-// ------------------------------------------------------------------------------------------------
-Property::Property() {
-}
-
-// ------------------------------------------------------------------------------------------------
-Property::~Property() {
-}
-
-namespace {
-
-// ------------------------------------------------------------------------------------------------
-// read a typed property out of a FBX element. The return value is nullptr if the property cannot be read.
-PropertyPtr ReadTypedProperty(const ElementPtr element) {
- //ai_assert(element.KeyToken().StringContents() == "P");
-
- const TokenList &tok = element->Tokens();
- //ai_assert(tok.size() >= 5);
-
- const std::string &s = ParseTokenAsString(tok[1]);
- const char *const cs = s.c_str();
- if (!strcmp(cs, "KString")) {
- return new TypedProperty<std::string>(ParseTokenAsString(tok[4]));
- } else if (!strcmp(cs, "bool") || !strcmp(cs, "Bool")) {
- return new TypedProperty<bool>(ParseTokenAsInt(tok[4]) != 0);
- } else if (!strcmp(cs, "int") || !strcmp(cs, "Int") || !strcmp(cs, "enum") || !strcmp(cs, "Enum")) {
- return new TypedProperty<int>(ParseTokenAsInt(tok[4]));
- } else if (!strcmp(cs, "ULongLong")) {
- return new TypedProperty<uint64_t>(ParseTokenAsID(tok[4]));
- } else if (!strcmp(cs, "KTime")) {
- return new TypedProperty<int64_t>(ParseTokenAsInt64(tok[4]));
- } else if (!strcmp(cs, "Vector3D") ||
- !strcmp(cs, "ColorRGB") ||
- !strcmp(cs, "Vector") ||
- !strcmp(cs, "Color") ||
- !strcmp(cs, "Lcl Translation") ||
- !strcmp(cs, "Lcl Rotation") ||
- !strcmp(cs, "Lcl Scaling")) {
- return new TypedProperty<Vector3>(Vector3(
- ParseTokenAsFloat(tok[4]),
- ParseTokenAsFloat(tok[5]),
- ParseTokenAsFloat(tok[6])));
- } else if (!strcmp(cs, "double") || !strcmp(cs, "Number") || !strcmp(cs, "Float") || !strcmp(cs, "float") || !strcmp(cs, "FieldOfView") || !strcmp(cs, "UnitScaleFactor")) {
- return new TypedProperty<float>(ParseTokenAsFloat(tok[4]));
- }
-
- return nullptr;
-}
-
-// ------------------------------------------------------------------------------------------------
-// peek into an element and check if it contains a FBX property, if so return its name.
-std::string PeekPropertyName(const Element &element) {
- //ai_assert(element.KeyToken().StringContents() == "P");
- const TokenList &tok = element.Tokens();
- if (tok.size() < 4) {
- return "";
- }
-
- return ParseTokenAsString(tok[0]);
-}
-} // namespace
-
-// ------------------------------------------------------------------------------------------------
-PropertyTable::PropertyTable() {
-}
-
-// Is used when dealing with FBX Objects not metadata.
-PropertyTable::PropertyTable(const ElementPtr element) :
- element(element) {
- Setup(element);
-}
-
-// ------------------------------------------------------------------------------------------------
-PropertyTable::~PropertyTable() {
- for (PropertyMap::value_type &v : props) {
- delete v.second;
- }
-}
-
-void PropertyTable::Setup(ElementPtr ptr) {
- const ScopePtr sc = GetRequiredScope(ptr);
- const ElementPtr Properties70 = sc->GetElement("Properties70");
- const ScopePtr scope = GetOptionalScope(Properties70);
-
- // no scope, no care.
- if (!scope) {
- return; // NOTE: this is not an error this is actually a Object, without properties, here we will nullptr it.
- }
-
- for (const ElementMap::value_type &v : scope->Elements()) {
- if (v.first != "P") {
- DOMWarning("expected only P elements in property table", v.second);
- continue;
- }
-
- const std::string &name = PeekPropertyName(*v.second);
- if (!name.length()) {
- DOMWarning("could not read property name", v.second);
- continue;
- }
-
- LazyPropertyMap::const_iterator it = lazyProps.find(name);
- if (it != lazyProps.end()) {
- DOMWarning("duplicate property name, will hide previous value: " + name, v.second);
- continue;
- }
-
- // since the above checks for duplicates we can be sure to insert the only match here.
- lazyProps[name] = v.second;
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-PropertyPtr PropertyTable::Get(const std::string &name) const {
- PropertyMap::const_iterator it = props.find(name);
- if (it == props.end()) {
- // hasn't been parsed yet?
- LazyPropertyMap::const_iterator lit = lazyProps.find(name);
- if (lit != lazyProps.end()) {
- props[name] = ReadTypedProperty(lit->second);
- it = props.find(name);
-
- //ai_assert(it != props.end());
- }
-
- if (it == props.end()) {
- // check property template
- return nullptr;
- }
- }
-
- return (*it).second;
-}
-
-DirectPropertyMap PropertyTable::GetUnparsedProperties() const {
- DirectPropertyMap result;
-
- // Loop through all the lazy properties (which is all the properties)
- for (const LazyPropertyMap::value_type &element : lazyProps) {
- // Skip parsed properties
- if (props.end() != props.find(element.first)) {
- continue;
- }
-
- // Read the element's value.
- // Wrap the naked pointer (since the call site is required to acquire ownership)
- // std::unique_ptr from C++11 would be preferred both as a wrapper and a return value.
- Property *prop = ReadTypedProperty(element.second);
-
- // Element could not be read. Skip it.
- if (!prop) {
- continue;
- }
-
- // Add to result
- result[element.first] = prop;
- }
-
- return result;
-}
-} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXProperties.h b/modules/fbx/fbx_parser/FBXProperties.h
deleted file mode 100644
index 4d74a1db17..0000000000
--- a/modules/fbx/fbx_parser/FBXProperties.h
+++ /dev/null
@@ -1,212 +0,0 @@
-/*************************************************************************/
-/* FBXProperties.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, assimp team
-
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
-
-* Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-
-/** @file FBXProperties.h
- * @brief FBX dynamic properties
- */
-#ifndef FBX_PROPERTIES_H
-#define FBX_PROPERTIES_H
-
-#include "FBXParser.h"
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-namespace FBXDocParser {
-
-// Forward declarations
-class Element;
-
-/** Represents a dynamic property. Type info added by deriving classes,
- * see #TypedProperty.
- Example:
- @verbatim
- P: "ShininessExponent", "double", "Number", "",0.5
- @endvebatim
-*/
-class Property {
-protected:
- Property();
-
-public:
- virtual ~Property();
-
-public:
- template <typename T>
- const T *As() const {
- return dynamic_cast<const T *>(this);
- }
-};
-
-template <typename T>
-class TypedProperty : public Property {
-public:
- explicit TypedProperty(const T &value) :
- value(value) {
- // empty
- }
-
- const T &Value() const {
- return value;
- }
-
-private:
- T value;
-};
-
-#define new_Property new Property
-typedef Property *PropertyPtr;
-typedef std::map<std::string, PropertyPtr> DirectPropertyMap;
-typedef std::map<std::string, PropertyPtr> PropertyMap;
-typedef std::map<std::string, ElementPtr> LazyPropertyMap;
-
-/**
- * Represents a property table as can be found in the newer FBX files (Properties60, Properties70)
- */
-class PropertyTable {
-public:
- // in-memory property table with no source element
- PropertyTable();
- PropertyTable(const ElementPtr element);
- virtual ~PropertyTable();
-
- PropertyPtr Get(const std::string &name) const;
- void Setup(ElementPtr ptr);
-
- // PropertyTable's need not be coupled with FBX elements so this can be NULL
- ElementPtr GetElement() {
- return element;
- }
-
- PropertyMap &GetProperties() {
- return props;
- }
-
- const LazyPropertyMap &GetLazyProperties() {
- return lazyProps;
- }
-
- DirectPropertyMap GetUnparsedProperties() const;
-
-private:
- LazyPropertyMap lazyProps;
- mutable PropertyMap props;
- ElementPtr element = nullptr;
-};
-
-// ------------------------------------------------------------------------------------------------
-template <typename T>
-inline T PropertyGet(const PropertyTable *in, const std::string &name, const T &defaultValue) {
- PropertyPtr prop = in->Get(name);
- if (nullptr == prop) {
- return defaultValue;
- }
-
- // strong typing, no need to be lenient
- const TypedProperty<T> *const tprop = prop->As<TypedProperty<T>>();
- if (nullptr == tprop) {
- return defaultValue;
- }
-
- return tprop->Value();
-}
-
-// ------------------------------------------------------------------------------------------------
-template <typename T>
-inline T PropertyGet(const PropertyTable *in, const std::string &name, bool &result, bool useTemplate = false) {
- PropertyPtr prop = in->Get(name);
- if (nullptr == prop) {
- if (nullptr == in) {
- result = false;
- return T();
- }
- prop = in->Get(name);
- if (nullptr == prop) {
- result = false;
- return T();
- }
- }
-
- // strong typing, no need to be lenient
- const TypedProperty<T> *const tprop = prop->As<TypedProperty<T>>();
- if (nullptr == tprop) {
- result = false;
- return T();
- }
-
- result = true;
- return tprop->Value();
-}
-} // namespace FBXDocParser
-
-#endif // FBX_PROPERTIES_H
diff --git a/modules/fbx/fbx_parser/FBXTokenizer.cpp b/modules/fbx/fbx_parser/FBXTokenizer.cpp
deleted file mode 100644
index bac3e6d5c4..0000000000
--- a/modules/fbx/fbx_parser/FBXTokenizer.cpp
+++ /dev/null
@@ -1,253 +0,0 @@
-/*************************************************************************/
-/* FBXTokenizer.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, assimp team
-
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
-
-* Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-
-/** @file FBXTokenizer.cpp
- * @brief Implementation of the FBX broadphase lexer
- */
-
-// tab width for logging columns
-#define ASSIMP_FBX_TAB_WIDTH 4
-
-#include "FBXTokenizer.h"
-#include "core/string/print_string.h"
-
-namespace FBXDocParser {
-
-// ------------------------------------------------------------------------------------------------
-Token::Token(const char *p_sbegin, const char *p_send, TokenType p_type, unsigned int p_line, unsigned int p_column) :
- sbegin(p_sbegin),
- send(p_send),
- type(p_type),
- line(p_line),
- column(p_column) {
-#ifdef DEBUG_ENABLED
- contents = std::string(sbegin, static_cast<size_t>(send - sbegin));
-#endif
-}
-
-// ------------------------------------------------------------------------------------------------
-Token::~Token() {
-}
-
-namespace {
-
-// ------------------------------------------------------------------------------------------------
-void TokenizeError(const std::string &message, unsigned int line, unsigned int column) {
- print_error("[FBX-Tokenize]" + String(message.c_str()) + " " + itos(line) + ":" + itos(column));
-}
-
-// process a potential data token up to 'cur', adding it to 'output_tokens'.
-// ------------------------------------------------------------------------------------------------
-void ProcessDataToken(TokenList &output_tokens, const char *&start, const char *&end,
- unsigned int line,
- unsigned int column,
- TokenType type = TokenType_DATA,
- bool must_have_token = false) {
- if (start && end) {
- // sanity check:
- // tokens should have no whitespace outside quoted text and [start,end] should
- // properly delimit the valid range.
- bool in_double_quotes = false;
- for (const char *c = start; c != end + 1; ++c) {
- if (*c == '\"') {
- in_double_quotes = !in_double_quotes;
- }
-
- if (!in_double_quotes && IsSpaceOrNewLine(*c)) {
- TokenizeError("unexpected whitespace in token", line, column);
- }
- }
-
- if (in_double_quotes) {
- TokenizeError("non-terminated double quotes", line, column);
- }
-
- output_tokens.push_back(new_Token(start, end + 1, type, line, column));
- } else if (must_have_token) {
- TokenizeError("unexpected character, expected data token", line, column);
- }
-
- start = end = nullptr;
-}
-} // namespace
-
-// ------------------------------------------------------------------------------------------------
-void Tokenize(TokenList &output_tokens, const char *input, size_t length, bool &corrupt) {
- // line and column numbers numbers are one-based
- unsigned int line = 1;
- unsigned int column = 1;
-
- bool comment = false;
- bool in_double_quotes = false;
- bool pending_data_token = false;
-
- const char *token_begin = nullptr, *token_end = nullptr;
-
- // input (starting string), *cur the current string, column +=
- // modified to fix strlen() and stop buffer overflow
- for (size_t x = 0; x < length; x++) {
- const char c = input[x];
- const char *cur = &input[x];
- column += (c == '\t' ? ASSIMP_FBX_TAB_WIDTH : 1);
-
- if (IsLineEnd(c)) {
- comment = false;
-
- column = 0;
- ++line;
- }
-
- if (comment) {
- continue;
- }
-
- if (in_double_quotes) {
- if (c == '\"') {
- in_double_quotes = false;
- token_end = cur;
-
- ProcessDataToken(output_tokens, token_begin, token_end, line, column);
- pending_data_token = false;
- }
- continue;
- }
-
- switch (c) {
- case '\"':
- if (token_begin) {
- TokenizeError("unexpected double-quote", line, column);
- corrupt = true;
- return;
- }
- token_begin = cur;
- in_double_quotes = true;
- continue;
-
- case ';':
- ProcessDataToken(output_tokens, token_begin, token_end, line, column);
- comment = true;
- continue;
-
- case '{':
- ProcessDataToken(output_tokens, token_begin, token_end, line, column);
- output_tokens.push_back(new_Token(cur, cur + 1, TokenType_OPEN_BRACKET, line, column));
- continue;
-
- case '}':
- ProcessDataToken(output_tokens, token_begin, token_end, line, column);
- output_tokens.push_back(new_Token(cur, cur + 1, TokenType_CLOSE_BRACKET, line, column));
- continue;
-
- case ',':
- if (pending_data_token) {
- ProcessDataToken(output_tokens, token_begin, token_end, line, column, TokenType_DATA, true);
- }
- output_tokens.push_back(new_Token(cur, cur + 1, TokenType_COMMA, line, column));
- continue;
-
- case ':':
- if (pending_data_token) {
- ProcessDataToken(output_tokens, token_begin, token_end, line, column, TokenType_KEY, true);
- } else {
- TokenizeError("unexpected colon", line, column);
- }
- continue;
- }
-
- if (IsSpaceOrNewLine(c)) {
- if (token_begin) {
- // peek ahead and check if the next token is a colon in which
- // case this counts as KEY token.
- TokenType type = TokenType_DATA;
- for (const char *peek = cur; *peek && IsSpaceOrNewLine(*peek); ++peek) {
- if (*peek == ':') {
- type = TokenType_KEY;
- cur = peek;
- break;
- }
- }
-
- ProcessDataToken(output_tokens, token_begin, token_end, line, column, type);
- }
-
- pending_data_token = false;
- } else {
- token_end = cur;
- if (!token_begin) {
- token_begin = cur;
- }
-
- pending_data_token = true;
- }
- }
-}
-} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXTokenizer.h b/modules/fbx/fbx_parser/FBXTokenizer.h
deleted file mode 100644
index 789f8b5d9d..0000000000
--- a/modules/fbx/fbx_parser/FBXTokenizer.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/*************************************************************************/
-/* FBXTokenizer.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, assimp team
-
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
-
-* Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-
-/** @file FBXTokenizer.h
- * @brief FBX lexer
- */
-#ifndef FBX_TOKENIZER_H
-#define FBX_TOKENIZER_H
-
-#include "FBXParseTools.h"
-#include "core/string/ustring.h"
-#include <iostream>
-#include <memory>
-#include <string>
-#include <vector>
-
-namespace FBXDocParser {
-/** Rough classification for text FBX tokens used for constructing the
- * basic scope hierarchy. */
-enum TokenType {
- // {
- TokenType_OPEN_BRACKET = 0,
-
- // }
- TokenType_CLOSE_BRACKET,
-
- // '"blablubb"', '2', '*14' - very general token class,
- // further processing happens at a later stage.
- TokenType_DATA,
-
- //
- TokenType_BINARY_DATA,
-
- // ,
- TokenType_COMMA,
-
- // blubb:
- TokenType_KEY
-};
-
-/** Represents a single token in a FBX file. Tokens are
- * classified by the #TokenType enumerated types.
- *
- * Offers iterator protocol. Tokens are immutable. */
-class Token {
-private:
- static const unsigned int BINARY_MARKER = static_cast<unsigned int>(-1);
-
-public:
- /** construct a textual token */
- Token(const char *p_sbegin, const char *p_send, TokenType p_type, unsigned int p_line, unsigned int p_column);
-
- /** construct a binary token */
- Token(const char *p_sbegin, const char *p_send, TokenType p_type, size_t p_offset);
- ~Token();
-
-public:
- std::string StringContents() const {
- return std::string(begin(), end());
- }
-
- bool IsBinary() const {
- return column == BINARY_MARKER;
- }
-
- const char *begin() const {
- return sbegin;
- }
-
- const char *end() const {
- return send;
- }
-
- TokenType Type() const {
- return type;
- }
-
- size_t Offset() const {
- return offset;
- }
-
- unsigned int Line() const {
- return static_cast<unsigned int>(line);
- }
-
- unsigned int Column() const {
- return column;
- }
-
-private:
-#ifdef DEBUG_ENABLED
- // full string copy for the sole purpose that it nicely appears
- // in msvc's debugger window.
- std::string contents;
-#endif
-
- const char *sbegin = nullptr;
- const char *send = nullptr;
- const TokenType type;
-
- union {
- size_t line;
- size_t offset;
- };
- const unsigned int column = 0;
-};
-
-// Fixed leak by using shared_ptr for tokens
-typedef Token *TokenPtr;
-typedef std::vector<TokenPtr> TokenList;
-
-#define new_Token new Token
-
-/** Main FBX tokenizer function. Transform input buffer into a list of preprocessed tokens.
- *
- * Skips over comments and generates line and column numbers.
- *
- * @param output_tokens Receives a list of all tokens in the input data.
- * @param input_buffer Textual input buffer to be processed, 0-terminated.
- * @print_error if something goes wrong */
-void Tokenize(TokenList &output_tokens, const char *input, size_t length, bool &corrupt);
-
-/** Tokenizer function for binary FBX files.
- *
- * Emits a token list suitable for direct parsing.
- *
- * @param output_tokens Receives a list of all tokens in the input data.
- * @param input_buffer Binary input buffer to be processed.
- * @param length Length of input buffer, in bytes. There is no 0-terminal.
- * @print_error if something goes wrong */
-void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, bool &corrupt);
-} // namespace FBXDocParser
-
-#endif // FBX_TOKENIZER_H
diff --git a/modules/fbx/fbx_parser/FBXUtil.cpp b/modules/fbx/fbx_parser/FBXUtil.cpp
deleted file mode 100644
index e4958547d4..0000000000
--- a/modules/fbx/fbx_parser/FBXUtil.cpp
+++ /dev/null
@@ -1,222 +0,0 @@
-/*************************************************************************/
-/* FBXUtil.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, assimp team
-
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
-
-* Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-
-/** @file FBXUtil.cpp
- * @brief Implementation of internal FBX utility functions
- */
-
-#include "FBXUtil.h"
-#include "FBXTokenizer.h"
-#include <cstring>
-#include <string>
-
-namespace FBXDocParser {
-namespace Util {
-
-// ------------------------------------------------------------------------------------------------
-const char *TokenTypeString(TokenType t) {
- switch (t) {
- case TokenType_OPEN_BRACKET:
- return "TOK_OPEN_BRACKET";
-
- case TokenType_CLOSE_BRACKET:
- return "TOK_CLOSE_BRACKET";
-
- case TokenType_DATA:
- return "TOK_DATA";
-
- case TokenType_COMMA:
- return "TOK_COMMA";
-
- case TokenType_KEY:
- return "TOK_KEY";
-
- case TokenType_BINARY_DATA:
- return "TOK_BINARY_DATA";
- }
-
- //ai_assert(false);
- return "";
-}
-
-// Generated by this formula: T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;
-static const uint8_t base64DecodeTable[128] = {
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255,
- 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
- 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255
-};
-
-uint8_t DecodeBase64(char ch) {
- const uint8_t idx = static_cast<uint8_t>(ch);
- if (idx > 127) {
- return 255;
- }
- return base64DecodeTable[idx];
-}
-
-size_t ComputeDecodedSizeBase64(const char *in, size_t inLength) {
- if (inLength < 2) {
- return 0;
- }
- const size_t equals = size_t(in[inLength - 1] == '=') + size_t(in[inLength - 2] == '=');
- const size_t full_length = (inLength * 3) >> 2; // div by 4
- if (full_length < equals) {
- return 0;
- }
- return full_length - equals;
-}
-
-size_t DecodeBase64(const char *in, size_t inLength, uint8_t *out, size_t maxOutLength) {
- if (maxOutLength == 0 || inLength < 2) {
- return 0;
- }
- const size_t realLength = inLength - size_t(in[inLength - 1] == '=') - size_t(in[inLength - 2] == '=');
- size_t dst_offset = 0;
- int val = 0, valb = -8;
- for (size_t src_offset = 0; src_offset < realLength; ++src_offset) {
- const uint8_t table_value = Util::DecodeBase64(in[src_offset]);
- if (table_value == 255) {
- return 0;
- }
- val = (val << 6) + table_value;
- valb += 6;
- if (valb >= 0) {
- out[dst_offset++] = static_cast<uint8_t>((val >> valb) & 0xFF);
- valb -= 8;
- val &= 0xFFF;
- }
- }
- return dst_offset;
-}
-
-static const char to_base64_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-char EncodeBase64(char byte) {
- return to_base64_string[(size_t)byte];
-}
-
-/** Encodes a block of 4 bytes to base64 encoding
- * @param bytes Bytes to encode.
- * @param out_string String to write encoded values to.
- * @param string_pos Position in out_string.
- */
-void EncodeByteBlock(const char *bytes, std::string &out_string, size_t string_pos) {
- char b0 = (bytes[0] & 0xFC) >> 2;
- char b1 = (bytes[0] & 0x03) << 4 | ((bytes[1] & 0xF0) >> 4);
- char b2 = (bytes[1] & 0x0F) << 2 | ((bytes[2] & 0xC0) >> 6);
- char b3 = (bytes[2] & 0x3F);
-
- out_string[string_pos + 0] = EncodeBase64(b0);
- out_string[string_pos + 1] = EncodeBase64(b1);
- out_string[string_pos + 2] = EncodeBase64(b2);
- out_string[string_pos + 3] = EncodeBase64(b3);
-}
-
-std::string EncodeBase64(const char *data, size_t length) {
- // calculate extra bytes needed to get a multiple of 3
- size_t extraBytes = 3 - length % 3;
-
- // number of base64 bytes
- size_t encodedBytes = 4 * (length + extraBytes) / 3;
-
- std::string encoded_string(encodedBytes, '=');
-
- // read blocks of 3 bytes
- for (size_t ib3 = 0; ib3 < length / 3; ib3++) {
- const size_t iByte = ib3 * 3;
- const size_t iEncodedByte = ib3 * 4;
- const char *currData = &data[iByte];
-
- EncodeByteBlock(currData, encoded_string, iEncodedByte);
- }
-
- // if size of data is not a multiple of 3, also encode the final bytes (and add zeros where needed)
- if (extraBytes > 0) {
- char finalBytes[4] = { 0, 0, 0, 0 };
- memcpy(&finalBytes[0], &data[length - length % 3], length % 3);
-
- const size_t iEncodedByte = encodedBytes - 4;
- EncodeByteBlock(&finalBytes[0], encoded_string, iEncodedByte);
-
- // add '=' at the end
- for (size_t i = 0; i < 4 * extraBytes / 3; i++) {
- encoded_string[encodedBytes - i - 1] = '=';
- }
- }
- return encoded_string;
-}
-} // namespace Util
-} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXUtil.h b/modules/fbx/fbx_parser/FBXUtil.h
deleted file mode 100644
index 8022233029..0000000000
--- a/modules/fbx/fbx_parser/FBXUtil.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*************************************************************************/
-/* FBXUtil.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, assimp team
-
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
-
-* Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-
-/** @file FBXUtil.h
- * @brief FBX utility functions for internal use
- */
-#ifndef FBX_UTIL_H
-#define FBX_UTIL_H
-
-#include "FBXTokenizer.h"
-#include <stdint.h>
-
-namespace FBXDocParser {
-
-namespace Util {
-
-/** Get a string representation for a #TokenType. */
-const char *TokenTypeString(TokenType t);
-
-/** Decode a single Base64-encoded character.
- *
- * @param ch Character to decode (from base64 to binary).
- * @return decoded byte value*/
-uint8_t DecodeBase64(char ch);
-
-/** Compute decoded size of a Base64-encoded string
- *
- * @param in Characters to decode.
- * @param inLength Number of characters to decode.
- * @return size of the decoded data (number of bytes)*/
-size_t ComputeDecodedSizeBase64(const char *in, size_t inLength);
-
-/** Decode a Base64-encoded string
- *
- * @param in Characters to decode.
- * @param inLength Number of characters to decode.
- * @param out Pointer where we will store the decoded data.
- * @param maxOutLength Size of output buffer.
- * @return size of the decoded data (number of bytes)*/
-size_t DecodeBase64(const char *in, size_t inLength, uint8_t *out, size_t maxOutLength);
-
-char EncodeBase64(char byte);
-
-/** Encode bytes in base64-encoding
- *
- * @param data Binary data to encode.
- * @param inLength Number of bytes to encode.
- * @return base64-encoded string*/
-std::string EncodeBase64(const char *data, size_t length);
-} // namespace Util
-} // namespace FBXDocParser
-
-#endif // FBX_UTIL_H
diff --git a/modules/fbx/fbx_parser/LICENSE b/modules/fbx/fbx_parser/LICENSE
deleted file mode 100644
index b42fc6efe6..0000000000
--- a/modules/fbx/fbx_parser/LICENSE
+++ /dev/null
@@ -1,39 +0,0 @@
-The files in this folder were originally from ASSIMP, but have been heavily modified to fix bugs and match coding
-conventions of the Godot Engine project. We have kept a copy of the applicable licenses in the folder as required by
-the license.
-
-Open Asset Import Library (assimp)
-
-Copyright (c) 2006-2020, assimp team
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
-
-* Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
diff --git a/modules/fbx/tools/import_utils.cpp b/modules/fbx/tools/import_utils.cpp
deleted file mode 100644
index 5a49f24c00..0000000000
--- a/modules/fbx/tools/import_utils.cpp
+++ /dev/null
@@ -1,151 +0,0 @@
-/*************************************************************************/
-/* import_utils.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "import_utils.h"
-
-Vector3 ImportUtils::deg2rad(const Vector3 &p_rotation) {
- return p_rotation / 180.0 * Math_PI;
-}
-
-Vector3 ImportUtils::rad2deg(const Vector3 &p_rotation) {
- return p_rotation / Math_PI * 180.0;
-}
-
-Basis ImportUtils::EulerToBasis(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation) {
- Basis ret;
-
- // FBX is using intrinsic euler, we can convert intrinsic to extrinsic (the one used in godot
- // by simply invert its order: https://www.cs.utexas.edu/~theshark/courses/cs354/lectures/cs354-14.pdf
- switch (mode) {
- case FBXDocParser::Model::RotOrder_EulerXYZ:
- ret.set_euler(p_rotation, Basis::EULER_ORDER_XYZ);
- break;
-
- case FBXDocParser::Model::RotOrder_EulerXZY:
- ret.set_euler(p_rotation, Basis::EULER_ORDER_XZY);
- break;
-
- case FBXDocParser::Model::RotOrder_EulerYZX:
- ret.set_euler(p_rotation, Basis::EULER_ORDER_YZX);
- break;
-
- case FBXDocParser::Model::RotOrder_EulerYXZ:
- ret.set_euler(p_rotation, Basis::EULER_ORDER_YXZ);
- break;
-
- case FBXDocParser::Model::RotOrder_EulerZXY:
- ret.set_euler(p_rotation, Basis::EULER_ORDER_ZXY);
- break;
-
- case FBXDocParser::Model::RotOrder_EulerZYX:
- ret.set_euler(p_rotation, Basis::EULER_ORDER_ZYX);
- break;
-
- case FBXDocParser::Model::RotOrder_SphericXYZ:
- // TODO do this.
- break;
-
- default:
- // If you land here, Please integrate all enums.
- CRASH_NOW_MSG("This is not unreachable.");
- }
-
- return ret;
-}
-
-Quaternion ImportUtils::EulerToQuaternion(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation) {
- return ImportUtils::EulerToBasis(mode, p_rotation);
-}
-
-Vector3 ImportUtils::BasisToEuler(FBXDocParser::Model::RotOrder mode, const Basis &p_rotation) {
- // FBX is using intrinsic euler, we can convert intrinsic to extrinsic (the one used in godot
- // by simply invert its order: https://www.cs.utexas.edu/~theshark/courses/cs354/lectures/cs354-14.pdf
- switch (mode) {
- case FBXDocParser::Model::RotOrder_EulerXYZ:
- return p_rotation.get_euler(Basis::EULER_ORDER_XYZ);
-
- case FBXDocParser::Model::RotOrder_EulerXZY:
- return p_rotation.get_euler(Basis::EULER_ORDER_XZY);
-
- case FBXDocParser::Model::RotOrder_EulerYZX:
- return p_rotation.get_euler(Basis::EULER_ORDER_YZX);
-
- case FBXDocParser::Model::RotOrder_EulerYXZ:
- return p_rotation.get_euler(Basis::EULER_ORDER_YXZ);
-
- case FBXDocParser::Model::RotOrder_EulerZXY:
- return p_rotation.get_euler(Basis::EULER_ORDER_ZXY);
-
- case FBXDocParser::Model::RotOrder_EulerZYX:
- return p_rotation.get_euler(Basis::EULER_ORDER_ZYX);
-
- case FBXDocParser::Model::RotOrder_SphericXYZ:
- // TODO
- return Vector3();
-
- default:
- // If you land here, Please integrate all enums.
- CRASH_NOW_MSG("This is not unreachable.");
- return Vector3();
- }
-}
-
-Vector3 ImportUtils::QuaternionToEuler(FBXDocParser::Model::RotOrder mode, const Quaternion &p_rotation) {
- return BasisToEuler(mode, p_rotation);
-}
-
-Transform3D get_unscaled_transform(const Transform3D &p_initial, real_t p_scale) {
- Transform3D unscaled = Transform3D(p_initial.basis, p_initial.origin * p_scale);
- ERR_FAIL_COND_V_MSG(unscaled.basis.determinant() == 0, Transform3D(), "det is zero unscaled?");
- return unscaled;
-}
-
-Vector3 get_poly_normal(const std::vector<Vector3> &p_vertices) {
- ERR_FAIL_COND_V_MSG(p_vertices.size() < 3, Vector3(0, 0, 0), "At least 3 vertices are necessary");
- // Using long double to make sure that normal is computed for even really tiny objects.
- typedef long double ldouble;
- ldouble x = 0.0;
- ldouble y = 0.0;
- ldouble z = 0.0;
- for (size_t i = 0; i < p_vertices.size(); i += 1) {
- const Vector3 current = p_vertices[i];
- const Vector3 next = p_vertices[(i + 1) % p_vertices.size()];
- x += (ldouble(current.y) - ldouble(next.y)) * (ldouble(current.z) + ldouble(next.z));
- y += (ldouble(current.z) - ldouble(next.z)) * (ldouble(current.x) + ldouble(next.x));
- z += (ldouble(current.x) - ldouble(next.x)) * (ldouble(current.y) + ldouble(next.y));
- }
- const ldouble l2 = x * x + y * y + z * z;
- if (l2 == 0.0) {
- return (p_vertices[0] - p_vertices[1]).normalized().cross((p_vertices[0] - p_vertices[2]).normalized()).normalized();
- } else {
- const double l = Math::sqrt(double(l2));
- return Vector3(x / l, y / l, z / l);
- }
-}
diff --git a/modules/fbx/tools/import_utils.h b/modules/fbx/tools/import_utils.h
deleted file mode 100644
index b52263c2ac..0000000000
--- a/modules/fbx/tools/import_utils.h
+++ /dev/null
@@ -1,400 +0,0 @@
-/*************************************************************************/
-/* import_utils.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef IMPORT_UTILS_FBX_IMPORTER_H
-#define IMPORT_UTILS_FBX_IMPORTER_H
-
-#include "core/io/image_loader.h"
-
-#include "data/import_state.h"
-#include "fbx_parser/FBXDocument.h"
-
-#include <string>
-
-#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
-
-/**
- * Import Utils
- * Conversion tools / glue code to convert from FBX to Godot
- */
-class ImportUtils {
-public:
- /// Convert a vector from degrees to radians.
- static Vector3 deg2rad(const Vector3 &p_rotation);
-
- /// Convert a vector from radians to degrees.
- static Vector3 rad2deg(const Vector3 &p_rotation);
-
- /// Converts rotation order vector (in rad) to quaternion.
- static Basis EulerToBasis(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation);
-
- /// Converts rotation order vector (in rad) to quaternion.
- static Quaternion EulerToQuaternion(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation);
-
- /// Converts basis into rotation order vector (in rad).
- static Vector3 BasisToEuler(FBXDocParser::Model::RotOrder mode, const Basis &p_rotation);
-
- /// Converts quaternion into rotation order vector (in rad).
- static Vector3 QuaternionToEuler(FBXDocParser::Model::RotOrder mode, const Quaternion &p_rotation);
-
- static void debug_xform(String name, const Transform3D &t) {
- print_verbose(name + " " + t.origin + " rotation: " + (t.basis.get_euler() * (180 / Math_PI)));
- }
-
- static String FBXNodeToName(const std::string &name) {
- // strip Model:: prefix, avoiding ambiguities (i.e. don't strip if
- // this causes ambiguities, well possible between empty identifiers,
- // such as "Model::" and ""). Make sure the behaviour is consistent
- // across multiple calls to FixNodeName().
-
- // We must remove this from the name
- // Some bones have this
- // SubDeformer::
- // Meshes, Joints have this, some other IK elements too.
- // Model::
-
- String node_name = String(name.c_str());
-
- if (node_name.substr(0, 7) == "Model::") {
- node_name = node_name.substr(7, node_name.length() - 7);
- return node_name.replace(":", "");
- }
-
- if (node_name.substr(0, 13) == "SubDeformer::") {
- node_name = node_name.substr(13, node_name.length() - 13);
- return node_name.replace(":", "");
- }
-
- if (node_name.substr(0, 11) == "AnimStack::") {
- node_name = node_name.substr(11, node_name.length() - 11);
- return node_name.replace(":", "");
- }
-
- if (node_name.substr(0, 15) == "AnimCurveNode::") {
- node_name = node_name.substr(15, node_name.length() - 15);
- return node_name.replace(":", "");
- }
-
- if (node_name.substr(0, 11) == "AnimCurve::") {
- node_name = node_name.substr(11, node_name.length() - 11);
- return node_name.replace(":", "");
- }
-
- if (node_name.substr(0, 10) == "Geometry::") {
- node_name = node_name.substr(10, node_name.length() - 10);
- return node_name.replace(":", "");
- }
-
- if (node_name.substr(0, 10) == "Material::") {
- node_name = node_name.substr(10, node_name.length() - 10);
- return node_name.replace(":", "");
- }
-
- if (node_name.substr(0, 9) == "Texture::") {
- node_name = node_name.substr(9, node_name.length() - 9);
- return node_name.replace(":", "");
- }
-
- return node_name.replace(":", "");
- }
-
- static std::string FBXAnimMeshName(const std::string &name) {
- if (name.length()) {
- size_t indexOf = name.find_first_of("::");
- if (indexOf != std::string::npos && indexOf < name.size() - 2) {
- return name.substr(indexOf + 2);
- }
- }
- return name.length() ? name : "AnimMesh";
- }
-
- static Vector3 safe_import_vector3(const Vector3 &p_vec) {
- Vector3 vector = p_vec;
- if (Math::is_zero_approx(vector.x)) {
- vector.x = 0;
- }
-
- if (Math::is_zero_approx(vector.y)) {
- vector.y = 0;
- }
-
- if (Math::is_zero_approx(vector.z)) {
- vector.z = 0;
- }
- return vector;
- }
-
- static void debug_xform(String name, const Basis &t) {
- //print_verbose(name + " rotation: " + (t.get_euler() * (180 / Math_PI)));
- }
-
- static Vector3 FixAxisConversions(Vector3 input) {
- return Vector3(input.x, input.y, input.z);
- }
-
- static void AlignMeshAxes(std::vector<Vector3> &vertex_data) {
- for (size_t x = 0; x < vertex_data.size(); x++) {
- vertex_data[x] = FixAxisConversions(vertex_data[x]);
- }
- }
-
- struct AssetImportFbx {
- enum ETimeMode {
- TIME_MODE_DEFAULT = 0,
- TIME_MODE_120 = 1,
- TIME_MODE_100 = 2,
- TIME_MODE_60 = 3,
- TIME_MODE_50 = 4,
- TIME_MODE_48 = 5,
- TIME_MODE_30 = 6,
- TIME_MODE_30_DROP = 7,
- TIME_MODE_NTSC_DROP_FRAME = 8,
- TIME_MODE_NTSC_FULL_FRAME = 9,
- TIME_MODE_PAL = 10,
- TIME_MODE_CINEMA = 11,
- TIME_MODE_1000 = 12,
- TIME_MODE_CINEMA_ND = 13,
- TIME_MODE_CUSTOM = 14,
- TIME_MODE_TIME_MODE_COUNT = 15
- };
- enum UpAxis {
- UP_VECTOR_AXIS_X = 1,
- UP_VECTOR_AXIS_Y = 2,
- UP_VECTOR_AXIS_Z = 3
- };
- enum FrontAxis {
- FRONT_PARITY_EVEN = 1,
- FRONT_PARITY_ODD = 2,
- };
-
- enum CoordAxis {
- COORD_RIGHT = 0,
- COORD_LEFT = 1
- };
- };
-
- /** Get fbx fps for time mode meta data
- */
- static float get_fbx_fps(int32_t time_mode) {
- switch (time_mode) {
- case AssetImportFbx::TIME_MODE_DEFAULT:
- return 24;
- case AssetImportFbx::TIME_MODE_120:
- return 120;
- case AssetImportFbx::TIME_MODE_100:
- return 100;
- case AssetImportFbx::TIME_MODE_60:
- return 60;
- case AssetImportFbx::TIME_MODE_50:
- return 50;
- case AssetImportFbx::TIME_MODE_48:
- return 48;
- case AssetImportFbx::TIME_MODE_30:
- return 30;
- case AssetImportFbx::TIME_MODE_30_DROP:
- return 30;
- case AssetImportFbx::TIME_MODE_NTSC_DROP_FRAME:
- return 29.9700262f;
- case AssetImportFbx::TIME_MODE_NTSC_FULL_FRAME:
- return 29.9700262f;
- case AssetImportFbx::TIME_MODE_PAL:
- return 25;
- case AssetImportFbx::TIME_MODE_CINEMA:
- return 24;
- case AssetImportFbx::TIME_MODE_1000:
- return 1000;
- case AssetImportFbx::TIME_MODE_CINEMA_ND:
- return 23.976f;
- case AssetImportFbx::TIME_MODE_CUSTOM:
- return -1;
- }
- return 0;
- }
-
- static float get_fbx_fps(const FBXDocParser::FileGlobalSettings *FBXSettings) {
- int time_mode = FBXSettings->TimeMode();
-
- // get the animation FPS
- float frames_per_second = get_fbx_fps(time_mode);
-
- // handle animation custom FPS time.
- if (time_mode == ImportUtils::AssetImportFbx::TIME_MODE_CUSTOM) {
- print_verbose("FBX Animation has custom FPS setting");
- frames_per_second = FBXSettings->CustomFrameRate();
-
- // not our problem this is the modeller, we can print as an error so they can fix the source.
- if (frames_per_second == 0) {
- print_error("Custom animation time in file is set to 0 value, animation won't play, please edit your file to correct the FPS value");
- }
- }
- return frames_per_second;
- }
-
- /**
- * Find hardcoded textures from assimp which could be in many different directories
- */
-
- /**
- * set_texture_mapping_mode
- * Helper to check the mapping mode of the texture (repeat, clamp and mirror)
- */
- // static void set_texture_mapping_mode(aiTextureMapMode *map_mode, Ref<ImageTexture> texture) {
- // ERR_FAIL_COND(texture.is_null());
- // ERR_FAIL_COND(map_mode == nullptr);
- // aiTextureMapMode tex_mode = map_mode[0];
-
- // int32_t flags = Texture::FLAGS_DEFAULT;
- // if (tex_mode == aiTextureMapMode_Wrap) {
- // //Default
- // } else if (tex_mode == aiTextureMapMode_Clamp) {
- // flags = flags & ~Texture::FLAG_REPEAT;
- // } else if (tex_mode == aiTextureMapMode_Mirror) {
- // flags = flags | Texture::FLAG_MIRRORED_REPEAT;
- // }
- // texture->set_flags(flags);
- // }
-
- /**
- * Load or load from cache image :)
- * We need to upgrade this in the later version :) should not be hard
- */
- //static Ref<Image> load_image(ImportState &state, const aiScene *p_scene, String p_path){
- // Map<String, Ref<Image> >::Element *match = state.path_to_image_cache.find(p_path);
-
- // // if our cache contains this image then don't bother
- // if (match) {
- // return match->get();
- // }
-
- // Vector<String> split_path = p_path.get_basename().split("*");
- // if (split_path.size() == 2) {
- // size_t texture_idx = split_path[1].to_int();
- // ERR_FAIL_COND_V(texture_idx >= p_scene->mNumTextures, Ref<Image>());
- // aiTexture *tex = p_scene->mTextures[texture_idx];
- // String filename = AssimpUtils::get_raw_string_from_assimp(tex->mFilename);
- // filename = filename.get_file();
- // print_verbose("Open Asset Import: Loading embedded texture " + filename);
- // if (tex->mHeight == 0) {
- // if (tex->CheckFormat("png")) {
- // Ref<Image> img = Image::_png_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth);
- // ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
- // state.path_to_image_cache.insert(p_path, img);
- // return img;
- // } else if (tex->CheckFormat("jpg")) {
- // Ref<Image> img = Image::_jpg_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth);
- // ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
- // state.path_to_image_cache.insert(p_path, img);
- // return img;
- // } else if (tex->CheckFormat("dds")) {
- // ERR_FAIL_COND_V_MSG(true, Ref<Image>(), "Open Asset Import: Embedded dds not implemented");
- // }
- // } else {
- // Ref<Image> img;
- // img.instantiate();
- // PoolByteArray arr;
- // uint32_t size = tex->mWidth * tex->mHeight;
- // arr.resize(size);
- // memcpy(arr.write().ptr(), tex->pcData, size);
- // ERR_FAIL_COND_V(arr.size() % 4 != 0, Ref<Image>());
- // //ARGB8888 to RGBA8888
- // for (int32_t i = 0; i < arr.size() / 4; i++) {
- // arr.write().ptr()[(4 * i) + 3] = arr[(4 * i) + 0];
- // arr.write().ptr()[(4 * i) + 0] = arr[(4 * i) + 1];
- // arr.write().ptr()[(4 * i) + 1] = arr[(4 * i) + 2];
- // arr.write().ptr()[(4 * i) + 2] = arr[(4 * i) + 3];
- // }
- // img->create(tex->mWidth, tex->mHeight, true, Image::FORMAT_RGBA8, arr);
- // ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
- // state.path_to_image_cache.insert(p_path, img);
- // return img;
- // }
- // return Ref<Image>();
- // } else {
- // Ref<Texture> texture = ResourceLoader::load(p_path);
- // ERR_FAIL_COND_V(texture.is_null(), Ref<Image>());
- // Ref<Image> image = texture->get_image();
- // ERR_FAIL_COND_V(image.is_null(), Ref<Image>());
- // state.path_to_image_cache.insert(p_path, image);
- // return image;
- // }
-
- // return Ref<Image>();
- //}
-
- // /* create texture from assimp data, if found in path */
- // static bool CreateAssimpTexture(
- // AssimpImporter::ImportState &state,
- // aiString texture_path,
- // String &filename,
- // String &path,
- // AssimpImageData &image_state) {
- // filename = get_raw_string_from_assimp(texture_path);
- // path = state.path.get_base_dir().plus_file(filename.replace("\\", "/"));
- // bool found = false;
- // find_texture_path(state.path, path, found);
- // if (found) {
- // image_state.raw_image = AssimpUtils::load_image(state, state.assimp_scene, path);
- // if (image_state.raw_image.is_valid()) {
- // image_state.texture.instantiate();
- // image_state.texture->create_from_image(image_state.raw_image);
- // image_state.texture->set_storage(ImageTexture::STORAGE_COMPRESS_LOSSY);
- // return true;
- // }
- // }
-
- // return false;
- // }
- // /** GetAssimpTexture
- // * Designed to retrieve textures for you
- // */
- // static bool GetAssimpTexture(
- // AssimpImporter::ImportState &state,
- // aiMaterial *ai_material,
- // aiTextureType texture_type,
- // String &filename,
- // String &path,
- // AssimpImageData &image_state) {
- // aiString ai_filename = aiString();
- // if (AI_SUCCESS == ai_material->GetTexture(texture_type, 0, &ai_filename, nullptr, nullptr, nullptr, nullptr, image_state.map_mode)) {
- // return CreateAssimpTexture(state, ai_filename, filename, path, image_state);
- // }
-
- // return false;
- // }
-};
-
-// Apply the transforms so the basis will have scale 1.
-Transform3D get_unscaled_transform(const Transform3D &p_initial, real_t p_scale);
-
-/// Uses the Newell's method to compute any polygon normal.
-/// The polygon must be at least size of 3 or bigger.
-Vector3 get_poly_normal(const std::vector<Vector3> &p_vertices);
-
-#endif // IMPORT_UTILS_FBX_IMPORTER_H
diff --git a/modules/freetype/SCsub b/modules/freetype/SCsub
index 27d0777c17..d23c4b637c 100644
--- a/modules/freetype/SCsub
+++ b/modules/freetype/SCsub
@@ -57,6 +57,26 @@ if env["builtin_freetype"]:
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
+ thirdparty_brotli_dir = "#thirdparty/brotli/"
+ thirdparty_brotli_sources = [
+ "common/constants.c",
+ "common/context.c",
+ "common/dictionary.c",
+ "common/platform.c",
+ "common/shared_dictionary.c",
+ "common/transform.c",
+ "dec/bit_reader.c",
+ "dec/decode.c",
+ "dec/huffman.c",
+ "dec/state.c",
+ ]
+ thirdparty_sources += [thirdparty_brotli_dir + file for file in thirdparty_brotli_sources]
+ env_freetype.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"])
+ env_freetype.Prepend(CPPPATH=[thirdparty_brotli_dir + "include"])
+
+ if env.get("use_ubsan") or env.get("use_asan") or env.get("use_tsan") or env.get("use_lsan") or env.get("use_msan"):
+ env_freetype.Append(CPPDEFINES=["BROTLI_BUILD_PORTABLE"])
+
if env["platform"] == "uwp":
# Include header for UWP to fix build issues
env_freetype.Append(CCFLAGS=["/FI", '"modules/freetype/uwpdef.h"'])
diff --git a/modules/freetype/register_types.cpp b/modules/freetype/register_types.cpp
index 28fd1a57c9..a5a60c0368 100644
--- a/modules/freetype/register_types.cpp
+++ b/modules/freetype/register_types.cpp
@@ -30,6 +30,14 @@
#include "register_types.h"
-void register_freetype_types() {}
+void initialize_freetype_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+}
-void unregister_freetype_types() {}
+void uninitialize_freetype_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+}
diff --git a/modules/freetype/register_types.h b/modules/freetype/register_types.h
index c4eb241636..3399c0b3bc 100644
--- a/modules/freetype/register_types.h
+++ b/modules/freetype/register_types.h
@@ -31,7 +31,9 @@
#ifndef FREETYPE_REGISTER_TYPES_H
#define FREETYPE_REGISTER_TYPES_H
-void register_freetype_types();
-void unregister_freetype_types();
+#include "modules/register_module_types.h"
+
+void initialize_freetype_module(ModuleInitializationLevel p_level);
+void uninitialize_freetype_module(ModuleInitializationLevel p_level);
#endif // FREETYPE_REGISTER_TYPES_H
diff --git a/modules/gdscript/SCsub b/modules/gdscript/SCsub
index c6121ec7fe..2f507db548 100644
--- a/modules/gdscript/SCsub
+++ b/modules/gdscript/SCsub
@@ -10,6 +10,8 @@ env_gdscript.add_source_files(env.modules_sources, "*.cpp")
if env["tools"]:
env_gdscript.add_source_files(env.modules_sources, "./editor/*.cpp")
+ SConscript("editor/script_templates/SCsub")
+
# Those two modules are required for the language server protocol
if env["module_jsonrpc_enabled"] and env["module_websocket_enabled"]:
env_gdscript.add_source_files(env.modules_sources, "./language_server/*.cpp")
@@ -18,8 +20,7 @@ if env["tools"]:
# in regular builds where all modules are enabled.
env_gdscript.Append(CPPDEFINES=["GDSCRIPT_NO_LSP"])
+
if env["tests"]:
env_gdscript.Append(CPPDEFINES=["TESTS_ENABLED"])
env_gdscript.add_source_files(env.modules_sources, "./tests/*.cpp")
-
-SConscript("editor_templates/SCsub")
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index d9fab01dce..d0926d317b 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -186,7 +186,7 @@
<description>
Returns an array with the given range. Range can be 1 argument [code]N[/code] (0 to [code]N[/code] - 1), two arguments ([code]initial[/code], [code]final - 1[/code]) or three arguments ([code]initial[/code], [code]final - 1[/code], [code]increment[/code]). Returns an empty array if the range isn't valid (e.g. [code]range(2, 5, -1)[/code] or [code]range(5, 5, 1)[/code]).
Returns an array with the given range. [code]range()[/code] can have 1 argument N ([code]0[/code] to [code]N - 1[/code]), two arguments ([code]initial[/code], [code]final - 1[/code]) or three arguments ([code]initial[/code], [code]final - 1[/code], [code]increment[/code]). [code]increment[/code] can be negative. If [code]increment[/code] is negative, [code]final - 1[/code] will become [code]final + 1[/code]. Also, the initial value must be greater than the final value for the loop to run.
- [code]range()(/code] converts all arguments to [int] before processing.
+ [code]range()[/code] converts all arguments to [int] before processing.
[codeblock]
print(range(4))
print(range(2, 5))
diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
index a8f4483cf4..9b540b16f2 100644
--- a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
+++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
@@ -44,7 +44,7 @@ Error GDScriptEditorTranslationParserPlugin::parse_file(const String &p_path, Ve
// Search strings in AssignmentNode -> text = "__", hint_tooltip = "__" etc.
Error err;
- RES loaded_res = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &err);
+ Ref<Resource> loaded_res = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &err);
if (err) {
ERR_PRINT("Failed to load " + p_path);
return err;
diff --git a/modules/gdscript/editor_templates/CharacterBody2D/basic_movement.gd b/modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd
index 34b5ba45b7..a379d915a9 100644
--- a/modules/gdscript/editor_templates/CharacterBody2D/basic_movement.gd
+++ b/modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd
@@ -2,8 +2,9 @@
extends _BASE_
-const SPEED: float = 300.0
-const JUMP_VELOCITY: float = -400.0
+
+const SPEED = 300.0
+const JUMP_VELOCITY = -400.0
# Get the gravity from the project settings to be synced with RigidDynamicBody nodes.
var gravity: int = ProjectSettings.get_setting("physics/2d/default_gravity")
diff --git a/modules/gdscript/editor_templates/CharacterBody3D/basic_movement.gd b/modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd
index cbc9cf1064..360b199e56 100644
--- a/modules/gdscript/editor_templates/CharacterBody3D/basic_movement.gd
+++ b/modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd
@@ -2,8 +2,9 @@
extends _BASE_
-const SPEED: float = 5.0
-const JUMP_VELOCITY: float = 4.5
+
+const SPEED = 5.0
+const JUMP_VELOCITY = 4.5
# Get the gravity from the project settings to be synced with RigidDynamicBody nodes.
var gravity: float = ProjectSettings.get_setting("physics/3d/default_gravity")
diff --git a/modules/gdscript/editor_templates/EditorPlugin/plugin.gd b/modules/gdscript/editor/script_templates/EditorPlugin/plugin.gd
index 8614bb8b17..b27b3e5655 100644
--- a/modules/gdscript/editor_templates/EditorPlugin/plugin.gd
+++ b/modules/gdscript/editor/script_templates/EditorPlugin/plugin.gd
@@ -2,10 +2,12 @@
@tool
extends EditorPlugin
+
func _enter_tree() -> void:
- # Initialization of the plugin goes here.
- pass
+ # Initialization of the plugin goes here.
+ pass
+
func _exit_tree() -> void:
- # Clean-up of the plugin goes here.
- pass
+ # Clean-up of the plugin goes here.
+ pass
diff --git a/modules/gdscript/editor_templates/EditorScript/basic_editor_script.gd b/modules/gdscript/editor/script_templates/EditorScript/basic_editor_script.gd
index fdb174c7ed..fdb8550d43 100644
--- a/modules/gdscript/editor_templates/EditorScript/basic_editor_script.gd
+++ b/modules/gdscript/editor/script_templates/EditorScript/basic_editor_script.gd
@@ -2,6 +2,7 @@
@tool
extends EditorScript
+
+# Called when the script is executed (using File -> Run in Script Editor).
func _run() -> void:
- # Called when the script is executed (using File -> Run in Script Editor).
- pass
+ pass
diff --git a/modules/gdscript/editor_templates/Node/default.gd b/modules/gdscript/editor/script_templates/Node/default.gd
index ee5c0b99cc..cb96a21537 100644
--- a/modules/gdscript/editor_templates/Node/default.gd
+++ b/modules/gdscript/editor/script_templates/Node/default.gd
@@ -2,10 +2,12 @@
extends _BASE_
+
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
pass # Replace with function body.
+
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
pass
diff --git a/modules/gdscript/editor_templates/Object/empty.gd b/modules/gdscript/editor/script_templates/Object/empty.gd
index 387786b0a4..387786b0a4 100644
--- a/modules/gdscript/editor_templates/Object/empty.gd
+++ b/modules/gdscript/editor/script_templates/Object/empty.gd
diff --git a/modules/gdscript/editor_templates/SCsub b/modules/gdscript/editor/script_templates/SCsub
index 2266ef2d01..2266ef2d01 100644
--- a/modules/gdscript/editor_templates/SCsub
+++ b/modules/gdscript/editor/script_templates/SCsub
diff --git a/modules/gdscript/editor_templates/VisualShaderNodeCustom/basic.gd b/modules/gdscript/editor/script_templates/VisualShaderNodeCustom/basic.gd
index cf6d68333d..283a95d3b4 100644
--- a/modules/gdscript/editor_templates/VisualShaderNodeCustom/basic.gd
+++ b/modules/gdscript/editor/script_templates/VisualShaderNodeCustom/basic.gd
@@ -1,38 +1,50 @@
# meta-description: Visual shader's node plugin template
@tool
-extends _BASE_
class_name VisualShaderNode_CLASS_
+extends _BASE_
+
func _get_name() -> String:
return "_CLASS_"
+
func _get_category() -> String:
return ""
+
func _get_description() -> String:
return ""
+
func _get_return_icon_type() -> int:
return PORT_TYPE_SCALAR
+
func _get_input_port_count() -> int:
return 0
+
func _get_input_port_name(port: int) -> String:
return ""
+
func _get_input_port_type(port: int) -> int:
return PORT_TYPE_SCALAR
+
func _get_output_port_count() -> int:
return 1
+
func _get_output_port_name(port: int) -> String:
return "result"
+
func _get_output_port_type(port: int) -> int:
return PORT_TYPE_SCALAR
-func _get_code(input_vars: Array[String], output_vars: Array[String], mode: int, type: int) -> String:
+
+func _get_code(input_vars: Array[String], output_vars: Array[String],
+ mode: int, type: int) -> String:
return output_vars[0] + " = 0.0;"
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index c12c1a43a3..1b4711804c 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -82,7 +82,7 @@ Variant GDScriptNativeClass::_new() {
RefCounted *rc = Object::cast_to<RefCounted>(o);
if (rc) {
- return REF(rc);
+ return Ref<RefCounted>(rc);
} else {
return o;
}
@@ -92,6 +92,21 @@ Object *GDScriptNativeClass::instantiate() {
return ClassDB::instantiate(name);
}
+Variant GDScriptNativeClass::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ if (p_method == SNAME("new")) {
+ // Constructor.
+ return Object::callp(p_method, p_args, p_argcount, r_error);
+ }
+ MethodBind *method = ClassDB::get_method(name, p_method);
+ if (method) {
+ // Native static method.
+ return method->call(nullptr, p_args, p_argcount, r_error);
+ }
+
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return Variant();
+}
+
GDScriptFunction *GDScript::_super_constructor(GDScript *p_script) {
if (p_script->initializer) {
return p_script->initializer;
@@ -180,7 +195,7 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallErr
}
r_error.error = Callable::CallError::CALL_OK;
- REF ref;
+ Ref<RefCounted> ref;
Object *owner = nullptr;
GDScript *_baseptr = this;
@@ -198,7 +213,7 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallErr
RefCounted *r = Object::cast_to<RefCounted>(owner);
if (r) {
- ref = REF(r);
+ ref = Ref<RefCounted>(r);
}
GDScriptInstance *instance = _create_instance(p_args, p_argcount, owner, r != nullptr, r_error);
@@ -824,11 +839,7 @@ Error GDScript::reload(bool p_keep_state) {
// Loading a template, don't parse.
#ifdef TOOLS_ENABLED
- if (basedir.begins_with(EditorSettings::get_singleton()->get_project_script_templates_dir())) {
- return OK;
- }
-#else
- if (source.contains("_BASE_")) {
+ if (EditorSettings::get_singleton() && basedir.begins_with(EditorSettings::get_singleton()->get_project_script_templates_dir())) {
return OK;
}
#endif
@@ -1019,17 +1030,21 @@ Error GDScript::load_byte_code(const String &p_path) {
Error GDScript::load_source_code(const String &p_path) {
Vector<uint8_t> sourcef;
Error err;
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
if (err) {
- ERR_FAIL_COND_V(err, err);
+ const char *err_name;
+ if (err < 0 || err >= ERR_MAX) {
+ err_name = "(invalid error code)";
+ } else {
+ err_name = error_names[err];
+ }
+ ERR_FAIL_COND_V_MSG(err, err, "Attempt to open script '" + p_path + "' resulted in error '" + err_name + "'.");
}
uint64_t len = f->get_length();
sourcef.resize(len + 1);
uint8_t *w = sourcef.ptrw();
uint64_t r = f->get_buffer(w, len);
- f->close();
- memdelete(f);
ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN);
w[len] = 0;
@@ -2088,7 +2103,7 @@ bool GDScriptLanguage::handles_global_class_type(const String &p_type) const {
String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const {
Vector<uint8_t> sourcef;
Error err;
- FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
if (err) {
return String();
}
@@ -2122,8 +2137,8 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
} else {
Vector<StringName> extend_classes = subclass->extends;
- FileAccessRef subfile = FileAccess::open(subclass->extends_path, FileAccess::READ);
- if (!subfile) {
+ Ref<FileAccess> subfile = FileAccess::open(subclass->extends_path, FileAccess::READ);
+ if (subfile.is_null()) {
break;
}
String subsource = subfile->get_as_utf8_string();
@@ -2277,7 +2292,7 @@ Ref<GDScript> GDScriptLanguage::get_orphan_subclass(const String &p_qualified_na
/*************** RESOURCE ***************/
-RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+Ref<Resource> ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_FILE_CANT_OPEN;
}
@@ -2320,8 +2335,8 @@ String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) con
}
void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) {
- FileAccessRef file = FileAccess::open(p_path, FileAccess::READ);
- ERR_FAIL_COND_MSG(!file, "Cannot open file '" + p_path + "'.");
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::READ);
+ ERR_FAIL_COND_MSG(file.is_null(), "Cannot open file '" + p_path + "'.");
String source = file->get_as_utf8_string();
if (source.is_empty()) {
@@ -2338,24 +2353,23 @@ void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<S
}
}
-Error ResourceFormatSaverGDScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
+Error ResourceFormatSaverGDScript::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) {
Ref<GDScript> sqscr = p_resource;
ERR_FAIL_COND_V(sqscr.is_null(), ERR_INVALID_PARAMETER);
String source = sqscr->get_source_code();
- Error err;
- FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err);
+ {
+ Error err;
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
- ERR_FAIL_COND_V_MSG(err, err, "Cannot save GDScript file '" + p_path + "'.");
+ ERR_FAIL_COND_V_MSG(err, err, "Cannot save GDScript file '" + p_path + "'.");
- file->store_string(source);
- if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
- memdelete(file);
- return ERR_CANT_CREATE;
+ file->store_string(source);
+ if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
+ return ERR_CANT_CREATE;
+ }
}
- file->close();
- memdelete(file);
if (ScriptServer::is_reload_scripts_on_save_enabled()) {
GDScriptLanguage::get_singleton()->reload_tool_script(p_resource, false);
@@ -2364,12 +2378,12 @@ Error ResourceFormatSaverGDScript::save(const String &p_path, const RES &p_resou
return OK;
}
-void ResourceFormatSaverGDScript::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
+void ResourceFormatSaverGDScript::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
if (Object::cast_to<GDScript>(*p_resource)) {
p_extensions->push_back("gd");
}
}
-bool ResourceFormatSaverGDScript::recognize(const RES &p_resource) const {
+bool ResourceFormatSaverGDScript::recognize(const Ref<Resource> &p_resource) const {
return Object::cast_to<GDScript>(*p_resource) != nullptr;
}
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 30e60e2b91..a20f3b2fca 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -52,6 +52,7 @@ public:
_FORCE_INLINE_ const StringName &get_name() const { return name; }
Variant _new();
Object *instantiate();
+ virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override;
GDScriptNativeClass(const StringName &p_name);
};
@@ -212,7 +213,7 @@ public:
virtual void update_exports() override;
#ifdef TOOLS_ENABLED
- virtual const Vector<DocData::ClassDoc> &get_documentation() const override {
+ virtual Vector<DocData::ClassDoc> get_documentation() const override {
return docs;
}
#endif // TOOLS_ENABLED
@@ -261,11 +262,12 @@ class GDScriptInstance : public ScriptInstance {
friend class GDScript;
friend class GDScriptFunction;
friend class GDScriptLambdaCallable;
+ friend class GDScriptLambdaSelfCallable;
friend class GDScriptCompiler;
friend struct GDScriptUtilityFunctionsDefinitions;
ObjectID owner_id;
- Object *owner;
+ Object *owner = nullptr;
Ref<GDScript> script;
#ifdef DEBUG_ENABLED
Map<StringName, int> member_indices_cache; //used only for hot script reloading
@@ -311,17 +313,17 @@ class GDScriptLanguage : public ScriptLanguage {
static GDScriptLanguage *singleton;
- Variant *_global_array;
+ Variant *_global_array = nullptr;
Vector<Variant> global_array;
Map<StringName, int> globals;
Map<StringName, Variant> named_globals;
struct CallLevel {
- Variant *stack;
- GDScriptFunction *function;
- GDScriptInstance *instance;
- int *ip;
- int *line;
+ Variant *stack = nullptr;
+ GDScriptFunction *function = nullptr;
+ GDScriptInstance *instance = nullptr;
+ int *ip = nullptr;
+ int *line = nullptr;
};
int _debug_parse_err_line;
@@ -329,7 +331,7 @@ class GDScriptLanguage : public ScriptLanguage {
String _debug_error;
int _debug_call_stack_pos;
int _debug_max_call_stack;
- CallLevel *_call_stack;
+ CallLevel *_call_stack = nullptr;
void _add_global(const StringName &p_name, const Variant &p_value);
@@ -455,7 +457,7 @@ public:
virtual bool can_inherit_from_file() const override { return true; }
virtual int find_function(const String &p_function, const String &p_code) const override;
virtual String make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const override;
- virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) override;
+ virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptLanguage::CodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) override;
#ifdef TOOLS_ENABLED
virtual Error lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result) override;
#endif
@@ -510,7 +512,7 @@ public:
class ResourceFormatLoaderGDScript : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
@@ -519,9 +521,9 @@ public:
class ResourceFormatSaverGDScript : public ResourceFormatSaver {
public:
- virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0);
- virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const;
- virtual bool recognize(const RES &p_resource) const;
+ virtual Error save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags = 0);
+ virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const;
+ virtual bool recognize(const Ref<Resource> &p_resource) const;
};
#endif // GDSCRIPT_H
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 326720ce86..d346264933 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -277,6 +277,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
base = parser->get_parser()->head->get_datatype();
} else {
if (p_class->extends.is_empty()) {
+ push_error("Could not resolve an empty super class path.", p_class);
return ERR_PARSE_ERROR;
}
const StringName &name = p_class->extends[extends_index++];
@@ -646,7 +647,7 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
}
}
- // Check if initalizer is an unset identifier (ie: a variable within scope, but declared below)
+ // Check if initializer is an unset identifier (ie: a variable within scope, but declared below)
if (member.variable->initializer && !member.variable->initializer->get_datatype().is_set()) {
if (member.variable->initializer->type == GDScriptParser::Node::IDENTIFIER) {
GDScriptParser::IdentifierNode *initializer_identifier = static_cast<GDScriptParser::IdentifierNode *>(member.variable->initializer);
@@ -1124,6 +1125,10 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
GDScriptParser::FunctionNode *previous_function = parser->current_function;
parser->current_function = p_function;
+#ifdef TOOLS_ENABLED
+ int default_value_count = 0;
+#endif // TOOLS_ENABLED
+
for (int i = 0; i < p_function->parameters.size(); i++) {
resolve_parameter(p_function->parameters[i]);
#ifdef DEBUG_ENABLED
@@ -1133,8 +1138,12 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
is_shadowing(p_function->parameters[i]->identifier, "function parameter");
#endif // DEBUG_ENABLED
#ifdef TOOLS_ENABLED
- if (p_function->parameters[i]->default_value && p_function->parameters[i]->default_value->is_constant) {
- p_function->default_arg_values.push_back(p_function->parameters[i]->default_value->reduced_value);
+ if (p_function->parameters[i]->default_value) {
+ default_value_count++;
+
+ if (p_function->parameters[i]->default_value->is_constant) {
+ p_function->default_arg_values.push_back(p_function->parameters[i]->default_value->reduced_value);
+ }
}
#endif // TOOLS_ENABLED
}
@@ -1169,7 +1178,7 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
int par_count_diff = p_function->parameters.size() - parameters_types.size();
valid = valid && par_count_diff >= 0;
- valid = valid && p_function->default_arg_values.size() >= default_par_count + par_count_diff;
+ valid = valid && default_value_count >= default_par_count + par_count_diff;
int i = 0;
for (const GDScriptParser::DataType &par_type : parameters_types) {
@@ -1203,7 +1212,7 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
push_error(vformat(R"(The function signature doesn't match the parent. Parent signature is "%s".)", parent_signature), p_function);
}
}
-#endif
+#endif // TOOLS_ENABLED
}
parser->current_function = previous_function;
@@ -2294,7 +2303,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
break;
#ifdef DEBUG_ENABLED
} else {
- if (par_type.builtin_type == Variant::INT && p_call->arguments[i]->get_datatype().builtin_type == Variant::FLOAT) {
+ if (par_type.builtin_type == Variant::INT && p_call->arguments[i]->get_datatype().builtin_type == Variant::FLOAT && builtin_type != Variant::INT) {
parser->push_warning(p_call, GDScriptWarning::NARROWING_CONVERSION, p_call->function_name);
}
#endif
@@ -2417,6 +2426,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
base_type = parser->current_class->base_type;
base_type.is_meta_type = false;
is_self = true;
+
+ if (p_call->callee == nullptr && !lambda_stack.is_empty()) {
+ push_error("Cannot use `super()` inside a lambda.", p_call);
+ }
} else if (callee_type == GDScriptParser::Node::IDENTIFIER) {
base_type = parser->current_class->get_datatype();
base_type.is_meta_type = false;
@@ -2485,18 +2498,24 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
}
if (is_self && parser->current_function != nullptr && parser->current_function->is_static && !is_static) {
- push_error(vformat(R"*(Cannot call non-static function "%s()" from static function "%s()".)*", p_call->function_name, parser->current_function->identifier->name), p_call->callee);
+ // Get the parent function above any lambda.
+ GDScriptParser::FunctionNode *parent_function = parser->current_function;
+ while (parent_function->source_lambda) {
+ parent_function = parent_function->source_lambda->parent_function;
+ }
+ push_error(vformat(R"*(Cannot call non-static function "%s()" from static function "%s()".)*", p_call->function_name, parent_function->identifier->name), p_call);
} else if (!is_self && base_type.is_meta_type && !is_static) {
base_type.is_meta_type = false; // For `to_string()`.
- push_error(vformat(R"*(Cannot call non-static function "%s()" on the class "%s" directly. Make an instance instead.)*", p_call->function_name, base_type.to_string()), p_call->callee);
- } else if (is_self && !is_static && !lambda_stack.is_empty()) {
- push_error(vformat(R"*(Cannot call non-static function "%s()" from a lambda function.)*", p_call->function_name), p_call->callee);
+ push_error(vformat(R"*(Cannot call non-static function "%s()" on the class "%s" directly. Make an instance instead.)*", p_call->function_name, base_type.to_string()), p_call);
+ } else if (is_self && !is_static) {
+ mark_lambda_use_self();
}
call_type = return_type;
} else {
- // Check if the name exists as something else.
bool found = false;
+
+ // Check if the name exists as something else.
if (!p_call->is_super && callee_type != GDScriptParser::Node::NONE) {
GDScriptParser::IdentifierNode *callee_id;
if (callee_type == GDScriptParser::Node::IDENTIFIER) {
@@ -2526,11 +2545,13 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
if (!found && (is_self || (base_type.is_hard_type() && base_type.kind == GDScriptParser::DataType::BUILTIN))) {
String base_name = is_self && !p_call->is_super ? "self" : base_type.to_string();
push_error(vformat(R"*(Function "%s()" not found in base %s.)*", p_call->function_name, base_name), p_call->is_super ? p_call : p_call->callee);
+ } else if (!found && (!p_call->is_super && base_type.is_hard_type() && base_type.kind == GDScriptParser::DataType::NATIVE && base_type.is_meta_type)) {
+ push_error(vformat(R"*(Static function "%s()" not found in base "%s".)*", p_call->function_name, base_type.native_type.operator String()), p_call);
}
}
if (call_type.is_coroutine && !p_is_await && !p_is_root) {
- push_error(vformat(R"*(Function "%s()" is a coroutine, so it must be called with "await".)*", p_call->function_name), p_call->callee);
+ push_error(vformat(R"*(Function "%s()" is a coroutine, so it must be called with "await".)*", p_call->function_name), p_call);
}
p_call->set_datatype(call_type);
@@ -2620,10 +2641,10 @@ void GDScriptAnalyzer::reduce_get_node(GDScriptParser::GetNodeNode *p_get_node)
if (!ClassDB::is_parent_class(parser->current_class->base_type.native_type, result.native_type)) {
push_error(R"*(Cannot use shorthand "get_node()" notation ("$") on a class that isn't a node.)*", p_get_node);
- } else if (!lambda_stack.is_empty()) {
- push_error(R"*(Cannot use shorthand "get_node()" notation ("$") inside a lambda. Use a captured variable instead.)*", p_get_node);
}
+ mark_lambda_use_self();
+
p_get_node->set_datatype(result);
}
@@ -2838,21 +2859,25 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
MethodBind *getter = ClassDB::get_method(native, getter_name);
if (getter != nullptr) {
p_identifier->set_datatype(type_from_property(getter->get_return_info()));
+ p_identifier->source = GDScriptParser::IdentifierNode::INHERITED_VARIABLE;
}
return;
}
if (ClassDB::get_method_info(native, name, &method_info)) {
// Method is callable.
p_identifier->set_datatype(make_callable_type(method_info));
+ p_identifier->source = GDScriptParser::IdentifierNode::INHERITED_VARIABLE;
return;
}
if (ClassDB::get_signal(native, name, &method_info)) {
// Signal is a type too.
p_identifier->set_datatype(make_signal_type(method_info));
+ p_identifier->source = GDScriptParser::IdentifierNode::INHERITED_VARIABLE;
return;
}
if (ClassDB::has_enum(native, name)) {
p_identifier->set_datatype(make_native_enum_type(native, name));
+ p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CONSTANT;
return;
}
bool valid = false;
@@ -2861,6 +2886,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
p_identifier->is_constant = true;
p_identifier->reduced_value = int_constant;
p_identifier->set_datatype(type_from_variant(int_constant, p_identifier));
+ p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CONSTANT;
return;
}
}
@@ -2911,7 +2937,11 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
p_identifier->reduced_value = p_identifier->constant_source->initializer->reduced_value;
found_source = true;
break;
+ case GDScriptParser::IdentifierNode::INHERITED_VARIABLE:
+ mark_lambda_use_self();
+ break;
case GDScriptParser::IdentifierNode::MEMBER_VARIABLE:
+ mark_lambda_use_self();
p_identifier->variable_source->usages++;
[[fallthrough]];
case GDScriptParser::IdentifierNode::LOCAL_VARIABLE:
@@ -2942,18 +2972,37 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
}
if (found_source) {
- // If the identifier is local, check if it's any kind of capture by comparing their source function.
- // Only capture locals and members and enum values. Constants are still accessible from the lambda using the script reference.
- if (p_identifier->source == GDScriptParser::IdentifierNode::UNDEFINED_SOURCE || p_identifier->source == GDScriptParser::IdentifierNode::MEMBER_CONSTANT || lambda_stack.is_empty()) {
- return;
+ if ((p_identifier->source == GDScriptParser::IdentifierNode::MEMBER_VARIABLE || p_identifier->source == GDScriptParser::IdentifierNode::INHERITED_VARIABLE) && parser->current_function && parser->current_function->is_static) {
+ // Get the parent function above any lambda.
+ GDScriptParser::FunctionNode *parent_function = parser->current_function;
+ while (parent_function->source_lambda) {
+ parent_function = parent_function->source_lambda->parent_function;
+ }
+ push_error(vformat(R"*(Cannot access instance variable "%s" from the static function "%s()".)*", p_identifier->name, parent_function->identifier->name), p_identifier);
}
- GDScriptParser::FunctionNode *function_test = lambda_stack.back()->get()->function;
- while (function_test != nullptr && function_test != p_identifier->source_function && function_test->source_lambda != nullptr && !function_test->source_lambda->captures_indices.has(p_identifier->name)) {
- function_test->source_lambda->captures_indices[p_identifier->name] = function_test->source_lambda->captures.size();
- function_test->source_lambda->captures.push_back(p_identifier);
- function_test = function_test->source_lambda->parent_function;
+ if (!lambda_stack.is_empty()) {
+ // If the identifier is a member variable (including the native class properties), we consider the lambda to be using `self`, so we keep a reference to the current instance.
+ if (p_identifier->source == GDScriptParser::IdentifierNode::MEMBER_VARIABLE || p_identifier->source == GDScriptParser::IdentifierNode::INHERITED_VARIABLE) {
+ mark_lambda_use_self();
+ return; // No need to capture.
+ }
+ // If the identifier is local, check if it's any kind of capture by comparing their source function.
+ // Only capture locals and enum values. Constants are still accessible from the lambda using the script reference. If not, this method is done.
+ if (p_identifier->source == GDScriptParser::IdentifierNode::UNDEFINED_SOURCE || p_identifier->source == GDScriptParser::IdentifierNode::MEMBER_CONSTANT) {
+ return;
+ }
+
+ GDScriptParser::FunctionNode *function_test = lambda_stack.back()->get()->function;
+ // Make sure we aren't capturing variable in the same lambda.
+ // This also add captures for nested lambdas.
+ while (function_test != nullptr && function_test != p_identifier->source_function && function_test->source_lambda != nullptr && !function_test->source_lambda->captures_indices.has(p_identifier->name)) {
+ function_test->source_lambda->captures_indices[p_identifier->name] = function_test->source_lambda->captures.size();
+ function_test->source_lambda->captures.push_back(p_identifier);
+ function_test = function_test->source_lambda->parent_function;
+ }
}
+
return;
}
@@ -3133,6 +3182,7 @@ void GDScriptAnalyzer::reduce_preload(GDScriptParser::PreloadNode *p_preload) {
void GDScriptAnalyzer::reduce_self(GDScriptParser::SelfNode *p_self) {
p_self->is_constant = false;
p_self->set_datatype(type_from_metatype(parser->current_class->get_datatype()));
+ mark_lambda_use_self();
}
void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscript) {
@@ -3143,6 +3193,12 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
reduce_identifier(static_cast<GDScriptParser::IdentifierNode *>(p_subscript->base), true);
} else {
reduce_expression(p_subscript->base);
+
+ if (p_subscript->base->type == GDScriptParser::Node::ARRAY) {
+ const_fold_array(static_cast<GDScriptParser::ArrayNode *>(p_subscript->base));
+ } else if (p_subscript->base->type == GDScriptParser::Node::DICTIONARY) {
+ const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(p_subscript->base));
+ }
}
GDScriptParser::DataType result_type;
@@ -3460,6 +3516,13 @@ void GDScriptAnalyzer::const_fold_array(GDScriptParser::ArrayNode *p_array) {
for (int i = 0; i < p_array->elements.size(); i++) {
GDScriptParser::ExpressionNode *element = p_array->elements[i];
+
+ if (element->type == GDScriptParser::Node::ARRAY) {
+ const_fold_array(static_cast<GDScriptParser::ArrayNode *>(element));
+ } else if (element->type == GDScriptParser::Node::DICTIONARY) {
+ const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(element));
+ }
+
all_is_constant = all_is_constant && element->is_constant;
if (!all_is_constant) {
return;
@@ -3480,6 +3543,13 @@ void GDScriptAnalyzer::const_fold_dictionary(GDScriptParser::DictionaryNode *p_d
for (int i = 0; i < p_dictionary->elements.size(); i++) {
const GDScriptParser::DictionaryNode::Pair &element = p_dictionary->elements[i];
+
+ if (element.value->type == GDScriptParser::Node::ARRAY) {
+ const_fold_array(static_cast<GDScriptParser::ArrayNode *>(element.value));
+ } else if (element.value->type == GDScriptParser::Node::DICTIONARY) {
+ const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(element.value));
+ }
+
all_is_constant = all_is_constant && element.key->is_constant && element.value->is_constant;
if (!all_is_constant) {
return;
@@ -3760,6 +3830,7 @@ bool GDScriptAnalyzer::function_signature_from_info(const MethodInfo &p_info, GD
r_return_type = type_from_property(p_info.return_val);
r_default_arg_count = p_info.default_arguments.size();
r_vararg = (p_info.flags & METHOD_FLAG_VARARG) != 0;
+ r_static = (p_info.flags & METHOD_FLAG_STATIC) != 0;
for (const PropertyInfo &E : p_info.arguments) {
r_par_types.push_back(type_from_property(E));
@@ -4104,6 +4175,12 @@ void GDScriptAnalyzer::mark_node_unsafe(const GDScriptParser::Node *p_node) {
#endif
}
+void GDScriptAnalyzer::mark_lambda_use_self() {
+ for (GDScriptParser::LambdaNode *lambda : lambda_stack) {
+ lambda->use_self = true;
+ }
+}
+
bool GDScriptAnalyzer::class_exists(const StringName &p_class) const {
return ClassDB::class_exists(p_class) && ClassDB::is_class_exposed(p_class);
}
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index 7b8883e1d3..519e1975c4 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -42,7 +42,7 @@ class GDScriptAnalyzer {
HashMap<String, Ref<GDScriptParserRef>> depended_parsers;
const GDScriptParser::EnumNode *current_enum = nullptr;
- List<const GDScriptParser::LambdaNode *> lambda_stack;
+ List<GDScriptParser::LambdaNode *> lambda_stack;
// Tests for detecting invalid overloading of script members
static _FORCE_INLINE_ bool has_member_name_conflict_in_script_class(const StringName &p_name, const GDScriptParser::ClassNode *p_current_class_node);
@@ -115,6 +115,7 @@ class GDScriptAnalyzer {
bool is_type_compatible(const GDScriptParser::DataType &p_target, const GDScriptParser::DataType &p_source, bool p_allow_implicit_conversion = false, const GDScriptParser::Node *p_source_node = nullptr);
void push_error(const String &p_message, const GDScriptParser::Node *p_origin);
void mark_node_unsafe(const GDScriptParser::Node *p_node);
+ void mark_lambda_use_self();
bool class_exists(const StringName &p_class) const;
Ref<GDScriptParserRef> get_parser_for(const String &p_path);
#ifdef DEBUG_ENABLED
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index 82aa14795e..e72069bcd5 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -468,7 +468,7 @@ void GDScriptByteCodeGenerator::write_type_adjust(const Address &p_target, Varia
append(GDScriptFunction::OPCODE_TYPE_ADJUST_BASIS, 1);
break;
case Variant::TRANSFORM3D:
- append(GDScriptFunction::OPCODE_TYPE_ADJUST_TRANSFORM, 1);
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_TRANSFORM3D, 1);
break;
case Variant::COLOR:
append(GDScriptFunction::OPCODE_TYPE_ADJUST_COLOR, 1);
@@ -1080,6 +1080,24 @@ void GDScriptByteCodeGenerator::write_call_builtin_type_static(const Address &p_
append(Variant::get_validated_builtin_method(p_type, p_method));
}
+void GDScriptByteCodeGenerator::write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) {
+ bool is_validated = false;
+
+ MethodBind *method = ClassDB::get_method(p_class, p_method);
+
+ if (!is_validated) {
+ // Perform regular call.
+ append(GDScriptFunction::OPCODE_CALL_NATIVE_STATIC, p_arguments.size() + 1);
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(p_target);
+ append(method);
+ append(p_arguments.size());
+ return;
+ }
+}
+
void GDScriptByteCodeGenerator::write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) {
append(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL_METHOD_BIND : GDScriptFunction::OPCODE_CALL_METHOD_BIND_RET, 2 + p_arguments.size());
for (int i = 0; i < p_arguments.size(); i++) {
@@ -1193,8 +1211,8 @@ void GDScriptByteCodeGenerator::write_call_script_function(const Address &p_targ
append(p_function_name);
}
-void GDScriptByteCodeGenerator::write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures) {
- append(GDScriptFunction::OPCODE_CREATE_LAMBDA, 1 + p_captures.size());
+void GDScriptByteCodeGenerator::write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures, bool p_use_self) {
+ append(p_use_self ? GDScriptFunction::OPCODE_CREATE_SELF_LAMBDA : GDScriptFunction::OPCODE_CREATE_LAMBDA, 1 + p_captures.size());
for (int i = 0; i < p_captures.size(); i++) {
append(p_captures[i]);
}
diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h
index db15dc55ef..0503f66161 100644
--- a/modules/gdscript/gdscript_byte_codegen.h
+++ b/modules/gdscript/gdscript_byte_codegen.h
@@ -464,12 +464,13 @@ public:
virtual void write_call_gdscript_utility(const Address &p_target, GDScriptUtilityFunctions::FunctionPtr p_function, const Vector<Address> &p_arguments) override;
virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override;
virtual void write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override;
+ virtual void write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) override;
virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override;
virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override;
virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_call_self_async(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
- virtual void write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures) override;
+ virtual void write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures, bool p_use_self) override;
virtual void write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) override;
virtual void write_construct_array(const Address &p_target, const Vector<Address> &p_arguments) override;
virtual void write_construct_typed_array(const Address &p_target, const GDScriptDataType &p_element_type, const Vector<Address> &p_arguments) override;
diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp
index 6ada7d36f5..8c198345c2 100644
--- a/modules/gdscript/gdscript_cache.cpp
+++ b/modules/gdscript/gdscript_cache.cpp
@@ -145,7 +145,7 @@ Ref<GDScriptParserRef> GDScriptCache::get_parser(const String &p_path, GDScriptP
String GDScriptCache::get_source_code(const String &p_path) {
Vector<uint8_t> source_file;
Error err;
- FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
if (err) {
ERR_FAIL_COND_V(err, "");
}
@@ -153,7 +153,6 @@ String GDScriptCache::get_source_code(const String &p_path) {
uint64_t len = f->get_length();
source_file.resize(len + 1);
uint64_t r = f->get_buffer(source_file.ptrw(), len);
- f->close();
ERR_FAIL_COND_V(r != len, "");
source_file.write[len] = 0;
diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h
index 4542dd94ae..326b66a295 100644
--- a/modules/gdscript/gdscript_codegen.h
+++ b/modules/gdscript/gdscript_codegen.h
@@ -125,12 +125,13 @@ public:
virtual void write_call_gdscript_utility(const Address &p_target, GDScriptUtilityFunctions::FunctionPtr p_function, const Vector<Address> &p_arguments) = 0;
virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) = 0;
virtual void write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) = 0;
+ virtual void write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) = 0;
virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_call_self_async(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
- virtual void write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures) = 0;
+ virtual void write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures, bool p_use_self) = 0;
virtual void write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) = 0;
virtual void write_construct_array(const Address &p_target, const Vector<Address> &p_arguments) = 0;
virtual void write_construct_typed_array(const Address &p_target, const GDScriptDataType &p_element_type, const Vector<Address> &p_arguments) = 0;
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 8190eecbc7..37a988ee4c 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -35,6 +35,7 @@
#include "gdscript_cache.h"
#include "gdscript_utility_functions.h"
+#include "core/config/engine.h"
#include "core/config/project_settings.h"
bool GDScriptCompiler::_is_class_member_property(CodeGen &codegen, const StringName &p_name) {
@@ -355,7 +356,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
class_node = class_node->outer;
}
- RES res;
+ Ref<Resource> res;
if (class_node->identifier && class_node->identifier->name == identifier) {
res = Ref<GDScript>(main_script);
@@ -575,6 +576,10 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
// May be static built-in method call.
if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) < Variant::VARIANT_MAX) {
gen->write_call_builtin_type_static(result, GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name), subscript->attribute->name, arguments);
+ } else if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && call->function_name != SNAME("new") &&
+ ClassDB::class_exists(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) && !Engine::get_singleton()->has_singleton(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name)) {
+ // It's a static native method call.
+ gen->write_call_native_static(result, static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name, subscript->attribute->name, arguments);
} else {
GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, subscript->base);
if (r_error) {
@@ -1192,7 +1197,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
return GDScriptCodeGenerator::Address();
}
- gen->write_lambda(result, function, captures);
+ gen->write_lambda(result, function, captures, lambda->use_self);
for (int i = 0; i < captures.size(); i++) {
if (captures[i].mode == GDScriptCodeGenerator::Address::TEMPORARY) {
diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp
index cc0be94a9e..dc114f2eff 100644
--- a/modules/gdscript/gdscript_disassembler.cpp
+++ b/modules/gdscript/gdscript_disassembler.cpp
@@ -564,6 +564,28 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr += 5 + argc;
} break;
+ case OPCODE_CALL_NATIVE_STATIC: {
+ MethodBind *method = _methods_ptr[_code_ptr[ip + 1 + instr_var_args]];
+ int argc = _code_ptr[ip + 2 + instr_var_args];
+
+ text += "call native method static ";
+ text += DADDR(1 + argc);
+ text += " = ";
+ text += method->get_instance_class();
+ text += ".";
+ text += method->get_name();
+ text += "(";
+
+ for (int i = 0; i < argc; i++) {
+ if (i > 0) {
+ text += ", ";
+ }
+ text += DADDR(1 + i);
+ }
+ text += ")";
+
+ incr += 4 + argc;
+ } break;
case OPCODE_CALL_PTRCALL_NO_RETURN: {
text += "call-ptrcall (no return) ";
@@ -770,6 +792,25 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr = 3 + captures_count;
} break;
+ case OPCODE_CREATE_SELF_LAMBDA: {
+ int captures_count = _code_ptr[ip + 1 + instr_var_args];
+ GDScriptFunction *lambda = _lambdas_ptr[_code_ptr[ip + 2 + instr_var_args]];
+
+ text += DADDR(1 + captures_count);
+ text += "create self lambda from ";
+ text += lambda->name.operator String();
+ text += "function, captures (";
+
+ for (int i = 0; i < captures_count; i++) {
+ if (i > 0) {
+ text += ", ";
+ }
+ text += DADDR(1 + i);
+ }
+ text += ")";
+
+ incr = 3 + captures_count;
+ } break;
case OPCODE_JUMP: {
text += "jump ";
text += itos(_code_ptr[ip + 1]);
@@ -968,7 +1009,7 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
DISASSEMBLE_TYPE_ADJUST(QUATERNION);
DISASSEMBLE_TYPE_ADJUST(AABB);
DISASSEMBLE_TYPE_ADJUST(BASIS);
- DISASSEMBLE_TYPE_ADJUST(TRANSFORM);
+ DISASSEMBLE_TYPE_ADJUST(TRANSFORM3D);
DISASSEMBLE_TYPE_ADJUST(COLOR);
DISASSEMBLE_TYPE_ADJUST(STRING_NAME);
DISASSEMBLE_TYPE_ADJUST(NODE_PATH);
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 350962ba1b..0197bf9ea3 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -33,7 +33,6 @@
#include "core/config/engine.h"
#include "core/core_constants.h"
#include "core/io/file_access.h"
-#include "editor_templates/templates.gen.h"
#include "gdscript_analyzer.h"
#include "gdscript_compiler.h"
#include "gdscript_parser.h"
@@ -44,6 +43,7 @@
#include "core/config/project_settings.h"
#include "editor/editor_file_system.h"
#include "editor/editor_settings.h"
+#include "editor/script_templates/templates.gen.h"
#endif
void GDScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
@@ -64,20 +64,20 @@ Ref<Script> GDScriptLanguage::make_template(const String &p_template, const Stri
Ref<GDScript> script;
script.instantiate();
String processed_template = p_template;
+ bool type_hints = false;
#ifdef TOOLS_ENABLED
- if (!EDITOR_GET("text_editor/completion/add_type_hints")) {
+ type_hints = EDITOR_GET("text_editor/completion/add_type_hints");
+#endif
+ if (!type_hints) {
processed_template = processed_template.replace(": int", "")
.replace(": String", "")
+ .replace(": Array[String]", "")
.replace(": float", "")
.replace(":=", "=")
+ .replace(" -> String", "")
+ .replace(" -> int", "")
.replace(" -> void", "");
}
-#else
- processed_template = processed_template.replace(": int", "")
- .replace(": String", "")
- .replace(": float", "")
- .replace(" -> void", "");
-#endif
processed_template = processed_template.replace("_BASE_", p_base_class_name)
.replace("_CLASS_", p_class_name)
@@ -88,11 +88,13 @@ Ref<Script> GDScriptLanguage::make_template(const String &p_template, const Stri
Vector<ScriptLanguage::ScriptTemplate> GDScriptLanguage::get_built_in_templates(StringName p_object) {
Vector<ScriptLanguage::ScriptTemplate> templates;
+#ifdef TOOLS_ENABLED
for (int i = 0; i < TEMPLATES_ARRAY_SIZE; i++) {
if (TEMPLATES[i].inherit == p_object) {
templates.append(TEMPLATES[i]);
}
}
+#endif
return templates;
}
@@ -483,6 +485,89 @@ struct GDScriptCompletionIdentifier {
const GDScriptParser::ExpressionNode *assigned_expression = nullptr;
};
+// LOCATION METHODS
+// These methods are used to populate the `CodeCompletionOption::location` integer.
+// For these methods, the location is based on the depth in the inheritance chain that the property
+// appears. For example, if you are completing code in a class that inherits Node2D, a property found on Node2D
+// will have a "better" (lower) location "score" than a property that is found on CanvasItem.
+
+static int _get_property_location(StringName p_class, StringName p_property) {
+ if (!ClassDB::has_property(p_class, p_property)) {
+ return ScriptLanguage::LOCATION_OTHER;
+ }
+
+ int depth = 0;
+ StringName class_test = p_class;
+ while (class_test && !ClassDB::has_property(class_test, p_property, true)) {
+ class_test = ClassDB::get_parent_class(class_test);
+ depth++;
+ }
+
+ return depth | ScriptLanguage::LOCATION_PARENT_MASK;
+}
+
+static int _get_constant_location(StringName p_class, StringName p_constant) {
+ if (!ClassDB::has_integer_constant(p_class, p_constant)) {
+ return ScriptLanguage::LOCATION_OTHER;
+ }
+
+ int depth = 0;
+ StringName class_test = p_class;
+ while (class_test && !ClassDB::has_integer_constant(class_test, p_constant, true)) {
+ class_test = ClassDB::get_parent_class(class_test);
+ depth++;
+ }
+
+ return depth | ScriptLanguage::LOCATION_PARENT_MASK;
+}
+
+static int _get_signal_location(StringName p_class, StringName p_signal) {
+ if (!ClassDB::has_signal(p_class, p_signal)) {
+ return ScriptLanguage::LOCATION_OTHER;
+ }
+
+ int depth = 0;
+ StringName class_test = p_class;
+ while (class_test && !ClassDB::has_signal(class_test, p_signal, true)) {
+ class_test = ClassDB::get_parent_class(class_test);
+ depth++;
+ }
+
+ return depth | ScriptLanguage::LOCATION_PARENT_MASK;
+}
+
+static int _get_method_location(StringName p_class, StringName p_method) {
+ if (!ClassDB::has_method(p_class, p_method)) {
+ return ScriptLanguage::LOCATION_OTHER;
+ }
+
+ int depth = 0;
+ StringName class_test = p_class;
+ while (class_test && !ClassDB::has_method(class_test, p_method, true)) {
+ class_test = ClassDB::get_parent_class(class_test);
+ depth++;
+ }
+
+ return depth | ScriptLanguage::LOCATION_PARENT_MASK;
+}
+
+static int _get_enum_constant_location(StringName p_class, StringName p_enum_constant) {
+ if (!ClassDB::get_integer_constant_enum(p_class, p_enum_constant)) {
+ return ScriptLanguage::LOCATION_OTHER;
+ }
+
+ int depth = 0;
+ StringName class_test = p_class;
+ while (class_test && !ClassDB::get_integer_constant_enum(class_test, p_enum_constant, true)) {
+ class_test = ClassDB::get_parent_class(class_test);
+ depth++;
+ }
+
+ return depth | ScriptLanguage::LOCATION_PARENT_MASK;
+}
+
+// END LOCATION METHODS
+
static String _get_visual_datatype(const PropertyInfo &p_info, bool p_is_arg = true) {
if (p_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
String enum_name = p_info.class_name;
@@ -637,11 +722,11 @@ static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_functio
return arghint;
}
-static void _get_directory_contents(EditorFileSystemDirectory *p_dir, Map<String, ScriptCodeCompletionOption> &r_list) {
+static void _get_directory_contents(EditorFileSystemDirectory *p_dir, Map<String, ScriptLanguage::CodeCompletionOption> &r_list) {
const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\"";
for (int i = 0; i < p_dir->get_file_count(); i++) {
- ScriptCodeCompletionOption option(p_dir->get_file_path(i), ScriptCodeCompletionOption::KIND_FILE_PATH);
+ ScriptLanguage::CodeCompletionOption option(p_dir->get_file_path(i), ScriptLanguage::CODE_COMPLETION_KIND_FILE_PATH);
option.insert_text = option.display.quote(quote_style);
r_list.insert(option.display, option);
}
@@ -651,29 +736,29 @@ static void _get_directory_contents(EditorFileSystemDirectory *p_dir, Map<String
}
}
-static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_annotation, int p_argument, const String p_quote_style, Map<String, ScriptCodeCompletionOption> &r_result) {
+static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_annotation, int p_argument, const String p_quote_style, Map<String, ScriptLanguage::CodeCompletionOption> &r_result) {
if (p_annotation->name == SNAME("@export_range")) {
if (p_argument == 3 || p_argument == 4) {
// Slider hint.
- ScriptCodeCompletionOption slider1("or_greater", ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
+ ScriptLanguage::CodeCompletionOption slider1("or_greater", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
slider1.insert_text = slider1.display.quote(p_quote_style);
r_result.insert(slider1.display, slider1);
- ScriptCodeCompletionOption slider2("or_lesser", ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
+ ScriptLanguage::CodeCompletionOption slider2("or_lesser", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
slider2.insert_text = slider2.display.quote(p_quote_style);
r_result.insert(slider2.display, slider2);
}
} else if (p_annotation->name == SNAME("@export_exp_easing")) {
if (p_argument == 0 || p_argument == 1) {
// Easing hint.
- ScriptCodeCompletionOption hint1("attenuation", ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
+ ScriptLanguage::CodeCompletionOption hint1("attenuation", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
hint1.insert_text = hint1.display.quote(p_quote_style);
r_result.insert(hint1.display, hint1);
- ScriptCodeCompletionOption hint2("inout", ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
+ ScriptLanguage::CodeCompletionOption hint2("inout", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
hint2.insert_text = hint2.display.quote(p_quote_style);
r_result.insert(hint2.display, hint2);
}
} else if (p_annotation->name == SNAME("@export_node_path")) {
- ScriptCodeCompletionOption node("Node", ScriptCodeCompletionOption::KIND_CLASS);
+ ScriptLanguage::CodeCompletionOption node("Node", ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
r_result.insert(node.display, node);
List<StringName> node_types;
ClassDB::get_inheriters_from_class("Node", &node_types);
@@ -681,23 +766,38 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a
if (!ClassDB::is_class_exposed(E)) {
continue;
}
- ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_CLASS);
+ ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
r_result.insert(option.display, option);
}
} else if (p_annotation->name == SNAME("@warning_ignore")) {
for (int warning_code = 0; warning_code < GDScriptWarning::WARNING_MAX; warning_code++) {
- ScriptCodeCompletionOption warning(GDScriptWarning::get_name_from_code((GDScriptWarning::Code)warning_code).to_lower(), ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
+ ScriptLanguage::CodeCompletionOption warning(GDScriptWarning::get_name_from_code((GDScriptWarning::Code)warning_code).to_lower(), ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
r_result.insert(warning.display, warning);
}
}
}
-static void _list_available_types(bool p_inherit_only, GDScriptParser::CompletionContext &p_context, Map<String, ScriptCodeCompletionOption> &r_result) {
+static void _find_built_in_variants(Map<String, ScriptLanguage::CodeCompletionOption> &r_result, bool exclude_nil = false) {
+ for (int i = 0; i < Variant::VARIANT_MAX; i++) {
+ if (!exclude_nil && Variant::Type(i) == Variant::Type::NIL) {
+ ScriptLanguage::CodeCompletionOption option("null", ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
+ r_result.insert(option.display, option);
+ } else {
+ ScriptLanguage::CodeCompletionOption option(Variant::get_type_name(Variant::Type(i)), ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
+ r_result.insert(option.display, option);
+ }
+ }
+}
+
+static void _list_available_types(bool p_inherit_only, GDScriptParser::CompletionContext &p_context, Map<String, ScriptLanguage::CodeCompletionOption> &r_result) {
+ // Built-in Variant Types
+ _find_built_in_variants(r_result, true);
+
List<StringName> native_types;
ClassDB::get_class_list(&native_types);
for (const StringName &E : native_types) {
if (ClassDB::is_class_exposed(E) && !Engine::get_singleton()->has_singleton(E)) {
- ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_CLASS);
+ ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
r_result.insert(option.display, option);
}
}
@@ -708,7 +808,7 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio
List<StringName> enums;
ClassDB::get_enum_list(p_context.current_class->base_type.native_type, &enums);
for (const StringName &E : enums) {
- ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_ENUM);
+ ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_ENUM);
r_result.insert(option.display, option);
}
}
@@ -719,18 +819,18 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio
const GDScriptParser::ClassNode::Member &member = current->members[i];
switch (member.type) {
case GDScriptParser::ClassNode::Member::CLASS: {
- ScriptCodeCompletionOption option(member.m_class->identifier->name, ScriptCodeCompletionOption::KIND_CLASS);
+ ScriptLanguage::CodeCompletionOption option(member.m_class->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_LOCAL);
r_result.insert(option.display, option);
} break;
case GDScriptParser::ClassNode::Member::ENUM: {
if (!p_inherit_only) {
- ScriptCodeCompletionOption option(member.m_enum->identifier->name, ScriptCodeCompletionOption::KIND_ENUM);
+ ScriptLanguage::CodeCompletionOption option(member.m_enum->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_ENUM, ScriptLanguage::LOCATION_LOCAL);
r_result.insert(option.display, option);
}
} break;
case GDScriptParser::ClassNode::Member::CONSTANT: {
if (member.constant->get_datatype().is_meta_type && p_context.current_class->outer != nullptr) {
- ScriptCodeCompletionOption option(member.constant->identifier->name, ScriptCodeCompletionOption::KIND_CLASS);
+ ScriptLanguage::CodeCompletionOption option(member.constant->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_LOCAL);
r_result.insert(option.display, option);
}
} break;
@@ -746,7 +846,7 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio
List<StringName> global_classes;
ScriptServer::get_global_class_list(&global_classes);
for (const StringName &E : global_classes) {
- ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_CLASS);
+ ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_OTHER_USER_CODE);
r_result.insert(option.display, option);
}
@@ -757,19 +857,19 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio
if (!info.is_singleton || info.path.get_extension().to_lower() != "gd") {
continue;
}
- ScriptCodeCompletionOption option(info.name, ScriptCodeCompletionOption::KIND_CLASS);
+ ScriptLanguage::CodeCompletionOption option(info.name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_OTHER_USER_CODE);
r_result.insert(option.display, option);
}
}
-static void _find_identifiers_in_suite(const GDScriptParser::SuiteNode *p_suite, Map<String, ScriptCodeCompletionOption> &r_result) {
+static void _find_identifiers_in_suite(const GDScriptParser::SuiteNode *p_suite, Map<String, ScriptLanguage::CodeCompletionOption> &r_result) {
for (int i = 0; i < p_suite->locals.size(); i++) {
- ScriptCodeCompletionOption option;
+ ScriptLanguage::CodeCompletionOption option;
if (p_suite->locals[i].type == GDScriptParser::SuiteNode::Local::CONSTANT) {
- option = ScriptCodeCompletionOption(p_suite->locals[i].name, ScriptCodeCompletionOption::KIND_CONSTANT);
+ option = ScriptLanguage::CodeCompletionOption(p_suite->locals[i].name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, ScriptLanguage::LOCATION_LOCAL);
option.default_value = p_suite->locals[i].constant->initializer->reduced_value;
} else {
- option = ScriptCodeCompletionOption(p_suite->locals[i].name, ScriptCodeCompletionOption::KIND_VARIABLE);
+ option = ScriptLanguage::CodeCompletionOption(p_suite->locals[i].name, ScriptLanguage::CODE_COMPLETION_KIND_VARIABLE, ScriptLanguage::LOCATION_LOCAL);
}
r_result.insert(option.display, option);
}
@@ -778,24 +878,26 @@ static void _find_identifiers_in_suite(const GDScriptParser::SuiteNode *p_suite,
}
}
-static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result, int p_recursion_depth);
+static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth);
-static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, bool p_only_functions, bool p_static, bool p_parent_only, Map<String, ScriptCodeCompletionOption> &r_result, int p_recursion_depth) {
+static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, bool p_only_functions, bool p_static, bool p_parent_only, Map<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth) {
ERR_FAIL_COND(p_recursion_depth > COMPLETION_RECURSION_LIMIT);
if (!p_parent_only) {
bool outer = false;
const GDScriptParser::ClassNode *clss = p_class;
+ int classes_processed = 0;
while (clss) {
for (int i = 0; i < clss->members.size(); i++) {
+ const int location = (classes_processed + p_recursion_depth) | ScriptLanguage::LOCATION_PARENT_MASK;
const GDScriptParser::ClassNode::Member &member = clss->members[i];
- ScriptCodeCompletionOption option;
+ ScriptLanguage::CodeCompletionOption option;
switch (member.type) {
case GDScriptParser::ClassNode::Member::VARIABLE:
if (p_only_functions || outer || (p_static)) {
continue;
}
- option = ScriptCodeCompletionOption(member.variable->identifier->name, ScriptCodeCompletionOption::KIND_MEMBER);
+ option = ScriptLanguage::CodeCompletionOption(member.variable->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, location);
break;
case GDScriptParser::ClassNode::Member::CONSTANT:
if (p_only_functions) {
@@ -804,7 +906,7 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,
if (r_result.has(member.constant->identifier->name)) {
continue;
}
- option = ScriptCodeCompletionOption(member.constant->identifier->name, ScriptCodeCompletionOption::KIND_CONSTANT);
+ option = ScriptLanguage::CodeCompletionOption(member.constant->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location);
if (member.constant->initializer) {
option.default_value = member.constant->initializer->reduced_value;
}
@@ -813,25 +915,25 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,
if (p_only_functions) {
continue;
}
- option = ScriptCodeCompletionOption(member.m_class->identifier->name, ScriptCodeCompletionOption::KIND_CLASS);
+ option = ScriptLanguage::CodeCompletionOption(member.m_class->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, location);
break;
case GDScriptParser::ClassNode::Member::ENUM_VALUE:
if (p_only_functions) {
continue;
}
- option = ScriptCodeCompletionOption(member.enum_value.identifier->name, ScriptCodeCompletionOption::KIND_CONSTANT);
+ option = ScriptLanguage::CodeCompletionOption(member.enum_value.identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location);
break;
case GDScriptParser::ClassNode::Member::ENUM:
if (p_only_functions) {
continue;
}
- option = ScriptCodeCompletionOption(member.m_enum->identifier->name, ScriptCodeCompletionOption::KIND_ENUM);
+ option = ScriptLanguage::CodeCompletionOption(member.m_enum->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_ENUM, location);
break;
case GDScriptParser::ClassNode::Member::FUNCTION:
if (outer || (p_static && !member.function->is_static) || member.function->identifier->name.operator String().begins_with("@")) {
continue;
}
- option = ScriptCodeCompletionOption(member.function->identifier->name, ScriptCodeCompletionOption::KIND_FUNCTION);
+ option = ScriptLanguage::CodeCompletionOption(member.function->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location);
if (member.function->parameters.size() > 0) {
option.insert_text += "(";
} else {
@@ -842,7 +944,7 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,
if (p_only_functions || outer) {
continue;
}
- option = ScriptCodeCompletionOption(member.signal->identifier->name, ScriptCodeCompletionOption::KIND_SIGNAL);
+ option = ScriptLanguage::CodeCompletionOption(member.signal->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL, location);
break;
case GDScriptParser::ClassNode::Member::UNDEFINED:
break;
@@ -851,6 +953,7 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,
}
outer = true;
clss = clss->outer;
+ classes_processed++;
}
}
@@ -862,14 +965,14 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,
_find_identifiers_in_base(base_type, p_only_functions, r_result, p_recursion_depth + 1);
}
-static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result, int p_recursion_depth) {
+static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth) {
ERR_FAIL_COND(p_recursion_depth > COMPLETION_RECURSION_LIMIT);
GDScriptParser::DataType base_type = p_base.type;
bool _static = base_type.is_meta_type;
if (_static && base_type.kind != GDScriptParser::DataType::BUILTIN) {
- ScriptCodeCompletionOption option("new", ScriptCodeCompletionOption::KIND_FUNCTION);
+ ScriptLanguage::CodeCompletionOption option("new", ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, ScriptLanguage::LOCATION_LOCAL);
option.insert_text += "(";
r_result.insert(option.display, option);
}
@@ -889,21 +992,24 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
List<PropertyInfo> members;
scr->get_script_property_list(&members);
for (const PropertyInfo &E : members) {
- ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_MEMBER);
+ int location = p_recursion_depth + _get_property_location(scr->get_class_name(), E.class_name);
+ ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, location);
r_result.insert(option.display, option);
}
}
Map<StringName, Variant> constants;
scr->get_constants(&constants);
for (const KeyValue<StringName, Variant> &E : constants) {
- ScriptCodeCompletionOption option(E.key.operator String(), ScriptCodeCompletionOption::KIND_CONSTANT);
+ int location = p_recursion_depth + _get_constant_location(scr->get_class_name(), E.key);
+ ScriptLanguage::CodeCompletionOption option(E.key.operator String(), ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location);
r_result.insert(option.display, option);
}
List<MethodInfo> signals;
scr->get_script_signal_list(&signals);
for (const MethodInfo &E : signals) {
- ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_SIGNAL);
+ int location = p_recursion_depth + _get_signal_location(scr->get_class_name(), E.name);
+ ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL, location);
r_result.insert(option.display, option);
}
}
@@ -914,7 +1020,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
if (E.name.begins_with("@")) {
continue;
}
- ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_FUNCTION);
+ int location = p_recursion_depth + _get_method_location(scr->get_class_name(), E.name);
+ ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location);
if (E.arguments.size()) {
option.insert_text += "(";
} else {
@@ -944,7 +1051,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
List<String> constants;
ClassDB::get_integer_constant_list(type, &constants);
for (const String &E : constants) {
- ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_CONSTANT);
+ int location = p_recursion_depth + _get_constant_location(type, StringName(E));
+ ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location);
r_result.insert(option.display, option);
}
@@ -958,29 +1066,33 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
if (E.name.contains("/")) {
continue;
}
- ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_MEMBER);
+ int location = p_recursion_depth + _get_property_location(type, E.class_name);
+ ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, location);
r_result.insert(option.display, option);
}
}
}
- if (!_static || Engine::get_singleton()->has_singleton(type)) {
- List<MethodInfo> methods;
- ClassDB::get_method_list(type, &methods, false, true);
- for (const MethodInfo &E : methods) {
- if (E.name.begins_with("_")) {
- continue;
- }
- ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_FUNCTION);
- if (E.arguments.size()) {
- option.insert_text += "(";
- } else {
- option.insert_text += "()";
- }
- r_result.insert(option.display, option);
+ bool only_static = _static && !Engine::get_singleton()->has_singleton(type);
+
+ List<MethodInfo> methods;
+ ClassDB::get_method_list(type, &methods, false, true);
+ for (const MethodInfo &E : methods) {
+ if (only_static && (E.flags & METHOD_FLAG_STATIC) == 0) {
+ continue;
+ }
+ if (E.name.begins_with("_")) {
+ continue;
+ }
+ int location = p_recursion_depth + _get_method_location(type, E.name);
+ ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location);
+ if (E.arguments.size()) {
+ option.insert_text += "(";
+ } else {
+ option.insert_text += "()";
}
+ r_result.insert(option.display, option);
}
-
return;
} break;
case GDScriptParser::DataType::BUILTIN: {
@@ -1001,7 +1113,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
for (const PropertyInfo &E : members) {
if (!String(E.name).contains("/")) {
- ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_MEMBER);
+ ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER);
r_result.insert(option.display, option);
}
}
@@ -1010,7 +1122,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
List<MethodInfo> methods;
tmp.get_method_list(&methods);
for (const MethodInfo &E : methods) {
- ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_FUNCTION);
+ ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
if (E.arguments.size()) {
option.insert_text += "(";
} else {
@@ -1028,7 +1140,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
}
}
-static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result, int p_recursion_depth) {
+static void _find_identifiers(const GDScriptParser::CompletionContext &p_context, bool p_only_functions, Map<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth) {
if (!p_only_functions && p_context.current_suite) {
// This includes function parameters, since they are also locals.
_find_identifiers_in_suite(p_context.current_suite, r_result);
@@ -1043,7 +1155,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
for (const StringName &E : functions) {
MethodInfo function = GDScriptUtilityFunctions::get_function_info(E);
- ScriptCodeCompletionOption option(String(E), ScriptCodeCompletionOption::KIND_FUNCTION);
+ ScriptLanguage::CodeCompletionOption option(String(E), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
if (function.arguments.size() || (function.flags & METHOD_FLAG_VARARG)) {
option.insert_text += "(";
} else {
@@ -1056,17 +1168,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
return;
}
- static const char *_type_names[Variant::VARIANT_MAX] = {
- "null", "bool", "int", "float", "String", "StringName", "Vector2", "Vector2i", "Rect2", "Rect2i", "Vector3", "Vector3i", "Transform2D", "Plane", "Quaternion", "AABB", "Basis", "Transform3D",
- "Color", "NodePath", "RID", "Signal", "Callable", "Object", "Dictionary", "Array", "PackedByteArray", "PackedInt32Array", "PackedInt64Array", "PackedFloat32Array", "PackedFloat64Array", "PackedStringArray",
- "PackedVector2Array", "PackedVector3Array", "PackedColorArray"
- };
- static_assert((sizeof(_type_names) / sizeof(*_type_names)) == Variant::VARIANT_MAX, "Completion for builtin types is incomplete");
-
- for (int i = 0; i < Variant::VARIANT_MAX; i++) {
- ScriptCodeCompletionOption option(_type_names[i], ScriptCodeCompletionOption::KIND_CLASS);
- r_result.insert(option.display, option);
- }
+ _find_built_in_variants(r_result);
static const char *_keywords[] = {
"false", "PI", "TAU", "INF", "NAN", "self", "true", "breakpoint", "tool", "super",
@@ -1076,7 +1178,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
const char **kw = _keywords;
while (*kw) {
- ScriptCodeCompletionOption option(*kw, ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
+ ScriptLanguage::CodeCompletionOption option(*kw, ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
r_result.insert(option.display, option);
kw++;
}
@@ -1089,7 +1191,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
const char **kws = _keywords_with_space;
while (*kws) {
- ScriptCodeCompletionOption option(*kws, ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
+ ScriptLanguage::CodeCompletionOption option(*kws, ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
option.insert_text += " ";
r_result.insert(option.display, option);
kws++;
@@ -1102,7 +1204,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
const char **kwa = _keywords_with_args;
while (*kwa) {
- ScriptCodeCompletionOption option(*kwa, ScriptCodeCompletionOption::KIND_FUNCTION);
+ ScriptLanguage::CodeCompletionOption option(*kwa, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
option.insert_text += "(";
r_result.insert(option.display, option);
kwa++;
@@ -1112,7 +1214,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
Variant::get_utility_function_list(&utility_func_names);
for (List<StringName>::Element *E = utility_func_names.front(); E; E = E->next()) {
- ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_FUNCTION);
+ ScriptLanguage::CodeCompletionOption option(E->get(), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
option.insert_text += "(";
r_result.insert(option.display, option);
}
@@ -1122,17 +1224,17 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
if (!E.value().is_singleton) {
continue;
}
- ScriptCodeCompletionOption option(E.key(), ScriptCodeCompletionOption::KIND_CONSTANT);
+ ScriptLanguage::CodeCompletionOption option(E.key(), ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
r_result.insert(option.display, option);
}
// Native classes and global constants.
for (const KeyValue<StringName, int> &E : GDScriptLanguage::get_singleton()->get_global_map()) {
- ScriptCodeCompletionOption option;
+ ScriptLanguage::CodeCompletionOption option;
if (ClassDB::class_exists(E.key) || Engine::get_singleton()->has_singleton(E.key)) {
- option = ScriptCodeCompletionOption(E.key.operator String(), ScriptCodeCompletionOption::KIND_CLASS);
+ option = ScriptLanguage::CodeCompletionOption(E.key.operator String(), ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
} else {
- option = ScriptCodeCompletionOption(E.key.operator String(), ScriptCodeCompletionOption::KIND_CONSTANT);
+ option = ScriptLanguage::CodeCompletionOption(E.key.operator String(), ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
}
r_result.insert(option.display, option);
}
@@ -2210,20 +2312,20 @@ static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContex
return false;
}
-static void _find_enumeration_candidates(GDScriptParser::CompletionContext &p_context, const String &p_enum_hint, Map<String, ScriptCodeCompletionOption> &r_result) {
+static void _find_enumeration_candidates(GDScriptParser::CompletionContext &p_context, const String &p_enum_hint, Map<String, ScriptLanguage::CodeCompletionOption> &r_result) {
if (!p_enum_hint.contains(".")) {
// Global constant or in the current class.
StringName current_enum = p_enum_hint;
if (p_context.current_class && p_context.current_class->has_member(current_enum) && p_context.current_class->get_member(current_enum).type == GDScriptParser::ClassNode::Member::ENUM) {
const GDScriptParser::EnumNode *_enum = p_context.current_class->get_member(current_enum).m_enum;
for (int i = 0; i < _enum->values.size(); i++) {
- ScriptCodeCompletionOption option(_enum->values[i].identifier->name, ScriptCodeCompletionOption::KIND_ENUM);
+ ScriptLanguage::CodeCompletionOption option(_enum->values[i].identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_ENUM);
r_result.insert(option.display, option);
}
} else {
for (int i = 0; i < CoreConstants::get_global_constant_count(); i++) {
if (CoreConstants::get_global_constant_enum(i) == current_enum) {
- ScriptCodeCompletionOption option(CoreConstants::get_global_constant_name(i), ScriptCodeCompletionOption::KIND_ENUM);
+ ScriptLanguage::CodeCompletionOption option(CoreConstants::get_global_constant_name(i), ScriptLanguage::CODE_COMPLETION_KIND_ENUM);
r_result.insert(option.display, option);
}
}
@@ -2240,13 +2342,14 @@ static void _find_enumeration_candidates(GDScriptParser::CompletionContext &p_co
ClassDB::get_enum_constants(class_name, enum_name, &enum_constants);
for (const StringName &E : enum_constants) {
String candidate = class_name + "." + E;
- ScriptCodeCompletionOption option(candidate, ScriptCodeCompletionOption::KIND_ENUM);
+ int location = _get_enum_constant_location(class_name, E);
+ ScriptLanguage::CodeCompletionOption option(candidate, ScriptLanguage::CODE_COMPLETION_KIND_ENUM, location);
r_result.insert(option.display, option);
}
}
}
-static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, int p_argidx, bool p_static, Map<String, ScriptCodeCompletionOption> &r_result, String &r_arghint) {
+static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, int p_argidx, bool p_static, Map<String, ScriptLanguage::CodeCompletionOption> &r_result, String &r_arghint) {
Variant base = p_base.value;
GDScriptParser::DataType base_type = p_base.type;
@@ -2287,7 +2390,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
if (opt.is_quoted()) {
opt = opt.unquote().quote(quote_style); // Handle user preference.
}
- ScriptCodeCompletionOption option(opt, ScriptCodeCompletionOption::KIND_FUNCTION);
+ ScriptLanguage::CodeCompletionOption option(opt, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
r_result.insert(option.display, option);
}
}
@@ -2314,7 +2417,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
continue;
}
String name = s.get_slice("/", 1);
- ScriptCodeCompletionOption option("/root/" + name, ScriptCodeCompletionOption::KIND_NODE_PATH);
+ ScriptLanguage::CodeCompletionOption option("/root/" + name, ScriptLanguage::CODE_COMPLETION_KIND_NODE_PATH);
option.insert_text = option.display.quote(quote_style);
r_result.insert(option.display, option);
}
@@ -2330,7 +2433,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
continue;
}
String name = s.get_slice("/", 1);
- ScriptCodeCompletionOption option(name, ScriptCodeCompletionOption::KIND_CONSTANT);
+ ScriptLanguage::CodeCompletionOption option(name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
option.insert_text = option.display.quote(quote_style);
r_result.insert(option.display, option);
}
@@ -2365,7 +2468,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
}
}
-static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, const GDScriptParser::Node *p_call, int p_argidx, Map<String, ScriptCodeCompletionOption> &r_result, bool &r_forced, String &r_arghint) {
+static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, const GDScriptParser::Node *p_call, int p_argidx, Map<String, ScriptLanguage::CodeCompletionOption> &r_result, bool &r_forced, String &r_arghint) {
if (p_call->type == GDScriptParser::Node::PRELOAD) {
if (p_argidx == 0 && bool(EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths"))) {
_get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), r_result);
@@ -2395,7 +2498,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
r_arghint = _make_arguments_hint(info, p_argidx);
return;
} else if (GDScriptParser::get_builtin_type(call->function_name) < Variant::VARIANT_MAX) {
- // Complete constructor
+ // Complete constructor.
List<MethodInfo> constructors;
Variant::get_constructor_list(GDScriptParser::get_builtin_type(call->function_name), &constructors);
@@ -2421,6 +2524,32 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
} else if (callee_type == GDScriptParser::Node::SUBSCRIPT) {
const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(call->callee);
+ if (subscript->base != nullptr && subscript->base->type == GDScriptParser::Node::IDENTIFIER) {
+ const GDScriptParser::IdentifierNode *base_identifier = static_cast<const GDScriptParser::IdentifierNode *>(subscript->base);
+
+ Variant::Type method_type = GDScriptParser::get_builtin_type(base_identifier->name);
+ if (method_type < Variant::VARIANT_MAX) {
+ Variant v;
+ Callable::CallError err;
+ Variant::construct(method_type, v, nullptr, 0, err);
+ if (err.error != Callable::CallError::CALL_OK) {
+ return;
+ }
+ List<MethodInfo> methods;
+ v.get_method_list(&methods);
+
+ for (MethodInfo &E : methods) {
+ if (p_argidx >= E.arguments.size()) {
+ continue;
+ }
+ if (E.name == call->function_name) {
+ r_arghint += _make_arguments_hint(E, p_argidx);
+ return;
+ }
+ }
+ }
+ }
+
if (subscript->is_attribute) {
GDScriptCompletionIdentifier ci;
if (_guess_expression_type(p_context, subscript->base, ci)) {
@@ -2444,7 +2573,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
r_forced = r_result.size() > 0;
}
-::Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) {
+::Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptLanguage::CodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) {
const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\"";
GDScriptParser parser;
@@ -2454,7 +2583,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
analyzer.analyze();
r_forced = false;
- Map<String, ScriptCodeCompletionOption> options;
+ Map<String, ScriptLanguage::CodeCompletionOption> options;
GDScriptParser::CompletionContext completion_context = parser.get_completion_context();
completion_context.base = p_owner;
@@ -2467,7 +2596,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
List<MethodInfo> annotations;
parser.get_annotation_list(&annotations);
for (const MethodInfo &E : annotations) {
- ScriptCodeCompletionOption option(E.name.substr(1), ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
+ ScriptLanguage::CodeCompletionOption option(E.name.substr(1), ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
if (E.arguments.size() > 0) {
option.insert_text += "(";
}
@@ -2483,17 +2612,36 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
_find_annotation_arguments(annotation, completion_context.current_argument, quote_style, options);
r_forced = true;
} break;
- case GDScriptParser::COMPLETION_BUILT_IN_TYPE_CONSTANT: {
- List<StringName> constants;
- Variant::get_constants_for_type(completion_context.builtin_type, &constants);
- for (const StringName &E : constants) {
- ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_CONSTANT);
- bool valid = false;
- Variant default_value = Variant::get_constant_value(completion_context.builtin_type, E, &valid);
- if (valid) {
- option.default_value = default_value;
+ case GDScriptParser::COMPLETION_BUILT_IN_TYPE_CONSTANT_OR_STATIC_METHOD: {
+ // Constants.
+ {
+ List<StringName> constants;
+ Variant::get_constants_for_type(completion_context.builtin_type, &constants);
+ for (const StringName &E : constants) {
+ ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
+ bool valid = false;
+ Variant default_value = Variant::get_constant_value(completion_context.builtin_type, E, &valid);
+ if (valid) {
+ option.default_value = default_value;
+ }
+ options.insert(option.display, option);
+ }
+ }
+ // Methods.
+ {
+ List<StringName> methods;
+ Variant::get_builtin_method_list(completion_context.builtin_type, &methods);
+ for (const StringName &E : methods) {
+ if (Variant::is_builtin_method_static(completion_context.builtin_type, E)) {
+ ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
+ if (Variant::get_builtin_method_argument_count(completion_context.builtin_type, E) > 0 || Variant::is_builtin_method_vararg(completion_context.builtin_type, E)) {
+ option.insert_text += "(";
+ } else {
+ option.insert_text += "()";
+ }
+ options.insert(option.display, option);
+ }
}
- options.insert(option.display, option);
}
} break;
case GDScriptParser::COMPLETION_INHERIT_TYPE: {
@@ -2501,7 +2649,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
r_forced = true;
} break;
case GDScriptParser::COMPLETION_TYPE_NAME_OR_VOID: {
- ScriptCodeCompletionOption option("void", ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
+ ScriptLanguage::CodeCompletionOption option("void", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
options.insert(option.display, option);
}
[[fallthrough]];
@@ -2511,16 +2659,16 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
} break;
case GDScriptParser::COMPLETION_PROPERTY_DECLARATION_OR_TYPE: {
_list_available_types(false, completion_context, options);
- ScriptCodeCompletionOption get("get", ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
+ ScriptLanguage::CodeCompletionOption get("get", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
options.insert(get.display, get);
- ScriptCodeCompletionOption set("set", ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
+ ScriptLanguage::CodeCompletionOption set("set", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
options.insert(set.display, set);
r_forced = true;
} break;
case GDScriptParser::COMPLETION_PROPERTY_DECLARATION: {
- ScriptCodeCompletionOption get("get", ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
+ ScriptLanguage::CodeCompletionOption get("get", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
options.insert(get.display, get);
- ScriptCodeCompletionOption set("set", ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
+ ScriptLanguage::CodeCompletionOption set("set", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
options.insert(set.display, set);
r_forced = true;
} break;
@@ -2536,7 +2684,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
if (member.function->is_static) {
continue;
}
- ScriptCodeCompletionOption option(member.function->identifier->name, ScriptCodeCompletionOption::KIND_FUNCTION);
+ ScriptLanguage::CodeCompletionOption option(member.function->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
options.insert(option.display, option);
}
r_forced = true;
@@ -2706,7 +2854,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
}
method_hint += ":";
- ScriptCodeCompletionOption option(method_hint, ScriptCodeCompletionOption::KIND_FUNCTION);
+ ScriptLanguage::CodeCompletionOption option(method_hint, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
options.insert(option.display, option);
}
} break;
@@ -2729,7 +2877,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
if (!opt.replace("/", "_").is_valid_identifier()) {
opt = opt.quote(quote_style); // Handle user preference.
}
- ScriptCodeCompletionOption option(opt, ScriptCodeCompletionOption::KIND_NODE_PATH);
+ ScriptLanguage::CodeCompletionOption option(opt, ScriptLanguage::CODE_COMPLETION_KIND_NODE_PATH);
options.insert(option.display, option);
}
@@ -2738,7 +2886,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) {
String path = "/root/" + E.key();
- ScriptCodeCompletionOption option(path.quote(quote_style), ScriptCodeCompletionOption::KIND_NODE_PATH);
+ ScriptLanguage::CodeCompletionOption option(path.quote(quote_style), ScriptLanguage::CODE_COMPLETION_KIND_NODE_PATH);
options.insert(option.display, option);
}
}
@@ -2751,7 +2899,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
} break;
}
- for (const KeyValue<String, ScriptCodeCompletionOption> &E : options) {
+ for (const KeyValue<String, ScriptLanguage::CodeCompletionOption> &E : options) {
r_options->push_back(E.value);
}
@@ -2760,7 +2908,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
#else
-Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) {
+Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptLanguage::CodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) {
return OK;
}
@@ -2859,7 +3007,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
case GDScriptParser::DataType::CLASS: {
if (base_type.class_type) {
if (base_type.class_type->has_member(p_symbol)) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_SCRIPT_LOCATION;
r_result.location = base_type.class_type->get_member(p_symbol).get_line();
r_result.class_path = base_type.script_path;
r_result.script = GDScriptCache::get_shallow_script(r_result.class_path);
@@ -2873,7 +3021,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
if (scr.is_valid()) {
int line = scr->get_member_line(p_symbol);
if (line >= 0) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_SCRIPT_LOCATION;
r_result.location = line;
r_result.script = scr;
return OK;
@@ -2897,7 +3045,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
}
if (ClassDB::has_method(class_name, p_symbol, true)) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD;
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_METHOD;
r_result.class_name = base_type.native_type;
r_result.class_member = p_symbol;
return OK;
@@ -2907,7 +3055,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
ClassDB::get_virtual_methods(class_name, &virtual_methods, true);
for (const MethodInfo &E : virtual_methods) {
if (E.name == p_symbol) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD;
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_METHOD;
r_result.class_name = base_type.native_type;
r_result.class_member = p_symbol;
return OK;
@@ -2916,7 +3064,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
StringName enum_name = ClassDB::get_integer_constant_enum(class_name, p_symbol, true);
if (enum_name != StringName()) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_ENUM;
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_ENUM;
r_result.class_name = base_type.native_type;
r_result.class_member = enum_name;
return OK;
@@ -2926,7 +3074,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
ClassDB::get_integer_constant_list(class_name, &constants, true);
for (const String &E : constants) {
if (E == p_symbol) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT;
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT;
r_result.class_name = base_type.native_type;
r_result.class_member = p_symbol;
return OK;
@@ -2934,7 +3082,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
}
if (ClassDB::has_property(class_name, p_symbol, true)) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_PROPERTY;
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_PROPERTY;
r_result.class_name = base_type.native_type;
r_result.class_member = p_symbol;
return OK;
@@ -2951,14 +3099,14 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
base_type.kind = GDScriptParser::DataType::UNRESOLVED;
if (Variant::has_constant(base_type.builtin_type, p_symbol)) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT;
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT;
r_result.class_name = Variant::get_type_name(base_type.builtin_type);
r_result.class_member = p_symbol;
return OK;
}
Variant v;
- REF v_ref;
+ Ref<RefCounted> v_ref;
if (base_type.builtin_type == Variant::OBJECT) {
v_ref.instantiate();
v = v_ref;
@@ -2971,7 +3119,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
}
if (v.has_method(p_symbol)) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD;
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_METHOD;
r_result.class_name = Variant::get_type_name(base_type.builtin_type);
r_result.class_member = p_symbol;
return OK;
@@ -2980,7 +3128,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
bool valid = false;
v.get(p_symbol, &valid);
if (valid) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_PROPERTY;
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_PROPERTY;
r_result.class_name = Variant::get_type_name(base_type.builtin_type);
r_result.class_member = p_symbol;
return OK;
@@ -2998,7 +3146,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
::Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result) {
// Before parsing, try the usual stuff
if (ClassDB::class_exists(p_symbol)) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS;
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS;
r_result.class_name = p_symbol;
return OK;
}
@@ -3006,21 +3154,21 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
for (int i = 0; i < Variant::VARIANT_MAX; i++) {
Variant::Type t = Variant::Type(i);
if (Variant::get_type_name(t) == p_symbol) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS;
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS;
r_result.class_name = Variant::get_type_name(t);
return OK;
}
}
if (GDScriptUtilityFunctions::function_exists(p_symbol)) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD;
+ r_result.type = ScriptLanguage::LOOKUP_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) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT;
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT;
r_result.class_name = "@GDScript";
r_result.class_member = p_symbol;
return OK;
@@ -3037,7 +3185,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
bool success = false;
ClassDB::get_integer_constant(context.current_class->extends[0], p_symbol, &success);
if (success) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT;
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT;
r_result.class_name = context.current_class->extends[0];
r_result.class_member = p_symbol;
return OK;
@@ -3047,11 +3195,21 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
bool is_function = false;
switch (context.type) {
- case GDScriptParser::COMPLETION_BUILT_IN_TYPE_CONSTANT: {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT;
- r_result.class_name = Variant::get_type_name(context.builtin_type);
- r_result.class_member = p_symbol;
- return OK;
+ case GDScriptParser::COMPLETION_BUILT_IN_TYPE_CONSTANT_OR_STATIC_METHOD: {
+ if (!Variant::has_builtin_method(context.builtin_type, StringName(p_symbol))) {
+ // A constant.
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT;
+ r_result.class_name = Variant::get_type_name(context.builtin_type);
+ r_result.class_member = p_symbol;
+ return OK;
+ }
+ // A method.
+ GDScriptParser::DataType base_type;
+ base_type.kind = GDScriptParser::DataType::BUILTIN;
+ base_type.builtin_type = context.builtin_type;
+ if (_lookup_symbol_from_base(base_type, p_symbol, true, r_result) == OK) {
+ return OK;
+ }
} break;
case GDScriptParser::COMPLETION_SUPER_METHOD:
case GDScriptParser::COMPLETION_METHOD: {
@@ -3076,7 +3234,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
const GDScriptParser::SuiteNode *suite = context.current_suite;
while (suite) {
if (suite->has_local(p_symbol)) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_SCRIPT_LOCATION;
r_result.location = suite->get_local(p_symbol).start_line;
return OK;
}
@@ -3101,7 +3259,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
}
if (FileAccess::exists(script)) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_SCRIPT_LOCATION;
r_result.location = 0;
r_result.script = ResourceLoader::load(script);
return OK;
@@ -3117,10 +3275,10 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
Object *obj = value;
if (obj) {
if (Object::cast_to<GDScriptNativeClass>(obj)) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS;
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS;
r_result.class_name = Object::cast_to<GDScriptNativeClass>(obj)->get_name();
} else {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS;
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS;
r_result.class_name = obj->get_class();
}
@@ -3137,18 +3295,18 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
// Otherwise these codes would work
StringName enumName = ClassDB::get_integer_constant_enum("@GlobalScope", p_symbol, true);
if (enumName != nullptr) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_ENUM;
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_ENUM;
r_result.class_name = "@GlobalScope";
r_result.class_member = enumName;
return OK;
}
else {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT;
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT;
r_result.class_name = "@GlobalScope";
r_result.class_member = p_symbol;
return OK;
}*/
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_TBD_GLOBALSCOPE;
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE;
r_result.class_name = "@GlobalScope";
r_result.class_member = p_symbol;
return OK;
@@ -3157,7 +3315,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
List<StringName> utility_functions;
Variant::get_utility_function_list(&utility_functions);
if (utility_functions.find(p_symbol) != nullptr) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_TBD_GLOBALSCOPE;
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE;
r_result.class_name = "@GlobalScope";
r_result.class_member = p_symbol;
return OK;
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index 3ee664c76d..ba0d51c5cc 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -259,6 +259,7 @@ public:
OPCODE_CALL_METHOD_BIND,
OPCODE_CALL_METHOD_BIND_RET,
OPCODE_CALL_BUILTIN_STATIC,
+ OPCODE_CALL_NATIVE_STATIC,
// ptrcall have one instruction per return type.
OPCODE_CALL_PTRCALL_NO_RETURN,
OPCODE_CALL_PTRCALL_BOOL,
@@ -298,6 +299,7 @@ public:
OPCODE_AWAIT,
OPCODE_AWAIT_RESUME,
OPCODE_CREATE_LAMBDA,
+ OPCODE_CREATE_SELF_LAMBDA,
OPCODE_JUMP,
OPCODE_JUMP_IF,
OPCODE_JUMP_IF_NOT,
@@ -364,7 +366,7 @@ public:
OPCODE_TYPE_ADJUST_QUATERNION,
OPCODE_TYPE_ADJUST_AABB,
OPCODE_TYPE_ADJUST_BASIS,
- OPCODE_TYPE_ADJUST_TRANSFORM,
+ OPCODE_TYPE_ADJUST_TRANSFORM3D,
OPCODE_TYPE_ADJUST_COLOR,
OPCODE_TYPE_ADJUST_STRING_NAME,
OPCODE_TYPE_ADJUST_NODE_PATH,
diff --git a/modules/gdscript/gdscript_lambda_callable.cpp b/modules/gdscript/gdscript_lambda_callable.cpp
index baf93e1098..c43fa12c8c 100644
--- a/modules/gdscript/gdscript_lambda_callable.cpp
+++ b/modules/gdscript/gdscript_lambda_callable.cpp
@@ -93,3 +93,81 @@ GDScriptLambdaCallable::GDScriptLambdaCallable(Ref<GDScript> p_script, GDScriptF
h = (uint32_t)hash_djb2_one_64((uint64_t)this);
}
+
+bool GDScriptLambdaSelfCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) {
+ // Lambda callables are only compared by reference.
+ return p_a == p_b;
+}
+
+bool GDScriptLambdaSelfCallable::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) {
+ // Lambda callables are only compared by reference.
+ return p_a < p_b;
+}
+
+uint32_t GDScriptLambdaSelfCallable::hash() const {
+ return h;
+}
+
+String GDScriptLambdaSelfCallable::get_as_text() const {
+ if (function->get_name() != StringName()) {
+ return function->get_name().operator String() + "(lambda)";
+ }
+ return "(anonymous lambda)";
+}
+
+CallableCustom::CompareEqualFunc GDScriptLambdaSelfCallable::get_compare_equal_func() const {
+ return compare_equal;
+}
+
+CallableCustom::CompareLessFunc GDScriptLambdaSelfCallable::get_compare_less_func() const {
+ return compare_less;
+}
+
+ObjectID GDScriptLambdaSelfCallable::get_object() const {
+ return object->get_instance_id();
+}
+
+void GDScriptLambdaSelfCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
+#ifdef DEBUG_ENABLED
+ if (object->get_script_instance() == nullptr || object->get_script_instance()->get_language() != GDScriptLanguage::get_singleton()) {
+ ERR_PRINT("Trying to call a lambda with an invalid instance.");
+ r_call_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
+ return;
+ }
+#endif
+
+ int captures_amount = captures.size();
+
+ if (captures_amount > 0) {
+ Vector<const Variant *> args;
+ args.resize(p_argcount + captures_amount);
+ for (int i = 0; i < captures_amount; i++) {
+ args.write[i] = &captures[i];
+ }
+ for (int i = 0; i < p_argcount; i++) {
+ args.write[i + captures_amount] = p_arguments[i];
+ }
+
+ r_return_value = function->call(static_cast<GDScriptInstance *>(object->get_script_instance()), args.ptrw(), args.size(), r_call_error);
+ r_call_error.argument -= captures_amount;
+ } else {
+ r_return_value = function->call(static_cast<GDScriptInstance *>(object->get_script_instance()), p_arguments, p_argcount, r_call_error);
+ }
+}
+
+GDScriptLambdaSelfCallable::GDScriptLambdaSelfCallable(Ref<RefCounted> p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures) {
+ reference = p_self;
+ object = p_self.ptr();
+ function = p_function;
+ captures = p_captures;
+
+ h = (uint32_t)hash_djb2_one_64((uint64_t)this);
+}
+
+GDScriptLambdaSelfCallable::GDScriptLambdaSelfCallable(Object *p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures) {
+ object = p_self;
+ function = p_function;
+ captures = p_captures;
+
+ h = (uint32_t)hash_djb2_one_64((uint64_t)this);
+}
diff --git a/modules/gdscript/gdscript_lambda_callable.h b/modules/gdscript/gdscript_lambda_callable.h
index f6a54a1a2f..248176e32c 100644
--- a/modules/gdscript/gdscript_lambda_callable.h
+++ b/modules/gdscript/gdscript_lambda_callable.h
@@ -62,4 +62,29 @@ public:
virtual ~GDScriptLambdaCallable() = default;
};
+// Lambda callable that references a particular object, so it can use `self` in the body.
+class GDScriptLambdaSelfCallable : public CallableCustom {
+ GDScriptFunction *function = nullptr;
+ Ref<RefCounted> reference; // For objects that are RefCounted, keep a reference.
+ Object *object = nullptr; // For non RefCounted objects, use a direct pointer.
+ uint32_t h;
+
+ Vector<Variant> captures;
+
+ static bool compare_equal(const CallableCustom *p_a, const CallableCustom *p_b);
+ static bool compare_less(const CallableCustom *p_a, const CallableCustom *p_b);
+
+public:
+ uint32_t hash() const override;
+ String get_as_text() const override;
+ CompareEqualFunc get_compare_equal_func() const override;
+ CompareLessFunc get_compare_less_func() const override;
+ ObjectID get_object() const override;
+ void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
+
+ GDScriptLambdaSelfCallable(Ref<RefCounted> p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures);
+ GDScriptLambdaSelfCallable(Object *p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures);
+ virtual ~GDScriptLambdaSelfCallable() = default;
+};
+
#endif // GDSCRIPT_LAMBDA_CALLABLE
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 725b62f6d6..67f6b61f14 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -1380,6 +1380,7 @@ GDScriptParser::AnnotationNode *GDScriptParser::parse_annotation(uint32_t p_vali
push_completion_call(annotation);
make_completion_context(COMPLETION_ANNOTATION_ARGUMENTS, annotation, 0, true);
if (!check(GDScriptTokenizer::Token::PARENTHESIS_CLOSE) && !is_at_end()) {
+ push_multiline(true);
int argument_index = 0;
do {
make_completion_context(COMPLETION_ANNOTATION_ARGUMENTS, annotation, argument_index, true);
@@ -1391,6 +1392,7 @@ GDScriptParser::AnnotationNode *GDScriptParser::parse_annotation(uint32_t p_vali
}
annotation->arguments.push_back(argument);
} while (match(GDScriptTokenizer::Token::COMMA));
+ pop_multiline();
consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected ")" after annotation arguments.)*");
}
@@ -2198,9 +2200,6 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_self(ExpressionNode *p_pre
if (current_function && current_function->is_static) {
push_error(R"(Cannot use "self" inside a static function.)");
}
- if (in_lambda) {
- push_error(R"(Cannot use "self" inside a lambda.)");
- }
SelfNode *self = alloc_node<SelfNode>();
self->current_class = current_class;
return self;
@@ -2683,7 +2682,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_attribute(ExpressionNode *
const IdentifierNode *id = static_cast<const IdentifierNode *>(p_previous_operand);
Variant::Type builtin_type = get_builtin_type(id->name);
if (builtin_type < Variant::VARIANT_MAX) {
- make_completion_context(COMPLETION_BUILT_IN_TYPE_CONSTANT, builtin_type, true);
+ make_completion_context(COMPLETION_BUILT_IN_TYPE_CONSTANT_OR_STATIC_METHOD, builtin_type, true);
is_builtin = true;
}
}
@@ -2750,7 +2749,11 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_call(ExpressionNode *p_pre
pop_multiline();
return nullptr;
}
- call->function_name = current_function->identifier->name;
+ if (current_function->identifier) {
+ call->function_name = current_function->identifier->name;
+ } else {
+ call->function_name = SNAME("<anonymous>");
+ }
} else {
consume(GDScriptTokenizer::Token::PERIOD, R"(Expected "." or "(" after "super".)");
make_completion_context(COMPLETION_SUPER_METHOD, call, true);
@@ -3480,6 +3483,15 @@ template <PropertyHint t_hint, Variant::Type t_type>
bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node *p_node) {
ERR_FAIL_COND_V_MSG(p_node->type != Node::VARIABLE, false, vformat(R"("%s" annotation can only be applied to variables.)", p_annotation->name));
+ {
+ const int max_flags = 32;
+
+ if (t_hint == PropertyHint::PROPERTY_HINT_FLAGS && p_annotation->resolved_arguments.size() > max_flags) {
+ push_error(vformat(R"(The argument count limit for "@export_flags" is exceeded (%d/%d).)", p_annotation->resolved_arguments.size(), max_flags), p_annotation);
+ return false;
+ }
+ }
+
VariableNode *variable = static_cast<VariableNode *>(p_node);
if (variable->exported) {
push_error(vformat(R"(Annotation "%s" cannot be used with another "@export" annotation.)", p_annotation->name), p_annotation);
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index c09b07282f..10474db02f 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -312,7 +312,7 @@ public:
bool is_constant = false;
Variant reduced_value;
- virtual bool is_expression() const { return true; }
+ virtual bool is_expression() const override { return true; }
virtual ~ExpressionNode() {}
protected:
@@ -767,6 +767,7 @@ public:
LOCAL_BIND, // Pattern bind.
MEMBER_VARIABLE,
MEMBER_CONSTANT,
+ INHERITED_VARIABLE,
};
Source source = UNDEFINED_SOURCE;
@@ -800,6 +801,7 @@ public:
FunctionNode *parent_function = nullptr;
Vector<IdentifierNode *> captures;
Map<StringName, int> captures_indices;
+ bool use_self = false;
bool has_name() const {
return function && function->identifier;
@@ -1146,7 +1148,7 @@ public:
COMPLETION_ASSIGN, // Assignment based on type (e.g. enum values).
COMPLETION_ATTRIBUTE, // After id.| to look for members.
COMPLETION_ATTRIBUTE_METHOD, // After id.| to look for methods.
- COMPLETION_BUILT_IN_TYPE_CONSTANT, // Constants inside a built-in type (e.g. Color.blue).
+ COMPLETION_BUILT_IN_TYPE_CONSTANT_OR_STATIC_METHOD, // Constants inside a built-in type (e.g. Color.BLUE) or static methods (e.g. Color.html).
COMPLETION_CALL_ARGUMENTS, // Complete with nodes, input actions, enum values (or usual expressions).
// TODO: COMPLETION_DECLARATION, // Potential declaration (var, const, func).
COMPLETION_GET_NODE, // Get node with $ notation.
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index d3287ab345..63fad0d9bb 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -1493,7 +1493,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::scan() {
}
default:
- return make_error(vformat(R"(Unknown character "%s".")", String(&c, 1)));
+ return make_error(vformat(R"(Unknown character "%s".)", String(&c, 1)));
}
}
diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp
index 16b2dac343..a914374985 100644
--- a/modules/gdscript/gdscript_utility_functions.cpp
+++ b/modules/gdscript/gdscript_utility_functions.cpp
@@ -432,21 +432,21 @@ struct GDScriptUtilityFunctionsDefinitions {
}
static inline void print_debug(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
- String str;
+ String s;
for (int i = 0; i < p_arg_count; i++) {
- str += p_args[i]->operator String();
+ s += p_args[i]->operator String();
}
if (Thread::get_caller_id() == Thread::get_main_id()) {
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) + "()";
+ s += "\n At: " + script->debug_get_stack_level_source(0) + ":" + itos(script->debug_get_stack_level_line(0)) + ":" + script->debug_get_stack_level_function(0) + "()";
}
} else {
- str += "\n At: Cannot retrieve debug info outside the main thread. Thread ID: " + itos(Thread::get_caller_id());
+ s += "\n At: Cannot retrieve debug info outside the main thread. Thread ID: " + itos(Thread::get_caller_id());
}
- print_line(str);
+ print_line(s);
*r_ret = Variant();
}
@@ -545,7 +545,7 @@ struct GDScriptUtilityFunctionsDefinitions {
};
struct GDScriptUtilityFunctionInfo {
- GDScriptUtilityFunctions::FunctionPtr function;
+ GDScriptUtilityFunctions::FunctionPtr function = nullptr;
MethodInfo info;
bool is_constant = false;
};
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index 41c59c7703..e28dd26c28 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -93,9 +93,13 @@ static String _get_var_type(const Variant *p_var) {
basestr = "null instance";
}
} else {
- basestr = bobj->get_class();
- if (bobj->get_script_instance()) {
- basestr += " (" + _get_script_name(bobj->get_script_instance()->get_script()) + ")";
+ if (bobj->is_class_ptr(GDScriptNativeClass::get_class_ptr_static())) {
+ basestr = Object::cast_to<GDScriptNativeClass>(bobj)->get_name();
+ } else {
+ basestr = bobj->get_class();
+ if (bobj->get_script_instance()) {
+ basestr += " (" + _get_script_name(bobj->get_script_instance()->get_script()) + ")";
+ }
}
}
@@ -263,6 +267,7 @@ void (*type_init_function_table[])(Variant *) = {
&&OPCODE_CALL_METHOD_BIND, \
&&OPCODE_CALL_METHOD_BIND_RET, \
&&OPCODE_CALL_BUILTIN_STATIC, \
+ &&OPCODE_CALL_NATIVE_STATIC, \
&&OPCODE_CALL_PTRCALL_NO_RETURN, \
&&OPCODE_CALL_PTRCALL_BOOL, \
&&OPCODE_CALL_PTRCALL_INT, \
@@ -301,6 +306,7 @@ void (*type_init_function_table[])(Variant *) = {
&&OPCODE_AWAIT, \
&&OPCODE_AWAIT_RESUME, \
&&OPCODE_CREATE_LAMBDA, \
+ &&OPCODE_CREATE_SELF_LAMBDA, \
&&OPCODE_JUMP, \
&&OPCODE_JUMP_IF, \
&&OPCODE_JUMP_IF_NOT, \
@@ -367,7 +373,7 @@ void (*type_init_function_table[])(Variant *) = {
&&OPCODE_TYPE_ADJUST_QUATERNION, \
&&OPCODE_TYPE_ADJUST_AABB, \
&&OPCODE_TYPE_ADJUST_BASIS, \
- &&OPCODE_TYPE_ADJUST_TRANSFORM, \
+ &&OPCODE_TYPE_ADJUST_TRANSFORM3D, \
&&OPCODE_TYPE_ADJUST_COLOR, \
&&OPCODE_TYPE_ADJUST_STRING_NAME, \
&&OPCODE_TYPE_ADJUST_NODE_PATH, \
@@ -1710,6 +1716,47 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
DISPATCH_OPCODE;
+ OPCODE(OPCODE_CALL_NATIVE_STATIC) {
+ CHECK_SPACE(3 + instr_arg_count);
+
+ ip += instr_arg_count;
+
+ GD_ERR_BREAK(_code_ptr[ip + 1] < 0 || _code_ptr[ip + 1] >= _methods_count);
+ MethodBind *method = _methods_ptr[_code_ptr[ip + 1]];
+
+ int argc = _code_ptr[ip + 2];
+ GD_ERR_BREAK(argc < 0);
+
+ GET_INSTRUCTION_ARG(ret, argc);
+
+ const Variant **argptrs = const_cast<const Variant **>(instruction_args);
+
+#ifdef DEBUG_ENABLED
+ uint64_t call_time = 0;
+
+ if (GDScriptLanguage::get_singleton()->profiling) {
+ call_time = OS::get_singleton()->get_ticks_usec();
+ }
+#endif
+
+ Callable::CallError err;
+ *ret = method->call(nullptr, argptrs, argc, err);
+
+#ifdef DEBUG_ENABLED
+ if (GDScriptLanguage::get_singleton()->profiling) {
+ function_call_time += OS::get_singleton()->get_ticks_usec() - call_time;
+ }
+
+ if (err.error != Callable::CallError::CALL_OK) {
+ err_text = _get_call_error(err, "static function '" + method->get_name().operator String() + "' in type '" + method->get_instance_class().operator String() + "'", argptrs);
+ OPCODE_BREAK;
+ }
+#endif
+
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
#ifdef DEBUG_ENABLED
#define OPCODE_CALL_PTR(m_type) \
OPCODE(OPCODE_CALL_PTRCALL_##m_type) { \
@@ -2231,6 +2278,41 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
DISPATCH_OPCODE;
+ OPCODE(OPCODE_CREATE_SELF_LAMBDA) {
+ CHECK_SPACE(2 + instr_arg_count);
+
+ GD_ERR_BREAK(p_instance == nullptr);
+
+ ip += instr_arg_count;
+
+ int captures_count = _code_ptr[ip + 1];
+ GD_ERR_BREAK(captures_count < 0);
+
+ int lambda_index = _code_ptr[ip + 2];
+ GD_ERR_BREAK(lambda_index < 0 || lambda_index >= _lambdas_count);
+ GDScriptFunction *lambda = _lambdas_ptr[lambda_index];
+
+ Vector<Variant> captures;
+ captures.resize(captures_count);
+ for (int i = 0; i < captures_count; i++) {
+ GET_INSTRUCTION_ARG(arg, i);
+ captures.write[i] = *arg;
+ }
+
+ GDScriptLambdaSelfCallable *callable;
+ if (Object::cast_to<RefCounted>(p_instance->owner)) {
+ callable = memnew(GDScriptLambdaSelfCallable(Ref<RefCounted>(Object::cast_to<RefCounted>(p_instance->owner)), lambda, captures));
+ } else {
+ callable = memnew(GDScriptLambdaSelfCallable(p_instance->owner, lambda, captures));
+ }
+
+ GET_INSTRUCTION_ARG(result, captures_count);
+ *result = Callable(callable);
+
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_JUMP) {
CHECK_SPACE(2);
int to = _code_ptr[ip + 1];
@@ -3217,7 +3299,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
OPCODE_TYPE_ADJUST(QUATERNION, Quaternion);
OPCODE_TYPE_ADJUST(AABB, AABB);
OPCODE_TYPE_ADJUST(BASIS, Basis);
- OPCODE_TYPE_ADJUST(TRANSFORM, Transform3D);
+ OPCODE_TYPE_ADJUST(TRANSFORM3D, Transform3D);
OPCODE_TYPE_ADJUST(COLOR, Color);
OPCODE_TYPE_ADJUST(STRING_NAME, StringName);
OPCODE_TYPE_ADJUST(NODE_PATH, NodePath);
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp
index 17886181d5..5516f59fe9 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.cpp
+++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp
@@ -108,7 +108,7 @@ void ExtendGDScriptParser::update_document_links(const String &p_code) {
document_links.clear();
GDScriptTokenizer tokenizer;
- FileAccessRef fs = FileAccess::create(FileAccess::ACCESS_RESOURCES);
+ Ref<FileAccess> fs = FileAccess::create(FileAccess::ACCESS_RESOURCES);
tokenizer.set_source_code(p_code);
while (true) {
GDScriptTokenizer::Token token = tokenizer.scan();
@@ -212,7 +212,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
const Variant &default_value = m.constant->initializer->reduced_value;
String value_text;
if (default_value.get_type() == Variant::OBJECT) {
- RES res = default_value;
+ Ref<Resource> res = default_value;
if (res.is_valid() && !res->get_path().is_empty()) {
value_text = "preload(\"" + res->get_path() + "\")";
if (symbol.documentation.is_empty()) {
diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp
index 961295b076..c42bd58aeb 100644
--- a/modules/gdscript/language_server/gdscript_text_document.cpp
+++ b/modules/gdscript/language_server/gdscript_text_document.cpp
@@ -166,49 +166,51 @@ Array GDScriptTextDocument::completion(const Dictionary &p_params) {
params.load(p_params);
Dictionary request_data = params.to_json();
- List<ScriptCodeCompletionOption> options;
+ List<ScriptLanguage::CodeCompletionOption> options;
GDScriptLanguageProtocol::get_singleton()->get_workspace()->completion(params, &options);
if (!options.is_empty()) {
int i = 0;
arr.resize(options.size());
- for (const ScriptCodeCompletionOption &option : options) {
+ for (const ScriptLanguage::CodeCompletionOption &option : options) {
lsp::CompletionItem item;
item.label = option.display;
item.data = request_data;
switch (option.kind) {
- case ScriptCodeCompletionOption::KIND_ENUM:
+ case ScriptLanguage::CODE_COMPLETION_KIND_ENUM:
item.kind = lsp::CompletionItemKind::Enum;
break;
- case ScriptCodeCompletionOption::KIND_CLASS:
+ case ScriptLanguage::CODE_COMPLETION_KIND_CLASS:
item.kind = lsp::CompletionItemKind::Class;
break;
- case ScriptCodeCompletionOption::KIND_MEMBER:
+ case ScriptLanguage::CODE_COMPLETION_KIND_MEMBER:
item.kind = lsp::CompletionItemKind::Property;
break;
- case ScriptCodeCompletionOption::KIND_FUNCTION:
+ case ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION:
item.kind = lsp::CompletionItemKind::Method;
break;
- case ScriptCodeCompletionOption::KIND_SIGNAL:
+ case ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL:
item.kind = lsp::CompletionItemKind::Event;
break;
- case ScriptCodeCompletionOption::KIND_CONSTANT:
+ case ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT:
item.kind = lsp::CompletionItemKind::Constant;
break;
- case ScriptCodeCompletionOption::KIND_VARIABLE:
+ case ScriptLanguage::CODE_COMPLETION_KIND_VARIABLE:
item.kind = lsp::CompletionItemKind::Variable;
break;
- case ScriptCodeCompletionOption::KIND_FILE_PATH:
+ case ScriptLanguage::CODE_COMPLETION_KIND_FILE_PATH:
item.kind = lsp::CompletionItemKind::File;
break;
- case ScriptCodeCompletionOption::KIND_NODE_PATH:
+ case ScriptLanguage::CODE_COMPLETION_KIND_NODE_PATH:
item.kind = lsp::CompletionItemKind::Snippet;
break;
- case ScriptCodeCompletionOption::KIND_PLAIN_TEXT:
+ case ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT:
item.kind = lsp::CompletionItemKind::Text;
break;
+ default: {
+ }
}
arr[i] = item.to_json();
@@ -422,10 +424,6 @@ GDScriptTextDocument::GDScriptTextDocument() {
file_checker = FileAccess::create(FileAccess::ACCESS_RESOURCES);
}
-GDScriptTextDocument::~GDScriptTextDocument() {
- memdelete(file_checker);
-}
-
void GDScriptTextDocument::sync_script_content(const String &p_path, const String &p_content) {
String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(p_path);
GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_script(path, p_content);
diff --git a/modules/gdscript/language_server/gdscript_text_document.h b/modules/gdscript/language_server/gdscript_text_document.h
index eb7b2c0240..9732765f34 100644
--- a/modules/gdscript/language_server/gdscript_text_document.h
+++ b/modules/gdscript/language_server/gdscript_text_document.h
@@ -40,7 +40,7 @@ class GDScriptTextDocument : public RefCounted {
protected:
static void _bind_methods();
- FileAccess *file_checker;
+ Ref<FileAccess> file_checker;
void didOpen(const Variant &p_param);
void didClose(const Variant &p_param);
@@ -75,7 +75,6 @@ public:
void initialize();
GDScriptTextDocument();
- virtual ~GDScriptTextDocument();
};
#endif
diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp
index d20b243616..89ee6b35e5 100644
--- a/modules/gdscript/language_server/gdscript_workspace.cpp
+++ b/modules/gdscript/language_server/gdscript_workspace.cpp
@@ -221,7 +221,7 @@ void GDScriptWorkspace::reload_all_workspace_scripts() {
void GDScriptWorkspace::list_script_files(const String &p_root_dir, List<String> &r_files) {
Error err;
- DirAccessRef dir = DirAccess::open(p_root_dir, &err);
+ Ref<DirAccess> dir = DirAccess::open(p_root_dir, &err);
if (OK == err) {
dir->list_dir_begin();
String file_name = dir->get_next();
@@ -560,7 +560,7 @@ Node *GDScriptWorkspace::_get_owner_scene_node(String p_path) {
for (int i = 0; i < owners.size(); i++) {
NodePath owner_path = owners[i];
- RES owner_res = ResourceLoader::load(owner_path);
+ Ref<Resource> owner_res = ResourceLoader::load(owner_path);
if (Object::cast_to<PackedScene>(owner_res.ptr())) {
Ref<PackedScene> owner_packed_scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*owner_res));
owner_scene_node = owner_packed_scene->instantiate();
@@ -571,7 +571,7 @@ Node *GDScriptWorkspace::_get_owner_scene_node(String p_path) {
return owner_scene_node;
}
-void GDScriptWorkspace::completion(const lsp::CompletionParams &p_params, List<ScriptCodeCompletionOption> *r_options) {
+void GDScriptWorkspace::completion(const lsp::CompletionParams &p_params, List<ScriptLanguage::CodeCompletionOption> *r_options) {
String path = get_file_path(p_params.textDocument.uri);
String call_hint;
bool forced = false;
@@ -638,7 +638,7 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu
symbol_identifier = "_init";
}
if (OK == GDScriptLanguage::get_singleton()->lookup_code(parser->get_text_for_lookup_symbol(pos, symbol_identifier, p_func_required), symbol_identifier, path, nullptr, ret)) {
- if (ret.type == ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION) {
+ if (ret.type == ScriptLanguage::LOOKUP_RESULT_SCRIPT_LOCATION) {
String target_script_path = path;
if (!ret.script.is_null()) {
target_script_path = ret.script->get_path();
diff --git a/modules/gdscript/language_server/gdscript_workspace.h b/modules/gdscript/language_server/gdscript_workspace.h
index ce5bba5f00..92e78f8992 100644
--- a/modules/gdscript/language_server/gdscript_workspace.h
+++ b/modules/gdscript/language_server/gdscript_workspace.h
@@ -85,7 +85,7 @@ public:
String get_file_uri(const String &p_path) const;
void publish_diagnostics(const String &p_path);
- void completion(const lsp::CompletionParams &p_params, List<ScriptCodeCompletionOption> *r_options);
+ void completion(const lsp::CompletionParams &p_params, List<ScriptLanguage::CodeCompletionOption> *r_options);
const lsp::DocumentSymbol *resolve_symbol(const lsp::TextDocumentPositionParams &p_doc_pos, const String &p_symbol_name = "", bool p_func_required = false);
void resolve_related_symbols(const lsp::TextDocumentPositionParams &p_doc_pos, List<const lsp::DocumentSymbol *> &r_list);
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index fcf122f567..59acb1c064 100644
--- a/modules/gdscript/register_types.cpp
+++ b/modules/gdscript/register_types.cpp
@@ -111,54 +111,62 @@ static void _editor_init() {
#endif // TOOLS_ENABLED
-void register_gdscript_types() {
- GDREGISTER_CLASS(GDScript);
+void initialize_gdscript_module(ModuleInitializationLevel p_level) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) {
+ GDREGISTER_CLASS(GDScript);
- script_language_gd = memnew(GDScriptLanguage);
- ScriptServer::register_language(script_language_gd);
+ script_language_gd = memnew(GDScriptLanguage);
+ ScriptServer::register_language(script_language_gd);
- resource_loader_gd.instantiate();
- ResourceLoader::add_resource_format_loader(resource_loader_gd);
+ resource_loader_gd.instantiate();
+ ResourceLoader::add_resource_format_loader(resource_loader_gd);
- resource_saver_gd.instantiate();
- ResourceSaver::add_resource_format_saver(resource_saver_gd);
+ resource_saver_gd.instantiate();
+ ResourceSaver::add_resource_format_saver(resource_saver_gd);
- gdscript_cache = memnew(GDScriptCache);
+ gdscript_cache = memnew(GDScriptCache);
+
+ GDScriptUtilityFunctions::register_functions();
+ }
#ifdef TOOLS_ENABLED
- EditorNode::add_init_callback(_editor_init);
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) {
+ EditorNode::add_init_callback(_editor_init);
- gdscript_translation_parser_plugin.instantiate();
- EditorTranslationParser::get_singleton()->add_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD);
+ gdscript_translation_parser_plugin.instantiate();
+ EditorTranslationParser::get_singleton()->add_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD);
+ }
#endif // TOOLS_ENABLED
-
- GDScriptUtilityFunctions::register_functions();
}
-void unregister_gdscript_types() {
- ScriptServer::unregister_language(script_language_gd);
+void uninitialize_gdscript_module(ModuleInitializationLevel p_level) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) {
+ ScriptServer::unregister_language(script_language_gd);
- if (gdscript_cache) {
- memdelete(gdscript_cache);
- }
+ if (gdscript_cache) {
+ memdelete(gdscript_cache);
+ }
- if (script_language_gd) {
- memdelete(script_language_gd);
- }
+ if (script_language_gd) {
+ memdelete(script_language_gd);
+ }
+
+ ResourceLoader::remove_resource_format_loader(resource_loader_gd);
+ resource_loader_gd.unref();
- ResourceLoader::remove_resource_format_loader(resource_loader_gd);
- resource_loader_gd.unref();
+ ResourceSaver::remove_resource_format_saver(resource_saver_gd);
+ resource_saver_gd.unref();
- ResourceSaver::remove_resource_format_saver(resource_saver_gd);
- resource_saver_gd.unref();
+ GDScriptParser::cleanup();
+ GDScriptUtilityFunctions::unregister_functions();
+ }
#ifdef TOOLS_ENABLED
- EditorTranslationParser::get_singleton()->remove_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD);
- gdscript_translation_parser_plugin.unref();
+ if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
+ EditorTranslationParser::get_singleton()->remove_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD);
+ gdscript_translation_parser_plugin.unref();
+ }
#endif // TOOLS_ENABLED
-
- GDScriptParser::cleanup();
- GDScriptUtilityFunctions::unregister_functions();
}
#ifdef TESTS_ENABLED
diff --git a/modules/gdscript/register_types.h b/modules/gdscript/register_types.h
index baa7dcbbd1..a7e6b02dcf 100644
--- a/modules/gdscript/register_types.h
+++ b/modules/gdscript/register_types.h
@@ -31,7 +31,9 @@
#ifndef GDSCRIPT_REGISTER_TYPES_H
#define GDSCRIPT_REGISTER_TYPES_H
-void register_gdscript_types();
-void unregister_gdscript_types();
+#include "modules/register_module_types.h"
+
+void initialize_gdscript_module(ModuleInitializationLevel p_level);
+void uninitialize_gdscript_module(ModuleInitializationLevel p_level);
#endif // GDSCRIPT_REGISTER_TYPES_H
diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp
index e8ddf90836..ea51990237 100644
--- a/modules/gdscript/tests/gdscript_test_runner.cpp
+++ b/modules/gdscript/tests/gdscript_test_runner.cpp
@@ -70,7 +70,7 @@ void init_autoloads() {
continue;
}
- RES res = ResourceLoader::load(info.path);
+ Ref<Resource> res = ResourceLoader::load(info.path);
ERR_CONTINUE_MSG(res.is_null(), "Can't autoload: " + info.path);
Node *n = nullptr;
Ref<PackedScene> scn = res;
@@ -80,7 +80,7 @@ void init_autoloads() {
} else if (script.is_valid()) {
StringName ibt = script->get_instance_base_type();
bool valid_type = ClassDB::is_parent_class(ibt, "Node");
- ERR_CONTINUE_MSG(!valid_type, "Script does not inherit a Node: " + info.path);
+ ERR_CONTINUE_MSG(!valid_type, "Script does not inherit from Node: " + info.path);
Object *obj = ClassDB::instantiate(ibt);
@@ -229,7 +229,7 @@ bool GDScriptTestRunner::generate_outputs() {
bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) {
Error err = OK;
- DirAccessRef dir(DirAccess::open(p_dir, &err));
+ Ref<DirAccess> dir(DirAccess::open(p_dir, &err));
if (err != OK) {
return false;
@@ -254,7 +254,7 @@ bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) {
#ifndef DEBUG_ENABLED
// On release builds, skip tests marked as debug only.
Error open_err = OK;
- FileAccessRef script_file(FileAccess::open(current_dir.plus_file(next), FileAccess::READ, &open_err));
+ Ref<FileAccess> script_file(FileAccess::open(current_dir.plus_file(next), FileAccess::READ, &open_err));
if (open_err != OK) {
ERR_PRINT(vformat(R"(Couldn't open test file "%s".)", next));
next = dir->get_next();
@@ -286,7 +286,7 @@ bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) {
bool GDScriptTestRunner::make_tests() {
Error err = OK;
- DirAccessRef dir(DirAccess::open(source_dir, &err));
+ Ref<DirAccess> dir(DirAccess::open(source_dir, &err));
ERR_FAIL_COND_V_MSG(err != OK, false, "Could not open specified test directory.");
@@ -611,7 +611,7 @@ bool GDScriptTest::generate_output() {
}
Error err = OK;
- FileAccessRef out_file = FileAccess::open(output_file, FileAccess::WRITE, &err);
+ Ref<FileAccess> out_file = FileAccess::open(output_file, FileAccess::WRITE, &err);
if (err != OK) {
return false;
}
@@ -620,7 +620,6 @@ bool GDScriptTest::generate_output() {
output += "\n"; // Make sure to insert newline for CI static checks.
out_file->store_string(output);
- out_file->close();
return true;
}
diff --git a/modules/gdscript/tests/gdscript_test_runner.h b/modules/gdscript/tests/gdscript_test_runner.h
index 1a950c6898..d6c6419e21 100644
--- a/modules/gdscript/tests/gdscript_test_runner.h
+++ b/modules/gdscript/tests/gdscript_test_runner.h
@@ -63,8 +63,8 @@ public:
private:
struct ErrorHandlerData {
- TestResult *result;
- GDScriptTest *self;
+ TestResult *result = nullptr;
+ GDScriptTest *self = nullptr;
ErrorHandlerData(TestResult *p_result, GDScriptTest *p_this) {
result = p_result;
self = p_this;
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.out b/modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.out
index 015ad756f8..6f7f0783f0 100644
--- a/modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.out
+++ b/modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.out
@@ -1,2 +1,2 @@
GDTEST_ANALYZER_ERROR
-Invalid index type "bool" for a base of type "Array".
+Cannot get index "true" from "[0, 1]".
diff --git a/modules/gdscript/tests/scripts/parser/features/arrays_dictionaries_nested_const.gd b/modules/gdscript/tests/scripts/parser/features/arrays_dictionaries_nested_const.gd
new file mode 100644
index 0000000000..cc78309ae4
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/arrays_dictionaries_nested_const.gd
@@ -0,0 +1,58 @@
+# https://github.com/godotengine/godot/issues/50285
+
+@warning_ignore(unused_local_constant)
+func test():
+ const CONST_INNER_DICTIONARY = { "key": true }
+ const CONST_NESTED_DICTIONARY_OLD_WORKAROUND = {
+ "key1": "value1",
+ "key2": CONST_INNER_DICTIONARY
+ }
+ # All of these should be valid
+ const CONST_NESTED_DICTIONARY = {
+ "key1": "value1",
+ "key2": { "key": true }
+ }
+
+
+ const CONST_DICTIONARY_WITH_ARRAY = {
+ "key1": [1,2,3,4]
+ }
+
+ const CONST_NESTED_ARRAY = [[],[2],[1,2,3]]
+ const CONST_ARRAY_WITH_DICT = [{"key1": 3}, {"key2": 5}]
+
+ const THREE_DIMENSIONAL_ARRAY = [[[],[],[]],[[],[],[]],[[],[],[]]]
+ const MANY_NESTED_DICT = {
+ "key1": {
+ "key11": {
+ "key111": {},
+ "key112": {},
+ },
+ "key12": {
+ "key121": {},
+ "key122": {},
+ },
+ },
+ "key2": {
+ "key21": {
+ "key211": {},
+ "key212": {},
+ },
+ "key22": {
+ "key221": {},
+ "key222": {},
+ },
+ }
+ }
+
+
+ const CONST_ARRAY_ACCESS = [1,2,3][0]
+ const CONST_DICT_ACCESS = {"key1": 5}["key1"]
+
+ const CONST_ARRAY_NESTED_ACCESS = [[1,2,3],[4,5,6],[8,9,10]][0][1]
+ const CONST_DICT_NESTED_ACCESS = {"key1": {"key2": 1}}["key1"]["key2"]
+
+ print(CONST_ARRAY_ACCESS)
+ print(CONST_DICT_ACCESS)
+ print(CONST_ARRAY_NESTED_ACCESS)
+ print(CONST_DICT_NESTED_ACCESS)
diff --git a/modules/gdscript/tests/scripts/parser/features/arrays_dictionaries_nested_const.out b/modules/gdscript/tests/scripts/parser/features/arrays_dictionaries_nested_const.out
new file mode 100644
index 0000000000..5883fc5c18
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/arrays_dictionaries_nested_const.out
@@ -0,0 +1,5 @@
+GDTEST_OK
+1
+5
+2
+1
diff --git a/modules/gdscript/tests/scripts/runtime/features/lambda_use_self.gd b/modules/gdscript/tests/scripts/runtime/features/lambda_use_self.gd
new file mode 100644
index 0000000000..3d063869ab
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/lambda_use_self.gd
@@ -0,0 +1,23 @@
+var member = "foo"
+
+func bar():
+ print("bar")
+
+func test():
+ var lambda1 = func():
+ print(member)
+ lambda1.call()
+
+ var lambda2 = func():
+ var nested = func():
+ print(member)
+ nested.call()
+ lambda2.call()
+
+ var lambda3 = func():
+ bar()
+ lambda3.call()
+
+ var lambda4 = func():
+ return self
+ print(lambda4.call() == self)
diff --git a/modules/gdscript/tests/scripts/runtime/features/lambda_use_self.out b/modules/gdscript/tests/scripts/runtime/features/lambda_use_self.out
new file mode 100644
index 0000000000..53d602b234
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/lambda_use_self.out
@@ -0,0 +1,5 @@
+GDTEST_OK
+foo
+foo
+bar
+true
diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp
index 4255030b4e..d8f60d5e9b 100644
--- a/modules/gdscript/tests/test_gdscript.cpp
+++ b/modules/gdscript/tests/test_gdscript.cpp
@@ -204,8 +204,8 @@ void test(TestType p_type) {
return;
}
- FileAccessRef fa = FileAccess::open(test, FileAccess::READ);
- ERR_FAIL_COND_MSG(!fa, "Could not open file: " + test);
+ Ref<FileAccess> fa = FileAccess::open(test, FileAccess::READ);
+ ERR_FAIL_COND_MSG(fa.is_null(), "Could not open file: " + test);
// Initialize the language for the test routine.
init_language(fa->get_path_absolute().get_base_dir());
diff --git a/modules/glslang/register_types.cpp b/modules/glslang/register_types.cpp
index 8e69ba78c7..64891d9ee8 100644
--- a/modules/glslang/register_types.cpp
+++ b/modules/glslang/register_types.cpp
@@ -190,7 +190,11 @@ static String _get_cache_key_function_glsl(const RenderingDevice::Capabilities *
return version;
}
-void preregister_glslang_types() {
+void initialize_glslang_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_CORE) {
+ return;
+ }
+
// Initialize in case it's not initialized. This is done once per thread
// and it's safe to call multiple times.
glslang::InitializeProcess();
@@ -198,9 +202,10 @@ void preregister_glslang_types() {
RenderingDevice::shader_set_get_cache_key_function(_get_cache_key_function_glsl);
}
-void register_glslang_types() {
-}
+void uninitialize_glslang_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_CORE) {
+ return;
+ }
-void unregister_glslang_types() {
glslang::FinalizeProcess();
}
diff --git a/modules/glslang/register_types.h b/modules/glslang/register_types.h
index 9d8dc9dc2a..d9611cc02f 100644
--- a/modules/glslang/register_types.h
+++ b/modules/glslang/register_types.h
@@ -33,8 +33,9 @@
#define MODULE_GLSLANG_HAS_PREREGISTER
-void preregister_glslang_types();
-void register_glslang_types();
-void unregister_glslang_types();
+#include "modules/register_module_types.h"
+
+void initialize_glslang_module(ModuleInitializationLevel p_level);
+void uninitialize_glslang_module(ModuleInitializationLevel p_level);
#endif // GLSLANG_REGISTER_TYPES_H
diff --git a/modules/gltf/SCsub b/modules/gltf/SCsub
index 5d03ee8361..3379404a00 100644
--- a/modules/gltf/SCsub
+++ b/modules/gltf/SCsub
@@ -4,7 +4,8 @@ Import("env")
Import("env_modules")
env_gltf = env_modules.Clone()
-env_gltf.Prepend(CPPPATH=["."])
# Godot's own source files
env_gltf.add_source_files(env.modules_sources, "*.cpp")
+if env["tools"]:
+ env_gltf.add_source_files(env.modules_sources, "editor/*.cpp")
diff --git a/modules/gltf/config.py b/modules/gltf/config.py
index a4736321fa..189b5a831a 100644
--- a/modules/gltf/config.py
+++ b/modules/gltf/config.py
@@ -8,12 +8,16 @@ def configure(env):
def get_doc_classes():
return [
- "EditorSceneImporterGLTF",
+ "EditorSceneFormatImporterBlend",
+ "EditorSceneFormatImporterFBX",
+ "EditorSceneFormatImporterGLTF",
"GLTFAccessor",
"GLTFAnimation",
"GLTFBufferView",
"GLTFCamera",
"GLTFDocument",
+ "GLTFDocumentExtension",
+ "GLTFDocumentExtensionConvertImporterMesh",
"GLTFLight",
"GLTFMesh",
"GLTFNode",
@@ -22,8 +26,6 @@ def get_doc_classes():
"GLTFSpecGloss",
"GLTFState",
"GLTFTexture",
- "GLTFDocumentExtension",
- "GLTFDocumentExtensionConvertImporterMesh",
]
diff --git a/modules/gltf/doc_classes/EditorSceneFormatImporterBlend.xml b/modules/gltf/doc_classes/EditorSceneFormatImporterBlend.xml
new file mode 100644
index 0000000000..ca8eb9854f
--- /dev/null
+++ b/modules/gltf/doc_classes/EditorSceneFormatImporterBlend.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="EditorSceneFormatImporterBlend" inherits="EditorSceneFormatImporter" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+ <brief_description>
+ Importer for Blender's [code].blend[/code] scene file format.
+ </brief_description>
+ <description>
+ Imports Blender scenes in the [code].blend[/code] file format through the glTF 2.0 3D import pipeline. This importer requires Blender to be installed by the user, so that it can be used to export the scene as glTF 2.0.
+ The location of the Blender binary is set via the [code]filesystem/import/blender/blender3_path[/code] editor setting.
+ This importer is only used if [member ProjectSettings.filesystem/import/blender/enabled] is enabled, otherwise [code].blend[/code] files present in the project folder are not imported.
+ Blend import requires Blender 3.0.
+ Internally, the EditorSceneFormatImporterBlend uses the Blender glTF "Use Original" mode to reference external textures.
+ </description>
+ <tutorials>
+ </tutorials>
+</class>
diff --git a/modules/gltf/doc_classes/EditorSceneFormatImporterFBX.xml b/modules/gltf/doc_classes/EditorSceneFormatImporterFBX.xml
new file mode 100644
index 0000000000..6754d963ff
--- /dev/null
+++ b/modules/gltf/doc_classes/EditorSceneFormatImporterFBX.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="EditorSceneFormatImporterFBX" inherits="EditorSceneFormatImporter" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+ <brief_description>
+ Importer for the [code].fbx[/code] scene file format.
+ </brief_description>
+ <description>
+ Imports Autodesk FBX 3D scenes by way of converting them to glTF 2.0 using the FBX2glTF command line tool.
+ The location of the FBX2glTF binary is set via the [code]filesystem/import/fbx/fbx2gltf_path[/code] editor setting.
+ This importer is only used if [member ProjectSettings.filesystem/import/fbx/enabled] is enabled, otherwise [code].fbx[/code] files present in the project folder are not imported.
+ </description>
+ <tutorials>
+ </tutorials>
+</class>
diff --git a/modules/gltf/doc_classes/EditorSceneFormatImporterGLTF.xml b/modules/gltf/doc_classes/EditorSceneFormatImporterGLTF.xml
new file mode 100644
index 0000000000..5a6a2f52d9
--- /dev/null
+++ b/modules/gltf/doc_classes/EditorSceneFormatImporterGLTF.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="EditorSceneFormatImporterGLTF" inherits="EditorSceneFormatImporter" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+</class>
diff --git a/modules/gltf/doc_classes/GLTFDocument.xml b/modules/gltf/doc_classes/GLTFDocument.xml
index 7adabdc605..cb0e3b6754 100644
--- a/modules/gltf/doc_classes/GLTFDocument.xml
+++ b/modules/gltf/doc_classes/GLTFDocument.xml
@@ -24,6 +24,7 @@
<argument index="1" name="state" type="GLTFState" />
<argument index="2" name="flags" type="int" default="0" />
<argument index="3" name="bake_fps" type="int" default="30" />
+ <argument index="4" name="base_path" type="String" default="&quot;&quot;" />
<description>
</description>
</method>
diff --git a/modules/gltf/editor_scene_exporter_gltf_plugin.cpp b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp
index 601c70791c..95db1c0965 100644
--- a/modules/gltf/editor_scene_exporter_gltf_plugin.cpp
+++ b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp
@@ -28,23 +28,24 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#if TOOLS_ENABLED
+#ifdef TOOLS_ENABLED
+
#include "editor_scene_exporter_gltf_plugin.h"
+#include "../gltf_document.h"
+#include "../gltf_state.h"
+
#include "core/config/project_settings.h"
#include "core/error/error_list.h"
#include "core/object/object.h"
#include "core/templates/vector.h"
#include "editor/editor_file_dialog.h"
#include "editor/editor_file_system.h"
-#include "gltf_document.h"
-#include "gltf_state.h"
+#include "editor/editor_node.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/gui/check_box.h"
#include "scene/main/node.h"
-#include "editor/editor_node.h"
-
String SceneExporterGLTFPlugin::get_name() const {
return "ConvertGLTF2";
}
@@ -63,9 +64,12 @@ SceneExporterGLTFPlugin::SceneExporterGLTFPlugin() {
file_export_lib->clear_filters();
file_export_lib->add_filter("*.glb");
file_export_lib->add_filter("*.gltf");
- file_export_lib->set_title(TTR("Export Mesh GLTF2"));
- String gltf_scene_name = TTR("Export GLTF...");
- add_tool_menu_item(gltf_scene_name, callable_mp(this, &SceneExporterGLTFPlugin::convert_scene_to_gltf2));
+ file_export_lib->set_title(TTR("Export Scene to glTF 2.0 File"));
+
+ PopupMenu *menu = get_export_as_menu();
+ int idx = menu->get_item_count();
+ menu->add_item(TTR("glTF 2.0 Scene..."));
+ menu->set_item_metadata(idx, callable_mp(this, &SceneExporterGLTFPlugin::convert_scene_to_gltf2));
}
void SceneExporterGLTFPlugin::_gltf2_dialog_action(String p_file) {
diff --git a/modules/gltf/editor_scene_exporter_gltf_plugin.h b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h
index c2c3f5710c..5af46bc752 100644
--- a/modules/gltf/editor_scene_exporter_gltf_plugin.h
+++ b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h
@@ -31,7 +31,8 @@
#ifndef EDITOR_SCENE_EXPORTER_GLTF_PLUGIN_H
#define EDITOR_SCENE_EXPORTER_GLTF_PLUGIN_H
-#if TOOLS_ENABLED
+#ifdef TOOLS_ENABLED
+
#include "editor/editor_plugin.h"
#include "editor_scene_importer_gltf.h"
@@ -47,5 +48,7 @@ public:
bool has_main_screen() const override;
SceneExporterGLTFPlugin();
};
+
#endif // TOOLS_ENABLED
+
#endif // EDITOR_SCENE_EXPORTER_GLTF_PLUGIN_H
diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp
new file mode 100644
index 0000000000..173d5131cf
--- /dev/null
+++ b/modules/gltf/editor/editor_scene_importer_blend.cpp
@@ -0,0 +1,575 @@
+/*************************************************************************/
+/* editor_scene_importer_blend.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "editor_scene_importer_blend.h"
+
+#ifdef TOOLS_ENABLED
+
+#include "../gltf_document.h"
+#include "../gltf_state.h"
+
+#include "core/config/project_settings.h"
+#include "editor/editor_file_dialog.h"
+#include "editor/editor_node.h"
+#include "editor/editor_scale.h"
+#include "editor/editor_settings.h"
+#include "main/main.h"
+#include "scene/main/node.h"
+#include "scene/resources/animation.h"
+
+#ifdef WINDOWS_ENABLED
+// Code by Pedro Estebanez (https://github.com/godotengine/godot/pull/59766)
+#include <shlwapi.h>
+#endif
+
+uint32_t EditorSceneFormatImporterBlend::get_import_flags() const {
+ return ImportFlags::IMPORT_SCENE | ImportFlags::IMPORT_ANIMATION;
+}
+
+void EditorSceneFormatImporterBlend::get_extensions(List<String> *r_extensions) const {
+ r_extensions->push_back("blend");
+}
+
+Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_t p_flags,
+ const Map<StringName, Variant> &p_options, int p_bake_fps,
+ List<String> *r_missing_deps, Error *r_err) {
+ // Get global paths for source and sink.
+
+ // Escape paths to be valid Python strings to embed in the script.
+ const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path).c_escape();
+ const String sink = ProjectSettings::get_singleton()->get_imported_files_path().plus_file(
+ vformat("%s-%s.gltf", p_path.get_file().get_basename(), p_path.md5_text()));
+ const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink).c_escape();
+
+ // Handle configuration options.
+
+ String parameters_arg;
+
+ if (p_options.has(SNAME("blender/nodes/custom_properties")) && p_options[SNAME("blender/nodes/custom_properties")]) {
+ parameters_arg += "export_extras=True,";
+ } else {
+ parameters_arg += "export_extras=False,";
+ }
+ if (p_options.has(SNAME("blender/meshes/skins")) && p_options[SNAME("blender/meshes/skins")]) {
+ int32_t skins = p_options["blender/meshes/skins"];
+ if (skins == BLEND_BONE_INFLUENCES_NONE) {
+ parameters_arg += "export_all_influences=False,";
+ } else if (skins == BLEND_BONE_INFLUENCES_COMPATIBLE) {
+ parameters_arg += "export_all_influences=False,";
+ } else if (skins == BLEND_BONE_INFLUENCES_ALL) {
+ parameters_arg += "export_all_influences=True,";
+ }
+ parameters_arg += "export_skins=True,";
+ } else {
+ parameters_arg += "export_skins=False,";
+ }
+ if (p_options.has(SNAME("blender/materials/export_materials")) && p_options[SNAME("blender/materials/export_materials")]) {
+ int32_t exports = p_options["blender/materials/export_materials"];
+ if (exports == BLEND_MATERIAL_EXPORT_PLACEHOLDER) {
+ parameters_arg += "export_materials='PLACEHOLDER',";
+ } else if (exports == BLEND_MATERIAL_EXPORT_EXPORT) {
+ parameters_arg += "export_materials='EXPORT',";
+ }
+ } else {
+ parameters_arg += "export_materials='PLACEHOLDER',";
+ }
+ if (p_options.has(SNAME("blender/nodes/cameras")) && p_options[SNAME("blender/nodes/cameras")]) {
+ parameters_arg += "export_cameras=True,";
+ } else {
+ parameters_arg += "export_cameras=False,";
+ }
+ if (p_options.has(SNAME("blender/nodes/punctual_lights")) && p_options[SNAME("blender/nodes/punctual_lights")]) {
+ parameters_arg += "export_lights=True,";
+ } else {
+ parameters_arg += "export_lights=False,";
+ }
+ if (p_options.has(SNAME("blender/meshes/colors")) && p_options[SNAME("blender/meshes/colors")]) {
+ parameters_arg += "export_colors=True,";
+ } else {
+ parameters_arg += "export_colors=False,";
+ }
+ if (p_options.has(SNAME("blender/nodes/visible")) && p_options[SNAME("blender/nodes/visible")]) {
+ int32_t visible = p_options["blender/nodes/visible"];
+ if (visible == BLEND_VISIBLE_VISIBLE_ONLY) {
+ parameters_arg += "use_visible=True,";
+ } else if (visible == BLEND_VISIBLE_RENDERABLE) {
+ parameters_arg += "use_renderable=True,";
+ } else if (visible == BLEND_VISIBLE_ALL) {
+ parameters_arg += "use_visible=False,use_renderable=False,";
+ }
+ } else {
+ parameters_arg += "use_visible=False,use_renderable=False,";
+ }
+
+ if (p_options.has(SNAME("blender/meshes/uvs")) && p_options[SNAME("blender/meshes/uvs")]) {
+ parameters_arg += "export_texcoords=True,";
+ } else {
+ parameters_arg += "export_texcoords=False,";
+ }
+ if (p_options.has(SNAME("blender/meshes/normals")) && p_options[SNAME("blender/meshes/normals")]) {
+ parameters_arg += "export_normals=True,";
+ } else {
+ parameters_arg += "export_normals=False,";
+ }
+ if (p_options.has(SNAME("blender/meshes/tangents")) && p_options[SNAME("blender/meshes/tangents")]) {
+ parameters_arg += "export_tangents=True,";
+ } else {
+ parameters_arg += "export_tangents=False,";
+ }
+ if (p_options.has(SNAME("blender/animation/group_tracks")) && p_options[SNAME("blender/animation/group_tracks")]) {
+ parameters_arg += "export_nla_strips=True,";
+ } else {
+ parameters_arg += "export_nla_strips=False,";
+ }
+ if (p_options.has(SNAME("blender/animation/limit_playback")) && p_options[SNAME("blender/animation/limit_playback")]) {
+ parameters_arg += "export_frame_range=True,";
+ } else {
+ parameters_arg += "export_frame_range=False,";
+ }
+ if (p_options.has(SNAME("blender/animation/always_sample")) && p_options[SNAME("blender/animation/always_sample")]) {
+ parameters_arg += "export_force_sampling=True,";
+ } else {
+ parameters_arg += "export_force_sampling=False,";
+ }
+ if (p_options.has(SNAME("blender/meshes/export_bones_deforming_mesh_only")) && p_options[SNAME("blender/meshes/export_bones_deforming_mesh_only")]) {
+ parameters_arg += "export_def_bones=True,";
+ } else {
+ parameters_arg += "export_def_bones=False,";
+ }
+ if (p_options.has(SNAME("blender/nodes/modifiers")) && p_options[SNAME("blender/nodes/modifiers")]) {
+ parameters_arg += "export_apply=True";
+ } else {
+ parameters_arg += "export_apply=False";
+ }
+
+ String unpack_all;
+ if (p_options.has(SNAME("blender/materials/unpack_enabled")) && p_options[SNAME("blender/materials/unpack_enabled")]) {
+ unpack_all = "bpy.ops.file.unpack_all(method='USE_LOCAL');";
+ }
+
+ // Prepare Blender export script.
+
+ String common_args = vformat("filepath='%s',", sink_global) +
+ "export_format='GLTF_SEPARATE',"
+ "export_yup=True," +
+ parameters_arg;
+ String script =
+ String("import bpy, sys;") +
+ "print('Blender 3.0 or higher is required.', file=sys.stderr) if bpy.app.version < (3, 0, 0) else None;" +
+ vformat("bpy.ops.wm.open_mainfile(filepath='%s');", source_global) +
+ unpack_all +
+ vformat("bpy.ops.export_scene.gltf(export_keep_originals=True,%s);", common_args);
+ print_verbose(script);
+
+ // Run script with configured Blender binary.
+
+ String blender_path = EDITOR_GET("filesystem/import/blender/blender3_path");
+
+#ifdef WINDOWS_ENABLED
+ blender_path = blender_path.plus_file("blender.exe");
+#else
+ blender_path = blender_path.plus_file("blender");
+#endif
+
+ List<String> args;
+ args.push_back("--background");
+ args.push_back("--python-expr");
+ args.push_back(script);
+
+ String standard_out;
+ int ret;
+ OS::get_singleton()->execute(blender_path, args, &standard_out, &ret, true);
+ print_verbose(blender_path);
+ print_verbose(standard_out);
+
+ if (ret != 0) {
+ if (r_err) {
+ *r_err = ERR_SCRIPT_FAILED;
+ }
+ ERR_PRINT(vformat("Blend export to glTF failed with error: %d.", ret));
+ return nullptr;
+ }
+
+ // Import the generated glTF.
+
+ // Use GLTFDocument instead of glTF importer to keep image references.
+ Ref<GLTFDocument> gltf;
+ gltf.instantiate();
+ Ref<GLTFState> state;
+ state.instantiate();
+ String base_dir;
+ if (p_options.has(SNAME("blender/materials/unpack_enabled")) && p_options[SNAME("blender/materials/unpack_enabled")]) {
+ base_dir = sink.get_base_dir();
+ }
+ Error err = gltf->append_from_file(sink.get_basename() + ".gltf", state, p_flags, p_bake_fps, base_dir);
+ if (err != OK) {
+ if (r_err) {
+ *r_err = FAILED;
+ }
+ return nullptr;
+ }
+ return gltf->generate_scene(state, p_bake_fps);
+}
+
+Variant EditorSceneFormatImporterBlend::get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option,
+ const Map<StringName, Variant> &p_options) {
+ if (p_path.get_extension().to_lower() != "blend") {
+ return true;
+ }
+
+ if (p_option.begins_with("animation/")) {
+ if (p_option != "animation/import" && !bool(p_options["animation/import"])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void EditorSceneFormatImporterBlend::get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options) {
+ if (p_path.get_extension().to_lower() != "blend") {
+ return;
+ }
+#define ADD_OPTION_BOOL(PATH, VALUE) \
+ r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, SNAME(PATH)), VALUE));
+#define ADD_OPTION_ENUM(PATH, ENUM_HINT, VALUE) \
+ r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, SNAME(PATH), PROPERTY_HINT_ENUM, ENUM_HINT), VALUE));
+
+ ADD_OPTION_ENUM("blender/nodes/visible", "Visible Only,Renderable,All", BLEND_VISIBLE_ALL);
+ ADD_OPTION_BOOL("blender/nodes/punctual_lights", true);
+ ADD_OPTION_BOOL("blender/nodes/cameras", true);
+ ADD_OPTION_BOOL("blender/nodes/custom_properties", true);
+ ADD_OPTION_ENUM("blender/nodes/modifiers", "No Modifiers,All Modifiers", BLEND_MODIFIERS_ALL);
+ ADD_OPTION_BOOL("blender/meshes/colors", false);
+ ADD_OPTION_BOOL("blender/meshes/uvs", true);
+ ADD_OPTION_BOOL("blender/meshes/normals", true);
+ ADD_OPTION_BOOL("blender/meshes/tangents", true);
+ ADD_OPTION_ENUM("blender/meshes/skins", "None,4 Influences (Compatible),All Influences", BLEND_BONE_INFLUENCES_ALL);
+ ADD_OPTION_BOOL("blender/meshes/export_bones_deforming_mesh_only", false);
+ ADD_OPTION_BOOL("blender/materials/unpack_enabled", true);
+ ADD_OPTION_ENUM("blender/materials/export_materials", "Placeholder,Export", BLEND_MATERIAL_EXPORT_EXPORT);
+ ADD_OPTION_BOOL("blender/animation/limit_playback", true);
+ ADD_OPTION_BOOL("blender/animation/always_sample", true);
+ ADD_OPTION_BOOL("blender/animation/group_tracks", true);
+
+#undef ADD_OPTION_BOOL
+#undef ADD_OPTION_ENUM
+}
+
+///////////////////////////
+
+static bool _test_blender_path(const String &p_path, String *r_err = nullptr) {
+ String path = p_path;
+#ifdef WINDOWS_ENABLED
+ path = path.plus_file("blender.exe");
+#else
+ path = path.plus_file("blender");
+#endif
+
+#if defined(OSX_ENABLED)
+ if (!FileAccess::exists(path)) {
+ path = path.plus_file("Blender");
+ }
+#endif
+
+ if (!FileAccess::exists(path)) {
+ if (r_err) {
+ *r_err = TTR("Path does not contain a Blender installation.");
+ }
+ return false;
+ }
+ List<String> args;
+ args.push_back("--version");
+ String pipe;
+ Error err = OS::get_singleton()->execute(path, args, &pipe);
+ if (err != OK) {
+ if (r_err) {
+ *r_err = TTR("Can't excecute Blender binary.");
+ }
+ return false;
+ }
+
+ if (pipe.find("Blender ") != 0) {
+ if (r_err) {
+ *r_err = vformat(TTR("Unexpected --version output from Blender binary at: %s"), path);
+ }
+ return false;
+ }
+ pipe = pipe.replace_first("Blender ", "");
+ int pp = pipe.find(".");
+ if (pp == -1) {
+ if (r_err) {
+ *r_err = TTR("Path supplied lacks a Blender binary.");
+ }
+ return false;
+ }
+ String v = pipe.substr(0, pp);
+ int version = v.to_int();
+ if (version < 3) {
+ if (r_err) {
+ *r_err = TTR("This Blender installation is too old for this importer (not 3.0+).");
+ }
+ return false;
+ }
+ if (version > 3) {
+ if (r_err) {
+ *r_err = TTR("This Blender installation is too new for this importer (not 3.x).");
+ }
+ return false;
+ }
+
+ return true;
+}
+
+bool EditorFileSystemImportFormatSupportQueryBlend::is_active() const {
+ bool blend_enabled = GLOBAL_GET("filesystem/import/blender/enabled");
+
+ String blender_path = EDITOR_GET("filesystem/import/blender/blender3_path");
+
+ if (blend_enabled && !_test_blender_path(blender_path)) {
+ // Intending to import Blender, but blend not configured.
+ return true;
+ }
+
+ return false;
+}
+Vector<String> EditorFileSystemImportFormatSupportQueryBlend::get_file_extensions() const {
+ Vector<String> ret;
+ ret.push_back("blend");
+ return ret;
+}
+
+void EditorFileSystemImportFormatSupportQueryBlend::_validate_path(String p_path) {
+ String error;
+ bool success = false;
+ if (p_path == "") {
+ error = TTR("Path is empty.");
+ } else {
+ if (_test_blender_path(p_path, &error)) {
+ success = true;
+ if (auto_detected_path == p_path) {
+ error = TTR("Path to Blender installation is valid (Autodetected).");
+ } else {
+ error = TTR("Path to Blender installation is valid.");
+ }
+ }
+ }
+
+ path_status->set_text(error);
+
+ if (success) {
+ path_status->add_theme_color_override("font_color", path_status->get_theme_color(SNAME("success_color"), SNAME("Editor")));
+ configure_blender_dialog->get_ok_button()->set_disabled(false);
+ } else {
+ path_status->add_theme_color_override("font_color", path_status->get_theme_color(SNAME("error_color"), SNAME("Editor")));
+ configure_blender_dialog->get_ok_button()->set_disabled(true);
+ }
+}
+
+bool EditorFileSystemImportFormatSupportQueryBlend::_autodetect_path(String p_path) {
+ if (_test_blender_path(p_path)) {
+ auto_detected_path = p_path;
+ return true;
+ }
+ return false;
+}
+
+void EditorFileSystemImportFormatSupportQueryBlend::_path_confirmed() {
+ confirmed = true;
+}
+
+void EditorFileSystemImportFormatSupportQueryBlend::_select_install(String p_path) {
+ blender_path->set_text(p_path);
+ _validate_path(p_path);
+}
+void EditorFileSystemImportFormatSupportQueryBlend::_browse_install() {
+ if (blender_path->get_text() != String()) {
+ browse_dialog->set_current_dir(blender_path->get_text());
+ }
+
+ browse_dialog->popup_centered_ratio();
+}
+
+bool EditorFileSystemImportFormatSupportQueryBlend::query() {
+ if (!configure_blender_dialog) {
+ configure_blender_dialog = memnew(ConfirmationDialog);
+ configure_blender_dialog->set_title(TTR("Configure Blender Importer"));
+ configure_blender_dialog->set_flag(Window::FLAG_BORDERLESS, true); // Avoid closing accidentally .
+ configure_blender_dialog->set_close_on_escape(false);
+
+ VBoxContainer *vb = memnew(VBoxContainer);
+ vb->add_child(memnew(Label(TTR("Blender 3.0+ is required to import '.blend' files.\nPlease provide a valid path to a Blender installation:"))));
+
+ HBoxContainer *hb = memnew(HBoxContainer);
+
+ blender_path = memnew(LineEdit);
+ blender_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ hb->add_child(blender_path);
+ blender_path_browse = memnew(Button);
+ hb->add_child(blender_path_browse);
+ blender_path_browse->set_text(TTR("Browse"));
+ blender_path_browse->connect("pressed", callable_mp(this, &EditorFileSystemImportFormatSupportQueryBlend::_browse_install));
+ hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ hb->set_custom_minimum_size(Size2(400 * EDSCALE, 0));
+
+ vb->add_child(hb);
+
+ path_status = memnew(Label);
+ vb->add_child(path_status);
+
+ configure_blender_dialog->add_child(vb);
+
+ blender_path->connect("text_changed", callable_mp(this, &EditorFileSystemImportFormatSupportQueryBlend::_validate_path));
+
+ EditorNode::get_singleton()->get_gui_base()->add_child(configure_blender_dialog);
+
+ configure_blender_dialog->get_ok_button()->set_text(TTR("Confirm Path"));
+ configure_blender_dialog->get_cancel_button()->set_text(TTR("Disable '.blend' Import"));
+ configure_blender_dialog->get_cancel_button()->set_tooltip(TTR("Disables Blender '.blend' files import for this project. Can be re-enabled in Project Settings."));
+ configure_blender_dialog->connect("confirmed", callable_mp(this, &EditorFileSystemImportFormatSupportQueryBlend::_path_confirmed));
+
+ browse_dialog = memnew(EditorFileDialog);
+ browse_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
+ browse_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_DIR);
+ browse_dialog->connect("dir_selected", callable_mp(this, &EditorFileSystemImportFormatSupportQueryBlend::_select_install));
+
+ EditorNode::get_singleton()->get_gui_base()->add_child(browse_dialog);
+ }
+
+ String path = EDITOR_GET("filesystem/import/blender/blender3_path");
+
+ if (path == "") {
+ // Autodetect
+ auto_detected_path = "";
+
+#if defined(OSX_ENABLED)
+
+ {
+ Vector<String> mdfind_paths;
+ {
+ List<String> mdfind_args;
+ mdfind_args.push_back("kMDItemCFBundleIdentifier=org.blenderfoundation.blender");
+
+ String output;
+ Error err = OS::get_singleton()->execute("mdfind", mdfind_args, &output);
+ if (err == OK) {
+ mdfind_paths = output.split("\n");
+ }
+ }
+
+ bool found = false;
+ for (const String &path : mdfind_paths) {
+ found = _autodetect_path(path.plus_file("Contents/MacOS"));
+ if (found) {
+ break;
+ }
+ }
+ if (!found) {
+ found = _autodetect_path("/opt/homebrew/bin");
+ }
+ if (!found) {
+ found = _autodetect_path("/opt/local/bin");
+ }
+ if (!found) {
+ found = _autodetect_path("/usr/local/bin");
+ }
+ if (!found) {
+ found = _autodetect_path("/usr/local/opt");
+ }
+ if (!found) {
+ found = _autodetect_path("/Applications/Blender.app/Contents/MacOS");
+ }
+ }
+#elif defined(WINDOWS_ENABLED)
+ {
+ char blender_opener_path[MAX_PATH];
+ DWORD path_len = MAX_PATH;
+ HRESULT res = AssocQueryString(0, ASSOCSTR_EXECUTABLE, ".blend", "open", blender_opener_path, &path_len);
+ if (res == S_OK && _autodetect_path(String(blender_opener_path).get_base_dir())) {
+ // Good.
+ } else if (_autodetect_path("C:\\Program Files\\Blender Foundation")) {
+ // Good.
+ } else {
+ _autodetect_path("C:\\Program Files (x86)\\Blender Foundation");
+ }
+ }
+
+#elif defined(UNIX_ENABLED)
+ if (_autodetect_path("/usr/bin")) {
+ // Good.
+ } else if (_autodetect_path("/usr/local/bin")) {
+ // Good
+ } else {
+ _autodetect_path("/opt/blender/bin");
+ }
+#endif
+ if (auto_detected_path != "") {
+ path = auto_detected_path;
+ }
+ }
+
+ blender_path->set_text(path);
+
+ _validate_path(path);
+
+ configure_blender_dialog->popup_centered();
+ confirmed = false;
+
+ while (true) {
+ OS::get_singleton()->delay_usec(1);
+ DisplayServer::get_singleton()->process_events();
+ Main::iteration();
+ if (!configure_blender_dialog->is_visible() || confirmed) {
+ break;
+ }
+ }
+
+ if (confirmed) {
+ // Can only confirm a valid path.
+ EditorSettings::get_singleton()->set("filesystem/import/blender/blender3_path", blender_path->get_text());
+ EditorSettings::get_singleton()->save();
+ } else {
+ // Disable Blender import
+ ProjectSettings::get_singleton()->set("filesystem/import/blender/enabled", false);
+ ProjectSettings::get_singleton()->save();
+
+ if (EditorNode::immediate_confirmation_dialog(TTR("Disabling '.blend' file import requires restarting the editor."), TTR("Save & Restart"), TTR("Restart"))) {
+ EditorNode::get_singleton()->save_all_scenes();
+ }
+ EditorNode::get_singleton()->restart_editor();
+ return true;
+ }
+
+ return false;
+}
+
+EditorFileSystemImportFormatSupportQueryBlend::EditorFileSystemImportFormatSupportQueryBlend() {
+}
+
+#endif // TOOLS_ENABLED
diff --git a/modules/gltf/editor/editor_scene_importer_blend.h b/modules/gltf/editor/editor_scene_importer_blend.h
new file mode 100644
index 0000000000..0925333a28
--- /dev/null
+++ b/modules/gltf/editor/editor_scene_importer_blend.h
@@ -0,0 +1,112 @@
+/*************************************************************************/
+/* editor_scene_importer_blend.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef EDITOR_SCENE_IMPORTER_BLEND_H
+#define EDITOR_SCENE_IMPORTER_BLEND_H
+
+#ifdef TOOLS_ENABLED
+
+#include "editor/editor_file_system.h"
+#include "editor/import/resource_importer_scene.h"
+
+class Animation;
+class Node;
+class ConfirmationDialog;
+
+class EditorSceneFormatImporterBlend : public EditorSceneFormatImporter {
+ GDCLASS(EditorSceneFormatImporterBlend, EditorSceneFormatImporter);
+
+public:
+ enum {
+ BLEND_VISIBLE_VISIBLE_ONLY,
+ BLEND_VISIBLE_RENDERABLE,
+ BLEND_VISIBLE_ALL
+ };
+ enum {
+ BLEND_BONE_INFLUENCES_NONE,
+ BLEND_BONE_INFLUENCES_COMPATIBLE,
+ BLEND_BONE_INFLUENCES_ALL
+ };
+ enum {
+ BLEND_MATERIAL_EXPORT_PLACEHOLDER,
+ BLEND_MATERIAL_EXPORT_EXPORT
+ };
+ enum {
+ BLEND_MODIFIERS_NONE,
+ BLEND_MODIFIERS_ALL
+ };
+
+ virtual uint32_t get_import_flags() const override;
+ virtual void get_extensions(List<String> *r_extensions) const override;
+ virtual Node *import_scene(const String &p_path, uint32_t p_flags,
+ const Map<StringName, Variant> &p_options, int p_bake_fps,
+ List<String> *r_missing_deps, Error *r_err = nullptr) override;
+ virtual void get_import_options(const String &p_path,
+ List<ResourceImporter::ImportOption> *r_options) override;
+ virtual Variant get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option,
+ const Map<StringName, Variant> &p_options) override;
+};
+
+class LineEdit;
+class Button;
+class EditorFileDialog;
+class Label;
+
+class EditorFileSystemImportFormatSupportQueryBlend : public EditorFileSystemImportFormatSupportQuery {
+ GDCLASS(EditorFileSystemImportFormatSupportQueryBlend, EditorFileSystemImportFormatSupportQuery);
+
+ ConfirmationDialog *configure_blender_dialog = nullptr;
+ LineEdit *blender_path = nullptr;
+ Button *blender_path_browse = nullptr;
+ EditorFileDialog *browse_dialog = nullptr;
+ Label *path_status = nullptr;
+ bool confirmed = false;
+
+ String auto_detected_path;
+ void _validate_path(String p_path);
+
+ bool _autodetect_path(String p_path);
+
+ void _path_confirmed();
+
+ void _select_install(String p_path);
+ void _browse_install();
+
+public:
+ virtual bool is_active() const override;
+ virtual Vector<String> get_file_extensions() const override;
+ virtual bool query() override;
+
+ EditorFileSystemImportFormatSupportQueryBlend();
+};
+
+#endif // TOOLS_ENABLED
+
+#endif // EDITOR_SCENE_IMPORTER_BLEND_H
diff --git a/modules/gltf/editor/editor_scene_importer_fbx.cpp b/modules/gltf/editor/editor_scene_importer_fbx.cpp
new file mode 100644
index 0000000000..893d2efcec
--- /dev/null
+++ b/modules/gltf/editor/editor_scene_importer_fbx.cpp
@@ -0,0 +1,117 @@
+/*************************************************************************/
+/* editor_scene_importer_fbx.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "editor_scene_importer_fbx.h"
+
+#if TOOLS_ENABLED
+
+#include "../gltf_document.h"
+#include "../gltf_state.h"
+
+#include "core/config/project_settings.h"
+#include "editor/editor_settings.h"
+#include "scene/main/node.h"
+#include "scene/resources/animation.h"
+
+uint32_t EditorSceneFormatImporterFBX::get_import_flags() const {
+ return ImportFlags::IMPORT_SCENE | ImportFlags::IMPORT_ANIMATION;
+}
+
+void EditorSceneFormatImporterFBX::get_extensions(List<String> *r_extensions) const {
+ r_extensions->push_back("fbx");
+}
+
+Node *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t p_flags,
+ const Map<StringName, Variant> &p_options, int p_bake_fps,
+ List<String> *r_missing_deps, Error *r_err) {
+ // Get global paths for source and sink.
+
+ // Don't use `c_escape()` as it can generate broken paths. These paths will be
+ // enclosed in double quotes by OS::execute(), so we only need to escape those.
+ // `c_escape_multiline()` seems to do this (escapes `\` and `"` only).
+ const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path).c_escape_multiline();
+ const String sink = ProjectSettings::get_singleton()->get_imported_files_path().plus_file(
+ vformat("%s-%s.glb", p_path.get_file().get_basename(), p_path.md5_text()));
+ const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink).c_escape_multiline();
+
+ // Run fbx2gltf.
+
+ String fbx2gltf_path = EDITOR_GET("filesystem/import/fbx/fbx2gltf_path");
+
+ List<String> args;
+ args.push_back("--pbr-metallic-roughness");
+ args.push_back("--input");
+ args.push_back(source_global);
+ args.push_back("--output");
+ args.push_back(sink_global);
+ args.push_back("--binary");
+
+ String standard_out;
+ int ret;
+ OS::get_singleton()->execute(fbx2gltf_path, args, &standard_out, &ret, true);
+ print_verbose(fbx2gltf_path);
+ print_verbose(standard_out);
+
+ if (ret != 0) {
+ if (r_err) {
+ *r_err = ERR_SCRIPT_FAILED;
+ }
+ ERR_PRINT(vformat("FBX conversion to glTF failed with error: %d.", ret));
+ return nullptr;
+ }
+
+ // Import the generated glTF.
+
+ // Use GLTFDocument instead of glTF importer to keep image references.
+ Ref<GLTFDocument> gltf;
+ gltf.instantiate();
+ Ref<GLTFState> state;
+ state.instantiate();
+ print_verbose(vformat("glTF path: %s", sink));
+ Error err = gltf->append_from_file(sink, state, p_flags, p_bake_fps);
+ if (err != OK) {
+ if (r_err) {
+ *r_err = FAILED;
+ }
+ return nullptr;
+ }
+ return gltf->generate_scene(state, p_bake_fps);
+}
+
+Variant EditorSceneFormatImporterFBX::get_option_visibility(const String &p_path, bool p_for_animation,
+ const String &p_option, const Map<StringName, Variant> &p_options) {
+ return true;
+}
+
+void EditorSceneFormatImporterFBX::get_import_options(const String &p_path,
+ List<ResourceImporter::ImportOption> *r_options) {
+}
+
+#endif // TOOLS_ENABLED
diff --git a/modules/fbx/tools/validation_tools.cpp b/modules/gltf/editor/editor_scene_importer_fbx.h
index f775480e69..84de7fd1cc 100644
--- a/modules/fbx/tools/validation_tools.cpp
+++ b/modules/gltf/editor/editor_scene_importer_fbx.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* validation_tools.cpp */
+/* editor_scene_importer_fbx.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,21 +28,31 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "validation_tools.h"
+#ifndef EDITOR_SCENE_IMPORTER_FBX_H
+#define EDITOR_SCENE_IMPORTER_FBX_H
#ifdef TOOLS_ENABLED
-#include "core/string/print_string.h"
-#include "core/string/ustring.h"
+#include "editor/import/resource_importer_scene.h"
-ValidationTracker::Entries *ValidationTracker::entries_singleton = memnew(ValidationTracker::Entries);
+class Animation;
+class Node;
-// for printing our CSV to dump validation problems of files
-// later we can make some agnostic tooling for this but this is fine for the time being.
-void ValidationTracker::Entries::add_validation_error(String asset_path, String message) {
- print_error(message);
- // note: implementation is static
- validation_entries[asset_path].push_back(message);
-}
+class EditorSceneFormatImporterFBX : public EditorSceneFormatImporter {
+ GDCLASS(EditorSceneFormatImporterFBX, EditorSceneFormatImporter);
+
+public:
+ virtual uint32_t get_import_flags() const override;
+ virtual void get_extensions(List<String> *r_extensions) const override;
+ virtual Node *import_scene(const String &p_path, uint32_t p_flags,
+ const Map<StringName, Variant> &p_options, int p_bake_fps,
+ List<String> *r_missing_deps, Error *r_err = nullptr) override;
+ virtual void get_import_options(const String &p_path,
+ List<ResourceImporter::ImportOption> *r_options) override;
+ virtual Variant get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option,
+ const Map<StringName, Variant> &p_options) override;
+};
#endif // TOOLS_ENABLED
+
+#endif // EDITOR_SCENE_IMPORTER_FBX_H
diff --git a/modules/gltf/editor_scene_importer_gltf.cpp b/modules/gltf/editor/editor_scene_importer_gltf.cpp
index f063cc1e2b..5e7811ad2b 100644
--- a/modules/gltf/editor_scene_importer_gltf.cpp
+++ b/modules/gltf/editor/editor_scene_importer_gltf.cpp
@@ -28,14 +28,14 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#if TOOLS_ENABLED
+#ifdef TOOLS_ENABLED
+
#include "editor_scene_importer_gltf.h"
-#include "gltf_document.h"
-#include "gltf_state.h"
+#include "../gltf_document.h"
+#include "../gltf_state.h"
-#include "scene/3d/node_3d.h"
-#include "scene/animation/animation_player.h"
+#include "scene/main/node.h"
#include "scene/resources/animation.h"
uint32_t EditorSceneFormatImporterGLTF::get_import_flags() const {
@@ -47,27 +47,21 @@ void EditorSceneFormatImporterGLTF::get_extensions(List<String> *r_extensions) c
r_extensions->push_back("glb");
}
-Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path,
- uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps,
- List<String> *r_missing_deps,
- Error *r_err) {
+Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, uint32_t p_flags,
+ const Map<StringName, Variant> &p_options, int p_bake_fps,
+ List<String> *r_missing_deps, Error *r_err) {
Ref<GLTFDocument> doc;
doc.instantiate();
Ref<GLTFState> state;
state.instantiate();
Error err = doc->append_from_file(p_path, state, p_flags, p_bake_fps);
if (err != OK) {
- *r_err = err;
+ if (r_err) {
+ *r_err = err;
+ }
return nullptr;
}
- Node *root = doc->generate_scene(state, p_bake_fps);
- return root;
-}
-
-Ref<Animation> EditorSceneFormatImporterGLTF::import_animation(const String &p_path,
- uint32_t p_flags, const Map<StringName, Variant> &p_options,
- int p_bake_fps) {
- return Ref<Animation>();
+ return doc->generate_scene(state, p_bake_fps);
}
#endif // TOOLS_ENABLED
diff --git a/modules/gltf/editor_scene_importer_gltf.h b/modules/gltf/editor/editor_scene_importer_gltf.h
index 4410559b3d..b714ada124 100644
--- a/modules/gltf/editor_scene_importer_gltf.h
+++ b/modules/gltf/editor/editor_scene_importer_gltf.h
@@ -30,16 +30,13 @@
#ifndef EDITOR_SCENE_IMPORTER_GLTF_H
#define EDITOR_SCENE_IMPORTER_GLTF_H
-#ifdef TOOLS_ENABLED
-#include "gltf_state.h"
-#include "gltf_document_extension.h"
+#ifdef TOOLS_ENABLED
#include "editor/import/resource_importer_scene.h"
-#include "scene/main/node.h"
-#include "scene/resources/packed_scene.h"
class Animation;
+class Node;
class EditorSceneFormatImporterGLTF : public EditorSceneFormatImporter {
GDCLASS(EditorSceneFormatImporterGLTF, EditorSceneFormatImporter);
@@ -47,9 +44,11 @@ class EditorSceneFormatImporterGLTF : public EditorSceneFormatImporter {
public:
virtual uint32_t get_import_flags() const override;
virtual void get_extensions(List<String> *r_extensions) const override;
- virtual Node *import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override;
- virtual Ref<Animation> import_animation(const String &p_path,
- uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps) override;
+ virtual Node *import_scene(const String &p_path, uint32_t p_flags,
+ const Map<StringName, Variant> &p_options, int p_bake_fps,
+ List<String> *r_missing_deps, Error *r_err = nullptr) override;
};
+
#endif // TOOLS_ENABLED
+
#endif // EDITOR_SCENE_IMPORTER_GLTF_H
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index c70081a620..082b4ce1ec 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -58,7 +58,6 @@
#include "core/variant/variant.h"
#include "core/version.h"
#include "drivers/png/png_driver_common.h"
-#include "editor/import/resource_importer_scene.h"
#include "scene/2d/node_2d.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/mesh_instance_3d.h"
@@ -66,6 +65,7 @@
#include "scene/3d/node_3d.h"
#include "scene/animation/animation_player.h"
#include "scene/resources/importer_mesh.h"
+#include "scene/resources/material.h"
#include "scene/resources/mesh.h"
#include "scene/resources/multimesh.h"
#include "scene/resources/surface_tool.h"
@@ -79,6 +79,10 @@
#include "modules/gridmap/grid_map.h"
#endif // MODULE_GRIDMAP_ENABLED
+// FIXME: Hardcoded to avoid editor dependency.
+#define GLTF_IMPORT_USE_NAMED_SKIN_BINDS 16
+#define GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS 32
+
#include <stdio.h>
#include <stdlib.h>
#include <cstdint>
@@ -254,8 +258,8 @@ Error GLTFDocument::_serialize_scenes(Ref<GLTFState> state) {
Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> state) {
Error err;
- FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err);
- if (!f) {
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
+ if (f.is_null()) {
return err;
}
@@ -276,7 +280,7 @@ Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> state) {
return OK;
}
-Error GLTFDocument::_parse_glb(FileAccess *f, Ref<GLTFState> state) {
+Error GLTFDocument::_parse_glb(Ref<FileAccess> f, Ref<GLTFState> state) {
ERR_FAIL_NULL_V(f, ERR_INVALID_PARAMETER);
ERR_FAIL_NULL_V(state, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(f->get_position() != 0, ERR_FILE_CANT_READ);
@@ -356,9 +360,9 @@ static Transform3D _arr_to_xform(const Array &p_array) {
ERR_FAIL_COND_V(p_array.size() != 16, Transform3D());
Transform3D xform;
- xform.basis.set_axis(Vector3::AXIS_X, Vector3(p_array[0], p_array[1], p_array[2]));
- xform.basis.set_axis(Vector3::AXIS_Y, Vector3(p_array[4], p_array[5], p_array[6]));
- xform.basis.set_axis(Vector3::AXIS_Z, Vector3(p_array[8], p_array[9], p_array[10]));
+ xform.basis.set_column(Vector3::AXIS_X, Vector3(p_array[0], p_array[1], p_array[2]));
+ xform.basis.set_column(Vector3::AXIS_Y, Vector3(p_array[4], p_array[5], p_array[6]));
+ xform.basis.set_column(Vector3::AXIS_Z, Vector3(p_array[8], p_array[9], p_array[10]));
xform.set_origin(Vector3(p_array[12], p_array[13], p_array[14]));
return xform;
@@ -367,17 +371,17 @@ static Transform3D _arr_to_xform(const Array &p_array) {
static Vector<real_t> _xform_to_array(const Transform3D p_transform) {
Vector<real_t> array;
array.resize(16);
- Vector3 axis_x = p_transform.get_basis().get_axis(Vector3::AXIS_X);
+ Vector3 axis_x = p_transform.get_basis().get_column(Vector3::AXIS_X);
array.write[0] = axis_x.x;
array.write[1] = axis_x.y;
array.write[2] = axis_x.z;
array.write[3] = 0.0f;
- Vector3 axis_y = p_transform.get_basis().get_axis(Vector3::AXIS_Y);
+ Vector3 axis_y = p_transform.get_basis().get_column(Vector3::AXIS_Y);
array.write[4] = axis_y.x;
array.write[5] = axis_y.y;
array.write[6] = axis_y.z;
array.write[7] = 0.0f;
- Vector3 axis_z = p_transform.get_basis().get_axis(Vector3::AXIS_Z);
+ Vector3 axis_z = p_transform.get_basis().get_column(Vector3::AXIS_Z);
array.write[8] = axis_z.x;
array.write[9] = axis_z.y;
array.write[10] = axis_z.z;
@@ -694,8 +698,8 @@ Error GLTFDocument::_encode_buffer_glb(Ref<GLTFState> state, const String &p_pat
String filename = p_path.get_basename().get_file() + itos(i) + ".bin";
String path = p_path.get_base_dir() + "/" + filename;
Error err;
- FileAccessRef f = FileAccess::open(path, FileAccess::WRITE, &err);
- if (!f) {
+ Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE, &err);
+ if (f.is_null()) {
return err;
}
if (buffer_data.size() == 0) {
@@ -703,7 +707,6 @@ Error GLTFDocument::_encode_buffer_glb(Ref<GLTFState> state, const String &p_pat
}
f->create(FileAccess::ACCESS_RESOURCES);
f->store_buffer(buffer_data.ptr(), buffer_data.size());
- f->close();
gltf_buffer["uri"] = filename;
gltf_buffer["byteLength"] = buffer_data.size();
buffers.push_back(gltf_buffer);
@@ -727,8 +730,8 @@ Error GLTFDocument::_encode_buffer_bins(Ref<GLTFState> state, const String &p_pa
String filename = p_path.get_basename().get_file() + itos(i) + ".bin";
String path = p_path.get_base_dir() + "/" + filename;
Error err;
- FileAccessRef f = FileAccess::open(path, FileAccess::WRITE, &err);
- if (!f) {
+ Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE, &err);
+ if (f.is_null()) {
return err;
}
if (buffer_data.size() == 0) {
@@ -736,7 +739,6 @@ Error GLTFDocument::_encode_buffer_bins(Ref<GLTFState> state, const String &p_pa
}
f->create(FileAccess::ACCESS_RESOURCES);
f->store_buffer(buffer_data.ptr(), buffer_data.size());
- f->close();
gltf_buffer["uri"] = filename;
gltf_buffer["byteLength"] = buffer_data.size();
buffers.push_back(gltf_buffer);
@@ -1958,20 +1960,20 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> state,
for (int i = 0; i < p_attribs.size(); i++) {
Transform3D attrib = p_attribs[i];
Basis basis = attrib.get_basis();
- Vector3 axis_0 = basis.get_axis(Vector3::AXIS_X);
+ Vector3 axis_0 = basis.get_column(Vector3::AXIS_X);
attribs.write[i * element_count + 0] = Math::snapped(axis_0.x, CMP_NORMALIZE_TOLERANCE);
attribs.write[i * element_count + 1] = Math::snapped(axis_0.y, CMP_NORMALIZE_TOLERANCE);
attribs.write[i * element_count + 2] = Math::snapped(axis_0.z, CMP_NORMALIZE_TOLERANCE);
attribs.write[i * element_count + 3] = 0.0;
- Vector3 axis_1 = basis.get_axis(Vector3::AXIS_Y);
+ Vector3 axis_1 = basis.get_column(Vector3::AXIS_Y);
attribs.write[i * element_count + 4] = Math::snapped(axis_1.x, CMP_NORMALIZE_TOLERANCE);
attribs.write[i * element_count + 5] = Math::snapped(axis_1.y, CMP_NORMALIZE_TOLERANCE);
attribs.write[i * element_count + 6] = Math::snapped(axis_1.z, CMP_NORMALIZE_TOLERANCE);
attribs.write[i * element_count + 7] = 0.0;
- Vector3 axis_2 = basis.get_axis(Vector3::AXIS_Z);
+ Vector3 axis_2 = basis.get_column(Vector3::AXIS_Z);
attribs.write[i * element_count + 8] = Math::snapped(axis_2.x, CMP_NORMALIZE_TOLERANCE);
attribs.write[i * element_count + 9] = Math::snapped(axis_2.y, CMP_NORMALIZE_TOLERANCE);
attribs.write[i * element_count + 10] = Math::snapped(axis_2.z, CMP_NORMALIZE_TOLERANCE);
@@ -2103,9 +2105,9 @@ Vector<Basis> GLTFDocument::_decode_accessor_as_basis(Ref<GLTFState> state, cons
ERR_FAIL_COND_V(attribs.size() % 9 != 0, ret);
ret.resize(attribs.size() / 9);
for (int i = 0; i < ret.size(); i++) {
- ret.write[i].set_axis(0, Vector3(attribs[i * 9 + 0], attribs[i * 9 + 1], attribs[i * 9 + 2]));
- ret.write[i].set_axis(1, Vector3(attribs[i * 9 + 3], attribs[i * 9 + 4], attribs[i * 9 + 5]));
- ret.write[i].set_axis(2, Vector3(attribs[i * 9 + 6], attribs[i * 9 + 7], attribs[i * 9 + 8]));
+ ret.write[i].set_column(0, Vector3(attribs[i * 9 + 0], attribs[i * 9 + 1], attribs[i * 9 + 2]));
+ ret.write[i].set_column(1, Vector3(attribs[i * 9 + 3], attribs[i * 9 + 4], attribs[i * 9 + 5]));
+ ret.write[i].set_column(2, Vector3(attribs[i * 9 + 6], attribs[i * 9 + 7], attribs[i * 9 + 8]));
}
return ret;
}
@@ -2121,9 +2123,9 @@ Vector<Transform3D> GLTFDocument::_decode_accessor_as_xform(Ref<GLTFState> state
ERR_FAIL_COND_V(attribs.size() % 16 != 0, ret);
ret.resize(attribs.size() / 16);
for (int i = 0; i < ret.size(); i++) {
- ret.write[i].basis.set_axis(0, Vector3(attribs[i * 16 + 0], attribs[i * 16 + 1], attribs[i * 16 + 2]));
- ret.write[i].basis.set_axis(1, Vector3(attribs[i * 16 + 4], attribs[i * 16 + 5], attribs[i * 16 + 6]));
- ret.write[i].basis.set_axis(2, Vector3(attribs[i * 16 + 8], attribs[i * 16 + 9], attribs[i * 16 + 10]));
+ ret.write[i].basis.set_column(0, Vector3(attribs[i * 16 + 0], attribs[i * 16 + 1], attribs[i * 16 + 2]));
+ ret.write[i].basis.set_column(1, Vector3(attribs[i * 16 + 4], attribs[i * 16 + 5], attribs[i * 16 + 6]));
+ ret.write[i].basis.set_column(2, Vector3(attribs[i * 16 + 8], attribs[i * 16 + 9], attribs[i * 16 + 10]));
ret.write[i].set_origin(Vector3(attribs[i * 16 + 12], attribs[i * 16 + 13], attribs[i * 16 + 14]));
}
return ret;
@@ -2907,34 +2909,43 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
}
array_copy = blend_surface_tool->commit_to_arrays();
+ // Enforce blend shape mask array format
+ for (int l = 0; l < Mesh::ARRAY_MAX; l++) {
+ if (!(Mesh::ARRAY_FORMAT_BLEND_SHAPE_MASK & (1 << l))) {
+ array_copy[l] = Variant();
+ }
+ }
+
morphs.push_back(array_copy);
}
}
- //just add it
-
Ref<BaseMaterial3D> mat;
- if (p.has("material")) {
- const int material = p["material"];
- ERR_FAIL_INDEX_V(material, state->materials.size(), ERR_FILE_CORRUPT);
- Ref<BaseMaterial3D> mat3d = state->materials[material];
- ERR_FAIL_NULL_V(mat3d, ERR_FILE_CORRUPT);
- if (has_vertex_color) {
- mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- }
- mat = mat3d;
+ String mat_name;
+ if (!state->discard_meshes_and_materials) {
+ if (p.has("material")) {
+ const int material = p["material"];
+ ERR_FAIL_INDEX_V(material, state->materials.size(), ERR_FILE_CORRUPT);
+ Ref<BaseMaterial3D> mat3d = state->materials[material];
+ ERR_FAIL_NULL_V(mat3d, ERR_FILE_CORRUPT);
+ if (has_vertex_color) {
+ mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ }
+ mat = mat3d;
- } else {
- Ref<StandardMaterial3D> mat3d;
- mat3d.instantiate();
- if (has_vertex_color) {
- mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ } else {
+ Ref<StandardMaterial3D> mat3d;
+ mat3d.instantiate();
+ if (has_vertex_color) {
+ mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ }
+ mat = mat3d;
}
- mat = mat3d;
+ ERR_FAIL_NULL_V(mat, ERR_FILE_CORRUPT);
+ mat_name = mat->get_name();
}
- ERR_FAIL_NULL_V(mat, ERR_FILE_CORRUPT);
import_mesh->add_surface(primitive, array, morphs,
- Dictionary(), mat, mat->get_name(), flags);
+ Dictionary(), mat, mat_name, flags);
}
Vector<float> blend_weights;
@@ -3012,7 +3023,7 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path
String texture_dir = "textures";
String path = p_path.get_base_dir();
String new_texture_dir = path + "/" + texture_dir;
- DirAccessRef da = DirAccess::open(path);
+ Ref<DirAccess> da = DirAccess::open(path);
if (!da->dir_exists(new_texture_dir)) {
da->make_dir(new_texture_dir);
}
@@ -3265,7 +3276,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
Dictionary mr;
{
Array arr;
- const Color c = material->get_albedo().to_linear();
+ const Color c = material->get_albedo().srgb_to_linear();
arr.push_back(c.r);
arr.push_back(c.g);
arr.push_back(c.b);
@@ -3466,7 +3477,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
}
if (material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) {
- const Color c = material->get_emission().to_srgb();
+ const Color c = material->get_emission().linear_to_srgb();
Array arr;
arr.push_back(c.r);
arr.push_back(c.g);
@@ -3548,7 +3559,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
if (sgm.has("diffuseFactor")) {
const Array &arr = sgm["diffuseFactor"];
ERR_FAIL_COND_V(arr.size() != 4, ERR_PARSE_ERROR);
- const Color c = Color(arr[0], arr[1], arr[2], arr[3]).to_srgb();
+ const Color c = Color(arr[0], arr[1], arr[2], arr[3]).linear_to_srgb();
spec_gloss->diffuse_factor = c;
material->set_albedo(spec_gloss->diffuse_factor);
}
@@ -3579,7 +3590,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
if (mr.has("baseColorFactor")) {
const Array &arr = mr["baseColorFactor"];
ERR_FAIL_COND_V(arr.size() != 4, ERR_PARSE_ERROR);
- const Color c = Color(arr[0], arr[1], arr[2], arr[3]).to_srgb();
+ const Color c = Color(arr[0], arr[1], arr[2], arr[3]).linear_to_srgb();
material->set_albedo(c);
}
@@ -3646,7 +3657,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
if (d.has("emissiveFactor")) {
const Array &arr = d["emissiveFactor"];
ERR_FAIL_COND_V(arr.size() != 3, ERR_PARSE_ERROR);
- const Color c = Color(arr[0], arr[1], arr[2]).to_srgb();
+ const Color c = Color(arr[0], arr[1], arr[2]).linear_to_srgb();
material->set_feature(BaseMaterial3D::FEATURE_EMISSION, true);
material->set_emission(c);
@@ -3730,11 +3741,11 @@ void GLTFDocument::spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, Re
}
for (int32_t y = 0; y < r_spec_gloss->spec_gloss_img->get_height(); y++) {
for (int32_t x = 0; x < r_spec_gloss->spec_gloss_img->get_width(); x++) {
- const Color specular_pixel = r_spec_gloss->spec_gloss_img->get_pixel(x, y).to_linear();
+ const Color specular_pixel = r_spec_gloss->spec_gloss_img->get_pixel(x, y).srgb_to_linear();
Color specular = Color(specular_pixel.r, specular_pixel.g, specular_pixel.b);
specular *= r_spec_gloss->specular_factor;
Color diffuse = Color(1.0f, 1.0f, 1.0f);
- diffuse *= r_spec_gloss->diffuse_img->get_pixel(x, y).to_linear();
+ diffuse *= r_spec_gloss->diffuse_img->get_pixel(x, y).srgb_to_linear();
float metallic = 0.0f;
Color base_color;
spec_gloss_to_metal_base_color(specular, diffuse, base_color, metallic);
@@ -3751,7 +3762,7 @@ void GLTFDocument::spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, Re
mr.g = 1.0f - mr.g;
rm_img->set_pixel(x, y, mr);
if (r_spec_gloss->diffuse_img.is_valid()) {
- r_spec_gloss->diffuse_img->set_pixel(x, y, base_color.to_srgb());
+ r_spec_gloss->diffuse_img->set_pixel(x, y, base_color.linear_to_srgb());
}
}
}
@@ -4619,7 +4630,7 @@ Error GLTFDocument::_parse_lights(Ref<GLTFState> state) {
if (d.has("color")) {
const Array &arr = d["color"];
ERR_FAIL_COND_V(arr.size() != 3, ERR_PARSE_ERROR);
- const Color c = Color(arr[0], arr[1], arr[2]).to_srgb();
+ const Color c = Color(arr[0], arr[1], arr[2]).linear_to_srgb();
light->color = c;
}
if (d.has("intensity")) {
@@ -5741,7 +5752,7 @@ void GLTFDocument::_generate_skeleton_bone_node(Ref<GLTFState> state, Node *scen
}
template <class T>
-struct EditorSceneFormatImporterGLTFInterpolate {
+struct SceneFormatImporterGLTFInterpolate {
T lerp(const T &a, const T &b, float c) const {
return a + (b - a) * c;
}
@@ -5767,7 +5778,7 @@ struct EditorSceneFormatImporterGLTFInterpolate {
// thank you for existing, partial specialization
template <>
-struct EditorSceneFormatImporterGLTFInterpolate<Quaternion> {
+struct SceneFormatImporterGLTFInterpolate<Quaternion> {
Quaternion lerp(const Quaternion &a, const Quaternion &b, const float c) const {
ERR_FAIL_COND_V_MSG(!a.is_normalized(), Quaternion(), "The quaternion \"a\" must be normalized.");
ERR_FAIL_COND_V_MSG(!b.is_normalized(), Quaternion(), "The quaternion \"b\" must be normalized.");
@@ -5806,7 +5817,7 @@ T GLTFDocument::_interpolate_track(const Vector<real_t> &p_times, const Vector<T
idx++;
}
- EditorSceneFormatImporterGLTFInterpolate<T> interp;
+ SceneFormatImporterGLTFInterpolate<T> interp;
switch (p_interp) {
case GLTFAnimation::INTERP_LINEAR: {
@@ -6088,7 +6099,14 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
animation->set_length(length);
- ap->add_animation(name, animation);
+ Ref<AnimationLibrary> library;
+ if (!ap->has_animation_library("")) {
+ library.instantiate();
+ ap->add_animation_library("", library);
+ } else {
+ library = ap->get_animation_library("");
+ }
+ library->add_animation(name, animation);
}
void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) {
@@ -6579,9 +6597,9 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
}
}
-Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, FileAccess *f, int p_bake_fps) {
+Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, Ref<FileAccess> f, int p_bake_fps) {
Error err;
- if (!f) {
+ if (f.is_null()) {
return FAILED;
}
f->seek(0);
@@ -6605,7 +6623,6 @@ Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, FileAccess *f, i
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
state->json = json.get_data();
}
- f->close();
if (!state->json.has("asset")) {
return ERR_PARSE_ERROR;
@@ -6694,8 +6711,8 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) {
if (p_path.to_lower().ends_with("glb")) {
err = _encode_buffer_glb(state, p_path);
ERR_FAIL_COND_V(err != OK, err);
- FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE, &err);
- ERR_FAIL_COND_V(!f, FAILED);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE, &err);
+ ERR_FAIL_COND_V(f.is_null(), FAILED);
String json = Variant(state->json).to_json_string();
@@ -6732,25 +6749,22 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) {
for (uint32_t pad_i = binary_data_length; pad_i < binary_chunk_length; pad_i++) {
f->store_8(0);
}
-
- f->close();
} else {
err = _encode_buffer_bins(state, p_path);
ERR_FAIL_COND_V(err != OK, err);
- FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE, &err);
- ERR_FAIL_COND_V(!f, FAILED);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE, &err);
+ ERR_FAIL_COND_V(f.is_null(), FAILED);
f->create(FileAccess::ACCESS_RESOURCES);
String json = Variant(state->json).to_json_string();
f->store_string(json);
- f->close();
}
return err;
}
void GLTFDocument::_bind_methods() {
- ClassDB::bind_method(D_METHOD("append_from_file", "path", "state", "flags", "bake_fps"),
- &GLTFDocument::append_from_file, DEFVAL(0), DEFVAL(30));
+ ClassDB::bind_method(D_METHOD("append_from_file", "path", "state", "flags", "bake_fps", "base_path"),
+ &GLTFDocument::append_from_file, DEFVAL(0), DEFVAL(30), DEFVAL(String()));
ClassDB::bind_method(D_METHOD("append_from_buffer", "bytes", "base_path", "state", "flags", "bake_fps"),
&GLTFDocument::append_from_buffer, DEFVAL(0), DEFVAL(30));
ClassDB::bind_method(D_METHOD("append_from_scene", "node", "state", "flags", "bake_fps"),
@@ -6898,8 +6912,8 @@ Node *GLTFDocument::generate_scene(Ref<GLTFState> state, int32_t p_bake_fps) {
Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> state, uint32_t p_flags, int32_t p_bake_fps) {
ERR_FAIL_COND_V(state.is_null(), FAILED);
- state->use_named_skin_binds =
- p_flags & EditorSceneFormatImporter::IMPORT_USE_NAMED_SKIN_BINDS;
+ state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS;
+ state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS;
_convert_scene_node(state, p_node, -1, -1);
if (!state->buffers.size()) {
@@ -6918,9 +6932,11 @@ Error GLTFDocument::append_from_buffer(PackedByteArray p_bytes, String p_base_pa
ERR_FAIL_COND_V(state.is_null(), FAILED);
// TODO Add missing texture and missing .bin file paths to r_missing_deps 2021-09-10 fire
Error err = FAILED;
- state->use_named_skin_binds =
- p_flags & EditorSceneFormatImporter::IMPORT_USE_NAMED_SKIN_BINDS;
- FileAccessMemory *file_access = memnew(FileAccessMemory);
+ state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS;
+ state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS;
+
+ Ref<FileAccessMemory> file_access;
+ file_access.instantiate();
file_access->open_custom(p_bytes.ptr(), p_bytes.size());
err = _parse(state, p_base_path.get_base_dir(), file_access, p_bake_fps);
ERR_FAIL_COND_V(err != OK, FAILED);
@@ -6957,20 +6973,22 @@ Error GLTFDocument::_parse_gltf_state(Ref<GLTFState> state, const String &p_sear
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
- /* PARSE IMAGES */
- err = _parse_images(state, p_search_path);
+ if (!state->discard_meshes_and_materials) {
+ /* PARSE IMAGES */
+ err = _parse_images(state, p_search_path);
- ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
+ ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
- /* PARSE TEXTURES */
- err = _parse_textures(state);
+ /* PARSE TEXTURES */
+ err = _parse_textures(state);
- ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
+ ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
- /* PARSE TEXTURES */
- err = _parse_materials(state);
+ /* PARSE TEXTURES */
+ err = _parse_materials(state);
- ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
+ ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
+ }
/* PARSE SKINS */
err = _parse_skins(state);
@@ -7015,20 +7033,23 @@ Error GLTFDocument::_parse_gltf_state(Ref<GLTFState> state, const String &p_sear
return OK;
}
-Error GLTFDocument::append_from_file(String p_path, Ref<GLTFState> r_state, uint32_t p_flags, int32_t p_bake_fps) {
+Error GLTFDocument::append_from_file(String p_path, Ref<GLTFState> r_state, uint32_t p_flags, int32_t p_bake_fps, String p_base_path) {
// TODO Add missing texture and missing .bin file paths to r_missing_deps 2021-09-10 fire
if (r_state == Ref<GLTFState>()) {
r_state.instantiate();
}
r_state->filename = p_path.get_file().get_basename();
- r_state->use_named_skin_binds =
- p_flags & EditorSceneFormatImporter::IMPORT_USE_NAMED_SKIN_BINDS;
+ r_state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS;
+ r_state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS;
Error err;
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
ERR_FAIL_COND_V(err != OK, ERR_FILE_CANT_OPEN);
ERR_FAIL_NULL_V(f, ERR_FILE_CANT_OPEN);
-
- err = _parse(r_state, p_path.get_base_dir(), f, p_bake_fps);
+ String base_path = p_base_path;
+ if (base_path.is_empty()) {
+ base_path = p_path.get_base_dir();
+ }
+ err = _parse(r_state, base_path, f, p_bake_fps);
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
return err;
}
diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h
index c0649e0129..19bc507a8d 100644
--- a/modules/gltf/gltf_document.h
+++ b/modules/gltf/gltf_document.h
@@ -196,7 +196,7 @@ private:
Ref<Texture2D> _get_texture(Ref<GLTFState> state,
const GLTFTextureIndex p_texture);
Error _parse_json(const String &p_path, Ref<GLTFState> state);
- Error _parse_glb(FileAccess *f, Ref<GLTFState> state);
+ Error _parse_glb(Ref<FileAccess> f, Ref<GLTFState> state);
void _compute_node_heights(Ref<GLTFState> state);
Error _parse_buffers(Ref<GLTFState> state, const String &p_base_path);
Error _parse_buffer_views(Ref<GLTFState> state);
@@ -381,7 +381,7 @@ private:
static float get_max_component(const Color &p_color);
public:
- Error append_from_file(String p_path, Ref<GLTFState> r_state, uint32_t p_flags = 0, int32_t p_bake_fps = 30);
+ Error append_from_file(String p_path, Ref<GLTFState> r_state, uint32_t p_flags = 0, int32_t p_bake_fps = 30, String p_base_path = String());
Error append_from_buffer(PackedByteArray p_bytes, String p_base_path, Ref<GLTFState> r_state, uint32_t p_flags = 0, int32_t p_bake_fps = 30);
Error append_from_scene(Node *p_node, Ref<GLTFState> r_state, uint32_t p_flags = 0, int32_t p_bake_fps = 30);
@@ -457,7 +457,7 @@ public:
void _convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
String p_animation_track_name);
Error _serialize(Ref<GLTFState> state, const String &p_path);
- Error _parse(Ref<GLTFState> state, String p_path, FileAccess *f, int p_bake_fps);
+ Error _parse(Ref<GLTFState> state, String p_path, Ref<FileAccess> f, int p_bake_fps);
};
#endif // GLTF_DOCUMENT_H
diff --git a/modules/gltf/gltf_mesh.cpp b/modules/gltf/gltf_mesh.cpp
index 1251622642..3add8304b1 100644
--- a/modules/gltf/gltf_mesh.cpp
+++ b/modules/gltf/gltf_mesh.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "gltf_mesh.h"
+
#include "scene/resources/importer_mesh.h"
void GLTFMesh::_bind_methods() {
diff --git a/modules/gltf/gltf_mesh.h b/modules/gltf/gltf_mesh.h
index aeab1ad68f..dc26120b48 100644
--- a/modules/gltf/gltf_mesh.h
+++ b/modules/gltf/gltf_mesh.h
@@ -32,7 +32,6 @@
#define GLTF_MESH_H
#include "core/io/resource.h"
-#include "editor/import/resource_importer_scene.h"
#include "scene/3d/importer_mesh_instance_3d.h"
#include "scene/resources/importer_mesh.h"
#include "scene/resources/mesh.h"
@@ -56,4 +55,5 @@ public:
Array get_instance_materials();
void set_instance_materials(Array p_instance_materials);
};
+
#endif // GLTF_MESH_H
diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp
index 3f638bbca5..6ead2f69c3 100644
--- a/modules/gltf/gltf_state.cpp
+++ b/modules/gltf/gltf_state.cpp
@@ -305,3 +305,11 @@ AnimationPlayer *GLTFState::get_animation_player(int idx) {
ERR_FAIL_INDEX_V(idx, animation_players.size(), nullptr);
return animation_players[idx];
}
+
+void GLTFState::set_discard_meshes_and_materials(bool p_discard_meshes_and_materials) {
+ discard_meshes_and_materials = p_discard_meshes_and_materials;
+}
+
+bool GLTFState::get_discard_meshes_and_materials() {
+ return discard_meshes_and_materials;
+}
diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h
index d03434d2f1..42ca079f1c 100644
--- a/modules/gltf/gltf_state.h
+++ b/modules/gltf/gltf_state.h
@@ -62,6 +62,7 @@ class GLTFState : public Resource {
Vector<uint8_t> glb_data;
bool use_named_skin_binds = false;
+ bool discard_meshes_and_materials = false;
Vector<Ref<GLTFNode>> nodes;
Vector<Vector<uint8_t>> buffers;
@@ -112,6 +113,9 @@ public:
bool get_use_named_skin_binds();
void set_use_named_skin_binds(bool p_use_named_skin_binds);
+ bool get_discard_meshes_and_materials();
+ void set_discard_meshes_and_materials(bool p_discard_meshes_and_materials);
+
Array get_nodes();
void set_nodes(Array p_nodes);
diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp
index 6ab202096d..b8bac79584 100644
--- a/modules/gltf/register_types.cpp
+++ b/modules/gltf/register_types.cpp
@@ -30,9 +30,8 @@
#include "register_types.h"
-#include "editor/editor_node.h"
-#include "editor_scene_exporter_gltf_plugin.h"
-#include "editor_scene_importer_gltf.h"
+#ifndef _3D_DISABLED
+
#include "gltf_accessor.h"
#include "gltf_animation.h"
#include "gltf_buffer_view.h"
@@ -49,43 +48,105 @@
#include "gltf_state.h"
#include "gltf_texture.h"
-#ifndef _3D_DISABLED
#ifdef TOOLS_ENABLED
+#include "core/config/project_settings.h"
+#include "editor/editor_node.h"
+#include "editor/editor_scene_exporter_gltf_plugin.h"
+#include "editor/editor_scene_importer_blend.h"
+#include "editor/editor_scene_importer_fbx.h"
+#include "editor/editor_scene_importer_gltf.h"
+#include "editor/editor_settings.h"
+
static void _editor_init() {
Ref<EditorSceneFormatImporterGLTF> import_gltf;
import_gltf.instantiate();
- ResourceImporterScene::get_singleton()->add_importer(import_gltf);
+ ResourceImporterScene::add_importer(import_gltf);
+
+ // Blend to glTF importer.
+
+ bool blend_enabled = GLOBAL_GET("filesystem/import/blender/enabled");
+ // Defined here because EditorSettings doesn't exist in `register_gltf_types` yet.
+ EDITOR_DEF_RST("filesystem/import/blender/blender3_path", "");
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,
+ "filesystem/import/blender/blender3_path", PROPERTY_HINT_GLOBAL_DIR));
+ if (blend_enabled) {
+ Ref<EditorSceneFormatImporterBlend> importer;
+ importer.instantiate();
+ ResourceImporterScene::add_importer(importer);
+
+ Ref<EditorFileSystemImportFormatSupportQueryBlend> blend_import_query;
+ blend_import_query.instantiate();
+ EditorFileSystem::get_singleton()->add_import_format_support_query(blend_import_query);
+ }
+
+ // FBX to glTF importer.
+
+ bool fbx_enabled = GLOBAL_GET("filesystem/import/fbx/enabled");
+ // Defined here because EditorSettings doesn't exist in `register_gltf_types` yet.
+ String fbx2gltf_path = EDITOR_DEF_RST("filesystem/import/fbx/fbx2gltf_path", "");
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,
+ "filesystem/import/fbx/fbx2gltf_path", PROPERTY_HINT_GLOBAL_FILE));
+ if (fbx_enabled) {
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ if (fbx2gltf_path.is_empty()) {
+ WARN_PRINT("FBX file import is enabled, but no FBX2glTF path is configured. FBX files will not be imported.");
+ } else if (!da->file_exists(fbx2gltf_path)) {
+ WARN_PRINT("FBX file import is enabled, but the FBX2glTF path doesn't point to a valid FBX2glTF executable. FBX files will not be imported.");
+ } else {
+ Ref<EditorSceneFormatImporterFBX> importer;
+ importer.instantiate();
+ ResourceImporterScene::add_importer(importer);
+ }
+ }
}
-#endif
-#endif
+#endif // TOOLS_ENABLED
+
+void initialize_gltf_module(ModuleInitializationLevel p_level) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
+ // glTF API available at runtime.
+ GDREGISTER_CLASS(GLTFAccessor);
+ GDREGISTER_CLASS(GLTFAnimation);
+ GDREGISTER_CLASS(GLTFBufferView);
+ GDREGISTER_CLASS(GLTFCamera);
+ GDREGISTER_CLASS(GLTFDocument);
+ GDREGISTER_CLASS(GLTFDocumentExtension);
+ GDREGISTER_CLASS(GLTFDocumentExtensionConvertImporterMesh);
+ GDREGISTER_CLASS(GLTFLight);
+ GDREGISTER_CLASS(GLTFMesh);
+ GDREGISTER_CLASS(GLTFNode);
+ GDREGISTER_CLASS(GLTFSkeleton);
+ GDREGISTER_CLASS(GLTFSkin);
+ GDREGISTER_CLASS(GLTFSpecGloss);
+ GDREGISTER_CLASS(GLTFState);
+ GDREGISTER_CLASS(GLTFTexture);
+ }
-void register_gltf_types() {
-#ifndef _3D_DISABLED
#ifdef TOOLS_ENABLED
- ClassDB::APIType prev_api = ClassDB::get_current_api();
- ClassDB::set_current_api(ClassDB::API_EDITOR);
- GDREGISTER_CLASS(EditorSceneFormatImporterGLTF);
- GDREGISTER_CLASS(GLTFMesh);
- EditorPlugins::add_by_type<SceneExporterGLTFPlugin>();
- ClassDB::set_current_api(prev_api);
- EditorNode::add_init_callback(_editor_init);
-#endif
- GDREGISTER_CLASS(GLTFSpecGloss);
- GDREGISTER_CLASS(GLTFNode);
- GDREGISTER_CLASS(GLTFAnimation);
- GDREGISTER_CLASS(GLTFBufferView);
- GDREGISTER_CLASS(GLTFAccessor);
- GDREGISTER_CLASS(GLTFTexture);
- GDREGISTER_CLASS(GLTFSkeleton);
- GDREGISTER_CLASS(GLTFSkin);
- GDREGISTER_CLASS(GLTFCamera);
- GDREGISTER_CLASS(GLTFLight);
- GDREGISTER_CLASS(GLTFState);
- GDREGISTER_CLASS(GLTFDocumentExtensionConvertImporterMesh);
- GDREGISTER_CLASS(GLTFDocumentExtension);
- GDREGISTER_CLASS(GLTFDocument);
-#endif
+ if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
+ // Editor-specific API.
+ ClassDB::APIType prev_api = ClassDB::get_current_api();
+ ClassDB::set_current_api(ClassDB::API_EDITOR);
+
+ GDREGISTER_CLASS(EditorSceneFormatImporterGLTF);
+ EditorPlugins::add_by_type<SceneExporterGLTFPlugin>();
+
+ // Project settings defined here so doctool finds them.
+ GLOBAL_DEF_RST("filesystem/import/blender/enabled", true);
+ GLOBAL_DEF_RST("filesystem/import/fbx/enabled", true);
+ GDREGISTER_CLASS(EditorSceneFormatImporterBlend);
+ GDREGISTER_CLASS(EditorSceneFormatImporterFBX);
+
+ ClassDB::set_current_api(prev_api);
+ EditorNode::add_init_callback(_editor_init);
+ }
+
+#endif // TOOLS_ENABLED
}
-void unregister_gltf_types() {
+void uninitialize_gltf_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
+
+#endif // _3D_DISABLED
diff --git a/modules/gltf/register_types.h b/modules/gltf/register_types.h
index 4a9c31241c..90b9a83c88 100644
--- a/modules/gltf/register_types.h
+++ b/modules/gltf/register_types.h
@@ -28,5 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-void register_gltf_types();
-void unregister_gltf_types();
+#include "modules/register_module_types.h"
+
+void initialize_gltf_module(ModuleInitializationLevel p_level);
+void uninitialize_gltf_module(ModuleInitializationLevel p_level);
diff --git a/modules/gridmap/SCsub b/modules/gridmap/SCsub
index 970ce534f0..52777235b8 100644
--- a/modules/gridmap/SCsub
+++ b/modules/gridmap/SCsub
@@ -5,4 +5,7 @@ Import("env_modules")
env_gridmap = env_modules.Clone()
+# Godot's own source files
env_gridmap.add_source_files(env.modules_sources, "*.cpp")
+if env["tools"]:
+ env_gridmap.add_source_files(env.modules_sources, "editor/*.cpp")
diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp
index e8e096d52b..68968325dd 100644
--- a/modules/gridmap/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp
@@ -29,14 +29,16 @@
/*************************************************************************/
#include "grid_map_editor_plugin.h"
+
+#ifdef TOOLS_ENABLED
+
#include "core/input/input.h"
+#include "core/os/keyboard.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/camera_3d.h"
-
-#include "core/os/keyboard.h"
#include "scene/main/window.h"
void GridMapEditor::_node_removed(Node *p_node) {
@@ -1479,3 +1481,5 @@ GridMapEditorPlugin::GridMapEditorPlugin() {
GridMapEditorPlugin::~GridMapEditorPlugin() {
}
+
+#endif // TOOLS_ENABLED
diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/editor/grid_map_editor_plugin.h
index c44c4ca7e0..3b29397502 100644
--- a/modules/gridmap/grid_map_editor_plugin.h
+++ b/modules/gridmap/editor/grid_map_editor_plugin.h
@@ -31,8 +31,10 @@
#ifndef GRID_MAP_EDITOR_PLUGIN_H
#define GRID_MAP_EDITOR_PLUGIN_H
+#ifdef TOOLS_ENABLED
+
+#include "../grid_map.h"
#include "editor/editor_plugin.h"
-#include "grid_map.h"
#include "scene/gui/item_list.h"
#include "scene/gui/slider.h"
#include "scene/gui/spin_box.h"
@@ -60,21 +62,21 @@ class GridMapEditor : public VBoxContainer {
DISPLAY_LIST
};
- UndoRedo *undo_redo;
+ UndoRedo *undo_redo = nullptr;
InputAction input_action = INPUT_NONE;
- Panel *panel;
- MenuButton *options;
- SpinBox *floor;
+ Panel *panel = nullptr;
+ MenuButton *options = nullptr;
+ SpinBox *floor = nullptr;
double accumulated_floor_delta = 0.0;
- Button *mode_thumbnail;
- Button *mode_list;
- LineEdit *search_box;
- HSlider *size_slider;
- HBoxContainer *spatial_editor_hb;
- ConfirmationDialog *settings_dialog;
- VBoxContainer *settings_vbc;
- SpinBox *settings_pick_distance;
- Label *spin_box_label;
+ Button *mode_thumbnail = nullptr;
+ Button *mode_list = nullptr;
+ LineEdit *search_box = nullptr;
+ HSlider *size_slider = nullptr;
+ HBoxContainer *spatial_editor_hb = nullptr;
+ ConfirmationDialog *settings_dialog = nullptr;
+ VBoxContainer *settings_vbc = nullptr;
+ SpinBox *settings_pick_distance = nullptr;
+ Label *spin_box_label = nullptr;
struct SetItem {
Vector3i position;
@@ -87,7 +89,7 @@ class GridMapEditor : public VBoxContainer {
List<SetItem> set_items;
GridMap *node = nullptr;
- MeshLibrary *last_mesh_library;
+ MeshLibrary *last_mesh_library = nullptr;
Transform3D grid_xform;
Transform3D edit_grid_xform;
@@ -171,15 +173,15 @@ class GridMapEditor : public VBoxContainer {
};
- Node3DEditorPlugin *spatial_editor;
+ Node3DEditorPlugin *spatial_editor = nullptr;
struct AreaDisplay {
RID mesh;
RID instance;
};
- ItemList *mesh_library_palette;
- Label *info_message;
+ ItemList *mesh_library_palette = nullptr;
+ Label *info_message = nullptr;
void update_grid(); // Change which and where the grid is displayed
void _draw_grids(const Vector3 &cell_size);
@@ -232,7 +234,7 @@ public:
class GridMapEditorPlugin : public EditorPlugin {
GDCLASS(GridMapEditorPlugin, EditorPlugin);
- GridMapEditor *grid_map_editor;
+ GridMapEditor *grid_map_editor = nullptr;
protected:
void _notification(int p_what);
@@ -249,4 +251,6 @@ public:
~GridMapEditorPlugin();
};
-#endif // CUBE_GRID_MAP_EDITOR_PLUGIN_H
+#endif // TOOLS_ENABLED
+
+#endif // GRID_MAP_EDITOR_PLUGIN_H
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index 02fe4d93de..3c7bd5eb70 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -797,7 +797,7 @@ void GridMap::clear() {
clear_baked_meshes();
}
-void GridMap::resource_changed(const RES &p_res) {
+void GridMap::resource_changed(const Ref<Resource> &p_res) {
_recreate_octant_data();
}
diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h
index b09cabfe25..5e367e149d 100644
--- a/modules/gridmap/grid_map.h
+++ b/modules/gridmap/grid_map.h
@@ -181,7 +181,7 @@ class GridMap : public Node3D {
void _queue_octants_dirty();
void _update_octants_callback();
- void resource_changed(const RES &p_res);
+ void resource_changed(const Ref<Resource> &p_res);
void _clear_internal();
diff --git a/modules/gridmap/register_types.cpp b/modules/gridmap/register_types.cpp
index f05c5de18b..9efd18a265 100644
--- a/modules/gridmap/register_types.cpp
+++ b/modules/gridmap/register_types.cpp
@@ -28,21 +28,32 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "register_types.h"
#ifndef _3D_DISABLED
+
+#include "register_types.h"
+
#include "core/object/class_db.h"
#include "grid_map.h"
-#include "grid_map_editor_plugin.h"
-#endif
-void register_gridmap_types() {
-#ifndef _3D_DISABLED
- GDREGISTER_CLASS(GridMap);
#ifdef TOOLS_ENABLED
- EditorPlugins::add_by_type<GridMapEditorPlugin>();
+#include "editor/grid_map_editor_plugin.h"
#endif
+
+void initialize_gridmap_module(ModuleInitializationLevel p_level) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
+ GDREGISTER_CLASS(GridMap);
+ }
+#ifdef TOOLS_ENABLED
+ if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
+ EditorPlugins::add_by_type<GridMapEditorPlugin>();
+ }
#endif
}
-void unregister_gridmap_types() {
+void uninitialize_gridmap_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
+
+#endif // _3D_DISABLED
diff --git a/modules/gridmap/register_types.h b/modules/gridmap/register_types.h
index fa3511c5d1..28f14cd398 100644
--- a/modules/gridmap/register_types.h
+++ b/modules/gridmap/register_types.h
@@ -31,7 +31,9 @@
#ifndef GRIDMAP_REGISTER_TYPES_H
#define GRIDMAP_REGISTER_TYPES_H
-void register_gridmap_types();
-void unregister_gridmap_types();
+#include "modules/register_module_types.h"
+
+void initialize_gridmap_module(ModuleInitializationLevel p_level);
+void uninitialize_gridmap_module(ModuleInitializationLevel p_level);
#endif // GRIDMAP_REGISTER_TYPES_H
diff --git a/modules/hdr/image_loader_hdr.cpp b/modules/hdr/image_loader_hdr.cpp
index 996bbfadd1..eca689e87a 100644
--- a/modules/hdr/image_loader_hdr.cpp
+++ b/modules/hdr/image_loader_hdr.cpp
@@ -33,7 +33,7 @@
#include "core/os/os.h"
#include "core/string/print_string.h"
-Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) {
+Error ImageLoaderHDR::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) {
String header = f->get_token();
ERR_FAIL_COND_V_MSG(header != "#?RADIANCE" && header != "#?RGBE", ERR_FILE_UNRECOGNIZED, "Unsupported header information in HDR: " + header + ".");
@@ -132,7 +132,7 @@ Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force
ptr[2] * exp / 255.0);
if (p_force_linear) {
- c = c.to_linear();
+ c = c.srgb_to_linear();
}
*(uint32_t *)ptr = c.to_rgbe9995();
diff --git a/modules/hdr/image_loader_hdr.h b/modules/hdr/image_loader_hdr.h
index 0213fdbcb2..f2d53cc206 100644
--- a/modules/hdr/image_loader_hdr.h
+++ b/modules/hdr/image_loader_hdr.h
@@ -35,7 +35,7 @@
class ImageLoaderHDR : public ImageFormatLoader {
public:
- virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderHDR();
};
diff --git a/modules/hdr/register_types.cpp b/modules/hdr/register_types.cpp
index 6bfeecc927..b988bf4587 100644
--- a/modules/hdr/register_types.cpp
+++ b/modules/hdr/register_types.cpp
@@ -34,11 +34,19 @@
static ImageLoaderHDR *image_loader_hdr = nullptr;
-void register_hdr_types() {
+void initialize_hdr_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
image_loader_hdr = memnew(ImageLoaderHDR);
ImageLoader::add_image_format_loader(image_loader_hdr);
}
-void unregister_hdr_types() {
+void uninitialize_hdr_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
memdelete(image_loader_hdr);
}
diff --git a/modules/hdr/register_types.h b/modules/hdr/register_types.h
index 4224aa2ce2..0254e43b6c 100644
--- a/modules/hdr/register_types.h
+++ b/modules/hdr/register_types.h
@@ -31,7 +31,9 @@
#ifndef HDR_REGISTER_TYPES_H
#define HDR_REGISTER_TYPES_H
-void register_hdr_types();
-void unregister_hdr_types();
+#include "modules/register_module_types.h"
+
+void initialize_hdr_module(ModuleInitializationLevel p_level);
+void uninitialize_hdr_module(ModuleInitializationLevel p_level);
#endif // HDR_REGISTER_TYPES_H
diff --git a/modules/jpg/image_loader_jpegd.cpp b/modules/jpg/image_loader_jpegd.cpp
index e8c66ab9da..51358876a4 100644
--- a/modules/jpg/image_loader_jpegd.cpp
+++ b/modules/jpg/image_loader_jpegd.cpp
@@ -103,7 +103,7 @@ Error jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p
return OK;
}
-Error ImageLoaderJPG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) {
+Error ImageLoaderJPG::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) {
Vector<uint8_t> src_image;
uint64_t src_image_len = f->get_length();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
@@ -113,8 +113,6 @@ Error ImageLoaderJPG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force
f->get_buffer(&w[0], src_image_len);
- f->close();
-
Error err = jpeg_load_image_from_buffer(p_image.ptr(), w, src_image_len);
return err;
diff --git a/modules/jpg/image_loader_jpegd.h b/modules/jpg/image_loader_jpegd.h
index 8e64f6fba7..de9700faec 100644
--- a/modules/jpg/image_loader_jpegd.h
+++ b/modules/jpg/image_loader_jpegd.h
@@ -35,7 +35,7 @@
class ImageLoaderJPG : public ImageFormatLoader {
public:
- virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderJPG();
};
diff --git a/modules/jpg/register_types.cpp b/modules/jpg/register_types.cpp
index 63203274f4..b8b48a550f 100644
--- a/modules/jpg/register_types.cpp
+++ b/modules/jpg/register_types.cpp
@@ -34,11 +34,19 @@
static ImageLoaderJPG *image_loader_jpg = nullptr;
-void register_jpg_types() {
+void initialize_jpg_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
image_loader_jpg = memnew(ImageLoaderJPG);
ImageLoader::add_image_format_loader(image_loader_jpg);
}
-void unregister_jpg_types() {
+void uninitialize_jpg_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
memdelete(image_loader_jpg);
}
diff --git a/modules/jpg/register_types.h b/modules/jpg/register_types.h
index 97223cefda..f0a205f6a8 100644
--- a/modules/jpg/register_types.h
+++ b/modules/jpg/register_types.h
@@ -31,7 +31,9 @@
#ifndef JPG_REGISTER_TYPES_H
#define JPG_REGISTER_TYPES_H
-void register_jpg_types();
-void unregister_jpg_types();
+#include "modules/register_module_types.h"
+
+void initialize_jpg_module(ModuleInitializationLevel p_level);
+void uninitialize_jpg_module(ModuleInitializationLevel p_level);
#endif // JPG_REGISTER_TYPES_H
diff --git a/modules/jsonrpc/register_types.cpp b/modules/jsonrpc/register_types.cpp
index d89b7e9353..6d35d6aeb8 100644
--- a/modules/jsonrpc/register_types.cpp
+++ b/modules/jsonrpc/register_types.cpp
@@ -32,9 +32,16 @@
#include "core/object/class_db.h"
#include "jsonrpc.h"
-void register_jsonrpc_types() {
+void initialize_jsonrpc_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
GDREGISTER_CLASS(JSONRPC);
}
-void unregister_jsonrpc_types() {
+void uninitialize_jsonrpc_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
diff --git a/modules/jsonrpc/register_types.h b/modules/jsonrpc/register_types.h
index 57744e6c07..83d315a9eb 100644
--- a/modules/jsonrpc/register_types.h
+++ b/modules/jsonrpc/register_types.h
@@ -31,7 +31,9 @@
#ifndef JSONRPC_REGISTER_TYPES_H
#define JSONRPC_REGISTER_TYPES_H
-void register_jsonrpc_types();
-void unregister_jsonrpc_types();
+#include "modules/register_module_types.h"
+
+void initialize_jsonrpc_module(ModuleInitializationLevel p_level);
+void uninitialize_jsonrpc_module(ModuleInitializationLevel p_level);
#endif // JSONRPC_REGISTER_TYPES_H
diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp
index 68b3a41b9a..214c60091c 100644
--- a/modules/lightmapper_rd/lightmapper_rd.cpp
+++ b/modules/lightmapper_rd/lightmapper_rd.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "lightmapper_rd.h"
+
#include "core/config/project_settings.h"
#include "core/math/geometry_2d.h"
#include "lm_blendseams.glsl.gen.h"
@@ -174,7 +175,7 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
}
if (p_step_function) {
- p_step_function(0.1, TTR("Determining optimal atlas size"), p_bake_userdata, true);
+ p_step_function(0.1, RTR("Determining optimal atlas size"), p_bake_userdata, true);
}
atlas_size = Size2i(max, max);
@@ -243,7 +244,7 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
emission_images.resize(atlas_slices);
if (p_step_function) {
- p_step_function(0.2, TTR("Blitting albedo and emission"), p_bake_userdata, true);
+ p_step_function(0.2, RTR("Blitting albedo and emission"), p_bake_userdata, true);
}
for (int i = 0; i < atlas_slices; i++) {
@@ -295,7 +296,7 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i
for (int m_i = 0; m_i < mesh_instances.size(); m_i++) {
if (p_step_function) {
float p = float(m_i + 1) / mesh_instances.size() * 0.1;
- p_step_function(0.3 + p, vformat(TTR("Plotting mesh into acceleration structure %d/%d"), m_i + 1, mesh_instances.size()), p_bake_userdata, false);
+ p_step_function(0.3 + p, vformat(RTR("Plotting mesh into acceleration structure %d/%d"), m_i + 1, mesh_instances.size()), p_bake_userdata, false);
}
HashMap<Edge, EdgeUV2, EdgeHash> edges;
@@ -409,7 +410,7 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i
seams.sort();
if (p_step_function) {
- p_step_function(0.4, TTR("Optimizing acceleration structure"), p_bake_userdata, true);
+ p_step_function(0.4, RTR("Optimizing acceleration structure"), p_bake_userdata, true);
}
//fill list of triangles in grid
@@ -668,7 +669,7 @@ LightmapperRD::BakeError LightmapperRD::_dilate(RenderingDevice *rd, Ref<RDShade
LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, int p_max_texture_size, bool p_bake_sh, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function, void *p_bake_userdata) {
if (p_step_function) {
- p_step_function(0.0, TTR("Begin Bake"), p_bake_userdata, true);
+ p_step_function(0.0, RTR("Begin Bake"), p_bake_userdata, true);
}
bake_textures.clear();
int grid_size = 128;
@@ -819,7 +820,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
_create_acceleration_structures(rd, atlas_size, atlas_slices, bounds, grid_size, probe_positions, p_generate_probes, slice_triangle_count, slice_seam_count, vertex_buffer, triangle_buffer, lights_buffer, triangle_cell_indices_buffer, probe_positions_buffer, grid_texture, seams_buffer, p_step_function, p_bake_userdata);
if (p_step_function) {
- p_step_function(0.47, TTR("Preparing shaders"), p_bake_userdata, true);
+ p_step_function(0.47, RTR("Preparing shaders"), p_bake_userdata, true);
}
//shaders
@@ -1027,17 +1028,17 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
push_constant.atlas_slice = 0;
push_constant.region_ofs[0] = 0;
push_constant.region_ofs[1] = 0;
- push_constant.environment_xform[0] = p_environment_transform.elements[0][0];
- push_constant.environment_xform[1] = p_environment_transform.elements[1][0];
- push_constant.environment_xform[2] = p_environment_transform.elements[2][0];
+ push_constant.environment_xform[0] = p_environment_transform.rows[0][0];
+ push_constant.environment_xform[1] = p_environment_transform.rows[1][0];
+ push_constant.environment_xform[2] = p_environment_transform.rows[2][0];
push_constant.environment_xform[3] = 0;
- push_constant.environment_xform[4] = p_environment_transform.elements[0][1];
- push_constant.environment_xform[5] = p_environment_transform.elements[1][1];
- push_constant.environment_xform[6] = p_environment_transform.elements[2][1];
+ push_constant.environment_xform[4] = p_environment_transform.rows[0][1];
+ push_constant.environment_xform[5] = p_environment_transform.rows[1][1];
+ push_constant.environment_xform[6] = p_environment_transform.rows[2][1];
push_constant.environment_xform[7] = 0;
- push_constant.environment_xform[8] = p_environment_transform.elements[0][2];
- push_constant.environment_xform[9] = p_environment_transform.elements[1][2];
- push_constant.environment_xform[10] = p_environment_transform.elements[2][2];
+ push_constant.environment_xform[8] = p_environment_transform.rows[0][2];
+ push_constant.environment_xform[9] = p_environment_transform.rows[1][2];
+ push_constant.environment_xform[10] = p_environment_transform.rows[2][2];
push_constant.environment_xform[11] = 0;
}
@@ -1046,7 +1047,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
rd->sync();
if (p_step_function) {
- p_step_function(0.49, TTR("Un-occluding geometry"), p_bake_userdata, true);
+ p_step_function(0.49, RTR("Un-occluding geometry"), p_bake_userdata, true);
}
/* UNOCCLUDE */
@@ -1086,7 +1087,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
}
if (p_step_function) {
- p_step_function(0.5, TTR("Plot direct lighting"), p_bake_userdata, true);
+ p_step_function(0.5, RTR("Plot direct lighting"), p_bake_userdata, true);
}
/* PRIMARY (direct) LIGHT PASS */
@@ -1166,7 +1167,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
/* SECONDARY (indirect) LIGHT PASS(ES) */
if (p_step_function) {
- p_step_function(0.6, TTR("Integrate indirect lighting"), p_bake_userdata, true);
+ p_step_function(0.6, RTR("Integrate indirect lighting"), p_bake_userdata, true);
}
if (p_bounces > 0) {
@@ -1298,7 +1299,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
int total = (atlas_slices * x_regions * y_regions * ray_iterations);
int percent = count * 100 / total;
float p = float(count) / total * 0.1;
- p_step_function(0.6 + p, vformat(TTR("Bounce %d/%d: Integrate indirect lighting %d%%"), b + 1, p_bounces, percent), p_bake_userdata, false);
+ p_step_function(0.6 + p, vformat(RTR("Bounce %d/%d: Integrate indirect lighting %d%%"), b + 1, p_bounces, percent), p_bake_userdata, false);
}
}
}
@@ -1323,7 +1324,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
light_probe_buffer = rd->storage_buffer_create(sizeof(float) * 4 * 9 * probe_positions.size());
if (p_step_function) {
- p_step_function(0.7, TTR("Baking lightprobes"), p_bake_userdata, true);
+ p_step_function(0.7, RTR("Baking lightprobes"), p_bake_userdata, true);
}
Vector<RD::Uniform> uniforms;
@@ -1398,7 +1399,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
if (p_step_function) {
int percent = i * 100 / ray_iterations;
float p = float(i) / ray_iterations * 0.1;
- p_step_function(0.7 + p, vformat(TTR("Integrating light probes %d%%"), percent), p_bake_userdata, false);
+ p_step_function(0.7 + p, vformat(RTR("Integrating light probes %d%%"), percent), p_bake_userdata, false);
}
}
@@ -1434,7 +1435,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
if (p_use_denoiser) {
if (p_step_function) {
- p_step_function(0.8, TTR("Denoising"), p_bake_userdata, true);
+ p_step_function(0.8, RTR("Denoising"), p_bake_userdata, true);
}
Ref<LightmapDenoiser> denoiser = LightmapDenoiser::create();
@@ -1639,7 +1640,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
}
#endif
if (p_step_function) {
- p_step_function(0.9, TTR("Retrieving textures"), p_bake_userdata, true);
+ p_step_function(0.9, RTR("Retrieving textures"), p_bake_userdata, true);
}
for (int i = 0; i < atlas_slices * (p_bake_sh ? 4 : 1); i++) {
diff --git a/modules/lightmapper_rd/register_types.cpp b/modules/lightmapper_rd/register_types.cpp
index 0a96a86076..0e0330c1a1 100644
--- a/modules/lightmapper_rd/register_types.cpp
+++ b/modules/lightmapper_rd/register_types.cpp
@@ -40,7 +40,11 @@ static Lightmapper *create_lightmapper_rd() {
}
#endif
-void register_lightmapper_rd_types() {
+void initialize_lightmapper_rd_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
GLOBAL_DEF("rendering/lightmapping/bake_quality/low_quality_ray_count", 16);
GLOBAL_DEF("rendering/lightmapping/bake_quality/medium_quality_ray_count", 64);
GLOBAL_DEF("rendering/lightmapping/bake_quality/high_quality_ray_count", 256);
@@ -59,5 +63,8 @@ void register_lightmapper_rd_types() {
#endif
}
-void unregister_lightmapper_rd_types() {
+void uninitialize_lightmapper_rd_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
diff --git a/modules/lightmapper_rd/register_types.h b/modules/lightmapper_rd/register_types.h
index 35a701ce01..42e0ebbf77 100644
--- a/modules/lightmapper_rd/register_types.h
+++ b/modules/lightmapper_rd/register_types.h
@@ -31,7 +31,9 @@
#ifndef LIGHTMAPPER_RD_REGISTER_TYPES_H
#define LIGHTMAPPER_RD_REGISTER_TYPES_H
-void register_lightmapper_rd_types();
-void unregister_lightmapper_rd_types();
+#include "modules/register_module_types.h"
+
+void initialize_lightmapper_rd_module(ModuleInitializationLevel p_level);
+void uninitialize_lightmapper_rd_module(ModuleInitializationLevel p_level);
#endif // XATLAS_UNWRAP_REGISTER_TYPES_H
diff --git a/modules/mbedtls/crypto_mbedtls.cpp b/modules/mbedtls/crypto_mbedtls.cpp
index ea6b6d8233..e62581ab40 100644
--- a/modules/mbedtls/crypto_mbedtls.cpp
+++ b/modules/mbedtls/crypto_mbedtls.cpp
@@ -55,14 +55,13 @@ Error CryptoKeyMbedTLS::load(String p_path, bool p_public_only) {
ERR_FAIL_COND_V_MSG(locks, ERR_ALREADY_IN_USE, "Key is in use");
PackedByteArray out;
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
- ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot open CryptoKeyMbedTLS file '" + p_path + "'.");
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
+ ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, "Cannot open CryptoKeyMbedTLS file '" + p_path + "'.");
uint64_t flen = f->get_length();
out.resize(flen + 1);
f->get_buffer(out.ptrw(), flen);
out.write[flen] = 0; // string terminator
- memdelete(f);
int ret = 0;
if (p_public_only) {
@@ -79,8 +78,8 @@ Error CryptoKeyMbedTLS::load(String p_path, bool p_public_only) {
}
Error CryptoKeyMbedTLS::save(String p_path, bool p_public_only) {
- FileAccess *f = FileAccess::open(p_path, FileAccess::WRITE);
- ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot save CryptoKeyMbedTLS file '" + p_path + "'.");
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE);
+ ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, "Cannot save CryptoKeyMbedTLS file '" + p_path + "'.");
unsigned char w[16000];
memset(w, 0, sizeof(w));
@@ -92,14 +91,12 @@ Error CryptoKeyMbedTLS::save(String p_path, bool p_public_only) {
ret = mbedtls_pk_write_key_pem(&pkey, w, sizeof(w));
}
if (ret != 0) {
- memdelete(f);
mbedtls_platform_zeroize(w, sizeof(w)); // Zeroize anything we might have written.
ERR_FAIL_V_MSG(FAILED, "Error writing key '" + itos(ret) + "'.");
}
size_t len = strlen((char *)w);
f->store_buffer(w, len);
- memdelete(f);
mbedtls_platform_zeroize(w, sizeof(w)); // Zeroize temporary buffer.
return OK;
}
@@ -143,14 +140,13 @@ Error X509CertificateMbedTLS::load(String p_path) {
ERR_FAIL_COND_V_MSG(locks, ERR_ALREADY_IN_USE, "Certificate is in use");
PackedByteArray out;
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
- ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot open X509CertificateMbedTLS file '" + p_path + "'.");
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
+ ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, "Cannot open X509CertificateMbedTLS file '" + p_path + "'.");
uint64_t flen = f->get_length();
out.resize(flen + 1);
f->get_buffer(out.ptrw(), flen);
out.write[flen] = 0; // string terminator
- memdelete(f);
int ret = mbedtls_x509_crt_parse(&cert, out.ptr(), out.size());
ERR_FAIL_COND_V_MSG(ret, FAILED, "Error parsing some certificates: " + itos(ret));
@@ -167,8 +163,8 @@ Error X509CertificateMbedTLS::load_from_memory(const uint8_t *p_buffer, int p_le
}
Error X509CertificateMbedTLS::save(String p_path) {
- FileAccess *f = FileAccess::open(p_path, FileAccess::WRITE);
- ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot save X509CertificateMbedTLS file '" + p_path + "'.");
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE);
+ ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, "Cannot save X509CertificateMbedTLS file '" + p_path + "'.");
mbedtls_x509_crt *crt = &cert;
while (crt) {
@@ -176,14 +172,12 @@ Error X509CertificateMbedTLS::save(String p_path) {
size_t wrote = 0;
int ret = mbedtls_pem_write_buffer(PEM_BEGIN_CRT, PEM_END_CRT, cert.raw.p, cert.raw.len, w, sizeof(w), &wrote);
if (ret != 0 || wrote == 0) {
- memdelete(f);
ERR_FAIL_V_MSG(FAILED, "Error writing certificate '" + itos(ret) + "'.");
}
f->store_buffer(w, wrote - 1); // don't write the string terminator
crt = crt->next;
}
- memdelete(f);
return OK;
}
diff --git a/modules/mbedtls/packet_peer_mbed_dtls.cpp b/modules/mbedtls/packet_peer_mbed_dtls.cpp
index 2a5eaa0109..1296a4587c 100644
--- a/modules/mbedtls/packet_peer_mbed_dtls.cpp
+++ b/modules/mbedtls/packet_peer_mbed_dtls.cpp
@@ -35,11 +35,11 @@
#include "core/io/stream_peer_ssl.h"
int PacketPeerMbedDTLS::bio_send(void *ctx, const unsigned char *buf, size_t len) {
- if (buf == nullptr || len <= 0) {
+ if (buf == nullptr || len == 0) {
return 0;
}
- PacketPeerMbedDTLS *sp = (PacketPeerMbedDTLS *)ctx;
+ PacketPeerMbedDTLS *sp = static_cast<PacketPeerMbedDTLS *>(ctx);
ERR_FAIL_COND_V(sp == nullptr, 0);
@@ -53,11 +53,11 @@ int PacketPeerMbedDTLS::bio_send(void *ctx, const unsigned char *buf, size_t len
}
int PacketPeerMbedDTLS::bio_recv(void *ctx, unsigned char *buf, size_t len) {
- if (buf == nullptr || len <= 0) {
+ if (buf == nullptr || len == 0) {
return 0;
}
- PacketPeerMbedDTLS *sp = (PacketPeerMbedDTLS *)ctx;
+ PacketPeerMbedDTLS *sp = static_cast<PacketPeerMbedDTLS *>(ctx);
ERR_FAIL_COND_V(sp == nullptr, 0);
@@ -115,7 +115,7 @@ Error PacketPeerMbedDTLS::_do_handshake() {
}
Error PacketPeerMbedDTLS::connect_to_peer(Ref<PacketPeerUDP> p_base, bool p_validate_certs, const String &p_for_hostname, Ref<X509Certificate> p_ca_certs) {
- ERR_FAIL_COND_V(!p_base.is_valid() || !p_base->is_connected_to_host(), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(!p_base.is_valid() || !p_base->is_socket_connected(), ERR_INVALID_PARAMETER);
base = p_base;
int ret = 0;
diff --git a/modules/mbedtls/register_types.cpp b/modules/mbedtls/register_types.cpp
index 1af978e70a..2d4a18b3fc 100644
--- a/modules/mbedtls/register_types.cpp
+++ b/modules/mbedtls/register_types.cpp
@@ -39,14 +39,22 @@
#include "tests/test_crypto_mbedtls.h"
#endif
-void register_mbedtls_types() {
+void initialize_mbedtls_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
CryptoMbedTLS::initialize_crypto();
StreamPeerMbedTLS::initialize_ssl();
PacketPeerMbedDTLS::initialize_dtls();
DTLSServerMbedTLS::initialize();
}
-void unregister_mbedtls_types() {
+void uninitialize_mbedtls_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
DTLSServerMbedTLS::finalize();
PacketPeerMbedDTLS::finalize_dtls();
StreamPeerMbedTLS::finalize_ssl();
diff --git a/modules/mbedtls/register_types.h b/modules/mbedtls/register_types.h
index 4bc2cca118..ebe76f44f1 100644
--- a/modules/mbedtls/register_types.h
+++ b/modules/mbedtls/register_types.h
@@ -31,7 +31,9 @@
#ifndef MBEDTLS_REGISTER_TYPES_H
#define MBEDTLS_REGISTER_TYPES_H
-void register_mbedtls_types();
-void unregister_mbedtls_types();
+#include "modules/register_module_types.h"
+
+void initialize_mbedtls_module(ModuleInitializationLevel p_level);
+void uninitialize_mbedtls_module(ModuleInitializationLevel p_level);
#endif // MBEDTLS_REGISTER_TYPES_H
diff --git a/modules/mbedtls/stream_peer_mbedtls.cpp b/modules/mbedtls/stream_peer_mbedtls.cpp
index 05a57607cd..1818048877 100644
--- a/modules/mbedtls/stream_peer_mbedtls.cpp
+++ b/modules/mbedtls/stream_peer_mbedtls.cpp
@@ -34,11 +34,11 @@
#include "core/io/stream_peer_tcp.h"
int StreamPeerMbedTLS::bio_send(void *ctx, const unsigned char *buf, size_t len) {
- if (buf == nullptr || len <= 0) {
+ if (buf == nullptr || len == 0) {
return 0;
}
- StreamPeerMbedTLS *sp = (StreamPeerMbedTLS *)ctx;
+ StreamPeerMbedTLS *sp = static_cast<StreamPeerMbedTLS *>(ctx);
ERR_FAIL_COND_V(sp == nullptr, 0);
@@ -54,11 +54,11 @@ int StreamPeerMbedTLS::bio_send(void *ctx, const unsigned char *buf, size_t len)
}
int StreamPeerMbedTLS::bio_recv(void *ctx, unsigned char *buf, size_t len) {
- if (buf == nullptr || len <= 0) {
+ if (buf == nullptr || len == 0) {
return 0;
}
- StreamPeerMbedTLS *sp = (StreamPeerMbedTLS *)ctx;
+ StreamPeerMbedTLS *sp = static_cast<StreamPeerMbedTLS *>(ctx);
ERR_FAIL_COND_V(sp == nullptr, 0);
diff --git a/modules/meshoptimizer/register_types.cpp b/modules/meshoptimizer/register_types.cpp
index 597c12ed23..3e212360c0 100644
--- a/modules/meshoptimizer/register_types.cpp
+++ b/modules/meshoptimizer/register_types.cpp
@@ -32,7 +32,11 @@
#include "scene/resources/surface_tool.h"
#include "thirdparty/meshoptimizer/meshoptimizer.h"
-void register_meshoptimizer_types() {
+void initialize_meshoptimizer_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
SurfaceTool::optimize_vertex_cache_func = meshopt_optimizeVertexCache;
SurfaceTool::simplify_func = meshopt_simplify;
SurfaceTool::simplify_with_attrib_func = meshopt_simplifyWithAttributes;
@@ -43,7 +47,11 @@ void register_meshoptimizer_types() {
SurfaceTool::remap_index_func = meshopt_remapIndexBuffer;
}
-void unregister_meshoptimizer_types() {
+void uninitialize_meshoptimizer_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
SurfaceTool::optimize_vertex_cache_func = nullptr;
SurfaceTool::simplify_func = nullptr;
SurfaceTool::simplify_scale_func = nullptr;
diff --git a/modules/meshoptimizer/register_types.h b/modules/meshoptimizer/register_types.h
index fdd8bed657..99c71efceb 100644
--- a/modules/meshoptimizer/register_types.h
+++ b/modules/meshoptimizer/register_types.h
@@ -31,7 +31,9 @@
#ifndef MESHOPTIMIZER_REGISTER_TYPES_H
#define MESHOPTIMIZER_REGISTER_TYPES_H
-void register_meshoptimizer_types();
-void unregister_meshoptimizer_types();
+#include "modules/register_module_types.h"
+
+void initialize_meshoptimizer_module(ModuleInitializationLevel p_level);
+void uninitialize_meshoptimizer_module(ModuleInitializationLevel p_level);
#endif // PVR_REGISTER_TYPES_H
diff --git a/modules/minimp3/register_types.cpp b/modules/minimp3/register_types.cpp
index 4d32ebf8ea..9d1b56abdf 100644
--- a/modules/minimp3/register_types.cpp
+++ b/modules/minimp3/register_types.cpp
@@ -37,7 +37,11 @@
#include "resource_importer_mp3.h"
#endif
-void register_minimp3_types() {
+void initialize_minimp3_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
Ref<ResourceImporterMP3> mp3_import;
@@ -48,5 +52,8 @@ void register_minimp3_types() {
GDREGISTER_CLASS(AudioStreamMP3);
}
-void unregister_minimp3_types() {
+void uninitialize_minimp3_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
diff --git a/modules/minimp3/register_types.h b/modules/minimp3/register_types.h
index fa7f67eefc..9e5eb85abe 100644
--- a/modules/minimp3/register_types.h
+++ b/modules/minimp3/register_types.h
@@ -31,7 +31,9 @@
#ifndef MINIMP3_REGISTER_TYPES_H
#define MINIMP3_REGISTER_TYPES_H
-void register_minimp3_types();
-void unregister_minimp3_types();
+#include "modules/register_module_types.h"
+
+void initialize_minimp3_module(ModuleInitializationLevel p_level);
+void uninitialize_minimp3_module(ModuleInitializationLevel p_level);
#endif // MINIMP3_REGISTER_TYPES_H
diff --git a/modules/minimp3/resource_importer_mp3.cpp b/modules/minimp3/resource_importer_mp3.cpp
index 0e0da806bf..6cd710e792 100644
--- a/modules/minimp3/resource_importer_mp3.cpp
+++ b/modules/minimp3/resource_importer_mp3.cpp
@@ -75,9 +75,8 @@ Error ResourceImporterMP3::import(const String &p_source_file, const String &p_s
bool loop = p_options["loop"];
float loop_offset = p_options["loop_offset"];
- FileAccess *f = FileAccess::open(p_source_file, FileAccess::READ);
-
- ERR_FAIL_COND_V(!f, ERR_CANT_OPEN);
+ Ref<FileAccess> f = FileAccess::open(p_source_file, FileAccess::READ);
+ ERR_FAIL_COND_V(f.is_null(), ERR_CANT_OPEN);
uint64_t len = f->get_length();
@@ -87,8 +86,6 @@ Error ResourceImporterMP3::import(const String &p_source_file, const String &p_s
f->get_buffer(w, len);
- memdelete(f);
-
Ref<AudioStreamMP3> mp3_stream;
mp3_stream.instantiate();
diff --git a/modules/mobile_vr/mobile_vr_interface.cpp b/modules/mobile_vr/mobile_vr_interface.cpp
index 8cd23ffb24..5876b6cbf3 100644
--- a/modules/mobile_vr/mobile_vr_interface.cpp
+++ b/modules/mobile_vr/mobile_vr_interface.cpp
@@ -112,9 +112,9 @@ Basis MobileVRInterface::combine_acc_mag(const Vector3 &p_grav, const Vector3 &p
// We use our gravity and magnetometer vectors to construct our matrix
Basis acc_mag_m3;
- acc_mag_m3.elements[0] = -magneto_east;
- acc_mag_m3.elements[1] = up;
- acc_mag_m3.elements[2] = magneto;
+ acc_mag_m3.rows[0] = -magneto_east;
+ acc_mag_m3.rows[1] = up;
+ acc_mag_m3.rows[2] = magneto;
return acc_mag_m3;
};
@@ -175,9 +175,9 @@ void MobileVRInterface::set_position_from_sensors() {
if (has_gyro) {
// start with applying our gyro (do NOT smooth our gyro!)
Basis rotate;
- rotate.rotate(orientation.get_axis(0), gyro.x * delta_time);
- rotate.rotate(orientation.get_axis(1), gyro.y * delta_time);
- rotate.rotate(orientation.get_axis(2), gyro.z * delta_time);
+ rotate.rotate(orientation.get_column(0), gyro.x * delta_time);
+ rotate.rotate(orientation.get_column(1), gyro.y * delta_time);
+ rotate.rotate(orientation.get_column(2), gyro.z * delta_time);
orientation = rotate * orientation;
tracking_state = XRInterface::XR_NORMAL_TRACKING;
diff --git a/modules/mobile_vr/register_types.cpp b/modules/mobile_vr/register_types.cpp
index 682d8bf59a..4df8af9009 100644
--- a/modules/mobile_vr/register_types.cpp
+++ b/modules/mobile_vr/register_types.cpp
@@ -34,7 +34,11 @@
Ref<MobileVRInterface> mobile_vr;
-void register_mobile_vr_types() {
+void initialize_mobile_vr_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
GDREGISTER_CLASS(MobileVRInterface);
if (XRServer::get_singleton()) {
@@ -43,7 +47,11 @@ void register_mobile_vr_types() {
}
}
-void unregister_mobile_vr_types() {
+void uninitialize_mobile_vr_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
if (mobile_vr.is_valid()) {
// uninitialise our interface if it is initialised
if (mobile_vr->is_initialized()) {
diff --git a/modules/mobile_vr/register_types.h b/modules/mobile_vr/register_types.h
index 8db96ac2fa..26812af512 100644
--- a/modules/mobile_vr/register_types.h
+++ b/modules/mobile_vr/register_types.h
@@ -31,7 +31,9 @@
#ifndef MOBILE_VR_REGISTER_TYPES_H
#define MOBILE_VR_REGISTER_TYPES_H
-void register_mobile_vr_types();
-void unregister_mobile_vr_types();
+#include "modules/register_module_types.h"
+
+void initialize_mobile_vr_module(ModuleInitializationLevel p_level);
+void uninitialize_mobile_vr_module(ModuleInitializationLevel p_level);
#endif // MOBILE_VR_REGISTER_TYPES_H
diff --git a/modules/mono/SCsub b/modules/mono/SCsub
index db35e804aa..3bafa351a9 100644
--- a/modules/mono/SCsub
+++ b/modules/mono/SCsub
@@ -63,5 +63,4 @@ elif env["platform"] == "android":
if env["tools"]:
env_mono.add_source_files(env.modules_sources, "editor/*.cpp")
-
-SConscript("editor_templates/SCsub")
+ SConscript("editor/script_templates/SCsub")
diff --git a/modules/mono/class_db_api_json.cpp b/modules/mono/class_db_api_json.cpp
index 5884a24454..9253f105bb 100644
--- a/modules/mono/class_db_api_json.cpp
+++ b/modules/mono/class_db_api_json.cpp
@@ -238,11 +238,10 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
}
}
- FileAccessRef f = FileAccess::open(p_output_file, FileAccess::WRITE);
- ERR_FAIL_COND_MSG(!f, "Cannot open file '" + p_output_file + "'.");
+ Ref<FileAccess> f = FileAccess::open(p_output_file, FileAccess::WRITE);
+ ERR_FAIL_COND_MSG(f.is_null(), "Cannot open file '" + p_output_file + "'.");
JSON json;
f->store_string(json.stringify(classes_dict, "\t"));
- f->close();
print_line(String() + "ClassDB API JSON written to: " + ProjectSettings::get_singleton()->globalize_path(p_output_file));
}
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 7ed0422236..5875a0fbd4 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -45,17 +45,17 @@
#ifdef TOOLS_ENABLED
#include "core/os/keyboard.h"
#include "editor/bindings_generator.h"
+#include "editor/editor_internal_calls.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
#include "editor/node_dock.h"
+#include "editor/script_templates/templates.gen.h"
#endif
#ifdef DEBUG_METHODS_ENABLED
#include "class_db_api_json.h"
#endif
-#include "editor/editor_internal_calls.h"
-#include "editor_templates/templates.gen.h"
#include "godotsharp_dirs.h"
#include "mono_gd/gd_mono_cache.h"
#include "mono_gd/gd_mono_class.h"
@@ -373,11 +373,13 @@ Ref<Script> CSharpLanguage::make_template(const String &p_template, const String
Vector<ScriptLanguage::ScriptTemplate> CSharpLanguage::get_built_in_templates(StringName p_object) {
Vector<ScriptLanguage::ScriptTemplate> templates;
+#ifdef TOOLS_ENABLED
for (int i = 0; i < TEMPLATES_ARRAY_SIZE; i++) {
if (TEMPLATES[i].inherit == p_object) {
templates.append(TEMPLATES[i]);
}
}
+#endif
return templates;
}
@@ -386,7 +388,7 @@ String CSharpLanguage::validate_path(const String &p_path) const {
List<String> keywords;
get_reserved_words(&keywords);
if (keywords.find(class_name)) {
- return TTR("Class name can't be a reserved keyword");
+ return RTR("Class name can't be a reserved keyword");
}
return "";
}
@@ -922,7 +924,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
for (Ref<CSharpScript> &script : scripts) {
while (script->instances.front()) {
Object *obj = script->instances.front()->get();
- obj->set_script(REF()); // Remove script and existing script instances (placeholder are not removed before domain reload)
+ obj->set_script(Ref<RefCounted>()); // Remove script and existing script instances (placeholder are not removed before domain reload)
}
script->_clear();
@@ -3219,10 +3221,10 @@ Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Callable::Cal
Object *owner = ClassDB::instantiate(NATIVE_GDMONOCLASS_NAME(native));
- REF ref;
+ Ref<RefCounted> ref;
RefCounted *r = Object::cast_to<RefCounted>(owner);
if (r) {
- ref = REF(r);
+ ref = Ref<RefCounted>(r);
}
CSharpInstance *instance = _create_instance(p_args, p_argcount, owner, r != nullptr, r_error);
@@ -3584,7 +3586,7 @@ void CSharpScript::get_members(Set<StringName> *p_members) {
/*************** RESOURCE ***************/
-RES ResourceFormatLoaderCSharpScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+Ref<Resource> ResourceFormatLoaderCSharpScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_FILE_CANT_OPEN;
}
@@ -3597,7 +3599,7 @@ RES ResourceFormatLoaderCSharpScript::load(const String &p_path, const String &p
#if defined(DEBUG_ENABLED) || defined(TOOLS_ENABLED)
Error err = script->load_source_code(p_path);
- ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot load C# script file '" + p_path + "'.");
+ ERR_FAIL_COND_V_MSG(err != OK, Ref<Resource>(), "Cannot load C# script file '" + p_path + "'.");
#endif
script->set_path(p_original_path);
@@ -3623,7 +3625,7 @@ String ResourceFormatLoaderCSharpScript::get_resource_type(const String &p_path)
return p_path.get_extension().to_lower() == "cs" ? CSharpLanguage::get_singleton()->get_type() : "";
}
-Error ResourceFormatSaverCSharpScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
+Error ResourceFormatSaverCSharpScript::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) {
Ref<CSharpScript> sqscr = p_resource;
ERR_FAIL_COND_V(sqscr.is_null(), ERR_INVALID_PARAMETER);
@@ -3639,20 +3641,18 @@ Error ResourceFormatSaverCSharpScript::save(const String &p_path, const RES &p_r
}
#endif
- Error err;
- FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err);
- ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save C# script file '" + p_path + "'.");
+ {
+ Error err;
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save C# script file '" + p_path + "'.");
- file->store_string(source);
+ file->store_string(source);
- if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
- memdelete(file);
- return ERR_CANT_CREATE;
+ if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
+ return ERR_CANT_CREATE;
+ }
}
- file->close();
- memdelete(file);
-
#ifdef TOOLS_ENABLED
if (ScriptServer::is_reload_scripts_on_save_enabled()) {
CSharpLanguage::get_singleton()->reload_tool_script(p_resource, false);
@@ -3662,13 +3662,13 @@ Error ResourceFormatSaverCSharpScript::save(const String &p_path, const RES &p_r
return OK;
}
-void ResourceFormatSaverCSharpScript::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
+void ResourceFormatSaverCSharpScript::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
if (Object::cast_to<CSharpScript>(p_resource.ptr())) {
p_extensions->push_back("cs");
}
}
-bool ResourceFormatSaverCSharpScript::recognize(const RES &p_resource) const {
+bool ResourceFormatSaverCSharpScript::recognize(const Ref<Resource> &p_resource) const {
return Object::cast_to<CSharpScript>(p_resource.ptr()) != nullptr;
}
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 3b97d2acc4..41b54248a3 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -202,9 +202,9 @@ public:
void set_source_code(const String &p_code) override;
#ifdef TOOLS_ENABLED
- virtual const Vector<DocData::ClassDoc> &get_documentation() const override {
+ virtual Vector<DocData::ClassDoc> get_documentation() const override {
// TODO
- static Vector<DocData::ClassDoc> docs;
+ Vector<DocData::ClassDoc> docs;
return docs;
}
#endif // TOOLS_ENABLED
@@ -534,7 +534,7 @@ public:
class ResourceFormatLoaderCSharpScript : public ResourceFormatLoader {
public:
- RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
+ Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
void get_recognized_extensions(List<String> *p_extensions) const override;
bool handles_type(const String &p_type) const override;
String get_resource_type(const String &p_path) const override;
@@ -542,9 +542,9 @@ public:
class ResourceFormatSaverCSharpScript : public ResourceFormatSaver {
public:
- Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0) override;
- void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const override;
- bool recognize(const RES &p_resource) const override;
+ Error save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags = 0) override;
+ void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override;
+ bool recognize(const Ref<Resource> &p_resource) const override;
};
#endif // CSHARP_SCRIPT_H
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs
index ed758cc137..e2f4d2f5fd 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs
@@ -107,7 +107,7 @@ namespace GodotTools.Export
ExecuteCompiler(FindCrossCompiler(compilerDirPath), compilerArgs, bclDir);
// The Godot exporter expects us to pass the abi in the tags parameter
- exporter.AddSharedObject(soFilePath, tags: new[] { abi });
+ exporter.AddSharedObject(soFilePath, tags: new[] { abi }, "");
}
}
}
@@ -134,7 +134,7 @@ namespace GodotTools.Export
if (platform == OS.Platforms.MacOS)
{
- exporter.AddSharedObject(tempOutputFilePath, tags: null);
+ exporter.AddSharedObject(tempOutputFilePath, tags: null, "");
}
else
{
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 272283432d..54c65c21e8 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -100,6 +100,9 @@
#define BINDINGS_GENERATOR_VERSION UINT32_C(13)
+// Types that will be ignored by the generator and won't be available in C#.
+const Vector<String> ignored_types = { "PhysicsServer3DExtension" };
+
const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN("\t%0 %1_in = %1;\n");
static String fix_doc_description(const String &p_bbcode) {
@@ -799,10 +802,13 @@ void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) {
const TypeInterface *return_type = _get_type_or_placeholder(imethod.return_type);
- String im_sig = "IntPtr " CS_PARAM_METHODBIND ", ";
- String im_unique_sig = imethod.return_type.cname.operator String() + ",IntPtr,IntPtr";
+ String im_sig = "IntPtr " CS_PARAM_METHODBIND;
+ String im_unique_sig = imethod.return_type.cname.operator String() + ",IntPtr";
- im_sig += "IntPtr " CS_PARAM_INSTANCE;
+ if (!imethod.is_static) {
+ im_sig += ", IntPtr " CS_PARAM_INSTANCE;
+ im_unique_sig += ",IntPtr";
+ }
// Get arguments information
int i = 0;
@@ -1029,8 +1035,8 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) {
ERR_FAIL_COND_V(!initialized, ERR_UNCONFIGURED);
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND_V(da.is_null(), ERR_CANT_CREATE);
if (!DirAccess::exists(p_proj_dir)) {
Error err = da->make_dir_recursive(p_proj_dir);
@@ -1164,8 +1170,8 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) {
Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir) {
ERR_FAIL_COND_V(!initialized, ERR_UNCONFIGURED);
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND_V(da.is_null(), ERR_CANT_CREATE);
if (!DirAccess::exists(p_proj_dir)) {
Error err = da->make_dir_recursive(p_proj_dir);
@@ -1274,8 +1280,8 @@ Error BindingsGenerator::generate_cs_api(const String &p_output_dir) {
String output_dir = path::abspath(path::realpath(p_output_dir));
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND_V(da.is_null(), ERR_CANT_CREATE);
if (!DirAccess::exists(output_dir)) {
Error err = da->make_dir_recursive(output_dir);
@@ -1730,8 +1736,10 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
String arguments_sig;
String cs_in_statements;
- String icall_params = method_bind_field + ", ";
- icall_params += sformat(p_itype.cs_in, "this");
+ String icall_params = method_bind_field;
+ if (!p_imethod.is_static) {
+ icall_params += ", " + sformat(p_itype.cs_in, "this");
+ }
StringBuilder default_args_doc;
@@ -1889,7 +1897,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
p_output.append(MEMBER_BEGIN);
p_output.append(p_imethod.is_internal ? "internal " : "public ");
- if (p_itype.is_singleton) {
+ if (p_itype.is_singleton || p_imethod.is_static) {
p_output.append("static ");
} else if (p_imethod.is_virtual) {
p_output.append("virtual ");
@@ -2247,12 +2255,10 @@ uint32_t BindingsGenerator::get_version() {
}
Error BindingsGenerator::_save_file(const String &p_path, const StringBuilder &p_content) {
- FileAccessRef file = FileAccess::open(p_path, FileAccess::WRITE);
-
- ERR_FAIL_COND_V_MSG(!file, ERR_FILE_CANT_WRITE, "Cannot open file: '" + p_path + "'.");
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE);
+ ERR_FAIL_COND_V_MSG(file.is_null(), ERR_FILE_CANT_WRITE, "Cannot open file: '" + p_path + "'.");
file->store_string(p_content.as_string());
- file->close();
return OK;
}
@@ -2268,7 +2274,10 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
String argc_str = itos(p_imethod.arguments.size());
- String c_func_sig = "MethodBind* " CS_PARAM_METHODBIND ", " + p_itype.c_type_in + " " CS_PARAM_INSTANCE;
+ String c_func_sig = "MethodBind* " CS_PARAM_METHODBIND;
+ if (!p_imethod.is_static) {
+ c_func_sig += ", " + p_itype.c_type_in + " " CS_PARAM_INSTANCE;
+ }
String c_in_statements;
String c_args_var_content;
@@ -2360,17 +2369,21 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
String fail_ret = return_type->c_type_out.ends_with("*") && !return_type->ret_as_byref_arg ? "nullptr" : return_type->c_type_out + "()";
- if (return_type->ret_as_byref_arg) {
- p_output.append("\tif (" CS_PARAM_INSTANCE " == nullptr) { *arg_ret = ");
- p_output.append(fail_ret);
- p_output.append("; ERR_FAIL_MSG(\"Parameter ' " CS_PARAM_INSTANCE " ' is null.\"); }\n");
- } else {
- p_output.append("\tERR_FAIL_NULL_V(" CS_PARAM_INSTANCE ", ");
- p_output.append(fail_ret);
- p_output.append(");\n");
+ if (!p_imethod.is_static) {
+ if (return_type->ret_as_byref_arg) {
+ p_output.append("\tif (" CS_PARAM_INSTANCE " == nullptr) { *arg_ret = ");
+ p_output.append(fail_ret);
+ p_output.append("; ERR_FAIL_MSG(\"Parameter ' " CS_PARAM_INSTANCE " ' is null.\"); }\n");
+ } else {
+ p_output.append("\tERR_FAIL_NULL_V(" CS_PARAM_INSTANCE ", ");
+ p_output.append(fail_ret);
+ p_output.append(");\n");
+ }
}
} else {
- p_output.append("\tERR_FAIL_NULL(" CS_PARAM_INSTANCE ");\n");
+ if (!p_imethod.is_static) {
+ p_output.append("\tERR_FAIL_NULL(" CS_PARAM_INSTANCE ");\n");
+ }
}
if (p_imethod.arguments.size()) {
@@ -2414,7 +2427,9 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
}
}
- p_output.append(CS_PARAM_METHODBIND "->call(" CS_PARAM_INSTANCE ", ");
+ p_output.append(CS_PARAM_METHODBIND "->call(");
+ p_output.append(p_imethod.is_static ? "nullptr" : CS_PARAM_INSTANCE);
+ p_output.append(", ");
p_output.append(p_imethod.arguments.size() ? C_LOCAL_PTRCALL_ARGS ".ptr()" : "nullptr");
p_output.append(", total_length, vcall_error);\n");
@@ -2425,7 +2440,9 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
}
}
} else {
- p_output.append("\t" CS_PARAM_METHODBIND "->ptrcall(" CS_PARAM_INSTANCE ", ");
+ p_output.append("\t" CS_PARAM_METHODBIND "->ptrcall(");
+ p_output.append(p_imethod.is_static ? "nullptr" : CS_PARAM_INSTANCE);
+ p_output.append(", ");
p_output.append(p_imethod.arguments.size() ? C_LOCAL_PTRCALL_ARGS ", " : "nullptr, ");
p_output.append(!ret_void ? "&" C_LOCAL_RET ");\n" : "nullptr);\n");
}
@@ -2645,6 +2662,12 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
continue;
}
+ if (ignored_types.has(type_cname)) {
+ _log("Ignoring type '%s' because it's in the list of ignored types\n", String(type_cname).utf8().get_data());
+ class_list.pop_front();
+ continue;
+ }
+
if (!ClassDB::is_class_exposed(type_cname)) {
_log("Ignoring type '%s' because it's not exposed\n", String(type_cname).utf8().get_data());
class_list.pop_front();
@@ -2763,6 +2786,10 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
imethod.name = method_info.name;
imethod.cname = cname;
+ if (method_info.flags & METHOD_FLAG_STATIC) {
+ imethod.is_static = true;
+ }
+
if (method_info.flags & METHOD_FLAG_VIRTUAL) {
imethod.is_virtual = true;
}
@@ -3175,7 +3202,7 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
if (transform == Transform2D()) {
r_iarg.default_argument = "Transform2D.Identity";
} else {
- r_iarg.default_argument = "new Transform2D(new Vector2" + transform.elements[0].operator String() + ", new Vector2" + transform.elements[1].operator String() + ", new Vector2" + transform.elements[2].operator String() + ")";
+ r_iarg.default_argument = "new Transform2D(new Vector2" + transform.columns[0].operator String() + ", new Vector2" + transform.columns[1].operator String() + ", new Vector2" + transform.columns[2].operator String() + ")";
}
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
} break;
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index f601ffde2b..dec4fae8cd 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -137,6 +137,11 @@ class BindingsGenerator {
bool is_vararg = false;
/**
+ * Determines if the method is static.
+ */
+ bool is_static = false;
+
+ /**
* Virtual methods ("virtual" as defined by the Godot API) are methods that by default do nothing,
* but can be overridden by the user to add custom functionality.
* e.g.: _ready, _process, etc.
diff --git a/modules/mono/editor/code_completion.cpp b/modules/mono/editor/code_completion.cpp
index 3a41b3f6f5..79015686c3 100644
--- a/modules/mono/editor/code_completion.cpp
+++ b/modules/mono/editor/code_completion.cpp
@@ -144,7 +144,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr
}
} break;
case CompletionKind::SCENE_PATHS: {
- DirAccessRef dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ Ref<DirAccess> dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
List<String> directories;
directories.push_back(dir_access->get_current_dir());
diff --git a/modules/mono/editor_templates/CharacterBody2D/basic_movement.cs b/modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs
index 2ca81ab7cd..2ca81ab7cd 100644
--- a/modules/mono/editor_templates/CharacterBody2D/basic_movement.cs
+++ b/modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs
diff --git a/modules/mono/editor_templates/CharacterBody3D/basic_movement.cs b/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs
index a6935fe497..a6935fe497 100644
--- a/modules/mono/editor_templates/CharacterBody3D/basic_movement.cs
+++ b/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs
diff --git a/modules/mono/editor_templates/EditorPlugin/plugin.cs b/modules/mono/editor/script_templates/EditorPlugin/plugin.cs
index 6e6a799be6..eba5fd12a4 100644
--- a/modules/mono/editor_templates/EditorPlugin/plugin.cs
+++ b/modules/mono/editor/script_templates/EditorPlugin/plugin.cs
@@ -1,4 +1,5 @@
// meta-description: Basic plugin template
+
#if TOOLS
using _BINDINGS_NAMESPACE_;
using System;
diff --git a/modules/mono/editor_templates/EditorScript/basic_editor_script.cs b/modules/mono/editor/script_templates/EditorScript/basic_editor_script.cs
index 2088822890..1b347edc1c 100644
--- a/modules/mono/editor_templates/EditorScript/basic_editor_script.cs
+++ b/modules/mono/editor/script_templates/EditorScript/basic_editor_script.cs
@@ -1,4 +1,5 @@
// meta-description: Basic editor script template
+
#if TOOLS
using _BINDINGS_NAMESPACE_;
using System;
@@ -6,9 +7,9 @@ using System;
[Tool]
public partial class _CLASS_ : _BASE_
{
+ // Called when the script is executed (using File -> Run in Script Editor).
public override void _Run()
{
- // Called when the script is executed (using File -> Run in Script Editor).
}
}
#endif
diff --git a/modules/mono/editor_templates/Node/default.cs b/modules/mono/editor/script_templates/Node/default.cs
index 73d69dd993..4c86d1666f 100644
--- a/modules/mono/editor_templates/Node/default.cs
+++ b/modules/mono/editor/script_templates/Node/default.cs
@@ -8,12 +8,10 @@ public partial class _CLASS_ : _BASE_
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
-
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(float delta)
{
-
}
}
diff --git a/modules/mono/editor_templates/Object/empty.cs b/modules/mono/editor/script_templates/Object/empty.cs
index e5bee64fe1..34526d514f 100644
--- a/modules/mono/editor_templates/Object/empty.cs
+++ b/modules/mono/editor/script_templates/Object/empty.cs
@@ -5,5 +5,4 @@ using System;
public partial class _CLASS_ : _BASE_
{
-
}
diff --git a/modules/mono/editor_templates/SCsub b/modules/mono/editor/script_templates/SCsub
index 39f6cb5c01..39f6cb5c01 100644
--- a/modules/mono/editor_templates/SCsub
+++ b/modules/mono/editor/script_templates/SCsub
diff --git a/modules/mono/editor_templates/VisualShaderNodeCustom/basic.cs b/modules/mono/editor/script_templates/VisualShaderNodeCustom/basic.cs
index a1b93e7daa..a1b93e7daa 100644
--- a/modules/mono/editor_templates/VisualShaderNodeCustom/basic.cs
+++ b/modules/mono/editor/script_templates/VisualShaderNodeCustom/basic.cs
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
index 656796c5c7..37bdc42c2d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
@@ -526,10 +526,10 @@ namespace Godot
/// <summary>
/// Introduce an additional rotation around the given <paramref name="axis"/>
- /// by <paramref name="phi"/> (in radians). The axis must be a normalized vector.
+ /// by <paramref name="angle"/> (in radians). The axis must be a normalized vector.
/// </summary>
/// <param name="axis">The axis to rotate around. Must be normalized.</param>
- /// <param name="phi">The angle to rotate, in radians.</param>
+ /// <param name="angle">The angle to rotate, in radians.</param>
/// <returns>The rotated basis matrix.</returns>
public Basis Rotated(Vector3 axis, real_t phi)
{
@@ -770,10 +770,10 @@ namespace Godot
/// <summary>
/// Constructs a pure rotation basis matrix, rotated around the given <paramref name="axis"/>
- /// by <paramref name="phi"/> (in radians). The axis must be a normalized vector.
+ /// by <paramref name="angle"/> (in radians). The axis must be a normalized vector.
/// </summary>
/// <param name="axis">The axis to rotate around. Must be normalized.</param>
- /// <param name="phi">The angle to rotate, in radians.</param>
+ /// <param name="angle">The angle to rotate, in radians.</param>
public Basis(Vector3 axis, real_t phi)
{
Vector3 axisSq = new Vector3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
index 8e253388bf..89947899cb 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
@@ -297,9 +297,9 @@ namespace Godot
}
/// <summary>
- /// Rotates the transform by <paramref name="phi"/> (in radians), using matrix multiplication.
+ /// Rotates the transform by <paramref name="angle"/> (in radians), using matrix multiplication.
/// </summary>
- /// <param name="phi">The angle to rotate, in radians.</param>
+ /// <param name="angle">The angle to rotate, in radians.</param>
/// <returns>The rotated transformation matrix.</returns>
public Transform2D Rotated(real_t phi)
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
index 5d9aabdd2f..7b211b6577 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
@@ -186,11 +186,11 @@ namespace Godot
}
/// <summary>
- /// Rotates the transform around the given <paramref name="axis"/> by <paramref name="phi"/> (in radians),
+ /// Rotates the transform around the given <paramref name="axis"/> by <paramref name="angle"/> (in radians),
/// using matrix multiplication. The axis must be a normalized vector.
/// </summary>
/// <param name="axis">The axis to rotate around. Must be normalized.</param>
- /// <param name="phi">The angle to rotate, in radians.</param>
+ /// <param name="angle">The angle to rotate, in radians.</param>
/// <returns>The rotated transformation matrix.</returns>
public Transform3D Rotated(Vector3 axis, real_t phi)
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
index d4b623b2ea..9e990ce83e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
@@ -470,9 +470,9 @@ namespace Godot
}
/// <summary>
- /// Rotates this vector by <paramref name="phi"/> radians.
+ /// Rotates this vector by <paramref name="angle"/> radians.
/// </summary>
- /// <param name="phi">The angle to rotate by, in radians.</param>
+ /// <param name="angle">The angle to rotate by, in radians.</param>
/// <returns>The rotated vector.</returns>
public Vector2 Rotated(real_t phi)
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
index eddfa76f10..56859da7f2 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
@@ -488,11 +488,11 @@ namespace Godot
}
/// <summary>
- /// Rotates this vector around a given <paramref name="axis"/> vector by <paramref name="phi"/> radians.
+ /// Rotates this vector around a given <paramref name="axis"/> vector by <paramref name="angle"/> (in radians).
/// The <paramref name="axis"/> vector must be a normalized vector.
/// </summary>
/// <param name="axis">The vector to rotate around. Must be normalized.</param>
- /// <param name="phi">The angle to rotate by, in radians.</param>
+ /// <param name="angle">The angle to rotate by, in radians.</param>
/// <returns>The rotated vector.</returns>
public Vector3 Rotated(Vector3 axis, real_t phi)
{
diff --git a/modules/mono/glue/arguments_vector.h b/modules/mono/glue/arguments_vector.h
index 7c991d87a4..4405809887 100644
--- a/modules/mono/glue/arguments_vector.h
+++ b/modules/mono/glue/arguments_vector.h
@@ -37,7 +37,7 @@ template <typename T, int POOL_SIZE = 5>
struct ArgumentsVector {
private:
T pool[POOL_SIZE];
- T *_ptr;
+ T *_ptr = nullptr;
int size;
ArgumentsVector() = delete;
diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp
index b5f2c98af5..b10d78c593 100644
--- a/modules/mono/glue/base_object_glue.cpp
+++ b/modules/mono/glue/base_object_glue.cpp
@@ -148,7 +148,7 @@ MonoObject *godot_icall_Object_weakref(Object *p_ptr) {
RefCounted *rc = Object::cast_to<RefCounted>(p_ptr);
if (rc) {
- REF r = rc;
+ Ref<RefCounted> r = rc;
if (!r.is_valid()) {
return nullptr;
}
diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp
index 7c2cb2e260..cb2b60fcce 100644
--- a/modules/mono/godotsharp_dirs.cpp
+++ b/modules/mono/godotsharp_dirs.cpp
@@ -76,7 +76,7 @@ String _get_mono_user_dir() {
exe_dir = exe_dir.plus_file("../../..").simplify_path();
}
- DirAccessRef d = DirAccess::create_for_path(exe_dir);
+ Ref<DirAccess> d = DirAccess::create_for_path(exe_dir);
if (d->file_exists("._sc_") || d->file_exists("_sc_")) {
// contain yourself
diff --git a/modules/mono/managed_callable.h b/modules/mono/managed_callable.h
index ea7231f43b..d50a8a7b08 100644
--- a/modules/mono/managed_callable.h
+++ b/modules/mono/managed_callable.h
@@ -43,7 +43,7 @@
class ManagedCallable : public CallableCustom {
friend class CSharpLanguage;
MonoGCHandleData delegate_handle;
- GDMonoMethod *delegate_invoke;
+ GDMonoMethod *delegate_invoke = nullptr;
#ifdef GD_MONO_HOT_RELOAD
SelfList<ManagedCallable> self_instance = this;
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index 424b74906f..e98ce8f6c1 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -643,7 +643,7 @@ bool GDMono::copy_prebuilt_api_assembly(ApiAssemblyInfo::Type p_api_type, const
// Create destination directory if needed
if (!DirAccess::exists(dst_dir)) {
- DirAccessRef da = DirAccess::create_for_path(dst_dir);
+ Ref<DirAccess> da = DirAccess::create_for_path(dst_dir);
Error err = da->make_dir_recursive(dst_dir);
if (err != OK) {
@@ -652,7 +652,7 @@ bool GDMono::copy_prebuilt_api_assembly(ApiAssemblyInfo::Type p_api_type, const
}
}
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
String xml_file = assembly_name + ".xml";
if (da->copy(src_dir.plus_file(xml_file), dst_dir.plus_file(xml_file)) != OK) {
diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h
index aab0b31c37..51fd0f8483 100644
--- a/modules/mono/mono_gd/gd_mono.h
+++ b/modules/mono/mono_gd/gd_mono.h
@@ -94,16 +94,16 @@ private:
UnhandledExceptionPolicy unhandled_exception_policy;
- MonoDomain *root_domain;
- MonoDomain *scripts_domain;
+ MonoDomain *root_domain = nullptr;
+ MonoDomain *scripts_domain = nullptr;
HashMap<int32_t, HashMap<String, GDMonoAssembly *>> assemblies;
- GDMonoAssembly *corlib_assembly;
- GDMonoAssembly *project_assembly;
+ GDMonoAssembly *corlib_assembly = nullptr;
+ GDMonoAssembly *project_assembly = nullptr;
#ifdef TOOLS_ENABLED
- GDMonoAssembly *tools_assembly;
- GDMonoAssembly *tools_project_editor_assembly;
+ GDMonoAssembly *tools_assembly = nullptr;
+ GDMonoAssembly *tools_project_editor_assembly = nullptr;
#endif
LoadedApiAssembly core_api_assembly;
@@ -150,7 +150,7 @@ private:
void _init_godot_api_hashes();
void _init_exception_policy();
- GDMonoLog *gdmono_log;
+ GDMonoLog *gdmono_log = nullptr;
#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED)
MonoRegInfo mono_reg_info;
@@ -250,7 +250,7 @@ public:
namespace gdmono {
class ScopeDomain {
- MonoDomain *prev_domain;
+ MonoDomain *prev_domain = nullptr;
public:
ScopeDomain(MonoDomain *p_domain) {
@@ -270,7 +270,7 @@ public:
};
class ScopeExitDomainUnload {
- MonoDomain *domain;
+ MonoDomain *domain = nullptr;
public:
ScopeExitDomainUnload(MonoDomain *p_domain) :
diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h
index b25d773be7..a96357b082 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.h
+++ b/modules/mono/mono_gd/gd_mono_assembly.h
@@ -68,8 +68,8 @@ class GDMonoAssembly {
};
String name;
- MonoImage *image;
- MonoAssembly *assembly;
+ MonoImage *image = nullptr;
+ MonoAssembly *assembly = nullptr;
bool attrs_fetched = false;
MonoCustomAttrInfo *attributes = nullptr;
diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h
index 49f47b0a15..4000342c94 100644
--- a/modules/mono/mono_gd/gd_mono_cache.h
+++ b/modules/mono/mono_gd/gd_mono_cache.h
@@ -41,91 +41,91 @@ struct CachedData {
// corlib classes
// Let's use the no-namespace format for these too
- GDMonoClass *class_MonoObject; // object
- GDMonoClass *class_bool; // bool
- GDMonoClass *class_int8_t; // sbyte
- GDMonoClass *class_int16_t; // short
- GDMonoClass *class_int32_t; // int
- GDMonoClass *class_int64_t; // long
- GDMonoClass *class_uint8_t; // byte
- GDMonoClass *class_uint16_t; // ushort
- GDMonoClass *class_uint32_t; // uint
- GDMonoClass *class_uint64_t; // ulong
- GDMonoClass *class_float; // float
- GDMonoClass *class_double; // double
- GDMonoClass *class_String; // string
- GDMonoClass *class_IntPtr; // System.IntPtr
-
- GDMonoClass *class_System_Collections_IEnumerable;
- GDMonoClass *class_System_Collections_ICollection;
- GDMonoClass *class_System_Collections_IDictionary;
+ GDMonoClass *class_MonoObject = nullptr; // object
+ GDMonoClass *class_bool = nullptr; // bool
+ GDMonoClass *class_int8_t = nullptr; // sbyte
+ GDMonoClass *class_int16_t = nullptr; // short
+ GDMonoClass *class_int32_t = nullptr; // int
+ GDMonoClass *class_int64_t = nullptr; // long
+ GDMonoClass *class_uint8_t = nullptr; // byte
+ GDMonoClass *class_uint16_t = nullptr; // ushort
+ GDMonoClass *class_uint32_t = nullptr; // uint
+ GDMonoClass *class_uint64_t = nullptr; // ulong
+ GDMonoClass *class_float = nullptr; // float
+ GDMonoClass *class_double = nullptr; // double
+ GDMonoClass *class_String = nullptr; // string
+ GDMonoClass *class_IntPtr = nullptr; // System.IntPtr
+
+ GDMonoClass *class_System_Collections_IEnumerable = nullptr;
+ GDMonoClass *class_System_Collections_ICollection = nullptr;
+ GDMonoClass *class_System_Collections_IDictionary = nullptr;
#ifdef DEBUG_ENABLED
- GDMonoClass *class_System_Diagnostics_StackTrace;
+ GDMonoClass *class_System_Diagnostics_StackTrace = nullptr;
GDMonoMethodThunkR<MonoArray *, MonoObject *> methodthunk_System_Diagnostics_StackTrace_GetFrames;
- GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_bool;
- GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_Exception_bool;
+ GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_bool = nullptr;
+ GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_Exception_bool = nullptr;
#endif
- GDMonoClass *class_KeyNotFoundException;
+ GDMonoClass *class_KeyNotFoundException = nullptr;
- MonoClass *rawclass_Dictionary;
+ MonoClass *rawclass_Dictionary = nullptr;
// -----------------------------------------------
- GDMonoClass *class_Vector2;
- GDMonoClass *class_Vector2i;
- GDMonoClass *class_Rect2;
- GDMonoClass *class_Rect2i;
- GDMonoClass *class_Transform2D;
- GDMonoClass *class_Vector3;
- GDMonoClass *class_Vector3i;
- GDMonoClass *class_Basis;
- GDMonoClass *class_Quaternion;
- GDMonoClass *class_Transform3D;
- GDMonoClass *class_AABB;
- GDMonoClass *class_Color;
- GDMonoClass *class_Plane;
- GDMonoClass *class_StringName;
- GDMonoClass *class_NodePath;
- GDMonoClass *class_RID;
- GDMonoClass *class_GodotObject;
- GDMonoClass *class_GodotResource;
- GDMonoClass *class_Node;
- GDMonoClass *class_Control;
- GDMonoClass *class_Node3D;
- GDMonoClass *class_WeakRef;
- GDMonoClass *class_Callable;
- GDMonoClass *class_SignalInfo;
- GDMonoClass *class_Array;
- GDMonoClass *class_Dictionary;
- GDMonoClass *class_MarshalUtils;
- GDMonoClass *class_ISerializationListener;
+ GDMonoClass *class_Vector2 = nullptr;
+ GDMonoClass *class_Vector2i = nullptr;
+ GDMonoClass *class_Rect2 = nullptr;
+ GDMonoClass *class_Rect2i = nullptr;
+ GDMonoClass *class_Transform2D = nullptr;
+ GDMonoClass *class_Vector3 = nullptr;
+ GDMonoClass *class_Vector3i = nullptr;
+ GDMonoClass *class_Basis = nullptr;
+ GDMonoClass *class_Quaternion = nullptr;
+ GDMonoClass *class_Transform3D = nullptr;
+ GDMonoClass *class_AABB = nullptr;
+ GDMonoClass *class_Color = nullptr;
+ GDMonoClass *class_Plane = nullptr;
+ GDMonoClass *class_StringName = nullptr;
+ GDMonoClass *class_NodePath = nullptr;
+ GDMonoClass *class_RID = nullptr;
+ GDMonoClass *class_GodotObject = nullptr;
+ GDMonoClass *class_GodotResource = nullptr;
+ GDMonoClass *class_Node = nullptr;
+ GDMonoClass *class_Control = nullptr;
+ GDMonoClass *class_Node3D = nullptr;
+ GDMonoClass *class_WeakRef = nullptr;
+ GDMonoClass *class_Callable = nullptr;
+ GDMonoClass *class_SignalInfo = nullptr;
+ GDMonoClass *class_Array = nullptr;
+ GDMonoClass *class_Dictionary = nullptr;
+ GDMonoClass *class_MarshalUtils = nullptr;
+ GDMonoClass *class_ISerializationListener = nullptr;
#ifdef DEBUG_ENABLED
- GDMonoClass *class_DebuggingUtils;
+ GDMonoClass *class_DebuggingUtils = nullptr;
GDMonoMethodThunk<MonoObject *, MonoString **, int *, MonoString **> methodthunk_DebuggingUtils_GetStackFrameInfo;
#endif
- GDMonoClass *class_ExportAttribute;
- GDMonoField *field_ExportAttribute_hint;
- GDMonoField *field_ExportAttribute_hintString;
- GDMonoClass *class_SignalAttribute;
- GDMonoClass *class_ToolAttribute;
- GDMonoClass *class_AnyPeerAttribute;
- GDMonoClass *class_AuthorityAttribute;
- GDMonoClass *class_GodotMethodAttribute;
- GDMonoField *field_GodotMethodAttribute_methodName;
- GDMonoClass *class_ScriptPathAttribute;
- GDMonoField *field_ScriptPathAttribute_path;
- GDMonoClass *class_AssemblyHasScriptsAttribute;
- GDMonoField *field_AssemblyHasScriptsAttribute_requiresLookup;
- GDMonoField *field_AssemblyHasScriptsAttribute_scriptTypes;
-
- GDMonoField *field_GodotObject_ptr;
- GDMonoField *field_StringName_ptr;
- GDMonoField *field_NodePath_ptr;
- GDMonoField *field_Image_ptr;
- GDMonoField *field_RID_ptr;
+ GDMonoClass *class_ExportAttribute = nullptr;
+ GDMonoField *field_ExportAttribute_hint = nullptr;
+ GDMonoField *field_ExportAttribute_hintString = nullptr;
+ GDMonoClass *class_SignalAttribute = nullptr;
+ GDMonoClass *class_ToolAttribute = nullptr;
+ GDMonoClass *class_AnyPeerAttribute = nullptr;
+ GDMonoClass *class_AuthorityAttribute = nullptr;
+ GDMonoClass *class_GodotMethodAttribute = nullptr;
+ GDMonoField *field_GodotMethodAttribute_methodName = nullptr;
+ GDMonoClass *class_ScriptPathAttribute = nullptr;
+ GDMonoField *field_ScriptPathAttribute_path = nullptr;
+ GDMonoClass *class_AssemblyHasScriptsAttribute = nullptr;
+ GDMonoField *field_AssemblyHasScriptsAttribute_requiresLookup = nullptr;
+ GDMonoField *field_AssemblyHasScriptsAttribute_scriptTypes = nullptr;
+
+ GDMonoField *field_GodotObject_ptr = nullptr;
+ GDMonoField *field_StringName_ptr = nullptr;
+ GDMonoField *field_NodePath_ptr = nullptr;
+ GDMonoField *field_Image_ptr = nullptr;
+ GDMonoField *field_RID_ptr = nullptr;
GDMonoMethodThunk<MonoObject *> methodthunk_GodotObject_Dispose;
GDMonoMethodThunkR<Array *, MonoObject *> methodthunk_Array_GetPtr;
diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp
index 89c37e087b..3fc0f16e05 100644
--- a/modules/mono/mono_gd/gd_mono_class.cpp
+++ b/modules/mono/mono_gd/gd_mono_class.cpp
@@ -194,7 +194,7 @@ void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base
#ifdef DEBUG_ENABLED
// For debug builds, we also fetched from native base classes as well before if this is not a native base class.
- // This allows us to warn the user here if he is using snake_case by mistake.
+ // This allows us to warn the user here if they are using snake_case by mistake.
if (p_native_base != this) {
GDMonoClass *native_top = p_native_base;
diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h
index bfb5797d4b..b32d561f61 100644
--- a/modules/mono/mono_gd/gd_mono_class.h
+++ b/modules/mono/mono_gd/gd_mono_class.h
@@ -70,11 +70,11 @@ class GDMonoClass {
StringName namespace_name;
StringName class_name;
- MonoClass *mono_class;
- GDMonoAssembly *assembly;
+ MonoClass *mono_class = nullptr;
+ GDMonoAssembly *assembly = nullptr;
bool attrs_fetched;
- MonoCustomAttrInfo *attributes;
+ MonoCustomAttrInfo *attributes = nullptr;
// This contains both the original method names and remapped method names from the native Godot identifiers to the C# functions.
// Most method-related functions refer to this and it's possible this is unintuitive for outside users; this may be a prime location for refactoring or renaming.
diff --git a/modules/mono/mono_gd/gd_mono_field.h b/modules/mono/mono_gd/gd_mono_field.h
index abcdef378c..87ef245f3f 100644
--- a/modules/mono/mono_gd/gd_mono_field.h
+++ b/modules/mono/mono_gd/gd_mono_field.h
@@ -36,14 +36,14 @@
#include "i_mono_class_member.h"
class GDMonoField : public IMonoClassMember {
- GDMonoClass *owner;
- MonoClassField *mono_field;
+ GDMonoClass *owner = nullptr;
+ MonoClassField *mono_field = nullptr;
StringName name;
ManagedType type;
bool attrs_fetched;
- MonoCustomAttrInfo *attributes;
+ MonoCustomAttrInfo *attributes = nullptr;
public:
virtual GDMonoClass *get_enclosing_class() const final { return owner; }
diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp
index 01a6521876..6ea3c5539e 100644
--- a/modules/mono/mono_gd/gd_mono_log.cpp
+++ b/modules/mono/mono_gd/gd_mono_log.cpp
@@ -77,23 +77,20 @@ static String make_text(const char *log_domain, const char *log_level, const cha
}
void GDMonoLog::mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *) {
- FileAccess *f = GDMonoLog::get_singleton()->log_file;
-
if (GDMonoLog::get_singleton()->log_level_id >= get_log_level_id(log_level)) {
String text = make_text(log_domain, log_level, message);
text += "\n";
- f->seek_end();
- f->store_string(text);
+ GDMonoLog::get_singleton()->log_file->seek_end();
+ GDMonoLog::get_singleton()->log_file->store_string(text);
}
if (fatal) {
String text = make_text(log_domain, log_level, message);
ERR_PRINT("Mono: FATAL ERROR '" + text + "', ABORTING! Logfile: '" + GDMonoLog::get_singleton()->log_file_path + "'.");
// Make sure to flush before aborting
- f->flush();
- f->close();
- memdelete(f);
+ GDMonoLog::get_singleton()->log_file->flush();
+ GDMonoLog::get_singleton()->log_file.unref();
abort();
}
@@ -101,8 +98,8 @@ void GDMonoLog::mono_log_callback(const char *log_domain, const char *log_level,
bool GDMonoLog::_try_create_logs_dir(const String &p_logs_dir) {
if (!DirAccess::exists(p_logs_dir)) {
- DirAccessRef diraccess = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- ERR_FAIL_COND_V(!diraccess, false);
+ Ref<DirAccess> diraccess = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND_V(diraccess.is_null(), false);
Error logs_mkdir_err = diraccess->make_dir_recursive(p_logs_dir);
ERR_FAIL_COND_V_MSG(logs_mkdir_err != OK, false, "Failed to create mono logs directory.");
}
@@ -113,8 +110,8 @@ bool GDMonoLog::_try_create_logs_dir(const String &p_logs_dir) {
void GDMonoLog::_delete_old_log_files(const String &p_logs_dir) {
static const uint64_t MAX_SECS = 5 * 86400; // 5 days
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- ERR_FAIL_COND(!da);
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND(da.is_null());
Error err = da->change_dir(p_logs_dir);
ERR_FAIL_COND_MSG(err != OK, "Cannot change directory to '" + p_logs_dir + "'.");
@@ -170,7 +167,7 @@ void GDMonoLog::initialize() {
log_file_path = logs_dir.plus_file(log_file_name);
log_file = FileAccess::open(log_file_path, FileAccess::WRITE);
- if (!log_file) {
+ if (log_file.is_null()) {
ERR_PRINT("Mono: Cannot create log file at: " + log_file_path);
}
}
@@ -178,7 +175,7 @@ void GDMonoLog::initialize() {
mono_trace_set_level_string(log_level.get_data());
log_level_id = get_log_level_id(log_level.get_data());
- if (log_file) {
+ if (log_file.is_valid()) {
OS::get_singleton()->print("Mono: Log file is: '%s'\n", log_file_path.utf8().get_data());
mono_trace_set_log_handler(mono_log_callback, this);
} else {
@@ -192,11 +189,6 @@ GDMonoLog::GDMonoLog() {
GDMonoLog::~GDMonoLog() {
singleton = nullptr;
-
- if (log_file) {
- log_file->close();
- memdelete(log_file);
- }
}
#else
diff --git a/modules/mono/mono_gd/gd_mono_log.h b/modules/mono/mono_gd/gd_mono_log.h
index 9aa67a09e2..9fc35f8e31 100644
--- a/modules/mono/mono_gd/gd_mono_log.h
+++ b/modules/mono/mono_gd/gd_mono_log.h
@@ -48,7 +48,7 @@ class GDMonoLog {
#ifdef GD_MONO_LOG_ENABLED
int log_level_id = -1;
- FileAccess *log_file = nullptr;
+ Ref<FileAccess> log_file;
String log_file_path;
bool _try_create_logs_dir(const String &p_logs_dir);
diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h
index 20d4743e5c..778e52b6cb 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.h
+++ b/modules/mono/mono_gd/gd_mono_marshal.h
@@ -196,14 +196,14 @@ PackedVector3Array mono_array_to_PackedVector3Array(MonoArray *p_array);
#pragma pack(push, 1)
struct M_Callable {
- MonoObject *target;
- MonoObject *method_string_name;
- MonoDelegate *delegate;
+ MonoObject *target = nullptr;
+ MonoObject *method_string_name = nullptr;
+ MonoDelegate *delegate = nullptr;
};
struct M_SignalInfo {
- MonoObject *owner;
- MonoObject *name_string_name;
+ MonoObject *owner = nullptr;
+ MonoObject *name_string_name = nullptr;
};
#pragma pack(pop)
@@ -367,9 +367,9 @@ struct M_Transform2D {
static _FORCE_INLINE_ M_Transform2D convert_from(const Transform2D &p_from) {
M_Transform2D ret = {
- M_Vector2::convert_from(p_from.elements[0]),
- M_Vector2::convert_from(p_from.elements[1]),
- M_Vector2::convert_from(p_from.elements[2])
+ M_Vector2::convert_from(p_from.columns[0]),
+ M_Vector2::convert_from(p_from.columns[1]),
+ M_Vector2::convert_from(p_from.columns[2])
};
return ret;
}
@@ -412,9 +412,9 @@ struct M_Basis {
static _FORCE_INLINE_ M_Basis convert_from(const Basis &p_from) {
M_Basis ret = {
- M_Vector3::convert_from(p_from.elements[0]),
- M_Vector3::convert_from(p_from.elements[1]),
- M_Vector3::convert_from(p_from.elements[2])
+ M_Vector3::convert_from(p_from.rows[0]),
+ M_Vector3::convert_from(p_from.rows[1]),
+ M_Vector3::convert_from(p_from.rows[2])
};
return ret;
}
diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h
index 6e87a60ee2..be11ef5bfe 100644
--- a/modules/mono/mono_gd/gd_mono_method.h
+++ b/modules/mono/mono_gd/gd_mono_method.h
@@ -54,7 +54,7 @@ class GDMonoMethod : public IMonoClassMember {
friend class GDMonoClass;
- MonoMethod *mono_method;
+ MonoMethod *mono_method = nullptr;
public:
virtual GDMonoClass *get_enclosing_class() const final;
diff --git a/modules/mono/mono_gd/gd_mono_property.h b/modules/mono/mono_gd/gd_mono_property.h
index 003bcf05e1..6fc681aeb5 100644
--- a/modules/mono/mono_gd/gd_mono_property.h
+++ b/modules/mono/mono_gd/gd_mono_property.h
@@ -36,14 +36,14 @@
#include "i_mono_class_member.h"
class GDMonoProperty : public IMonoClassMember {
- GDMonoClass *owner;
- MonoProperty *mono_property;
+ GDMonoClass *owner = nullptr;
+ MonoProperty *mono_property = nullptr;
StringName name;
ManagedType type;
bool attrs_fetched;
- MonoCustomAttrInfo *attributes;
+ MonoCustomAttrInfo *attributes = nullptr;
unsigned int param_buffer_size;
diff --git a/modules/mono/mono_gd/gd_mono_wasm_m2n.h b/modules/mono/mono_gd/gd_mono_wasm_m2n.h
index 68299aa984..83e2750e5a 100644
--- a/modules/mono/mono_gd/gd_mono_wasm_m2n.h
+++ b/modules/mono/mono_gd/gd_mono_wasm_m2n.h
@@ -47,11 +47,11 @@ struct Mono_InterpMethodArguments {
size_t ilen;
void **iargs;
size_t flen;
- double *fargs;
+ double *fargs = nullptr;
void **retval;
size_t is_float_ret;
//#ifdef TARGET_WASM
- void *sig;
+ void *sig = nullptr;
//#endif
};
} // extern "C"
diff --git a/modules/mono/register_types.cpp b/modules/mono/register_types.cpp
index 531a4bb11f..755e1f7a30 100644
--- a/modules/mono/register_types.cpp
+++ b/modules/mono/register_types.cpp
@@ -40,7 +40,11 @@ Ref<ResourceFormatSaverCSharpScript> resource_saver_cs;
mono_bind::GodotSharp *_godotsharp = nullptr;
-void register_mono_types() {
+void initialize_mono_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
GDREGISTER_CLASS(CSharpScript);
_godotsharp = memnew(mono_bind::GodotSharp);
@@ -59,7 +63,11 @@ void register_mono_types() {
ResourceSaver::add_resource_format_saver(resource_saver_cs);
}
-void unregister_mono_types() {
+void uninitialize_mono_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
ScriptServer::unregister_language(script_language_cs);
if (script_language_cs) {
diff --git a/modules/mono/register_types.h b/modules/mono/register_types.h
index 12f7e36f02..bc2690c277 100644
--- a/modules/mono/register_types.h
+++ b/modules/mono/register_types.h
@@ -31,7 +31,9 @@
#ifndef MONO_REGISTER_TYPES_H
#define MONO_REGISTER_TYPES_H
-void register_mono_types();
-void unregister_mono_types();
+#include "modules/register_module_types.h"
+
+void initialize_mono_module(ModuleInitializationLevel p_level);
+void uninitialize_mono_module(ModuleInitializationLevel p_level);
#endif // MONO_REGISTER_TYPES_H
diff --git a/modules/mono/signal_awaiter_utils.h b/modules/mono/signal_awaiter_utils.h
index 1a62f36625..532aa3e327 100644
--- a/modules/mono/signal_awaiter_utils.h
+++ b/modules/mono/signal_awaiter_utils.h
@@ -68,7 +68,7 @@ public:
};
class EventSignalCallable : public CallableCustom {
- Object *owner;
+ Object *owner = nullptr;
const CSharpScript::EventSignal *event_signal;
public:
diff --git a/modules/mono/utils/string_utils.cpp b/modules/mono/utils/string_utils.cpp
index dd29299330..e6975611d2 100644
--- a/modules/mono/utils/string_utils.cpp
+++ b/modules/mono/utils/string_utils.cpp
@@ -167,15 +167,13 @@ String escape_csharp_keyword(const String &p_name) {
Error read_all_file_utf8(const String &p_path, String &r_content) {
Vector<uint8_t> sourcef;
Error err;
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot open file '" + p_path + "'.");
uint64_t len = f->get_length();
sourcef.resize(len + 1);
uint8_t *w = sourcef.ptrw();
uint64_t r = f->get_buffer(w, len);
- f->close();
- memdelete(f);
ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN);
w[len] = 0;
diff --git a/modules/msdfgen/register_types.cpp b/modules/msdfgen/register_types.cpp
index 69855d93fe..2d3a2a0c69 100644
--- a/modules/msdfgen/register_types.cpp
+++ b/modules/msdfgen/register_types.cpp
@@ -30,6 +30,14 @@
#include "register_types.h"
-void register_msdfgen_types() {}
+void initialize_msdfgen_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+}
-void unregister_msdfgen_types() {}
+void uninitialize_msdfgen_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+}
diff --git a/modules/msdfgen/register_types.h b/modules/msdfgen/register_types.h
index 0e2fed2ce8..749204f390 100644
--- a/modules/msdfgen/register_types.h
+++ b/modules/msdfgen/register_types.h
@@ -31,7 +31,9 @@
#ifndef MSDFGEN_REGISTER_TYPES_H
#define MSDFGEN_REGISTER_TYPES_H
-void register_msdfgen_types();
-void unregister_msdfgen_types();
+#include "modules/register_module_types.h"
+
+void initialize_msdfgen_module(ModuleInitializationLevel p_level);
+void uninitialize_msdfgen_module(ModuleInitializationLevel p_level);
#endif // MSDFGEN_REGISTER_TYPES_H
diff --git a/modules/navigation/SCsub b/modules/navigation/SCsub
index 22b5509b32..24a6b12639 100644
--- a/modules/navigation/SCsub
+++ b/modules/navigation/SCsub
@@ -57,6 +57,8 @@ env.modules_sources += thirdparty_obj
module_obj = []
env_navigation.add_source_files(module_obj, "*.cpp")
+if env["tools"]:
+ env_navigation.add_source_files(module_obj, "editor/*.cpp")
env.modules_sources += module_obj
# Needed to force rebuilding the module files when the thirdparty library is updated.
diff --git a/modules/navigation/navigation_mesh_editor_plugin.cpp b/modules/navigation/editor/navigation_mesh_editor_plugin.cpp
index 511490ba07..c243e3e6e3 100644
--- a/modules/navigation/navigation_mesh_editor_plugin.cpp
+++ b/modules/navigation/editor/navigation_mesh_editor_plugin.cpp
@@ -28,13 +28,14 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef TOOLS_ENABLED
#include "navigation_mesh_editor_plugin.h"
+#ifdef TOOLS_ENABLED
+
+#include "../navigation_mesh_generator.h"
#include "core/io/marshalls.h"
#include "core/io/resource_saver.h"
#include "editor/editor_node.h"
-#include "navigation_mesh_generator.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/gui/box_container.h"
@@ -153,4 +154,4 @@ NavigationMeshEditorPlugin::NavigationMeshEditorPlugin() {
NavigationMeshEditorPlugin::~NavigationMeshEditorPlugin() {
}
-#endif
+#endif // TOOLS_ENABLED
diff --git a/modules/navigation/navigation_mesh_editor_plugin.h b/modules/navigation/editor/navigation_mesh_editor_plugin.h
index d581b453b3..bc9e4185b7 100644
--- a/modules/navigation/navigation_mesh_editor_plugin.h
+++ b/modules/navigation/editor/navigation_mesh_editor_plugin.h
@@ -42,14 +42,14 @@ class NavigationMeshEditor : public Control {
GDCLASS(NavigationMeshEditor, Control);
- AcceptDialog *err_dialog;
+ AcceptDialog *err_dialog = nullptr;
- HBoxContainer *bake_hbox;
- Button *button_bake;
- Button *button_reset;
- Label *bake_info;
+ HBoxContainer *bake_hbox = nullptr;
+ Button *button_bake = nullptr;
+ Button *button_reset = nullptr;
+ Label *bake_info = nullptr;
- NavigationRegion3D *node;
+ NavigationRegion3D *node = nullptr;
void _bake_pressed();
void _clear_pressed();
@@ -68,7 +68,7 @@ public:
class NavigationMeshEditorPlugin : public EditorPlugin {
GDCLASS(NavigationMeshEditorPlugin, EditorPlugin);
- NavigationMeshEditor *navigation_mesh_editor;
+ NavigationMeshEditor *navigation_mesh_editor = nullptr;
public:
virtual String get_name() const override { return "NavigationMesh"; }
@@ -81,6 +81,6 @@ public:
~NavigationMeshEditorPlugin();
};
-#endif
+#endif // TOOLS_ENABLED
-#endif
+#endif // NAVIGATION_MESH_EDITOR_PLUGIN_H
diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp
index f3da85063a..d16d41b438 100644
--- a/modules/navigation/godot_navigation_server.cpp
+++ b/modules/navigation/godot_navigation_server.cpp
@@ -40,43 +40,43 @@
/// an instance of that struct with the submitted parameters.
/// Then, that struct is stored in an array; the `sync` function consume that array.
-#define COMMAND_1(F_NAME, T_0, D_0) \
- struct MERGE(F_NAME, _command) : public SetCommand { \
- T_0 d_0; \
- MERGE(F_NAME, _command) \
- (T_0 p_d_0) : \
- d_0(p_d_0) {} \
- virtual void exec(GodotNavigationServer *server) { \
- server->MERGE(_cmd_, F_NAME)(d_0); \
- } \
- }; \
- void GodotNavigationServer::F_NAME(T_0 D_0) const { \
- auto cmd = memnew(MERGE(F_NAME, _command)( \
- D_0)); \
- add_command(cmd); \
- } \
+#define COMMAND_1(F_NAME, T_0, D_0) \
+ struct MERGE(F_NAME, _command) : public SetCommand { \
+ T_0 d_0; \
+ MERGE(F_NAME, _command) \
+ (T_0 p_d_0) : \
+ d_0(p_d_0) {} \
+ virtual void exec(GodotNavigationServer *server) override { \
+ server->MERGE(_cmd_, F_NAME)(d_0); \
+ } \
+ }; \
+ void GodotNavigationServer::F_NAME(T_0 D_0) const { \
+ auto cmd = memnew(MERGE(F_NAME, _command)( \
+ D_0)); \
+ add_command(cmd); \
+ } \
void GodotNavigationServer::MERGE(_cmd_, F_NAME)(T_0 D_0)
-#define COMMAND_2(F_NAME, T_0, D_0, T_1, D_1) \
- struct MERGE(F_NAME, _command) : public SetCommand { \
- T_0 d_0; \
- T_1 d_1; \
- MERGE(F_NAME, _command) \
- ( \
- T_0 p_d_0, \
- T_1 p_d_1) : \
- d_0(p_d_0), \
- d_1(p_d_1) {} \
- virtual void exec(GodotNavigationServer *server) { \
- server->MERGE(_cmd_, F_NAME)(d_0, d_1); \
- } \
- }; \
- void GodotNavigationServer::F_NAME(T_0 D_0, T_1 D_1) const { \
- auto cmd = memnew(MERGE(F_NAME, _command)( \
- D_0, \
- D_1)); \
- add_command(cmd); \
- } \
+#define COMMAND_2(F_NAME, T_0, D_0, T_1, D_1) \
+ struct MERGE(F_NAME, _command) : public SetCommand { \
+ T_0 d_0; \
+ T_1 d_1; \
+ MERGE(F_NAME, _command) \
+ ( \
+ T_0 p_d_0, \
+ T_1 p_d_1) : \
+ d_0(p_d_0), \
+ d_1(p_d_1) {} \
+ virtual void exec(GodotNavigationServer *server) override { \
+ server->MERGE(_cmd_, F_NAME)(d_0, d_1); \
+ } \
+ }; \
+ void GodotNavigationServer::F_NAME(T_0 D_0, T_1 D_1) const { \
+ auto cmd = memnew(MERGE(F_NAME, _command)( \
+ D_0, \
+ D_1)); \
+ add_command(cmd); \
+ } \
void GodotNavigationServer::MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1)
#define COMMAND_4(F_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3) \
@@ -95,7 +95,7 @@
d_1(p_d_1), \
d_2(p_d_2), \
d_3(p_d_3) {} \
- virtual void exec(GodotNavigationServer *server) { \
+ virtual void exec(GodotNavigationServer *server) override { \
server->MERGE(_cmd_, F_NAME)(d_0, d_1, d_2, d_3); \
} \
}; \
@@ -109,9 +109,7 @@
} \
void GodotNavigationServer::MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3)
-GodotNavigationServer::GodotNavigationServer() :
- NavigationServer3D() {
-}
+GodotNavigationServer::GodotNavigationServer() {}
GodotNavigationServer::~GodotNavigationServer() {
flush_queries();
diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h
index c555a358db..7ad5e2d501 100644
--- a/modules/navigation/godot_navigation_server.h
+++ b/modules/navigation/godot_navigation_server.h
@@ -45,16 +45,16 @@
#define MERGE_INTERNAL(A, B) A##B
#define MERGE(A, B) MERGE_INTERNAL(A, B)
-#define COMMAND_1(F_NAME, T_0, D_0) \
- virtual void F_NAME(T_0 D_0) const; \
+#define COMMAND_1(F_NAME, T_0, D_0) \
+ virtual void F_NAME(T_0 D_0) const override; \
void MERGE(_cmd_, F_NAME)(T_0 D_0)
-#define COMMAND_2(F_NAME, T_0, D_0, T_1, D_1) \
- virtual void F_NAME(T_0 D_0, T_1 D_1) const; \
+#define COMMAND_2(F_NAME, T_0, D_0, T_1, D_1) \
+ virtual void F_NAME(T_0 D_0, T_1 D_1) const override; \
void MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1)
-#define COMMAND_4_DEF(F_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3, D_3_DEF) \
- virtual void F_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3 = D_3_DEF) const; \
+#define COMMAND_4_DEF(F_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3, D_3_DEF) \
+ virtual void F_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3 = D_3_DEF) const override; \
void MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3)
class GodotNavigationServer;
@@ -85,38 +85,38 @@ public:
void add_command(SetCommand *command) const;
- virtual RID map_create() const;
+ virtual RID map_create() const override;
COMMAND_2(map_set_active, RID, p_map, bool, p_active);
- virtual bool map_is_active(RID p_map) const;
+ virtual bool map_is_active(RID p_map) const override;
COMMAND_2(map_set_up, RID, p_map, Vector3, p_up);
- virtual Vector3 map_get_up(RID p_map) const;
+ virtual Vector3 map_get_up(RID p_map) const override;
COMMAND_2(map_set_cell_size, RID, p_map, real_t, p_cell_size);
- virtual real_t map_get_cell_size(RID p_map) const;
+ virtual real_t map_get_cell_size(RID p_map) const override;
COMMAND_2(map_set_edge_connection_margin, RID, p_map, real_t, p_connection_margin);
- virtual real_t map_get_edge_connection_margin(RID p_map) const;
+ virtual real_t map_get_edge_connection_margin(RID p_map) const override;
- virtual Vector<Vector3> map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_layers = 1) const;
+ virtual Vector<Vector3> map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_layers = 1) const override;
- virtual Vector3 map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision = false) const;
- virtual Vector3 map_get_closest_point(RID p_map, const Vector3 &p_point) const;
- virtual Vector3 map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const;
- virtual RID map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const;
+ virtual Vector3 map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision = false) const override;
+ virtual Vector3 map_get_closest_point(RID p_map, const Vector3 &p_point) const override;
+ virtual Vector3 map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const override;
+ virtual RID map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const override;
- virtual RID region_create() const;
+ virtual RID region_create() const override;
COMMAND_2(region_set_map, RID, p_region, RID, p_map);
COMMAND_2(region_set_layers, RID, p_region, uint32_t, p_layers);
- virtual uint32_t region_get_layers(RID p_region) const;
+ virtual uint32_t region_get_layers(RID p_region) const override;
COMMAND_2(region_set_transform, RID, p_region, Transform3D, p_transform);
COMMAND_2(region_set_navmesh, RID, p_region, Ref<NavigationMesh>, p_nav_mesh);
- virtual void region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const;
- virtual int region_get_connections_count(RID p_region) const;
- virtual Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const;
- virtual Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const;
+ virtual void region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const override;
+ virtual int region_get_connections_count(RID p_region) const override;
+ virtual Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const override;
+ virtual Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const override;
- virtual RID agent_create() const;
+ virtual RID agent_create() const override;
COMMAND_2(agent_set_map, RID, p_agent, RID, p_map);
COMMAND_2(agent_set_neighbor_dist, RID, p_agent, real_t, p_dist);
COMMAND_2(agent_set_max_neighbors, RID, p_agent, int, p_count);
@@ -127,15 +127,15 @@ public:
COMMAND_2(agent_set_target_velocity, RID, p_agent, Vector3, p_velocity);
COMMAND_2(agent_set_position, RID, p_agent, Vector3, p_position);
COMMAND_2(agent_set_ignore_y, RID, p_agent, bool, p_ignore);
- virtual bool agent_is_map_changed(RID p_agent) const;
+ virtual bool agent_is_map_changed(RID p_agent) const override;
COMMAND_4_DEF(agent_set_callback, RID, p_agent, Object *, p_receiver, StringName, p_method, Variant, p_udata, Variant());
COMMAND_1(free, RID, p_object);
- virtual void set_active(bool p_active) const;
+ virtual void set_active(bool p_active) const override;
void flush_queries();
- virtual void process(real_t p_delta_time);
+ virtual void process(real_t p_delta_time) override;
};
#undef COMMAND_1
diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp
index 1151df6390..cbc0adc574 100644
--- a/modules/navigation/nav_map.cpp
+++ b/modules/navigation/nav_map.cpp
@@ -30,7 +30,6 @@
#include "nav_map.h"
-#include "core/os/threaded_array_processor.h"
#include "nav_region.h"
#include "rvo_agent.h"
@@ -142,10 +141,10 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
bool is_reachable = true;
while (true) {
- gd::NavigationPoly *least_cost_poly = &navigation_polys[least_cost_id];
-
// Takes the current least_cost_poly neighbors (iterating over its edges) and compute the traveled_distance.
- for (size_t i = 0; i < least_cost_poly->poly->edges.size(); i++) {
+ for (size_t i = 0; i < navigation_polys[least_cost_id].poly->edges.size(); i++) {
+ gd::NavigationPoly *least_cost_poly = &navigation_polys[least_cost_id];
+
const gd::Edge &edge = least_cost_poly->poly->edges[i];
// Iterate over connections in this edge, then compute the new optimized travel distance assigned to this polygon.
@@ -226,6 +225,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
navigation_polys.push_back(np);
to_visit.clear();
to_visit.push_back(0);
+ least_cost_id = 0;
reachable_end = nullptr;
@@ -245,6 +245,8 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
}
}
+ ERR_BREAK(least_cost_id == -1);
+
// Stores the further reachable end polygon, in case our goal is not reachable.
if (is_reachable) {
float d = navigation_polys[least_cost_id].entry.distance_to(p_destination);
@@ -254,8 +256,6 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
}
}
- ERR_BREAK(least_cost_id == -1);
-
// Check if we reached the end
if (navigation_polys[least_cost_id].poly == end_poly) {
found_route = true;
@@ -351,11 +351,15 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
// Add mid points
int np_id = least_cost_id;
- while (np_id != -1) {
- path.push_back(navigation_polys[np_id].entry);
+ while (np_id != -1 && navigation_polys[np_id].back_navigation_poly_id != -1) {
+ int prev = navigation_polys[np_id].back_navigation_edge;
+ int prev_n = (navigation_polys[np_id].back_navigation_edge + 1) % navigation_polys[np_id].poly->points.size();
+ Vector3 point = (navigation_polys[np_id].poly->points[prev].pos + navigation_polys[np_id].poly->points[prev_n].pos) * 0.5;
+ path.push_back(point);
np_id = navigation_polys[np_id].back_navigation_poly_id;
}
+ path.push_back(begin_point);
path.reverse();
}
@@ -669,7 +673,10 @@ void NavMap::compute_single_step(uint32_t index, RvoAgent **agent) {
void NavMap::step(real_t p_deltatime) {
deltatime = p_deltatime;
if (controlled_agents.size() > 0) {
- thread_process_array(
+ if (step_work_pool.get_thread_count() == 0) {
+ step_work_pool.init();
+ }
+ step_work_pool.do_work(
controlled_agents.size(),
this,
&NavMap::compute_single_step,
@@ -714,3 +721,10 @@ void NavMap::clip_path(const std::vector<gd::NavigationPoly> &p_navigation_polys
}
}
}
+
+NavMap::NavMap() {
+}
+
+NavMap::~NavMap() {
+ step_work_pool.finish();
+}
diff --git a/modules/navigation/nav_map.h b/modules/navigation/nav_map.h
index f46297a7ce..5232e42bed 100644
--- a/modules/navigation/nav_map.h
+++ b/modules/navigation/nav_map.h
@@ -35,6 +35,7 @@
#include "core/math/math_defs.h"
#include "core/templates/map.h"
+#include "core/templates/thread_work_pool.h"
#include "nav_utils.h"
#include <KdTree.h>
@@ -80,8 +81,12 @@ class NavMap : public NavRid {
/// Change the id each time the map is updated.
uint32_t map_update_id = 0;
+ /// Pooled threads for computing steps
+ ThreadWorkPool step_work_pool;
+
public:
- NavMap() {}
+ NavMap();
+ ~NavMap();
void set_up(Vector3 p_up);
Vector3 get_up() const {
diff --git a/modules/navigation/nav_utils.h b/modules/navigation/nav_utils.h
index 0c02885b10..5b6c695ca4 100644
--- a/modules/navigation/nav_utils.h
+++ b/modules/navigation/nav_utils.h
@@ -89,7 +89,7 @@ struct Edge {
};
struct Polygon {
- NavRegion *owner;
+ NavRegion *owner = nullptr;
/// The points of this `Polygon`
std::vector<Point> points;
diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp
index 61c3cefc7a..2d6c78f704 100644
--- a/modules/navigation/navigation_mesh_generator.cpp
+++ b/modules/navigation/navigation_mesh_generator.cpp
@@ -34,7 +34,6 @@
#include "core/math/convex_hull.h"
#include "core/os/thread.h"
-#include "scene/3d/collision_shape_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/multimesh_instance_3d.h"
#include "scene/3d/physics_body_3d.h"
@@ -124,6 +123,28 @@ void NavigationMeshGenerator::_add_mesh(const Ref<Mesh> &p_mesh, const Transform
}
}
+void NavigationMeshGenerator::_add_mesh_array(const Array &p_array, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices) {
+ Vector<Vector3> mesh_vertices = p_array[Mesh::ARRAY_VERTEX];
+ const Vector3 *vr = mesh_vertices.ptr();
+
+ Vector<int> mesh_indices = p_array[Mesh::ARRAY_INDEX];
+ const int *ir = mesh_indices.ptr();
+
+ const int face_count = mesh_indices.size() / 3;
+ const int current_vertex_count = p_vertices.size() / 3;
+
+ for (int j = 0; j < mesh_vertices.size(); j++) {
+ _add_vertex(p_xform.xform(vr[j]), p_vertices);
+ }
+
+ for (int j = 0; j < face_count; j++) {
+ // CCW
+ p_indices.push_back(current_vertex_count + (ir[j * 3 + 0]));
+ p_indices.push_back(current_vertex_count + (ir[j * 3 + 2]));
+ p_indices.push_back(current_vertex_count + (ir[j * 3 + 1]));
+ }
+}
+
void NavigationMeshGenerator::_add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices) {
int face_count = p_faces.size() / 3;
int current_vertex_count = p_vertices.size() / 3;
@@ -180,50 +201,48 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans
StaticBody3D *static_body = Object::cast_to<StaticBody3D>(p_node);
if (static_body->get_collision_layer() & p_collision_mask) {
- for (int i = 0; i < p_node->get_child_count(); ++i) {
- Node *child = p_node->get_child(i);
- if (Object::cast_to<CollisionShape3D>(child)) {
- CollisionShape3D *col_shape = Object::cast_to<CollisionShape3D>(child);
-
- Transform3D transform = p_navmesh_transform * static_body->get_global_transform() * col_shape->get_transform();
+ List<uint32_t> shape_owners;
+ static_body->get_shape_owners(&shape_owners);
+ for (uint32_t shape_owner : shape_owners) {
+ const int shape_count = static_body->shape_owner_get_shape_count(shape_owner);
+ for (int i = 0; i < shape_count; i++) {
+ Ref<Shape3D> s = static_body->shape_owner_get_shape(shape_owner, i);
+ if (s.is_null()) {
+ continue;
+ }
- Ref<Mesh> mesh;
- Ref<Shape3D> s = col_shape->get_shape();
+ const Transform3D transform = p_navmesh_transform * static_body->get_global_transform() * static_body->shape_owner_get_transform(shape_owner);
BoxShape3D *box = Object::cast_to<BoxShape3D>(*s);
if (box) {
- Ref<BoxMesh> box_mesh;
- box_mesh.instantiate();
- box_mesh->set_size(box->get_size());
- mesh = box_mesh;
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ BoxMesh::create_mesh_array(arr, box->get_size());
+ _add_mesh_array(arr, transform, p_vertices, p_indices);
}
CapsuleShape3D *capsule = Object::cast_to<CapsuleShape3D>(*s);
if (capsule) {
- Ref<CapsuleMesh> capsule_mesh;
- capsule_mesh.instantiate();
- capsule_mesh->set_radius(capsule->get_radius());
- capsule_mesh->set_height(capsule->get_height());
- mesh = capsule_mesh;
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ CapsuleMesh::create_mesh_array(arr, capsule->get_radius(), capsule->get_height());
+ _add_mesh_array(arr, transform, p_vertices, p_indices);
}
CylinderShape3D *cylinder = Object::cast_to<CylinderShape3D>(*s);
if (cylinder) {
- Ref<CylinderMesh> cylinder_mesh;
- cylinder_mesh.instantiate();
- cylinder_mesh->set_height(cylinder->get_height());
- cylinder_mesh->set_bottom_radius(cylinder->get_radius());
- cylinder_mesh->set_top_radius(cylinder->get_radius());
- mesh = cylinder_mesh;
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ CylinderMesh::create_mesh_array(arr, cylinder->get_radius(), cylinder->get_radius(), cylinder->get_height());
+ _add_mesh_array(arr, transform, p_vertices, p_indices);
}
SphereShape3D *sphere = Object::cast_to<SphereShape3D>(*s);
if (sphere) {
- Ref<SphereMesh> sphere_mesh;
- sphere_mesh.instantiate();
- sphere_mesh->set_radius(sphere->get_radius());
- sphere_mesh->set_height(sphere->get_radius() * 2.0);
- mesh = sphere_mesh;
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ SphereMesh::create_mesh_array(arr, sphere->get_radius(), sphere->get_radius() * 2.0);
+ _add_mesh_array(arr, transform, p_vertices, p_indices);
}
ConcavePolygonShape3D *concave_polygon = Object::cast_to<ConcavePolygonShape3D>(*s);
@@ -254,10 +273,6 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans
_add_faces(faces, transform, p_vertices, p_indices);
}
}
-
- if (mesh.is_valid()) {
- _add_mesh(mesh, transform, p_vertices, p_indices);
- }
}
}
}
@@ -284,44 +299,39 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans
RID shape = shapes[i + 1];
PhysicsServer3D::ShapeType type = PhysicsServer3D::get_singleton()->shape_get_type(shape);
Variant data = PhysicsServer3D::get_singleton()->shape_get_data(shape);
- Ref<Mesh> mesh;
switch (type) {
case PhysicsServer3D::SHAPE_SPHERE: {
real_t radius = data;
- Ref<SphereMesh> sphere_mesh;
- sphere_mesh.instantiate();
- sphere_mesh->set_radius(radius);
- sphere_mesh->set_height(radius * 2.0);
- mesh = sphere_mesh;
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ SphereMesh::create_mesh_array(arr, radius, radius * 2.0);
+ _add_mesh_array(arr, shapes[i], p_vertices, p_indices);
} break;
case PhysicsServer3D::SHAPE_BOX: {
Vector3 extents = data;
- Ref<BoxMesh> box_mesh;
- box_mesh.instantiate();
- box_mesh->set_size(2.0 * extents);
- mesh = box_mesh;
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ BoxMesh::create_mesh_array(arr, extents * 2.0);
+ _add_mesh_array(arr, shapes[i], p_vertices, p_indices);
} break;
case PhysicsServer3D::SHAPE_CAPSULE: {
Dictionary dict = data;
real_t radius = dict["radius"];
real_t height = dict["height"];
- Ref<CapsuleMesh> capsule_mesh;
- capsule_mesh.instantiate();
- capsule_mesh->set_radius(radius);
- capsule_mesh->set_height(height);
- mesh = capsule_mesh;
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ CapsuleMesh::create_mesh_array(arr, radius, height);
+ _add_mesh_array(arr, shapes[i], p_vertices, p_indices);
} break;
case PhysicsServer3D::SHAPE_CYLINDER: {
Dictionary dict = data;
real_t radius = dict["radius"];
real_t height = dict["height"];
- Ref<CylinderMesh> cylinder_mesh;
- cylinder_mesh.instantiate();
- cylinder_mesh->set_height(height);
- cylinder_mesh->set_bottom_radius(radius);
- cylinder_mesh->set_top_radius(radius);
- mesh = cylinder_mesh;
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ CylinderMesh::create_mesh_array(arr, radius, radius, height);
+ _add_mesh_array(arr, shapes[i], p_vertices, p_indices);
} break;
case PhysicsServer3D::SHAPE_CONVEX_POLYGON: {
PackedVector3Array vertices = data;
@@ -354,10 +364,6 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans
WARN_PRINT("Unsupported collision shape type.");
} break;
}
-
- if (mesh.is_valid()) {
- _add_mesh(mesh, shapes[i], p_vertices, p_indices);
- }
}
}
}
diff --git a/modules/navigation/navigation_mesh_generator.h b/modules/navigation/navigation_mesh_generator.h
index 21f7a4941b..8cc1531b53 100644
--- a/modules/navigation/navigation_mesh_generator.h
+++ b/modules/navigation/navigation_mesh_generator.h
@@ -51,6 +51,7 @@ protected:
static void _add_vertex(const Vector3 &p_vec3, Vector<float> &p_vertices);
static void _add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices);
+ static void _add_mesh_array(const Array &p_array, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices);
static void _add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices);
static void _parse_geometry(const Transform3D &p_navmesh_transform, Node *p_node, Vector<float> &p_vertices, Vector<int> &p_indices, NavigationMesh::ParsedGeometryType p_generate_from, uint32_t p_collision_mask, bool p_recurse_children);
diff --git a/modules/navigation/register_types.cpp b/modules/navigation/register_types.cpp
index e2264e843c..62ae2c7f02 100644
--- a/modules/navigation/register_types.cpp
+++ b/modules/navigation/register_types.cpp
@@ -40,7 +40,7 @@
#endif
#ifdef TOOLS_ENABLED
-#include "navigation_mesh_editor_plugin.h"
+#include "editor/navigation_mesh_editor_plugin.h"
#endif
#ifndef _3D_DISABLED
@@ -51,21 +51,29 @@ NavigationServer3D *new_server() {
return memnew(GodotNavigationServer);
}
-void register_navigation_types() {
- NavigationServer3DManager::set_default_server(new_server);
+void initialize_navigation_module(ModuleInitializationLevel p_level) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) {
+ NavigationServer3DManager::set_default_server(new_server);
#ifndef _3D_DISABLED
- _nav_mesh_generator = memnew(NavigationMeshGenerator);
- GDREGISTER_CLASS(NavigationMeshGenerator);
- Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationMeshGenerator", NavigationMeshGenerator::get_singleton()));
+ _nav_mesh_generator = memnew(NavigationMeshGenerator);
+ GDREGISTER_CLASS(NavigationMeshGenerator);
+ Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationMeshGenerator", NavigationMeshGenerator::get_singleton()));
#endif
+ }
#ifdef TOOLS_ENABLED
- EditorPlugins::add_by_type<NavigationMeshEditorPlugin>();
+ if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
+ EditorPlugins::add_by_type<NavigationMeshEditorPlugin>();
+ }
#endif
}
-void unregister_navigation_types() {
+void uninitialize_navigation_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SERVERS) {
+ return;
+ }
+
#ifndef _3D_DISABLED
if (_nav_mesh_generator) {
memdelete(_nav_mesh_generator);
diff --git a/modules/navigation/register_types.h b/modules/navigation/register_types.h
index 11fa5769d7..c4dbd19ed3 100644
--- a/modules/navigation/register_types.h
+++ b/modules/navigation/register_types.h
@@ -31,7 +31,9 @@
#ifndef NAVIGATION_REGISTER_TYPES_H
#define NAVIGATION_REGISTER_TYPES_H
-void register_navigation_types();
-void unregister_navigation_types();
+#include "modules/register_module_types.h"
+
+void initialize_navigation_module(ModuleInitializationLevel p_level);
+void uninitialize_navigation_module(ModuleInitializationLevel p_level);
#endif // NAVIGATION_REGISTER_TYPES_H
diff --git a/modules/opensimplex/SCsub b/modules/noise/SCsub
index 86d77c3dfb..1430aa0c4e 100644
--- a/modules/opensimplex/SCsub
+++ b/modules/noise/SCsub
@@ -3,21 +3,21 @@
Import("env")
Import("env_modules")
-env_opensimplex = env_modules.Clone()
+env_noise = env_modules.Clone()
# Thirdparty source files
thirdparty_obj = []
-thirdparty_dir = "#thirdparty/misc/"
+thirdparty_dir = "#thirdparty/noise/"
thirdparty_sources = [
- "open-simplex-noise.c",
+ # Add C++ source files for noise modules here
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
-env_opensimplex.Prepend(CPPPATH=[thirdparty_dir])
+env_noise.Prepend(CPPPATH=[thirdparty_dir])
-env_thirdparty = env_opensimplex.Clone()
+env_thirdparty = env_noise.Clone()
env_thirdparty.disable_warnings()
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
env.modules_sources += thirdparty_obj
@@ -26,7 +26,8 @@ env.modules_sources += thirdparty_obj
module_obj = []
-env_opensimplex.add_source_files(module_obj, "*.cpp")
+env_noise.add_source_files(module_obj, "*.cpp")
+env_noise.add_source_files(module_obj, "editor/*.cpp")
env.modules_sources += module_obj
# Needed to force rebuilding the module files when the thirdparty library is updated.
diff --git a/modules/opensimplex/config.py b/modules/noise/config.py
index 90b85dbd70..74db20f2a4 100644
--- a/modules/opensimplex/config.py
+++ b/modules/noise/config.py
@@ -8,8 +8,9 @@ def configure(env):
def get_doc_classes():
return [
+ "FastNoiseLite",
+ "Noise",
"NoiseTexture",
- "OpenSimplexNoise",
]
diff --git a/modules/noise/doc_classes/FastNoiseLite.xml b/modules/noise/doc_classes/FastNoiseLite.xml
new file mode 100644
index 0000000000..6ca4ba2d46
--- /dev/null
+++ b/modules/noise/doc_classes/FastNoiseLite.xml
@@ -0,0 +1,163 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="FastNoiseLite" inherits="Noise" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+ <brief_description>
+ Generates noise using the FastNoiseLite library.
+ </brief_description>
+ <description>
+ This class generates noise using the FastNoiseLite library, which is a collection of several noise algorithms including Cellular, Perlin, Value, and more.
+ Most generated noise values are in the range of [code][-1,1][/code], however not always. Some of the cellular noise algorithms return results above [code]1[/code].
+ </description>
+ <tutorials>
+ </tutorials>
+ <members>
+ <member name="cellular_distance_function" type="int" setter="set_cellular_distance_function" getter="get_cellular_distance_function" enum="FastNoiseLite.CellularDistanceFunction" default="0">
+ Determines how the distance to the nearest/second-nearest point is computed. See [enum CellularDistanceFunction] for options.
+ </member>
+ <member name="cellular_jitter" type="float" setter="set_cellular_jitter" getter="get_cellular_jitter" default="0.45">
+ Maximum distance a point can move off of its grid position. Set to [code]0[/code] for an even grid.
+ </member>
+ <member name="cellular_return_type" type="int" setter="set_cellular_return_type" getter="get_cellular_return_type" enum="FastNoiseLite.CellularReturnType" default="1">
+ Return type from cellular noise calculations. See [enum CellularReturnType].
+ </member>
+ <member name="domain_warp_amplitude" type="float" setter="set_domain_warp_amplitude" getter="get_domain_warp_amplitude" default="30.0">
+ Sets the maximum warp distance from the origin.
+ </member>
+ <member name="domain_warp_enabled" type="bool" setter="set_domain_warp_enabled" getter="is_domain_warp_enabled" default="false">
+ If enabled, another FastNoiseLite instance is used to warp the space, resulting in a distortion of the noise.
+ </member>
+ <member name="domain_warp_fractal_gain" type="float" setter="set_domain_warp_fractal_gain" getter="get_domain_warp_fractal_gain" default="0.5">
+ Determines the strength of each subsequent layer of the noise which is used to warp the space.
+ A low value places more emphasis on the lower frequency base layers, while a high value puts more emphasis on the higher frequency layers.
+ </member>
+ <member name="domain_warp_fractal_lacunarity" type="float" setter="set_domain_warp_fractal_lacunarity" getter="get_domain_warp_fractal_lacunarity" default="6.0">
+ Octave lacunarity of the fractal noise which warps the space. Increasing this value results in higher octaves producing noise with finer details and a rougher appearance.
+ </member>
+ <member name="domain_warp_fractal_octaves" type="int" setter="set_domain_warp_fractal_octaves" getter="get_domain_warp_fractal_octaves" default="5">
+ The number of noise layers that are sampled to get the final value for the fractal noise which warps the space.
+ </member>
+ <member name="domain_warp_fractal_type" type="int" setter="set_domain_warp_fractal_type" getter="get_domain_warp_fractal_type" enum="FastNoiseLite.DomainWarpFractalType" default="1">
+ The method for combining octaves into a fractal which is used to warp the space. See [enum DomainWarpFractalType].
+ </member>
+ <member name="domain_warp_frequency" type="float" setter="set_domain_warp_frequency" getter="get_domain_warp_frequency" default="0.05">
+ Frequency of the noise which warps the space. Low frequency results in smooth noise while high frequency results in rougher, more granular noise.
+ </member>
+ <member name="domain_warp_type" type="int" setter="set_domain_warp_type" getter="get_domain_warp_type" enum="FastNoiseLite.DomainWarpType" default="0">
+ Sets the warp algorithm. See [enum DomainWarpType].
+ </member>
+ <member name="fractal_gain" type="float" setter="set_fractal_gain" getter="get_fractal_gain" default="0.5">
+ Determines the strength of each subsequent layer of noise in fractal noise.
+ A low value places more emphasis on the lower frequency base layers, while a high value puts more emphasis on the higher frequency layers.
+ </member>
+ <member name="fractal_lacunarity" type="float" setter="set_fractal_lacunarity" getter="get_fractal_lacunarity" default="2.0">
+ Frequency multiplier between subsequent octaves. Increasing this value results in higher octaves producing noise with finer details and a rougher appearance.
+ </member>
+ <member name="fractal_octaves" type="int" setter="set_fractal_octaves" getter="get_fractal_octaves" default="5">
+ The number of noise layers that are sampled to get the final value for fractal noise types.
+ </member>
+ <member name="fractal_ping_pong_strength" type="float" setter="set_fractal_ping_pong_strength" getter="get_fractal_ping_pong_strength" default="2.0">
+ Sets the strength of the fractal ping pong type.
+ </member>
+ <member name="fractal_type" type="int" setter="set_fractal_type" getter="get_fractal_type" enum="FastNoiseLite.FractalType" default="1">
+ The method for combining octaves into a fractal. See [enum FractalType].
+ </member>
+ <member name="fractal_weighted_strength" type="float" setter="set_fractal_weighted_strength" getter="get_fractal_weighted_strength" default="0.0">
+ Higher weighting means higher octaves have less impact if lower octaves have a large impact.
+ </member>
+ <member name="frequency" type="float" setter="set_frequency" getter="get_frequency" default="0.01">
+ The frequency for all noise types. Low frequency results in smooth noise while high frequency results in rougher, more granular noise.
+ </member>
+ <member name="noise_type" type="int" setter="set_noise_type" getter="get_noise_type" enum="FastNoiseLite.NoiseType" default="1">
+ The noise algorithm used. See [enum NoiseType].
+ </member>
+ <member name="offset" type="Vector3" setter="set_offset" getter="get_offset" default="Vector3(0, 0, 0)">
+ Translate the noise input coordinates by the given [Vector3].
+ </member>
+ <member name="seed" type="int" setter="set_seed" getter="get_seed" default="0">
+ The random number seed for all noise types.
+ </member>
+ </members>
+ <constants>
+ <constant name="TYPE_VALUE" value="5" enum="NoiseType">
+ A lattice of points are assigned random values then interpolated based on neighboring values.
+ </constant>
+ <constant name="TYPE_VALUE_CUBIC" value="4" enum="NoiseType">
+ Similar to Value noise, but slower. Has more variance in peaks and valleys.
+ Cubic noise can be used to avoid certain artifacts when using value noise to create a bumpmap. In general, you should always use this mode if the value noise is being used for a heightmap or bumpmap.
+ </constant>
+ <constant name="TYPE_PERLIN" value="3" enum="NoiseType">
+ A lattice of random gradients. Their dot products are interpolated to obtain values in between the lattices.
+ </constant>
+ <constant name="TYPE_CELLULAR" value="2" enum="NoiseType">
+ Cellular includes both Worley noise and Voronoi diagrams which creates various regions of the same value.
+ </constant>
+ <constant name="TYPE_SIMPLEX" value="0" enum="NoiseType">
+ As opposed to [constant TYPE_PERLIN], gradients exist in a simplex lattice rather than a grid lattice, avoiding directional artifacts.
+ </constant>
+ <constant name="TYPE_SIMPLEX_SMOOTH" value="1" enum="NoiseType">
+ Modified, higher quality version of [constant TYPE_SIMPLEX], but slower.
+ </constant>
+ <constant name="FRACTAL_NONE" value="0" enum="FractalType">
+ No fractal noise.
+ </constant>
+ <constant name="FRACTAL_FBM" value="1" enum="FractalType">
+ Method using Fractional Brownian Motion to combine octaves into a fractal.
+ </constant>
+ <constant name="FRACTAL_RIDGED" value="2" enum="FractalType">
+ Method of combining octaves into a fractal resulting in a "ridged" look.
+ </constant>
+ <constant name="FRACTAL_PING_PONG" value="3" enum="FractalType">
+ Method of combining octaves into a fractal with a ping pong effect.
+ </constant>
+ <constant name="DISTANCE_EUCLIDEAN" value="0" enum="CellularDistanceFunction">
+ Euclidean distance to the nearest point.
+ </constant>
+ <constant name="DISTANCE_EUCLIDEAN_SQUARED" value="1" enum="CellularDistanceFunction">
+ Squared Euclidean distance to the nearest point.
+ </constant>
+ <constant name="DISTANCE_MANHATTAN" value="2" enum="CellularDistanceFunction">
+ Manhattan distance (taxicab metric) to the nearest point.
+ </constant>
+ <constant name="DISTANCE_HYBRID" value="3" enum="CellularDistanceFunction">
+ Blend of [constant DISTANCE_EUCLIDEAN] and [constant DISTANCE_MANHATTAN] to give curved cell boundaries
+ </constant>
+ <constant name="RETURN_CELL_VALUE" value="0" enum="CellularReturnType">
+ The cellular distance function will return the same value for all points within a cell.
+ </constant>
+ <constant name="RETURN_DISTANCE" value="1" enum="CellularReturnType">
+ The cellular distance function will return a value determined by the distance to the nearest point.
+ </constant>
+ <constant name="RETURN_DISTANCE2" value="2" enum="CellularReturnType">
+ The cellular distance function returns the distance to the second-nearest point.
+ </constant>
+ <constant name="RETURN_DISTANCE2_ADD" value="3" enum="CellularReturnType">
+ The distance to the nearest point is added to the distance to the second-nearest point.
+ </constant>
+ <constant name="RETURN_DISTANCE2_SUB" value="4" enum="CellularReturnType">
+ The distance to the nearest point is subtracted from the distance to the second-nearest point.
+ </constant>
+ <constant name="RETURN_DISTANCE2_MUL" value="5" enum="CellularReturnType">
+ The distance to the nearest point is multiplied with the distance to the second-nearest point.
+ </constant>
+ <constant name="RETURN_DISTANCE2_DIV" value="6" enum="CellularReturnType">
+ The distance to the nearest point is divided by the distance to the second-nearest point.
+ </constant>
+ <constant name="DOMAIN_WARP_SIMPLEX" value="0" enum="DomainWarpType">
+ The domain is warped using the simplex noise algorithm.
+ </constant>
+ <constant name="DOMAIN_WARP_SIMPLEX_REDUCED" value="1" enum="DomainWarpType">
+ The domain is warped using a simplified version of the simplex noise algorithm.
+ </constant>
+ <constant name="DOMAIN_WARP_BASIC_GRID" value="2" enum="DomainWarpType">
+ The domain is warped using a simple noise grid (not as smooth as the other methods, but more performant).
+ </constant>
+ <constant name="DOMAIN_WARP_FRACTAL_NONE" value="0" enum="DomainWarpFractalType">
+ No fractal noise for warping the space.
+ </constant>
+ <constant name="DOMAIN_WARP_FRACTAL_PROGRESSIVE" value="1" enum="DomainWarpFractalType">
+ Warping the space progressively, octave for octave, resulting in a more "liquified" distortion.
+ </constant>
+ <constant name="DOMAIN_WARP_FRACTAL_INDEPENDENT" value="2" enum="DomainWarpFractalType">
+ Warping the space independently for each octave, resulting in a more chaotic distortion.
+ </constant>
+ </constants>
+</class>
diff --git a/modules/noise/doc_classes/Noise.xml b/modules/noise/doc_classes/Noise.xml
new file mode 100644
index 0000000000..5af204575c
--- /dev/null
+++ b/modules/noise/doc_classes/Noise.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="Noise" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+ <brief_description>
+ Abstract base class for noise generators.
+ </brief_description>
+ <description>
+ This class defines the interface for noise generation libraries to inherit from.
+ A default get_seamless_noise() implementation is provided for libraries that do not provide seamless noise. This function requests a larger image from get_image(), reverses the quadrants of the image, then uses the strips of extra width to blend over the seams.
+ Inheriting noise classes can optionally override this function to provide a more optimal algorithm.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_image" qualifiers="const">
+ <return type="Image" />
+ <argument index="0" name="width" type="int" />
+ <argument index="1" name="height" type="int" />
+ <argument index="2" name="invert" type="bool" default="false" />
+ <argument index="3" name="in_3d_space" type="bool" default="false" />
+ <description>
+ Returns a 2D [Image] noise image.
+ </description>
+ </method>
+ <method name="get_noise_1d" qualifiers="const">
+ <return type="float" />
+ <argument index="0" name="x" type="float" />
+ <description>
+ Returns the 1D noise value at the given (x) coordinate.
+ </description>
+ </method>
+ <method name="get_noise_2d" qualifiers="const">
+ <return type="float" />
+ <argument index="0" name="x" type="float" />
+ <argument index="1" name="y" type="float" />
+ <description>
+ Returns the 2D noise value at the given position.
+ </description>
+ </method>
+ <method name="get_noise_2dv" qualifiers="const">
+ <return type="float" />
+ <argument index="0" name="v" type="Vector2" />
+ <description>
+ Returns the 2D noise value at the given position.
+ </description>
+ </method>
+ <method name="get_noise_3d" qualifiers="const">
+ <return type="float" />
+ <argument index="0" name="x" type="float" />
+ <argument index="1" name="y" type="float" />
+ <argument index="2" name="z" type="float" />
+ <description>
+ Returns the 3D noise value at the given position.
+ </description>
+ </method>
+ <method name="get_noise_3dv" qualifiers="const">
+ <return type="float" />
+ <argument index="0" name="v" type="Vector3" />
+ <description>
+ Returns the 3D noise value at the given position.
+ </description>
+ </method>
+ <method name="get_seamless_image" qualifiers="const">
+ <return type="Image" />
+ <argument index="0" name="width" type="int" />
+ <argument index="1" name="height" type="int" />
+ <argument index="2" name="invert" type="bool" default="false" />
+ <argument index="3" name="in_3d_space" type="bool" default="false" />
+ <argument index="4" name="skirt" type="float" default="0.1" />
+ <description>
+ Returns a seamless 2D [Image] noise image.
+ </description>
+ </method>
+ </methods>
+</class>
diff --git a/modules/noise/doc_classes/NoiseTexture.xml b/modules/noise/doc_classes/NoiseTexture.xml
new file mode 100644
index 0000000000..62a223b387
--- /dev/null
+++ b/modules/noise/doc_classes/NoiseTexture.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="NoiseTexture" inherits="Texture2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+ <brief_description>
+ A texture filled with noise generated by a [Noise] object.
+ </brief_description>
+ <description>
+ Uses [FastNoiseLite] or other libraries to fill the texture data of your desired size.
+ NoiseTexture can also generate normalmap textures.
+ The class uses [Thread]s to generate the texture data internally, so [method Texture2D.get_image] may return [code]null[/code] if the generation process has not completed yet. In that case, you need to wait for the texture to be generated before accessing the image and the generated byte data:
+ [codeblock]
+ var texture = NoiseTexture.new()
+ texture.noise = FastNoiseLite.new()
+ await texture.changed
+ var image = texture.get_image()
+ var data = image.get_data()
+ [/codeblock]
+ </description>
+ <tutorials>
+ </tutorials>
+ <members>
+ <member name="as_normal_map" type="bool" setter="set_as_normal_map" getter="is_normal_map" default="false">
+ If [code]true[/code], the resulting texture contains a normal map created from the original noise interpreted as a bump map.
+ </member>
+ <member name="bump_strength" type="float" setter="set_bump_strength" getter="get_bump_strength" default="8.0">
+ Strength of the bump maps used in this texture. A higher value will make the bump maps appear larger while a lower value will make them appear softer.
+ </member>
+ <member name="color_ramp" type="Gradient" setter="set_color_ramp" getter="get_color_ramp">
+ A [Gradient] which is used to map the luminance of each pixel to a color value.
+ </member>
+ <member name="generate_mipmaps" type="bool" setter="set_generate_mipmaps" getter="is_generating_mipmaps" default="true">
+ Determines whether mipmaps are generated for this texture.
+ Enabling this results in less texture aliasing, but the noise texture generation may take longer.
+ Requires (anisotropic) mipmap filtering to be enabled for a material to have an effect.
+ </member>
+ <member name="height" type="int" setter="set_height" getter="get_height" default="512">
+ Height of the generated texture.
+ </member>
+ <member name="in_3d_space" type="bool" setter="set_in_3d_space" getter="is_in_3d_space" default="false">
+ Determines whether the noise image is calculated in 3D space. May result in reduced contrast.
+ </member>
+ <member name="invert" type="bool" setter="set_invert" getter="get_invert" default="false">
+ If [code]true[/code], inverts the noise texture. White becomes black, black becomes white.
+ </member>
+ <member name="noise" type="Noise" setter="set_noise" getter="get_noise">
+ The instance of the [Noise] object.
+ </member>
+ <member name="seamless" type="bool" setter="set_seamless" getter="get_seamless" default="false">
+ If [code]true[/code], a seamless texture is requested from the [Noise] resource.
+ [b]Note:[/b] Seamless noise textures may take longer to generate and/or can have a lower contrast compared to non-seamless noise depending on the used [Noise] resource. This is because some implementations use higher dimensions for generating seamless noise.
+ </member>
+ <member name="seamless_blend_skirt" type="float" setter="set_seamless_blend_skirt" getter="get_seamless_blend_skirt" default="0.1">
+ Used for the default/fallback implementation of the seamless texture generation. It determines the distance over which the seams are blended. High values may result in less details and contrast. See [Noise] for further details.
+ </member>
+ <member name="width" type="int" setter="set_width" getter="get_width" default="512">
+ Width of the generated texture.
+ </member>
+ </members>
+</class>
diff --git a/modules/noise/editor/noise_editor_plugin.cpp b/modules/noise/editor/noise_editor_plugin.cpp
new file mode 100644
index 0000000000..32c3f0aad4
--- /dev/null
+++ b/modules/noise/editor/noise_editor_plugin.cpp
@@ -0,0 +1,149 @@
+/*************************************************************************/
+/* noise_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "noise_editor_plugin.h"
+
+#ifdef TOOLS_ENABLED
+
+#include "editor/editor_scale.h"
+
+#include "modules/noise/noise.h"
+#include "modules/noise/noise_texture.h"
+
+class NoisePreview : public Control {
+ GDCLASS(NoisePreview, Control)
+
+ static const int PREVIEW_HEIGHT = 150;
+ static const int PADDING_3D_SPACE_SWITCH = 2;
+
+ Ref<Noise> _noise;
+ Size2i _preview_texture_size;
+
+ TextureRect *_texture_rect = nullptr;
+ Button *_3d_space_switch = nullptr;
+
+public:
+ NoisePreview() {
+ set_custom_minimum_size(Size2(0, EDSCALE * PREVIEW_HEIGHT));
+
+ _texture_rect = memnew(TextureRect);
+ _texture_rect->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+ _texture_rect->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_COVERED);
+ add_child(_texture_rect);
+
+ _3d_space_switch = memnew(Button);
+ _3d_space_switch->set_text(TTR("3D"));
+ _3d_space_switch->set_tooltip(TTR("Toggles whether the noise preview is computed in 3D space."));
+ _3d_space_switch->set_toggle_mode(true);
+ _3d_space_switch->set_offset(SIDE_LEFT, PADDING_3D_SPACE_SWITCH);
+ _3d_space_switch->set_offset(SIDE_TOP, PADDING_3D_SPACE_SWITCH);
+ _3d_space_switch->connect("pressed", callable_mp(this, &NoisePreview::_on_3d_button_pressed));
+ add_child(_3d_space_switch);
+ }
+
+ void set_noise(Ref<Noise> noise) {
+ if (_noise == noise) {
+ return;
+ }
+ _noise = noise;
+ if (_noise.is_valid()) {
+ if (_noise->has_meta("_preview_in_3d_space_")) {
+ _3d_space_switch->set_pressed(true);
+ }
+
+ update_preview();
+ }
+ }
+
+private:
+ void _on_3d_button_pressed() {
+ if (_3d_space_switch->is_pressed()) {
+ _noise->set_meta("_preview_in_3d_space_", true);
+ } else {
+ _noise->remove_meta("_preview_in_3d_space_");
+ }
+ }
+
+ void _notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_RESIZED: {
+ _preview_texture_size = get_size();
+ update_preview();
+ } break;
+ }
+ }
+
+ void update_preview() {
+ if (MIN(_preview_texture_size.width, _preview_texture_size.height) > 0) {
+ Ref<NoiseTexture> tex;
+ tex.instantiate();
+ tex->set_width(_preview_texture_size.width);
+ tex->set_height(_preview_texture_size.height);
+ tex->set_in_3d_space(_3d_space_switch->is_pressed());
+ tex->set_noise(_noise);
+ _texture_rect->set_texture(tex);
+ }
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+
+class NoiseEditorInspectorPlugin : public EditorInspectorPlugin {
+ GDCLASS(NoiseEditorInspectorPlugin, EditorInspectorPlugin)
+public:
+ bool can_handle(Object *p_object) override {
+ return Object::cast_to<Noise>(p_object) != nullptr;
+ }
+
+ void parse_begin(Object *p_object) override {
+ Noise *noise_ptr = Object::cast_to<Noise>(p_object);
+ if (noise_ptr) {
+ Ref<Noise> noise(noise_ptr);
+
+ NoisePreview *viewer = memnew(NoisePreview);
+ viewer->set_noise(noise);
+ add_custom_control(viewer);
+ }
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+
+String NoiseEditorPlugin::get_name() const {
+ return Noise::get_class_static();
+}
+
+NoiseEditorPlugin::NoiseEditorPlugin() {
+ Ref<NoiseEditorInspectorPlugin> plugin;
+ plugin.instantiate();
+ add_inspector_plugin(plugin);
+}
+
+#endif // TOOLS_ENABLED
diff --git a/modules/fbx/register_types.h b/modules/noise/editor/noise_editor_plugin.h
index 6e3cc0dc46..55a01deb2d 100644
--- a/modules/fbx/register_types.h
+++ b/modules/noise/editor/noise_editor_plugin.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* register_types.h */
+/* noise_editor_plugin.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,10 +28,22 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef FBX_REGISTER_TYPES_H
-#define FBX_REGISTER_TYPES_H
+#ifndef NOISE_EDITOR_PLUGIN_H
+#define NOISE_EDITOR_PLUGIN_H
-void register_fbx_types();
-void unregister_fbx_types();
+#ifdef TOOLS_ENABLED
-#endif // FBX_REGISTER_TYPES_H
+#include "editor/editor_plugin.h"
+
+class NoiseEditorPlugin : public EditorPlugin {
+ GDCLASS(NoiseEditorPlugin, EditorPlugin)
+
+public:
+ String get_name() const override;
+
+ NoiseEditorPlugin();
+};
+
+#endif // TOOLS_ENABLED
+
+#endif // NOISE_EDITOR_PLUGIN_H
diff --git a/modules/noise/fastnoise_lite.cpp b/modules/noise/fastnoise_lite.cpp
new file mode 100644
index 0000000000..a8d38dee62
--- /dev/null
+++ b/modules/noise/fastnoise_lite.cpp
@@ -0,0 +1,486 @@
+/*************************************************************************/
+/* fastnoise_lite.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "fastnoise_lite.h"
+
+FastNoiseLite::FastNoiseLite() {
+ _noise.SetNoiseType((_FastNoiseLite::NoiseType)noise_type);
+ _noise.SetSeed(seed);
+ _noise.SetFrequency(frequency);
+
+ _noise.SetFractalType((_FastNoiseLite::FractalType)fractal_type);
+ _noise.SetFractalOctaves(fractal_octaves);
+ _noise.SetFractalLacunarity(fractal_lacunarity);
+ _noise.SetFractalGain(fractal_gain);
+ _noise.SetFractalWeightedStrength(fractal_weighted_strength);
+ _noise.SetFractalPingPongStrength(fractal_ping_pong_strength);
+
+ _noise.SetCellularDistanceFunction((_FastNoiseLite::CellularDistanceFunction)cellular_distance_function);
+ _noise.SetCellularReturnType((_FastNoiseLite::CellularReturnType)cellular_return_type);
+ _noise.SetCellularJitter(cellular_jitter);
+
+ _domain_warp_noise.SetDomainWarpType((_FastNoiseLite::DomainWarpType)domain_warp_type);
+ _domain_warp_noise.SetSeed(seed);
+ _domain_warp_noise.SetDomainWarpAmp(domain_warp_amplitude);
+ _domain_warp_noise.SetFrequency(domain_warp_frequency);
+ _domain_warp_noise.SetFractalType(_FastNoiseLite::FractalType_None);
+ _domain_warp_noise.SetFractalOctaves(domain_warp_fractal_octaves);
+ _domain_warp_noise.SetFractalLacunarity(domain_warp_fractal_lacunarity);
+ _domain_warp_noise.SetFractalGain(domain_warp_fractal_gain);
+}
+
+FastNoiseLite::~FastNoiseLite() {
+}
+
+// General settings.
+
+void FastNoiseLite::set_noise_type(NoiseType p_noise_type) {
+ noise_type = p_noise_type;
+ _noise.SetNoiseType((_FastNoiseLite::NoiseType)p_noise_type);
+ emit_changed();
+ notify_property_list_changed();
+}
+
+FastNoiseLite::NoiseType FastNoiseLite::get_noise_type() const {
+ return noise_type;
+}
+
+void FastNoiseLite::set_seed(int p_seed) {
+ seed = p_seed;
+ _noise.SetSeed(p_seed);
+ _domain_warp_noise.SetSeed(p_seed);
+ emit_changed();
+}
+
+int FastNoiseLite::get_seed() const {
+ return seed;
+}
+
+void FastNoiseLite::set_frequency(real_t p_freq) {
+ frequency = p_freq;
+ _noise.SetFrequency(p_freq);
+ emit_changed();
+}
+
+real_t FastNoiseLite::get_frequency() const {
+ return frequency;
+}
+
+void FastNoiseLite::set_offset(Vector3 p_offset) {
+ offset = p_offset;
+ emit_changed();
+}
+
+Vector3 FastNoiseLite::get_offset() const {
+ return offset;
+}
+
+// Fractal.
+
+void FastNoiseLite::set_fractal_type(FractalType p_type) {
+ fractal_type = p_type;
+ _noise.SetFractalType((_FastNoiseLite::FractalType)p_type);
+ emit_changed();
+ notify_property_list_changed();
+}
+
+FastNoiseLite::FractalType FastNoiseLite::get_fractal_type() const {
+ return fractal_type;
+}
+
+void FastNoiseLite::set_fractal_octaves(int p_octaves) {
+ fractal_octaves = p_octaves;
+ _noise.SetFractalOctaves(p_octaves);
+ emit_changed();
+}
+
+int FastNoiseLite::get_fractal_octaves() const {
+ return fractal_octaves;
+}
+
+void FastNoiseLite::set_fractal_lacunarity(real_t p_lacunarity) {
+ fractal_lacunarity = p_lacunarity;
+ _noise.SetFractalLacunarity(p_lacunarity);
+ emit_changed();
+}
+
+real_t FastNoiseLite::get_fractal_lacunarity() const {
+ return fractal_lacunarity;
+}
+
+void FastNoiseLite::set_fractal_gain(real_t p_gain) {
+ fractal_gain = p_gain;
+ _noise.SetFractalGain(p_gain);
+ emit_changed();
+}
+
+real_t FastNoiseLite::get_fractal_gain() const {
+ return fractal_gain;
+}
+
+void FastNoiseLite::set_fractal_weighted_strength(real_t p_weighted_strength) {
+ fractal_weighted_strength = p_weighted_strength;
+ _noise.SetFractalWeightedStrength(p_weighted_strength);
+ emit_changed();
+}
+real_t FastNoiseLite::get_fractal_weighted_strength() const {
+ return fractal_weighted_strength;
+}
+
+void FastNoiseLite::set_fractal_ping_pong_strength(real_t p_ping_pong_strength) {
+ fractal_ping_pong_strength = p_ping_pong_strength;
+ _noise.SetFractalPingPongStrength(p_ping_pong_strength);
+ emit_changed();
+}
+real_t FastNoiseLite::get_fractal_ping_pong_strength() const {
+ return fractal_ping_pong_strength;
+}
+
+// Cellular.
+
+void FastNoiseLite::set_cellular_distance_function(CellularDistanceFunction p_func) {
+ cellular_distance_function = p_func;
+ _noise.SetCellularDistanceFunction((_FastNoiseLite::CellularDistanceFunction)p_func);
+ emit_changed();
+}
+
+FastNoiseLite::CellularDistanceFunction FastNoiseLite::get_cellular_distance_function() const {
+ return cellular_distance_function;
+}
+
+void FastNoiseLite::set_cellular_jitter(real_t p_jitter) {
+ cellular_jitter = p_jitter;
+ _noise.SetCellularJitter(p_jitter);
+ emit_changed();
+}
+
+real_t FastNoiseLite::get_cellular_jitter() const {
+ return cellular_jitter;
+}
+
+void FastNoiseLite::set_cellular_return_type(CellularReturnType p_ret) {
+ cellular_return_type = p_ret;
+ _noise.SetCellularReturnType((_FastNoiseLite::CellularReturnType)p_ret);
+ emit_changed();
+}
+
+FastNoiseLite::CellularReturnType FastNoiseLite::get_cellular_return_type() const {
+ return cellular_return_type;
+}
+
+// Domain warp specific.
+
+void FastNoiseLite::set_domain_warp_enabled(bool p_enabled) {
+ if (domain_warp_enabled != p_enabled) {
+ domain_warp_enabled = p_enabled;
+ emit_changed();
+ notify_property_list_changed();
+ }
+}
+
+bool FastNoiseLite::is_domain_warp_enabled() const {
+ return domain_warp_enabled;
+}
+
+void FastNoiseLite::set_domain_warp_type(DomainWarpType p_domain_warp_type) {
+ domain_warp_type = p_domain_warp_type;
+ _domain_warp_noise.SetDomainWarpType((_FastNoiseLite::DomainWarpType)p_domain_warp_type);
+ emit_changed();
+}
+
+FastNoiseLite::DomainWarpType FastNoiseLite::get_domain_warp_type() const {
+ return domain_warp_type;
+}
+
+void FastNoiseLite::set_domain_warp_amplitude(real_t p_amplitude) {
+ domain_warp_amplitude = p_amplitude;
+ _domain_warp_noise.SetDomainWarpAmp(p_amplitude);
+ emit_changed();
+}
+real_t FastNoiseLite::get_domain_warp_amplitude() const {
+ return domain_warp_amplitude;
+}
+
+void FastNoiseLite::set_domain_warp_frequency(real_t p_frequency) {
+ domain_warp_frequency = p_frequency;
+ _domain_warp_noise.SetFrequency(p_frequency);
+ emit_changed();
+}
+
+real_t FastNoiseLite::get_domain_warp_frequency() const {
+ return domain_warp_frequency;
+}
+
+void FastNoiseLite::set_domain_warp_fractal_type(DomainWarpFractalType p_domain_warp_fractal_type) {
+ domain_warp_fractal_type = p_domain_warp_fractal_type;
+
+ // This needs manual conversion because Godots Inspector property API does not support discontiguous enum indices.
+ _FastNoiseLite::FractalType type;
+ switch (p_domain_warp_fractal_type) {
+ case DOMAIN_WARP_FRACTAL_NONE:
+ type = _FastNoiseLite::FractalType_None;
+ break;
+ case DOMAIN_WARP_FRACTAL_PROGRESSIVE:
+ type = _FastNoiseLite::FractalType_DomainWarpProgressive;
+ break;
+ case DOMAIN_WARP_FRACTAL_INDEPENDENT:
+ type = _FastNoiseLite::FractalType_DomainWarpIndependent;
+ break;
+ default:
+ type = _FastNoiseLite::FractalType_None;
+ }
+
+ _domain_warp_noise.SetFractalType(type);
+ emit_changed();
+}
+
+FastNoiseLite::DomainWarpFractalType FastNoiseLite::get_domain_warp_fractal_type() const {
+ return domain_warp_fractal_type;
+}
+
+void FastNoiseLite::set_domain_warp_fractal_octaves(int p_octaves) {
+ domain_warp_fractal_octaves = p_octaves;
+ _domain_warp_noise.SetFractalOctaves(p_octaves);
+ emit_changed();
+}
+
+int FastNoiseLite::get_domain_warp_fractal_octaves() const {
+ return domain_warp_fractal_octaves;
+}
+
+void FastNoiseLite::set_domain_warp_fractal_lacunarity(real_t p_lacunarity) {
+ domain_warp_fractal_lacunarity = p_lacunarity;
+ _domain_warp_noise.SetFractalLacunarity(p_lacunarity);
+ emit_changed();
+}
+
+real_t FastNoiseLite::get_domain_warp_fractal_lacunarity() const {
+ return domain_warp_fractal_lacunarity;
+}
+
+void FastNoiseLite::set_domain_warp_fractal_gain(real_t p_gain) {
+ domain_warp_fractal_gain = p_gain;
+ _domain_warp_noise.SetFractalGain(p_gain);
+ emit_changed();
+}
+
+real_t FastNoiseLite::get_domain_warp_fractal_gain() const {
+ return domain_warp_fractal_gain;
+}
+
+// Noise interface functions.
+
+real_t FastNoiseLite::get_noise_1d(real_t p_x) const {
+ return get_noise_2d(p_x, 0.0);
+}
+
+real_t FastNoiseLite::get_noise_2dv(Vector2 p_v) const {
+ return get_noise_2d(p_v.x, p_v.y);
+}
+
+real_t FastNoiseLite::get_noise_2d(real_t p_x, real_t p_y) const {
+ if (domain_warp_enabled) {
+ _domain_warp_noise.DomainWarp(p_x, p_y);
+ }
+ return _noise.GetNoise(p_x + offset.x, p_y + offset.y);
+}
+
+real_t FastNoiseLite::get_noise_3dv(Vector3 p_v) const {
+ return get_noise_3d(p_v.x, p_v.y, p_v.z);
+}
+
+real_t FastNoiseLite::get_noise_3d(real_t p_x, real_t p_y, real_t p_z) const {
+ if (domain_warp_enabled) {
+ _domain_warp_noise.DomainWarp(p_x, p_y, p_z);
+ }
+ return _noise.GetNoise(p_x + offset.x, p_y + offset.y, p_z + offset.z);
+}
+
+void FastNoiseLite::_changed() {
+ emit_changed();
+}
+
+void FastNoiseLite::_bind_methods() {
+ // General settings.
+
+ ClassDB::bind_method(D_METHOD("set_noise_type", "type"), &FastNoiseLite::set_noise_type);
+ ClassDB::bind_method(D_METHOD("get_noise_type"), &FastNoiseLite::get_noise_type);
+
+ ClassDB::bind_method(D_METHOD("set_seed", "seed"), &FastNoiseLite::set_seed);
+ ClassDB::bind_method(D_METHOD("get_seed"), &FastNoiseLite::get_seed);
+
+ ClassDB::bind_method(D_METHOD("set_frequency", "freq"), &FastNoiseLite::set_frequency);
+ ClassDB::bind_method(D_METHOD("get_frequency"), &FastNoiseLite::get_frequency);
+
+ ClassDB::bind_method(D_METHOD("set_offset", "offset"), &FastNoiseLite::set_offset);
+ ClassDB::bind_method(D_METHOD("get_offset"), &FastNoiseLite::get_offset);
+
+ // Fractal.
+
+ ClassDB::bind_method(D_METHOD("set_fractal_type", "type"), &FastNoiseLite::set_fractal_type);
+ ClassDB::bind_method(D_METHOD("get_fractal_type"), &FastNoiseLite::get_fractal_type);
+
+ ClassDB::bind_method(D_METHOD("set_fractal_octaves", "octave_count"), &FastNoiseLite::set_fractal_octaves);
+ ClassDB::bind_method(D_METHOD("get_fractal_octaves"), &FastNoiseLite::get_fractal_octaves);
+
+ ClassDB::bind_method(D_METHOD("set_fractal_lacunarity", "lacunarity"), &FastNoiseLite::set_fractal_lacunarity);
+ ClassDB::bind_method(D_METHOD("get_fractal_lacunarity"), &FastNoiseLite::get_fractal_lacunarity);
+
+ ClassDB::bind_method(D_METHOD("set_fractal_gain", "gain"), &FastNoiseLite::set_fractal_gain);
+ ClassDB::bind_method(D_METHOD("get_fractal_gain"), &FastNoiseLite::get_fractal_gain);
+
+ ClassDB::bind_method(D_METHOD("set_fractal_weighted_strength", "weighted_strength"), &FastNoiseLite::set_fractal_weighted_strength);
+ ClassDB::bind_method(D_METHOD("get_fractal_weighted_strength"), &FastNoiseLite::get_fractal_weighted_strength);
+
+ ClassDB::bind_method(D_METHOD("set_fractal_ping_pong_strength", "ping_pong_strength"), &FastNoiseLite::set_fractal_ping_pong_strength);
+ ClassDB::bind_method(D_METHOD("get_fractal_ping_pong_strength"), &FastNoiseLite::get_fractal_ping_pong_strength);
+
+ // Cellular.
+
+ ClassDB::bind_method(D_METHOD("set_cellular_distance_function", "func"), &FastNoiseLite::set_cellular_distance_function);
+ ClassDB::bind_method(D_METHOD("get_cellular_distance_function"), &FastNoiseLite::get_cellular_distance_function);
+
+ ClassDB::bind_method(D_METHOD("set_cellular_jitter", "jitter"), &FastNoiseLite::set_cellular_jitter);
+ ClassDB::bind_method(D_METHOD("get_cellular_jitter"), &FastNoiseLite::get_cellular_jitter);
+
+ ClassDB::bind_method(D_METHOD("set_cellular_return_type", "ret"), &FastNoiseLite::set_cellular_return_type);
+ ClassDB::bind_method(D_METHOD("get_cellular_return_type"), &FastNoiseLite::get_cellular_return_type);
+
+ // Domain warp.
+
+ ClassDB::bind_method(D_METHOD("set_domain_warp_enabled", "domain_warp_enabled"), &FastNoiseLite::set_domain_warp_enabled);
+ ClassDB::bind_method(D_METHOD("is_domain_warp_enabled"), &FastNoiseLite::is_domain_warp_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_domain_warp_type", "domain_warp_type"), &FastNoiseLite::set_domain_warp_type);
+ ClassDB::bind_method(D_METHOD("get_domain_warp_type"), &FastNoiseLite::get_domain_warp_type);
+
+ ClassDB::bind_method(D_METHOD("set_domain_warp_amplitude", "domain_warp_amplitude"), &FastNoiseLite::set_domain_warp_amplitude);
+ ClassDB::bind_method(D_METHOD("get_domain_warp_amplitude"), &FastNoiseLite::get_domain_warp_amplitude);
+
+ ClassDB::bind_method(D_METHOD("set_domain_warp_frequency", "domain_warp_frequency"), &FastNoiseLite::set_domain_warp_frequency);
+ ClassDB::bind_method(D_METHOD("get_domain_warp_frequency"), &FastNoiseLite::get_domain_warp_frequency);
+
+ ClassDB::bind_method(D_METHOD("set_domain_warp_fractal_type", "domain_warp_fractal_type"), &FastNoiseLite::set_domain_warp_fractal_type);
+ ClassDB::bind_method(D_METHOD("get_domain_warp_fractal_type"), &FastNoiseLite::get_domain_warp_fractal_type);
+
+ ClassDB::bind_method(D_METHOD("set_domain_warp_fractal_octaves", "domain_warp_octave_count"), &FastNoiseLite::set_domain_warp_fractal_octaves);
+ ClassDB::bind_method(D_METHOD("get_domain_warp_fractal_octaves"), &FastNoiseLite::get_domain_warp_fractal_octaves);
+
+ ClassDB::bind_method(D_METHOD("set_domain_warp_fractal_lacunarity", "domain_warp_lacunarity"), &FastNoiseLite::set_domain_warp_fractal_lacunarity);
+ ClassDB::bind_method(D_METHOD("get_domain_warp_fractal_lacunarity"), &FastNoiseLite::get_domain_warp_fractal_lacunarity);
+
+ ClassDB::bind_method(D_METHOD("set_domain_warp_fractal_gain", "domain_warp_gain"), &FastNoiseLite::set_domain_warp_fractal_gain);
+ ClassDB::bind_method(D_METHOD("get_domain_warp_fractal_gain"), &FastNoiseLite::get_domain_warp_fractal_gain);
+
+ ClassDB::bind_method(D_METHOD("_changed"), &FastNoiseLite::_changed);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "noise_type", PROPERTY_HINT_ENUM, "Simplex,Simplex Smooth,Cellular,Perlin,Value Cubic,Value"), "set_noise_type", "get_noise_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "seed"), "set_seed", "get_seed");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frequency", PROPERTY_HINT_RANGE, ".001,1"), "set_frequency", "get_frequency");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "offset", PROPERTY_HINT_RANGE, "-999999999,999999999,0.01"), "set_offset", "get_offset");
+
+ ADD_GROUP("Fractal", "fractal_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "fractal_type", PROPERTY_HINT_ENUM, "None,FBM,Ridged,Ping-Pong"), "set_fractal_type", "get_fractal_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "fractal_octaves", PROPERTY_HINT_RANGE, "1,10,1"), "set_fractal_octaves", "get_fractal_octaves");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_lacunarity"), "set_fractal_lacunarity", "get_fractal_lacunarity");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_gain"), "set_fractal_gain", "get_fractal_gain");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_weighted_strength", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_fractal_weighted_strength", "get_fractal_weighted_strength");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_ping_pong_strength"), "set_fractal_ping_pong_strength", "get_fractal_ping_pong_strength");
+
+ ADD_GROUP("Cellular", "cellular_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "cellular_distance_function", PROPERTY_HINT_ENUM, "Euclidean,Euclidean Squared,Manhattan,Hybrid"), "set_cellular_distance_function", "get_cellular_distance_function");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cellular_jitter"), "set_cellular_jitter", "get_cellular_jitter");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "cellular_return_type", PROPERTY_HINT_ENUM, "Cell Value,Distance,Distance2,Distance2Add,Distance2Sub,Distance2Mul,Distance2Div"), "set_cellular_return_type", "get_cellular_return_type");
+
+ ADD_GROUP("Domain Warp", "domain_warp_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "domain_warp_enabled"), "set_domain_warp_enabled", "is_domain_warp_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "domain_warp_type", PROPERTY_HINT_ENUM, "Simplex,Simplex Reduced,Basic Grid"), "set_domain_warp_type", "get_domain_warp_type");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_amplitude"), "set_domain_warp_amplitude", "get_domain_warp_amplitude");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_frequency"), "set_domain_warp_frequency", "get_domain_warp_frequency");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "domain_warp_fractal_type", PROPERTY_HINT_ENUM, "None,Progressive,Independent"), "set_domain_warp_fractal_type", "get_domain_warp_fractal_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "domain_warp_fractal_octaves", PROPERTY_HINT_RANGE, "1,10,1"), "set_domain_warp_fractal_octaves", "get_domain_warp_fractal_octaves");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_fractal_lacunarity"), "set_domain_warp_fractal_lacunarity", "get_domain_warp_fractal_lacunarity");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_fractal_gain"), "set_domain_warp_fractal_gain", "get_domain_warp_fractal_gain");
+
+ BIND_ENUM_CONSTANT(TYPE_VALUE);
+ BIND_ENUM_CONSTANT(TYPE_VALUE_CUBIC);
+ BIND_ENUM_CONSTANT(TYPE_PERLIN);
+ BIND_ENUM_CONSTANT(TYPE_CELLULAR);
+ BIND_ENUM_CONSTANT(TYPE_SIMPLEX);
+ BIND_ENUM_CONSTANT(TYPE_SIMPLEX_SMOOTH);
+
+ BIND_ENUM_CONSTANT(FRACTAL_NONE);
+ BIND_ENUM_CONSTANT(FRACTAL_FBM);
+ BIND_ENUM_CONSTANT(FRACTAL_RIDGED);
+ BIND_ENUM_CONSTANT(FRACTAL_PING_PONG);
+
+ BIND_ENUM_CONSTANT(DISTANCE_EUCLIDEAN);
+ BIND_ENUM_CONSTANT(DISTANCE_EUCLIDEAN_SQUARED);
+ BIND_ENUM_CONSTANT(DISTANCE_MANHATTAN);
+ BIND_ENUM_CONSTANT(DISTANCE_HYBRID);
+
+ BIND_ENUM_CONSTANT(RETURN_CELL_VALUE);
+ BIND_ENUM_CONSTANT(RETURN_DISTANCE);
+ BIND_ENUM_CONSTANT(RETURN_DISTANCE2);
+ BIND_ENUM_CONSTANT(RETURN_DISTANCE2_ADD);
+ BIND_ENUM_CONSTANT(RETURN_DISTANCE2_SUB);
+ BIND_ENUM_CONSTANT(RETURN_DISTANCE2_MUL);
+ BIND_ENUM_CONSTANT(RETURN_DISTANCE2_DIV);
+
+ BIND_ENUM_CONSTANT(DOMAIN_WARP_SIMPLEX);
+ BIND_ENUM_CONSTANT(DOMAIN_WARP_SIMPLEX_REDUCED);
+ BIND_ENUM_CONSTANT(DOMAIN_WARP_BASIC_GRID);
+
+ BIND_ENUM_CONSTANT(DOMAIN_WARP_FRACTAL_NONE);
+ BIND_ENUM_CONSTANT(DOMAIN_WARP_FRACTAL_PROGRESSIVE);
+ BIND_ENUM_CONSTANT(DOMAIN_WARP_FRACTAL_INDEPENDENT);
+}
+
+void FastNoiseLite::_validate_property(PropertyInfo &property) const {
+ if (property.name.begins_with("cellular") && get_noise_type() != TYPE_CELLULAR) {
+ property.usage = PROPERTY_USAGE_NO_EDITOR;
+ return;
+ }
+
+ if (property.name != "fractal_type" && property.name.begins_with("fractal") && get_fractal_type() == FRACTAL_NONE) {
+ property.usage = PROPERTY_USAGE_NO_EDITOR;
+ return;
+ }
+
+ if (property.name == "fractal_ping_pong_strength" && get_fractal_type() != FRACTAL_PING_PONG) {
+ property.usage = PROPERTY_USAGE_NO_EDITOR;
+ return;
+ }
+
+ if (property.name != "domain_warp_enabled" && property.name.begins_with("domain_warp") && !domain_warp_enabled) {
+ property.usage = PROPERTY_USAGE_NO_EDITOR;
+ return;
+ }
+}
diff --git a/modules/noise/fastnoise_lite.h b/modules/noise/fastnoise_lite.h
new file mode 100644
index 0000000000..0a4251868b
--- /dev/null
+++ b/modules/noise/fastnoise_lite.h
@@ -0,0 +1,224 @@
+/*************************************************************************/
+/* fastnoise_lite.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef FASTNOISE_LITE_H
+#define FASTNOISE_LITE_H
+
+#include "core/io/image.h"
+#include "core/object/ref_counted.h"
+#include "noise.h"
+#include "scene/resources/gradient.h"
+
+#include <thirdparty/noise/FastNoiseLite.h>
+
+typedef fastnoiselite::FastNoiseLite _FastNoiseLite;
+
+class FastNoiseLite : public Noise {
+ GDCLASS(FastNoiseLite, Noise);
+ OBJ_SAVE_TYPE(FastNoiseLite);
+
+public:
+ enum NoiseType {
+ TYPE_SIMPLEX = _FastNoiseLite::NoiseType_OpenSimplex2,
+ TYPE_SIMPLEX_SMOOTH = _FastNoiseLite::NoiseType_OpenSimplex2S,
+ TYPE_CELLULAR = _FastNoiseLite::NoiseType_Cellular,
+ TYPE_PERLIN = _FastNoiseLite::NoiseType_Perlin,
+ TYPE_VALUE_CUBIC = _FastNoiseLite::NoiseType_ValueCubic,
+ TYPE_VALUE = _FastNoiseLite::NoiseType_Value,
+ };
+
+ enum FractalType {
+ FRACTAL_NONE = _FastNoiseLite::FractalType_None,
+ FRACTAL_FBM = _FastNoiseLite::FractalType_FBm,
+ FRACTAL_RIDGED = _FastNoiseLite::FractalType_Ridged,
+ FRACTAL_PING_PONG = _FastNoiseLite::FractalType_PingPong,
+ };
+
+ enum CellularDistanceFunction {
+ DISTANCE_EUCLIDEAN = _FastNoiseLite::CellularDistanceFunction_Euclidean,
+ DISTANCE_EUCLIDEAN_SQUARED = _FastNoiseLite::CellularDistanceFunction_EuclideanSq,
+ DISTANCE_MANHATTAN = _FastNoiseLite::CellularDistanceFunction_Manhattan,
+ DISTANCE_HYBRID = _FastNoiseLite::CellularDistanceFunction_Hybrid
+ };
+
+ enum CellularReturnType {
+ RETURN_CELL_VALUE = _FastNoiseLite::CellularReturnType_CellValue,
+ RETURN_DISTANCE = _FastNoiseLite::CellularReturnType_Distance,
+ RETURN_DISTANCE2 = _FastNoiseLite::CellularReturnType_Distance2,
+ RETURN_DISTANCE2_ADD = _FastNoiseLite::CellularReturnType_Distance2Add,
+ RETURN_DISTANCE2_SUB = _FastNoiseLite::CellularReturnType_Distance2Sub,
+ RETURN_DISTANCE2_MUL = _FastNoiseLite::CellularReturnType_Distance2Mul,
+ RETURN_DISTANCE2_DIV = _FastNoiseLite::CellularReturnType_Distance2Div
+ };
+
+ enum DomainWarpType {
+ DOMAIN_WARP_SIMPLEX = _FastNoiseLite::DomainWarpType_OpenSimplex2,
+ DOMAIN_WARP_SIMPLEX_REDUCED = _FastNoiseLite::DomainWarpType_OpenSimplex2Reduced,
+ DOMAIN_WARP_BASIC_GRID = _FastNoiseLite::DomainWarpType_BasicGrid
+ };
+
+ enum DomainWarpFractalType {
+ DOMAIN_WARP_FRACTAL_NONE,
+ DOMAIN_WARP_FRACTAL_PROGRESSIVE,
+ DOMAIN_WARP_FRACTAL_INDEPENDENT
+ };
+
+protected:
+ static void _bind_methods();
+ virtual void _validate_property(PropertyInfo &property) const override;
+
+private:
+ _FastNoiseLite _noise;
+ _FastNoiseLite _domain_warp_noise;
+
+ Vector3 offset;
+ NoiseType noise_type = TYPE_SIMPLEX_SMOOTH;
+
+ int seed = 0;
+ real_t frequency = 0.01;
+
+ // Fractal specific.
+ FractalType fractal_type = FRACTAL_FBM;
+ int fractal_octaves = 5;
+ real_t fractal_lacunarity = 2;
+ real_t fractal_gain = 0.5;
+ real_t fractal_weighted_strength = 0;
+ real_t fractal_ping_pong_strength = 2;
+
+ // Cellular specific.
+ CellularDistanceFunction cellular_distance_function = DISTANCE_EUCLIDEAN;
+ CellularReturnType cellular_return_type = RETURN_DISTANCE;
+ real_t cellular_jitter = 0.45;
+
+ // Domain warp specific.
+ bool domain_warp_enabled = false;
+ DomainWarpType domain_warp_type = DOMAIN_WARP_SIMPLEX;
+ real_t domain_warp_amplitude = 30.0;
+ real_t domain_warp_frequency = 0.05;
+ DomainWarpFractalType domain_warp_fractal_type = DOMAIN_WARP_FRACTAL_PROGRESSIVE;
+ int domain_warp_fractal_octaves = 5;
+ real_t domain_warp_fractal_lacunarity = 6;
+ real_t domain_warp_fractal_gain = 0.5;
+
+public:
+ FastNoiseLite();
+ ~FastNoiseLite();
+
+ // General noise settings.
+
+ void set_noise_type(NoiseType p_noise_type);
+ NoiseType get_noise_type() const;
+
+ void set_seed(int p_seed);
+ int get_seed() const;
+
+ void set_frequency(real_t p_freq);
+ real_t get_frequency() const;
+
+ void set_offset(Vector3 p_offset);
+ Vector3 get_offset() const;
+
+ // Fractal specific.
+
+ void set_fractal_type(FractalType p_type);
+ FractalType get_fractal_type() const;
+
+ void set_fractal_octaves(int p_octaves);
+ int get_fractal_octaves() const;
+
+ void set_fractal_lacunarity(real_t p_lacunarity);
+ real_t get_fractal_lacunarity() const;
+
+ void set_fractal_gain(real_t p_gain);
+ real_t get_fractal_gain() const;
+
+ void set_fractal_weighted_strength(real_t p_weighted_strength);
+ real_t get_fractal_weighted_strength() const;
+
+ void set_fractal_ping_pong_strength(real_t p_ping_pong_strength);
+ real_t get_fractal_ping_pong_strength() const;
+
+ // Cellular specific.
+
+ void set_cellular_distance_function(CellularDistanceFunction p_func);
+ CellularDistanceFunction get_cellular_distance_function() const;
+
+ void set_cellular_return_type(CellularReturnType p_ret);
+ CellularReturnType get_cellular_return_type() const;
+
+ void set_cellular_jitter(real_t p_jitter);
+ real_t get_cellular_jitter() const;
+
+ // Domain warp specific.
+
+ void set_domain_warp_enabled(bool p_enabled);
+ bool is_domain_warp_enabled() const;
+
+ void set_domain_warp_type(DomainWarpType p_domain_warp_type);
+ DomainWarpType get_domain_warp_type() const;
+
+ void set_domain_warp_amplitude(real_t p_amplitude);
+ real_t get_domain_warp_amplitude() const;
+
+ void set_domain_warp_frequency(real_t p_frequency);
+ real_t get_domain_warp_frequency() const;
+
+ void set_domain_warp_fractal_type(DomainWarpFractalType p_domain_warp_fractal_type);
+ DomainWarpFractalType get_domain_warp_fractal_type() const;
+
+ void set_domain_warp_fractal_octaves(int p_octaves);
+ int get_domain_warp_fractal_octaves() const;
+
+ void set_domain_warp_fractal_lacunarity(real_t p_lacunarity);
+ real_t get_domain_warp_fractal_lacunarity() const;
+
+ void set_domain_warp_fractal_gain(real_t p_gain);
+ real_t get_domain_warp_fractal_gain() const;
+
+ // Interface methods.
+ real_t get_noise_1d(real_t p_x) const override;
+
+ real_t get_noise_2dv(Vector2 p_v) const override;
+ real_t get_noise_2d(real_t p_x, real_t p_y) const override;
+
+ real_t get_noise_3dv(Vector3 p_v) const override;
+ real_t get_noise_3d(real_t p_x, real_t p_y, real_t p_z) const override;
+
+ void _changed();
+};
+
+VARIANT_ENUM_CAST(FastNoiseLite::NoiseType);
+VARIANT_ENUM_CAST(FastNoiseLite::FractalType);
+VARIANT_ENUM_CAST(FastNoiseLite::CellularDistanceFunction);
+VARIANT_ENUM_CAST(FastNoiseLite::CellularReturnType);
+VARIANT_ENUM_CAST(FastNoiseLite::DomainWarpType);
+VARIANT_ENUM_CAST(FastNoiseLite::DomainWarpFractalType);
+
+#endif // FASTNOISE_LITE_H
diff --git a/modules/opensimplex/icons/NoiseTexture.svg b/modules/noise/icons/NoiseTexture.svg
index 479684cde2..479684cde2 100644
--- a/modules/opensimplex/icons/NoiseTexture.svg
+++ b/modules/noise/icons/NoiseTexture.svg
diff --git a/modules/noise/noise.cpp b/modules/noise/noise.cpp
new file mode 100644
index 0000000000..d14b63f7c8
--- /dev/null
+++ b/modules/noise/noise.cpp
@@ -0,0 +1,116 @@
+/*************************************************************************/
+/* noise.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "noise.h"
+
+Ref<Image> Noise::get_seamless_image(int p_width, int p_height, bool p_invert, bool p_in_3d_space, real_t p_blend_skirt) const {
+ ERR_FAIL_COND_V(p_width <= 0 || p_height <= 0, Ref<Image>());
+
+ int skirt_width = p_width * p_blend_skirt;
+ int skirt_height = p_height * p_blend_skirt;
+ int src_width = p_width + skirt_width;
+ int src_height = p_height + skirt_height;
+
+ Ref<Image> src = get_image(src_width, src_height, p_invert, p_in_3d_space);
+ bool grayscale = (src->get_format() == Image::FORMAT_L8);
+ if (grayscale) {
+ return _generate_seamless_image<uint8_t>(src, p_width, p_height, p_invert, p_blend_skirt);
+ } else {
+ return _generate_seamless_image<uint32_t>(src, p_width, p_height, p_invert, p_blend_skirt);
+ }
+}
+
+// Template specialization for faster grayscale blending.
+template <>
+uint8_t Noise::_alpha_blend<uint8_t>(uint8_t p_bg, uint8_t p_fg, int p_alpha) const {
+ uint16_t alpha = p_alpha + 1;
+ uint16_t inv_alpha = 256 - p_alpha;
+
+ return (uint8_t)((alpha * p_fg + inv_alpha * p_bg) >> 8);
+}
+
+Ref<Image> Noise::get_image(int p_width, int p_height, bool p_invert, bool p_in_3d_space) const {
+ ERR_FAIL_COND_V(p_width <= 0 || p_height <= 0, Ref<Image>());
+
+ Vector<uint8_t> data;
+ data.resize(p_width * p_height);
+
+ uint8_t *wd8 = data.ptrw();
+
+ // Get all values and identify min/max values.
+ Vector<real_t> values;
+ values.resize(p_width * p_height);
+ real_t min_val = 1000;
+ real_t max_val = -1000;
+
+ for (int y = 0, i = 0; y < p_height; y++) {
+ for (int x = 0; x < p_width; x++, i++) {
+ values.set(i, p_in_3d_space ? get_noise_3d(x, y, 0.0) : get_noise_2d(x, y));
+ if (values[i] > max_val) {
+ max_val = values[i];
+ }
+ if (values[i] < min_val) {
+ min_val = values[i];
+ }
+ }
+ }
+
+ // Normalize values and write to texture.
+ uint8_t value;
+ for (int i = 0, x = 0; i < p_height; i++) {
+ for (int j = 0; j < p_width; j++, x++) {
+ if (max_val == min_val) {
+ value = 0;
+ } else {
+ value = uint8_t(CLAMP((values[x] - min_val) / (max_val - min_val) * 255.f, 0, 255));
+ }
+ if (p_invert) {
+ value = 255 - value;
+ }
+
+ wd8[x] = value;
+ }
+ }
+
+ return memnew(Image(p_width, p_height, false, Image::FORMAT_L8, data));
+}
+
+void Noise::_bind_methods() {
+ // Noise functions.
+ ClassDB::bind_method(D_METHOD("get_noise_1d", "x"), &Noise::get_noise_1d);
+ ClassDB::bind_method(D_METHOD("get_noise_2d", "x", "y"), &Noise::get_noise_2d);
+ ClassDB::bind_method(D_METHOD("get_noise_2dv", "v"), &Noise::get_noise_2dv);
+ ClassDB::bind_method(D_METHOD("get_noise_3d", "x", "y", "z"), &Noise::get_noise_3d);
+ ClassDB::bind_method(D_METHOD("get_noise_3dv", "v"), &Noise::get_noise_3dv);
+
+ // Textures.
+ ClassDB::bind_method(D_METHOD("get_image", "width", "height", "invert", "in_3d_space"), &Noise::get_image, DEFVAL(false), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_seamless_image", "width", "height", "invert", "in_3d_space", "skirt"), &Noise::get_seamless_image, DEFVAL(false), DEFVAL(false), DEFVAL(0.1));
+}
diff --git a/modules/noise/noise.h b/modules/noise/noise.h
new file mode 100644
index 0000000000..8083334388
--- /dev/null
+++ b/modules/noise/noise.h
@@ -0,0 +1,240 @@
+/*************************************************************************/
+/* noise.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef NOISE_H
+#define NOISE_H
+
+#include "core/io/image.h"
+
+class Noise : public Resource {
+ GDCLASS(Noise, Resource);
+
+ // Helper struct for get_seamless_image(). See comments in .cpp for usage.
+ template <typename T>
+ struct img_buff {
+ T *img = nullptr;
+ int width; // Array dimensions & default modulo for image.
+ int height;
+ int offset_x; // Offset index location on image (wrapped by specified modulo).
+ int offset_y;
+ int alt_width; // Alternate module for image.
+ int alt_height;
+
+ enum ALT_MODULO {
+ DEFAULT = 0,
+ ALT_X,
+ ALT_Y,
+ ALT_XY
+ };
+
+ // Multi-dimensional array indexer (e.g. img[x][y]) that supports multiple modulos.
+ T &operator()(int x, int y, ALT_MODULO mode = DEFAULT) {
+ switch (mode) {
+ case ALT_XY:
+ return img[(x + offset_x) % alt_width + ((y + offset_y) % alt_height) * width];
+ case ALT_X:
+ return img[(x + offset_x) % alt_width + ((y + offset_y) % height) * width];
+ case ALT_Y:
+ return img[(x + offset_x) % width + ((y + offset_y) % alt_height) * width];
+ default:
+ return img[(x + offset_x) % width + ((y + offset_y) % height) * width];
+ }
+ }
+ };
+
+ union l2c {
+ uint32_t l;
+ uint8_t c[4];
+ struct {
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+ uint8_t a;
+ };
+ };
+
+ template <typename T>
+ Ref<Image> _generate_seamless_image(Ref<Image> p_src, int p_width, int p_height, bool p_invert, real_t p_blend_skirt) const {
+ /*
+ To make a seamless image, we swap the quadrants so the edges are perfect matches.
+ We initially get a 10% larger image so we have an overlap we can use to blend over the seams.
+
+ Noise::img_buff::operator() acts as a multi-dimensional array indexer.
+ It does the array math, translates between the flipped and non-flipped quadrants, and manages offsets and modulos.
+
+ Here is how the larger source image and final output image map to each other:
+
+ Output size = p_width*p_height Source w/ extra 10% skirt `s` size = src_width*src_height
+ Q1 Q2 Q4 Q3 s1
+ Q3 Q4 Q2 Q1 s2
+ s5 s4 s3
+
+ All of the loops use output coordinates, so Output:Q1 == Source:Q1
+ Ex: Output(half_width, half_height) [the midpoint, corner of Q1/Q4] =>
+ on Source it's translated to
+ corner of Q1/s3 unless the ALT_XY modulo moves it to Q4
+ */
+ ERR_FAIL_COND_V(p_blend_skirt < 0, Ref<Image>());
+
+ int skirt_width = MAX(1, p_width * p_blend_skirt);
+ int skirt_height = MAX(1, p_height * p_blend_skirt);
+ int src_width = p_width + skirt_width;
+ int src_height = p_height + skirt_height;
+ int half_width = p_width * .5;
+ int half_height = p_height * .5;
+ int skirt_edge_x = half_width + skirt_width;
+ int skirt_edge_y = half_height + skirt_height;
+
+ Vector<uint8_t> dest;
+ dest.resize(p_width * p_height * Image::get_format_pixel_size(p_src->get_format()));
+
+ img_buff<T> rd_src = {
+ (T *)p_src->get_data().ptr(),
+ src_width, src_height,
+ half_width, half_height,
+ p_width, p_height
+ };
+
+ // `wr` is setup for straight x/y coordinate array access.
+ img_buff<T> wr = {
+ (T *)dest.ptrw(),
+ p_width, p_height,
+ 0, 0, 0, 0
+ };
+ // `rd_dest` is a readable pointer to `wr`, i.e. what has already been written to the output buffer.
+ img_buff<T> rd_dest = {
+ (T *)dest.ptr(),
+ p_width, p_height,
+ 0, 0, 0, 0
+ };
+
+ // Swap the quadrants to make edges seamless.
+ for (int y = 0; y < p_height; y++) {
+ for (int x = 0; x < p_width; x++) {
+ // rd_src has a half offset and the shorter modulo ignores the skirt.
+ // It reads and writes in Q1-4 order (see map above), skipping the skirt.
+ wr(x, y) = rd_src(x, y, img_buff<T>::ALT_XY);
+ }
+ }
+
+ // Blend the vertical skirt over the middle seam.
+ for (int x = half_width; x < skirt_edge_x; x++) {
+ int alpha = 255 * (1 - Math::smoothstep(.1f, .9f, float(x - half_width) / float(skirt_width)));
+ for (int y = 0; y < p_height; y++) {
+ // Skip the center square
+ if (y == half_height) {
+ y = skirt_edge_y - 1;
+ } else {
+ // Starts reading at s2, ALT_Y skips s3, and continues with s1.
+ wr(x, y) = _alpha_blend<T>(rd_dest(x, y), rd_src(x, y, img_buff<T>::ALT_Y), alpha);
+ }
+ }
+ }
+
+ // Blend the horizontal skirt over the middle seam.
+ for (int y = half_height; y < skirt_edge_y; y++) {
+ int alpha = 255 * (1 - Math::smoothstep(.1f, .9f, float(y - half_height) / float(skirt_height)));
+ for (int x = 0; x < p_width; x++) {
+ // Skip the center square
+ if (x == half_width) {
+ x = skirt_edge_x - 1;
+ } else {
+ // Starts reading at s4, skips s3, continues with s5.
+ wr(x, y) = _alpha_blend<T>(rd_dest(x, y), rd_src(x, y, img_buff<T>::ALT_X), alpha);
+ }
+ }
+ }
+
+ // Fill in the center square. Wr starts at the top left of Q4, which is the equivalent of the top left of s3, unless a modulo is used.
+ for (int y = half_height; y < skirt_edge_y; y++) {
+ for (int x = half_width; x < skirt_edge_x; x++) {
+ int xpos = 255 * (1 - Math::smoothstep(.1f, .9f, float(x - half_width) / float(skirt_width)));
+ int ypos = 255 * (1 - Math::smoothstep(.1f, .9f, float(y - half_height) / float(skirt_height)));
+
+ // Blend s3(Q1) onto s5(Q2) for the top half.
+ T top_blend = _alpha_blend<T>(rd_src(x, y, img_buff<T>::ALT_X), rd_src(x, y, img_buff<T>::DEFAULT), xpos);
+ // Blend s1(Q3) onto Q4 for the bottom half.
+ T bottom_blend = _alpha_blend<T>(rd_src(x, y, img_buff<T>::ALT_XY), rd_src(x, y, img_buff<T>::ALT_Y), xpos);
+ // Blend the top half onto the bottom half.
+ wr(x, y) = _alpha_blend<T>(bottom_blend, top_blend, ypos);
+ }
+ }
+ Ref<Image> image = memnew(Image(p_width, p_height, false, p_src->get_format(), dest));
+ p_src.unref();
+ return image;
+ }
+
+ template <typename T>
+ T _alpha_blend(T p_bg, T p_fg, int p_alpha) const {
+ l2c fg, bg, out;
+
+ fg.l = p_fg;
+ bg.l = p_bg;
+
+ uint16_t alpha;
+ uint16_t inv_alpha;
+
+ // If no alpha argument specified, use the alpha channel in the color
+ if (p_alpha == -1) {
+ alpha = fg.c[3] + 1;
+ inv_alpha = 256 - fg.c[3];
+ } else {
+ alpha = p_alpha + 1;
+ inv_alpha = 256 - p_alpha;
+ }
+
+ out.c[0] = (uint8_t)((alpha * fg.c[0] + inv_alpha * bg.c[0]) >> 8);
+ out.c[1] = (uint8_t)((alpha * fg.c[1] + inv_alpha * bg.c[1]) >> 8);
+ out.c[2] = (uint8_t)((alpha * fg.c[2] + inv_alpha * bg.c[2]) >> 8);
+ out.c[3] = 0xFF;
+
+ return out.l;
+ }
+
+protected:
+ static void _bind_methods();
+
+public:
+ // Virtual destructor so we can delete any Noise derived object when referenced as a Noise*.
+ virtual ~Noise() {}
+
+ virtual real_t get_noise_1d(real_t p_x) const = 0;
+
+ virtual real_t get_noise_2dv(Vector2 p_v) const = 0;
+ virtual real_t get_noise_2d(real_t p_x, real_t p_y) const = 0;
+
+ virtual real_t get_noise_3dv(Vector3 p_v) const = 0;
+ virtual real_t get_noise_3d(real_t p_x, real_t p_y, real_t p_z) const = 0;
+
+ virtual Ref<Image> get_image(int p_width, int p_height, bool p_invert = false, bool p_in_3d_space = false) const;
+ virtual Ref<Image> get_seamless_image(int p_width, int p_height, bool p_invert = false, bool p_in_3d_space = false, real_t p_blend_skirt = 0.1) const;
+};
+
+#endif // NOISE_H
diff --git a/modules/opensimplex/noise_texture.cpp b/modules/noise/noise_texture.cpp
index f3342dfd84..e9d16e548c 100644
--- a/modules/opensimplex/noise_texture.cpp
+++ b/modules/noise/noise_texture.cpp
@@ -31,9 +31,10 @@
#include "noise_texture.h"
#include "core/core_string_names.h"
+#include "noise.h"
NoiseTexture::NoiseTexture() {
- noise = Ref<OpenSimplexNoise>();
+ noise = Ref<Noise>();
_queue_update();
}
@@ -46,35 +47,51 @@ NoiseTexture::~NoiseTexture() {
}
void NoiseTexture::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_update_texture"), &NoiseTexture::_update_texture);
+ ClassDB::bind_method(D_METHOD("_generate_texture"), &NoiseTexture::_generate_texture);
+ ClassDB::bind_method(D_METHOD("_thread_done", "image"), &NoiseTexture::_thread_done);
+
ClassDB::bind_method(D_METHOD("set_width", "width"), &NoiseTexture::set_width);
ClassDB::bind_method(D_METHOD("set_height", "height"), &NoiseTexture::set_height);
- ClassDB::bind_method(D_METHOD("set_noise", "noise"), &NoiseTexture::set_noise);
- ClassDB::bind_method(D_METHOD("get_noise"), &NoiseTexture::get_noise);
+ ClassDB::bind_method(D_METHOD("set_invert", "invert"), &NoiseTexture::set_invert);
+ ClassDB::bind_method(D_METHOD("get_invert"), &NoiseTexture::get_invert);
- ClassDB::bind_method(D_METHOD("set_noise_offset", "noise_offset"), &NoiseTexture::set_noise_offset);
- ClassDB::bind_method(D_METHOD("get_noise_offset"), &NoiseTexture::get_noise_offset);
+ ClassDB::bind_method(D_METHOD("set_in_3d_space", "enable"), &NoiseTexture::set_in_3d_space);
+ ClassDB::bind_method(D_METHOD("is_in_3d_space"), &NoiseTexture::is_in_3d_space);
+
+ ClassDB::bind_method(D_METHOD("set_generate_mipmaps", "invert"), &NoiseTexture::set_generate_mipmaps);
+ ClassDB::bind_method(D_METHOD("is_generating_mipmaps"), &NoiseTexture::is_generating_mipmaps);
ClassDB::bind_method(D_METHOD("set_seamless", "seamless"), &NoiseTexture::set_seamless);
ClassDB::bind_method(D_METHOD("get_seamless"), &NoiseTexture::get_seamless);
+ ClassDB::bind_method(D_METHOD("set_seamless_blend_skirt", "seamless_blend_skirt"), &NoiseTexture::set_seamless_blend_skirt);
+ ClassDB::bind_method(D_METHOD("get_seamless_blend_skirt"), &NoiseTexture::get_seamless_blend_skirt);
+
ClassDB::bind_method(D_METHOD("set_as_normal_map", "as_normal_map"), &NoiseTexture::set_as_normal_map);
ClassDB::bind_method(D_METHOD("is_normal_map"), &NoiseTexture::is_normal_map);
ClassDB::bind_method(D_METHOD("set_bump_strength", "bump_strength"), &NoiseTexture::set_bump_strength);
ClassDB::bind_method(D_METHOD("get_bump_strength"), &NoiseTexture::get_bump_strength);
- ClassDB::bind_method(D_METHOD("_update_texture"), &NoiseTexture::_update_texture);
- ClassDB::bind_method(D_METHOD("_generate_texture"), &NoiseTexture::_generate_texture);
- ClassDB::bind_method(D_METHOD("_thread_done", "image"), &NoiseTexture::_thread_done);
+ ClassDB::bind_method(D_METHOD("set_color_ramp", "gradient"), &NoiseTexture::set_color_ramp);
+ ClassDB::bind_method(D_METHOD("get_color_ramp"), &NoiseTexture::get_color_ramp);
+
+ ClassDB::bind_method(D_METHOD("set_noise", "noise"), &NoiseTexture::set_noise);
+ ClassDB::bind_method(D_METHOD("get_noise"), &NoiseTexture::get_noise);
ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,2048,1,or_greater"), "set_width", "get_width");
ADD_PROPERTY(PropertyInfo(Variant::INT, "height", PROPERTY_HINT_RANGE, "1,2048,1,or_greater"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "invert"), "set_invert", "get_invert");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "in_3d_space"), "set_in_3d_space", "is_in_3d_space");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_mipmaps"), "set_generate_mipmaps", "is_generating_mipmaps");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "seamless"), "set_seamless", "get_seamless");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "seamless_blend_skirt", PROPERTY_HINT_RANGE, "0.05,1,0.001"), "set_seamless_blend_skirt", "get_seamless_blend_skirt");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "as_normal_map"), "set_as_normal_map", "is_normal_map");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bump_strength", PROPERTY_HINT_RANGE, "0,32,0.1,or_greater"), "set_bump_strength", "get_bump_strength");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "noise", PROPERTY_HINT_RESOURCE_TYPE, "OpenSimplexNoise"), "set_noise", "get_noise");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "noise_offset"), "set_noise_offset", "get_noise_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_color_ramp", "get_color_ramp");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "noise", PROPERTY_HINT_RESOURCE_TYPE, "Noise"), "set_noise", "get_noise");
}
void NoiseTexture::_validate_property(PropertyInfo &property) const {
@@ -83,6 +100,12 @@ void NoiseTexture::_validate_property(PropertyInfo &property) const {
property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
}
}
+
+ if (property.name == "seamless_blend_skirt") {
+ if (!seamless) {
+ property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
+ }
}
void NoiseTexture::_set_texture_image(const Ref<Image> &p_image) {
@@ -108,7 +131,7 @@ void NoiseTexture::_thread_done(const Ref<Image> &p_image) {
}
void NoiseTexture::_thread_function(void *p_ud) {
- NoiseTexture *tex = (NoiseTexture *)p_ud;
+ NoiseTexture *tex = static_cast<NoiseTexture *>(p_ud);
tex->call_deferred(SNAME("_thread_done"), tex->_generate_texture());
}
@@ -123,7 +146,7 @@ void NoiseTexture::_queue_update() {
Ref<Image> NoiseTexture::_generate_texture() {
// Prevent memdelete due to unref() on other thread.
- Ref<OpenSimplexNoise> ref_noise = noise;
+ Ref<Noise> ref_noise = noise;
if (ref_noise.is_null()) {
return Ref<Image>();
@@ -132,18 +155,42 @@ Ref<Image> NoiseTexture::_generate_texture() {
Ref<Image> image;
if (seamless) {
- image = ref_noise->get_seamless_image(size.x);
+ image = ref_noise->get_seamless_image(size.x, size.y, invert, in_3d_space, seamless_blend_skirt);
} else {
- image = ref_noise->get_image(size.x, size.y, noise_offset);
+ image = ref_noise->get_image(size.x, size.y, invert, in_3d_space);
+ }
+ if (color_ramp.is_valid()) {
+ image = _modulate_with_gradient(image, color_ramp);
}
-
if (as_normal_map) {
image->bump_map_to_normal_map(bump_strength);
}
+ if (generate_mipmaps) {
+ image->generate_mipmaps();
+ }
return image;
}
+Ref<Image> NoiseTexture::_modulate_with_gradient(Ref<Image> p_image, Ref<Gradient> p_gradient) {
+ int width = p_image->get_width();
+ int height = p_image->get_height();
+
+ Ref<Image> new_image;
+ new_image.instantiate();
+ new_image->create(width, height, false, Image::FORMAT_RGBA8);
+
+ for (int row = 0; row < height; row++) {
+ for (int col = 0; col < width; col++) {
+ Color pixel_color = p_image->get_pixel(col, row);
+ Color ramp_color = color_ramp->get_color_at_offset(pixel_color.get_luminance());
+ new_image->set_pixel(col, row, ramp_color);
+ }
+ }
+
+ return new_image;
+}
+
void NoiseTexture::_update_texture() {
bool use_thread = true;
if (first_time) {
@@ -168,7 +215,7 @@ void NoiseTexture::_update_texture() {
update_queued = false;
}
-void NoiseTexture::set_noise(Ref<OpenSimplexNoise> p_noise) {
+void NoiseTexture::set_noise(Ref<Noise> p_noise) {
if (p_noise == noise) {
return;
}
@@ -182,7 +229,7 @@ void NoiseTexture::set_noise(Ref<OpenSimplexNoise> p_noise) {
_queue_update();
}
-Ref<OpenSimplexNoise> NoiseTexture::get_noise() {
+Ref<Noise> NoiseTexture::get_noise() {
return noise;
}
@@ -204,26 +251,67 @@ void NoiseTexture::set_height(int p_height) {
_queue_update();
}
-void NoiseTexture::set_noise_offset(Vector2 p_noise_offset) {
- if (noise_offset == p_noise_offset) {
+void NoiseTexture::set_invert(bool p_invert) {
+ if (p_invert == invert) {
return;
}
- noise_offset = p_noise_offset;
+ invert = p_invert;
_queue_update();
}
+bool NoiseTexture::get_invert() const {
+ return invert;
+}
+
+void NoiseTexture::set_in_3d_space(bool p_enable) {
+ if (p_enable == in_3d_space) {
+ return;
+ }
+ in_3d_space = p_enable;
+ _queue_update();
+}
+bool NoiseTexture::is_in_3d_space() const {
+ return in_3d_space;
+}
+
+void NoiseTexture::set_generate_mipmaps(bool p_enable) {
+ if (p_enable == generate_mipmaps) {
+ return;
+ }
+ generate_mipmaps = p_enable;
+ _queue_update();
+}
+
+bool NoiseTexture::is_generating_mipmaps() const {
+ return generate_mipmaps;
+}
+
void NoiseTexture::set_seamless(bool p_seamless) {
if (p_seamless == seamless) {
return;
}
seamless = p_seamless;
_queue_update();
+ notify_property_list_changed();
}
bool NoiseTexture::get_seamless() {
return seamless;
}
+void NoiseTexture::set_seamless_blend_skirt(real_t p_blend_skirt) {
+ ERR_FAIL_COND(p_blend_skirt < 0.05 || p_blend_skirt > 1);
+
+ if (p_blend_skirt == seamless_blend_skirt) {
+ return;
+ }
+ seamless_blend_skirt = p_blend_skirt;
+ _queue_update();
+}
+real_t NoiseTexture::get_seamless_blend_skirt() {
+ return seamless_blend_skirt;
+}
+
void NoiseTexture::set_as_normal_map(bool p_as_normal_map) {
if (p_as_normal_map == as_normal_map) {
return;
@@ -251,6 +339,24 @@ float NoiseTexture::get_bump_strength() {
return bump_strength;
}
+void NoiseTexture::set_color_ramp(const Ref<Gradient> &p_gradient) {
+ if (p_gradient == color_ramp) {
+ return;
+ }
+ if (color_ramp.is_valid()) {
+ color_ramp->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture::_queue_update));
+ }
+ color_ramp = p_gradient;
+ if (color_ramp.is_valid()) {
+ color_ramp->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture::_queue_update));
+ }
+ _queue_update();
+}
+
+Ref<Gradient> NoiseTexture::get_color_ramp() const {
+ return color_ramp;
+}
+
int NoiseTexture::get_width() const {
return size.x;
}
@@ -259,10 +365,6 @@ int NoiseTexture::get_height() const {
return size.y;
}
-Vector2 NoiseTexture::get_noise_offset() const {
- return noise_offset;
-}
-
RID NoiseTexture::get_rid() const {
if (!texture.is_valid()) {
texture = RS::get_singleton()->texture_2d_placeholder_create();
diff --git a/modules/opensimplex/noise_texture.h b/modules/noise/noise_texture.h
index ee8f88aaca..6c088562a1 100644
--- a/modules/opensimplex/noise_texture.h
+++ b/modules/noise/noise_texture.h
@@ -31,10 +31,10 @@
#ifndef NOISE_TEXTURE_H
#define NOISE_TEXTURE_H
-#include "open_simplex_noise.h"
+#include "noise.h"
-#include "core/io/image.h"
#include "core/object/ref_counted.h"
+#include "scene/resources/texture.h"
class NoiseTexture : public Texture2D {
GDCLASS(NoiseTexture, Texture2D);
@@ -51,13 +51,18 @@ private:
mutable RID texture;
uint32_t flags = 0;
- Ref<OpenSimplexNoise> noise;
- Vector2i size = Vector2i(512, 512);
- Vector2 noise_offset;
+ Size2i size = Size2i(512, 512);
+ bool invert = false;
+ bool in_3d_space = false;
+ bool generate_mipmaps = true;
bool seamless = false;
+ real_t seamless_blend_skirt = 0.1;
bool as_normal_map = false;
float bump_strength = 8.0;
+ Ref<Gradient> color_ramp;
+ Ref<Noise> noise;
+
void _thread_done(const Ref<Image> &p_image);
static void _thread_function(void *p_ud);
@@ -66,29 +71,43 @@ private:
void _update_texture();
void _set_texture_image(const Ref<Image> &p_image);
+ Ref<Image> _modulate_with_gradient(Ref<Image> p_image, Ref<Gradient> p_gradient);
+
protected:
static void _bind_methods();
virtual void _validate_property(PropertyInfo &property) const override;
public:
- void set_noise(Ref<OpenSimplexNoise> p_noise);
- Ref<OpenSimplexNoise> get_noise();
+ void set_noise(Ref<Noise> p_noise);
+ Ref<Noise> get_noise();
void set_width(int p_width);
void set_height(int p_height);
- void set_noise_offset(Vector2 p_noise_offset);
- Vector2 get_noise_offset() const;
+ void set_invert(bool p_invert);
+ bool get_invert() const;
+
+ void set_in_3d_space(bool p_enable);
+ bool is_in_3d_space() const;
+
+ void set_generate_mipmaps(bool p_enable);
+ bool is_generating_mipmaps() const;
void set_seamless(bool p_seamless);
bool get_seamless();
+ void set_seamless_blend_skirt(real_t p_blend_skirt);
+ real_t get_seamless_blend_skirt();
+
void set_as_normal_map(bool p_as_normal_map);
bool is_normal_map();
void set_bump_strength(float p_bump_strength);
float get_bump_strength();
+ void set_color_ramp(const Ref<Gradient> &p_gradient);
+ Ref<Gradient> get_color_ramp() const;
+
int get_width() const override;
int get_height() const override;
diff --git a/modules/fbx/register_types.cpp b/modules/noise/register_types.cpp
index 73e15e38b4..d0cfc4e944 100644
--- a/modules/fbx/register_types.cpp
+++ b/modules/noise/register_types.cpp
@@ -30,29 +30,31 @@
#include "register_types.h"
-#include "editor/editor_node.h"
-#include "modules/fbx/editor_scene_importer_fbx.h"
+#include "fastnoise_lite.h"
+#include "noise.h"
+#include "noise_texture.h"
#ifdef TOOLS_ENABLED
-static void _editor_init() {
- Ref<EditorSceneFormatImporterFBX> import_fbx;
- import_fbx.instantiate();
- ResourceImporterScene::get_singleton()->add_importer(import_fbx);
-}
+#include "editor/editor_plugin.h"
+#include "editor/noise_editor_plugin.h"
#endif
-void register_fbx_types() {
-#ifdef TOOLS_ENABLED
- ClassDB::APIType prev_api = ClassDB::get_current_api();
- ClassDB::set_current_api(ClassDB::API_EDITOR);
-
- GDREGISTER_CLASS(EditorSceneFormatImporterFBX);
+void initialize_noise_module(ModuleInitializationLevel p_level) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
+ GDREGISTER_CLASS(NoiseTexture);
+ GDREGISTER_ABSTRACT_CLASS(Noise);
+ GDREGISTER_CLASS(FastNoiseLite);
+ }
- ClassDB::set_current_api(prev_api);
-
- EditorNode::add_init_callback(_editor_init);
+#ifdef TOOLS_ENABLED
+ if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
+ EditorPlugins::add_by_type<NoiseEditorPlugin>();
+ }
#endif
}
-void unregister_fbx_types() {
+void uninitialize_noise_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
diff --git a/modules/opensimplex/register_types.h b/modules/noise/register_types.h
index 2262ab2f5e..dfe5a480de 100644
--- a/modules/opensimplex/register_types.h
+++ b/modules/noise/register_types.h
@@ -28,10 +28,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef OPENSIMPLEX_REGISTER_TYPES_H
-#define OPENSIMPLEX_REGISTER_TYPES_H
+#ifndef NOISE_REGISTER_TYPES_H
+#define NOISE_REGISTER_TYPES_H
-void register_opensimplex_types();
-void unregister_opensimplex_types();
+#include "modules/register_module_types.h"
-#endif // OPENSIMPLEX_REGISTER_TYPES_H
+void initialize_noise_module(ModuleInitializationLevel p_level);
+void uninitialize_noise_module(ModuleInitializationLevel p_level);
+
+#endif // NOISE_REGISTER_TYPES_H
diff --git a/modules/ogg/register_types.cpp b/modules/ogg/register_types.cpp
index 3d04351032..01f04aa3d5 100644
--- a/modules/ogg/register_types.cpp
+++ b/modules/ogg/register_types.cpp
@@ -32,9 +32,17 @@
#include "ogg_packet_sequence.h"
-void register_ogg_types() {
+void initialize_ogg_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
GDREGISTER_CLASS(OGGPacketSequence);
GDREGISTER_CLASS(OGGPacketSequencePlayback);
}
-void unregister_ogg_types() {}
+void uninitialize_ogg_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+}
diff --git a/modules/ogg/register_types.h b/modules/ogg/register_types.h
index 6ef7dc93ca..9065d26d07 100644
--- a/modules/ogg/register_types.h
+++ b/modules/ogg/register_types.h
@@ -31,7 +31,9 @@
#ifndef OGG_REGISTER_TYPES_H
#define OGG_REGISTER_TYPES_H
-void register_ogg_types();
-void unregister_ogg_types();
+#include "modules/register_module_types.h"
+
+void initialize_ogg_module(ModuleInitializationLevel p_level);
+void uninitialize_ogg_module(ModuleInitializationLevel p_level);
#endif // OGG_REGISTER_TYPES_H
diff --git a/modules/opensimplex/doc_classes/NoiseTexture.xml b/modules/opensimplex/doc_classes/NoiseTexture.xml
deleted file mode 100644
index 497735ccf3..0000000000
--- a/modules/opensimplex/doc_classes/NoiseTexture.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NoiseTexture" inherits="Texture2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- [OpenSimplexNoise] filled texture.
- </brief_description>
- <description>
- Uses an [OpenSimplexNoise] to fill the texture data. You can specify the texture size but keep in mind that larger textures will take longer to generate and seamless noise only works with square sized textures.
- NoiseTexture can also generate normal map textures.
- The class uses [Thread]s to generate the texture data internally, so [method Texture2D.get_image] may return [code]null[/code] if the generation process has not completed yet. In that case, you need to wait for the texture to be generated before accessing the image and the generated byte data:
- [codeblock]
- var texture = NoiseTexture.new()
- texture.noise = OpenSimplexNoise.new()
- await texture.changed
- var image = texture.get_image()
- var data = image.get_data()
- [/codeblock]
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="as_normal_map" type="bool" setter="set_as_normal_map" getter="is_normal_map" default="false">
- If [code]true[/code], the resulting texture contains a normal map created from the original noise interpreted as a bump map.
- </member>
- <member name="bump_strength" type="float" setter="set_bump_strength" getter="get_bump_strength" default="8.0">
- Strength of the bump maps used in this texture. A higher value will make the bump maps appear larger while a lower value will make them appear softer.
- </member>
- <member name="height" type="int" setter="set_height" getter="get_height" default="512">
- Height of the generated texture.
- </member>
- <member name="noise" type="OpenSimplexNoise" setter="set_noise" getter="get_noise">
- The [OpenSimplexNoise] instance used to generate the noise.
- </member>
- <member name="noise_offset" type="Vector2" setter="set_noise_offset" getter="get_noise_offset" default="Vector2(0, 0)">
- An offset used to specify the noise space coordinate of the top left corner of the generated noise. This value is ignored if [member seamless] is enabled.
- </member>
- <member name="seamless" type="bool" setter="set_seamless" getter="get_seamless" default="false">
- Whether the texture can be tiled without visible seams or not. Seamless textures take longer to generate.
- [b]Note:[/b] Seamless noise has a lower contrast compared to non-seamless noise. This is due to the way noise uses higher dimensions for generating seamless noise.
- </member>
- <member name="width" type="int" setter="set_width" getter="get_width" default="512">
- Width of the generated texture.
- </member>
- </members>
-</class>
diff --git a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml
deleted file mode 100644
index 51dd83efc3..0000000000
--- a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml
+++ /dev/null
@@ -1,112 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="OpenSimplexNoise" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- Noise generator based on Open Simplex.
- </brief_description>
- <description>
- This resource allows you to configure and sample a fractal noise space. Here is a brief usage example that configures an OpenSimplexNoise and gets samples at various positions and dimensions:
- [codeblock]
- var noise = OpenSimplexNoise.new()
-
- # Configure
- noise.seed = randi()
- noise.octaves = 4
- noise.period = 20.0
- noise.persistence = 0.8
-
- # Sample
- print("Values:")
- print(noise.get_noise_2d(1.0, 1.0))
- print(noise.get_noise_3d(0.5, 3.0, 15.0))
- print(noise.get_noise_4d(0.5, 1.9, 4.7, 0.0))
- [/codeblock]
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_image" qualifiers="const">
- <return type="Image" />
- <argument index="0" name="width" type="int" />
- <argument index="1" name="height" type="int" />
- <argument index="2" name="noise_offset" type="Vector2" default="Vector2(0, 0)" />
- <description>
- Generate a noise image in [constant Image.FORMAT_L8] format with the requested [code]width[/code] and [code]height[/code], based on the current noise parameters. If [code]noise_offset[/code] is specified, then the offset value is used as the coordinates of the top-left corner of the generated noise.
- </description>
- </method>
- <method name="get_noise_1d" qualifiers="const">
- <return type="float" />
- <argument index="0" name="x" type="float" />
- <description>
- Returns the 1D noise value [code][-1,1][/code] at the given x-coordinate.
- [b]Note:[/b] This method actually returns the 2D noise value [code][-1,1][/code] with fixed y-coordinate value 0.0.
- </description>
- </method>
- <method name="get_noise_2d" qualifiers="const">
- <return type="float" />
- <argument index="0" name="x" type="float" />
- <argument index="1" name="y" type="float" />
- <description>
- Returns the 2D noise value [code][-1,1][/code] at the given position.
- </description>
- </method>
- <method name="get_noise_2dv" qualifiers="const">
- <return type="float" />
- <argument index="0" name="pos" type="Vector2" />
- <description>
- Returns the 2D noise value [code][-1,1][/code] at the given position.
- </description>
- </method>
- <method name="get_noise_3d" qualifiers="const">
- <return type="float" />
- <argument index="0" name="x" type="float" />
- <argument index="1" name="y" type="float" />
- <argument index="2" name="z" type="float" />
- <description>
- Returns the 3D noise value [code][-1,1][/code] at the given position.
- </description>
- </method>
- <method name="get_noise_3dv" qualifiers="const">
- <return type="float" />
- <argument index="0" name="pos" type="Vector3" />
- <description>
- Returns the 3D noise value [code][-1,1][/code] at the given position.
- </description>
- </method>
- <method name="get_noise_4d" qualifiers="const">
- <return type="float" />
- <argument index="0" name="x" type="float" />
- <argument index="1" name="y" type="float" />
- <argument index="2" name="z" type="float" />
- <argument index="3" name="w" type="float" />
- <description>
- Returns the 4D noise value [code][-1,1][/code] at the given position.
- </description>
- </method>
- <method name="get_seamless_image" qualifiers="const">
- <return type="Image" />
- <argument index="0" name="size" type="int" />
- <description>
- Generate a tileable noise image in [constant Image.FORMAT_L8] format, based on the current noise parameters. Generated seamless images are always square ([code]size[/code] × [code]size[/code]).
- [b]Note:[/b] Seamless noise has a lower contrast compared to non-seamless noise. This is due to the way noise uses higher dimensions for generating seamless noise.
- </description>
- </method>
- </methods>
- <members>
- <member name="lacunarity" type="float" setter="set_lacunarity" getter="get_lacunarity" default="2.0">
- Difference in period between [member octaves].
- </member>
- <member name="octaves" type="int" setter="set_octaves" getter="get_octaves" default="3">
- Number of OpenSimplex noise layers that are sampled to get the fractal noise. Higher values result in more detailed noise but take more time to generate.
- [b]Note:[/b] The maximum allowed value is 9.
- </member>
- <member name="period" type="float" setter="set_period" getter="get_period" default="64.0">
- Period of the base octave. A lower period results in a higher-frequency noise (more value changes across the same distance).
- </member>
- <member name="persistence" type="float" setter="set_persistence" getter="get_persistence" default="0.5">
- Contribution factor of the different octaves. A [code]persistence[/code] value of 1 means all the octaves have the same contribution, a value of 0.5 means each octave contributes half as much as the previous one.
- </member>
- <member name="seed" type="int" setter="set_seed" getter="get_seed" default="0">
- Seed used to generate random values, different seeds will generate different noise maps.
- </member>
- </members>
-</class>
diff --git a/modules/opensimplex/open_simplex_noise.cpp b/modules/opensimplex/open_simplex_noise.cpp
deleted file mode 100644
index b7c901fd06..0000000000
--- a/modules/opensimplex/open_simplex_noise.cpp
+++ /dev/null
@@ -1,250 +0,0 @@
-/*************************************************************************/
-/* open_simplex_noise.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "open_simplex_noise.h"
-
-#include "core/core_string_names.h"
-
-OpenSimplexNoise::OpenSimplexNoise() {
- _init_seeds();
-}
-
-OpenSimplexNoise::~OpenSimplexNoise() {
-}
-
-void OpenSimplexNoise::_init_seeds() {
- for (int i = 0; i < MAX_OCTAVES; ++i) {
- open_simplex_noise(seed + i * 2, &(contexts[i]));
- }
-}
-
-void OpenSimplexNoise::set_seed(int p_seed) {
- if (seed == p_seed) {
- return;
- }
-
- seed = p_seed;
-
- _init_seeds();
-
- emit_changed();
-}
-
-int OpenSimplexNoise::get_seed() const {
- return seed;
-}
-
-void OpenSimplexNoise::set_octaves(int p_octaves) {
- if (p_octaves == octaves) {
- return;
- }
-
- ERR_FAIL_COND_MSG(p_octaves > MAX_OCTAVES, vformat("The number of OpenSimplexNoise octaves is limited to %d; ignoring the new value.", MAX_OCTAVES));
-
- octaves = CLAMP(p_octaves, 1, MAX_OCTAVES);
- emit_changed();
-}
-
-void OpenSimplexNoise::set_period(float p_period) {
- if (p_period == period) {
- return;
- }
- period = p_period;
- emit_changed();
-}
-
-void OpenSimplexNoise::set_persistence(float p_persistence) {
- if (p_persistence == persistence) {
- return;
- }
- persistence = p_persistence;
- emit_changed();
-}
-
-void OpenSimplexNoise::set_lacunarity(float p_lacunarity) {
- if (p_lacunarity == lacunarity) {
- return;
- }
- lacunarity = p_lacunarity;
- emit_changed();
-}
-
-Ref<Image> OpenSimplexNoise::get_image(int p_width, int p_height, const Vector2 &p_noise_offset) const {
- Vector<uint8_t> data;
- data.resize(p_width * p_height);
-
- uint8_t *wd8 = data.ptrw();
-
- for (int i = 0; i < p_height; i++) {
- for (int j = 0; j < p_width; j++) {
- float v = get_noise_2d(float(j) + p_noise_offset.x, float(i) + p_noise_offset.y);
- v = v * 0.5 + 0.5; // Normalize [0..1]
- wd8[(i * p_width + j)] = uint8_t(CLAMP(v * 255.0, 0, 255));
- }
- }
-
- Ref<Image> image = memnew(Image(p_width, p_height, false, Image::FORMAT_L8, data));
- return image;
-}
-
-Ref<Image> OpenSimplexNoise::get_seamless_image(int p_size) const {
- Vector<uint8_t> data;
- data.resize(p_size * p_size);
-
- uint8_t *wd8 = data.ptrw();
-
- for (int i = 0; i < p_size; i++) {
- for (int j = 0; j < p_size; j++) {
- float ii = (float)i / (float)p_size;
- float jj = (float)j / (float)p_size;
-
- ii *= Math_TAU;
- jj *= Math_TAU;
-
- float radius = p_size / Math_TAU;
-
- float x = radius * Math::sin(jj);
- float y = radius * Math::cos(jj);
- float z = radius * Math::sin(ii);
- float w = radius * Math::cos(ii);
- float v = get_noise_4d(x, y, z, w);
-
- v = v * 0.5 + 0.5; // Normalize [0..1]
- wd8[(i * p_size + j)] = uint8_t(CLAMP(v * 255.0, 0, 255));
- }
- }
-
- Ref<Image> image = memnew(Image(p_size, p_size, false, Image::FORMAT_L8, data));
- return image;
-}
-
-void OpenSimplexNoise::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_seed"), &OpenSimplexNoise::get_seed);
- ClassDB::bind_method(D_METHOD("set_seed", "seed"), &OpenSimplexNoise::set_seed);
-
- ClassDB::bind_method(D_METHOD("set_octaves", "octave_count"), &OpenSimplexNoise::set_octaves);
- ClassDB::bind_method(D_METHOD("get_octaves"), &OpenSimplexNoise::get_octaves);
-
- ClassDB::bind_method(D_METHOD("set_period", "period"), &OpenSimplexNoise::set_period);
- ClassDB::bind_method(D_METHOD("get_period"), &OpenSimplexNoise::get_period);
-
- ClassDB::bind_method(D_METHOD("set_persistence", "persistence"), &OpenSimplexNoise::set_persistence);
- ClassDB::bind_method(D_METHOD("get_persistence"), &OpenSimplexNoise::get_persistence);
-
- ClassDB::bind_method(D_METHOD("set_lacunarity", "lacunarity"), &OpenSimplexNoise::set_lacunarity);
- ClassDB::bind_method(D_METHOD("get_lacunarity"), &OpenSimplexNoise::get_lacunarity);
-
- ClassDB::bind_method(D_METHOD("get_image", "width", "height", "noise_offset"), &OpenSimplexNoise::get_image, DEFVAL(Vector2()));
- ClassDB::bind_method(D_METHOD("get_seamless_image", "size"), &OpenSimplexNoise::get_seamless_image);
-
- ClassDB::bind_method(D_METHOD("get_noise_1d", "x"), &OpenSimplexNoise::get_noise_1d);
- ClassDB::bind_method(D_METHOD("get_noise_2d", "x", "y"), &OpenSimplexNoise::get_noise_2d);
- ClassDB::bind_method(D_METHOD("get_noise_3d", "x", "y", "z"), &OpenSimplexNoise::get_noise_3d);
- ClassDB::bind_method(D_METHOD("get_noise_4d", "x", "y", "z", "w"), &OpenSimplexNoise::get_noise_4d);
-
- ClassDB::bind_method(D_METHOD("get_noise_2dv", "pos"), &OpenSimplexNoise::get_noise_2dv);
- ClassDB::bind_method(D_METHOD("get_noise_3dv", "pos"), &OpenSimplexNoise::get_noise_3dv);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "seed"), "set_seed", "get_seed");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "octaves", PROPERTY_HINT_RANGE, vformat("1,%d,1", MAX_OCTAVES)), "set_octaves", "get_octaves");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "period", PROPERTY_HINT_RANGE, "0.1,256.0,0.1"), "set_period", "get_period");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "persistence", PROPERTY_HINT_RANGE, "0.0,1.0,0.001"), "set_persistence", "get_persistence");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lacunarity", PROPERTY_HINT_RANGE, "0.1,4.0,0.01"), "set_lacunarity", "get_lacunarity");
-}
-
-float OpenSimplexNoise::get_noise_1d(float x) const {
- return get_noise_2d(x, 1.0);
-}
-
-float OpenSimplexNoise::get_noise_2d(float x, float y) const {
- x /= period;
- y /= period;
-
- float amp = 1.0;
- float max = 1.0;
- float sum = _get_octave_noise_2d(0, x, y);
-
- int i = 0;
- while (++i < octaves) {
- x *= lacunarity;
- y *= lacunarity;
- amp *= persistence;
- max += amp;
- sum += _get_octave_noise_2d(i, x, y) * amp;
- }
-
- return sum / max;
-}
-
-float OpenSimplexNoise::get_noise_3d(float x, float y, float z) const {
- x /= period;
- y /= period;
- z /= period;
-
- float amp = 1.0;
- float max = 1.0;
- float sum = _get_octave_noise_3d(0, x, y, z);
-
- int i = 0;
- while (++i < octaves) {
- x *= lacunarity;
- y *= lacunarity;
- z *= lacunarity;
- amp *= persistence;
- max += amp;
- sum += _get_octave_noise_3d(i, x, y, z) * amp;
- }
-
- return sum / max;
-}
-
-float OpenSimplexNoise::get_noise_4d(float x, float y, float z, float w) const {
- x /= period;
- y /= period;
- z /= period;
- w /= period;
-
- float amp = 1.0;
- float max = 1.0;
- float sum = _get_octave_noise_4d(0, x, y, z, w);
-
- int i = 0;
- while (++i < octaves) {
- x *= lacunarity;
- y *= lacunarity;
- z *= lacunarity;
- w *= lacunarity;
- amp *= persistence;
- max += amp;
- sum += _get_octave_noise_4d(i, x, y, z, w) * amp;
- }
-
- return sum / max;
-}
diff --git a/modules/opensimplex/open_simplex_noise.h b/modules/opensimplex/open_simplex_noise.h
deleted file mode 100644
index c34f998b78..0000000000
--- a/modules/opensimplex/open_simplex_noise.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*************************************************************************/
-/* open_simplex_noise.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef OPEN_SIMPLEX_NOISE_H
-#define OPEN_SIMPLEX_NOISE_H
-
-#include "core/io/image.h"
-#include "core/object/ref_counted.h"
-#include "scene/resources/texture.h"
-
-#include "thirdparty/misc/open-simplex-noise.h"
-
-class OpenSimplexNoise : public Resource {
- GDCLASS(OpenSimplexNoise, Resource);
- OBJ_SAVE_TYPE(OpenSimplexNoise);
-
- // The maximum number of octaves allowed. Note that these are statically allocated.
- // Higher values become exponentially slower, so this shouldn't be set too high
- // to avoid freezing the editor for long periods of time.
- static const int MAX_OCTAVES = 9;
-
- osn_context contexts[MAX_OCTAVES];
-
- int seed = 0;
- float persistence = 0.5; // Controls details, value in [0,1]. Higher increases grain, lower increases smoothness.
- int octaves = 3; // Number of noise layers
- float period = 64.0; // Distance above which we start to see similarities. The higher, the longer "hills" will be on a terrain.
- float lacunarity = 2.0; // Controls period change across octaves. 2 is usually a good value to address all detail levels.
-
-public:
- OpenSimplexNoise();
- ~OpenSimplexNoise();
-
- void _init_seeds();
-
- void set_seed(int seed);
- int get_seed() const;
-
- void set_octaves(int p_octaves);
- int get_octaves() const { return octaves; }
-
- void set_period(float p_period);
- float get_period() const { return period; }
-
- void set_persistence(float p_persistence);
- float get_persistence() const { return persistence; }
-
- void set_lacunarity(float p_lacunarity);
- float get_lacunarity() const { return lacunarity; }
-
- Ref<Image> get_image(int p_width, int p_height, const Vector2 &p_noise_offset = Vector2()) const;
- Ref<Image> get_seamless_image(int p_size) const;
-
- float get_noise_1d(float x) const;
- float get_noise_2d(float x, float y) const;
- float get_noise_3d(float x, float y, float z) const;
- float get_noise_4d(float x, float y, float z, float w) const;
-
- _FORCE_INLINE_ float _get_octave_noise_2d(int octave, float x, float y) const { return open_simplex_noise2(&(contexts[octave]), x, y); }
- _FORCE_INLINE_ float _get_octave_noise_3d(int octave, float x, float y, float z) const { return open_simplex_noise3(&(contexts[octave]), x, y, z); }
- _FORCE_INLINE_ float _get_octave_noise_4d(int octave, float x, float y, float z, float w) const { return open_simplex_noise4(&(contexts[octave]), x, y, z, w); }
-
- // Convenience
-
- _FORCE_INLINE_ float get_noise_2dv(const Vector2 &v) const { return get_noise_2d(v.x, v.y); }
- _FORCE_INLINE_ float get_noise_3dv(const Vector3 &v) const { return get_noise_3d(v.x, v.y, v.z); }
-
-protected:
- static void _bind_methods();
-};
-
-#endif // OPEN_SIMPLEX_NOISE_H
diff --git a/modules/opensimplex/register_types.cpp b/modules/opensimplex/register_types.cpp
deleted file mode 100644
index 30dfdc3764..0000000000
--- a/modules/opensimplex/register_types.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/*************************************************************************/
-/* register_types.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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 "noise_texture.h"
-#include "open_simplex_noise.h"
-
-void register_opensimplex_types() {
- GDREGISTER_CLASS(OpenSimplexNoise);
- GDREGISTER_CLASS(NoiseTexture);
-}
-
-void unregister_opensimplex_types() {
-}
diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub
index 37a8f3909a..ff320236a7 100644
--- a/modules/openxr/SCsub
+++ b/modules/openxr/SCsub
@@ -75,7 +75,7 @@ module_obj = []
env_openxr.add_source_files(module_obj, "*.cpp")
env_openxr.add_source_files(module_obj, "action_map/*.cpp")
-# We're a little more targetted with our extensions
+# We're a little more targeted with our extensions
if env["platform"] == "android":
env_openxr.add_source_files(module_obj, "extensions/openxr_android_extension.cpp")
if env["vulkan"]:
@@ -83,5 +83,8 @@ if env["vulkan"]:
env.modules_sources += module_obj
+if env["tools"]:
+ SConscript("editor/SCsub")
+
# Needed to force rebuilding the module files when the thirdparty library is updated.
env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/openxr/action_map/openxr_action.cpp b/modules/openxr/action_map/openxr_action.cpp
index 59ee3f4292..359975a480 100644
--- a/modules/openxr/action_map/openxr_action.cpp
+++ b/modules/openxr/action_map/openxr_action.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "openxr_action.h"
+#include "openxr_action_set.h"
void OpenXRAction::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_localized_name", "localized_name"), &OpenXRAction::set_localized_name);
@@ -62,6 +63,16 @@ Ref<OpenXRAction> OpenXRAction::new_action(const char *p_name, const char *p_loc
return action;
}
+String OpenXRAction::get_name_with_set() const {
+ String name = get_name();
+
+ if (action_set != nullptr) {
+ name = action_set->get_name() + "/" + name;
+ }
+
+ return name;
+}
+
void OpenXRAction::set_localized_name(const String p_localized_name) {
localized_name = p_localized_name;
}
@@ -86,6 +97,18 @@ PackedStringArray OpenXRAction::get_toplevel_paths() const {
return toplevel_paths;
}
+void OpenXRAction::add_toplevel_path(const String p_toplevel_path) {
+ if (!toplevel_paths.has(p_toplevel_path)) {
+ toplevel_paths.push_back(p_toplevel_path);
+ }
+}
+
+void OpenXRAction::rem_toplevel_path(const String p_toplevel_path) {
+ if (toplevel_paths.has(p_toplevel_path)) {
+ toplevel_paths.erase(p_toplevel_path);
+ }
+}
+
void OpenXRAction::parse_toplevel_paths(const String p_toplevel_paths) {
toplevel_paths = p_toplevel_paths.split(",", false);
}
diff --git a/modules/openxr/action_map/openxr_action.h b/modules/openxr/action_map/openxr_action.h
index e2cfe79e64..5e57f89133 100644
--- a/modules/openxr/action_map/openxr_action.h
+++ b/modules/openxr/action_map/openxr_action.h
@@ -33,6 +33,8 @@
#include "core/io/resource.h"
+class OpenXRActionSet;
+
class OpenXRAction : public Resource {
GDCLASS(OpenXRAction, Resource);
@@ -43,6 +45,7 @@ public:
OPENXR_ACTION_VECTOR2,
OPENXR_ACTION_POSE,
OPENXR_ACTION_HAPTIC,
+ OPENXR_ACTION_MAX
};
private:
@@ -52,21 +55,31 @@ private:
PackedStringArray toplevel_paths;
protected:
+ friend class OpenXRActionSet;
+
+ OpenXRActionSet *action_set = nullptr; // action belongs to this action set.
+
static void _bind_methods();
public:
- static Ref<OpenXRAction> new_action(const char *p_name, const char *p_localized_name, const ActionType p_action_type, const char *p_toplevel_paths);
+ static Ref<OpenXRAction> new_action(const char *p_name, const char *p_localized_name, const ActionType p_action_type, const char *p_toplevel_paths); // Helper function to add and configure an action
+ OpenXRActionSet *get_action_set() const { return action_set; } // Get the action set this action belongs to
+
+ String get_name_with_set() const; // Retrieve the name of this action as <action_set>/<action>
+
+ void set_localized_name(const String p_localized_name); // Set the localized name of this action
+ String get_localized_name() const; // Get the localized name of this action
- void set_localized_name(const String p_localized_name);
- String get_localized_name() const;
+ void set_action_type(const ActionType p_action_type); // Set the type of this action
+ ActionType get_action_type() const; // Get the type of this action
- void set_action_type(const ActionType p_action_type);
- ActionType get_action_type() const;
+ void set_toplevel_paths(const PackedStringArray p_toplevel_paths); // Set the toplevel paths of this action
+ PackedStringArray get_toplevel_paths() const; // Get the toplevel paths of this action
- void set_toplevel_paths(const PackedStringArray p_toplevel_paths);
- PackedStringArray get_toplevel_paths() const;
+ void add_toplevel_path(const String p_toplevel_path); // Add a top level path to this action
+ void rem_toplevel_path(const String p_toplevel_path); // Remove a toplevel path from this action
- void parse_toplevel_paths(const String p_toplevel_paths);
+ void parse_toplevel_paths(const String p_toplevel_paths); // Parse and set the top level paths from a comma separated string
};
VARIANT_ENUM_CAST(OpenXRAction::ActionType);
diff --git a/modules/openxr/action_map/openxr_action_map.cpp b/modules/openxr/action_map/openxr_action_map.cpp
index 5391f9569a..366e131369 100644
--- a/modules/openxr/action_map/openxr_action_map.cpp
+++ b/modules/openxr/action_map/openxr_action_map.cpp
@@ -35,6 +35,9 @@ void OpenXRActionMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_action_sets"), &OpenXRActionMap::get_action_sets);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "action_sets", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRActionSet", PROPERTY_USAGE_NO_EDITOR), "set_action_sets", "get_action_sets");
+ ClassDB::bind_method(D_METHOD("get_action_set_count"), &OpenXRActionMap::get_action_set_count);
+ ClassDB::bind_method(D_METHOD("find_action_set", "name"), &OpenXRActionMap::find_action_set);
+ ClassDB::bind_method(D_METHOD("get_action_set", "idx"), &OpenXRActionMap::get_action_set);
ClassDB::bind_method(D_METHOD("add_action_set", "action_set"), &OpenXRActionMap::add_action_set);
ClassDB::bind_method(D_METHOD("remove_action_set", "action_set"), &OpenXRActionMap::remove_action_set);
@@ -42,6 +45,9 @@ void OpenXRActionMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_interaction_profiles"), &OpenXRActionMap::get_interaction_profiles);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "interaction_profiles", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRInteractionProfile", PROPERTY_USAGE_NO_EDITOR), "set_interaction_profiles", "get_interaction_profiles");
+ ClassDB::bind_method(D_METHOD("get_interaction_profile_count"), &OpenXRActionMap::get_interaction_profile_count);
+ ClassDB::bind_method(D_METHOD("find_interaction_profile", "name"), &OpenXRActionMap::find_interaction_profile);
+ ClassDB::bind_method(D_METHOD("get_interaction_profile", "idx"), &OpenXRActionMap::get_interaction_profile);
ClassDB::bind_method(D_METHOD("add_interaction_profile", "interaction_profile"), &OpenXRActionMap::add_interaction_profile);
ClassDB::bind_method(D_METHOD("remove_interaction_profile", "interaction_profile"), &OpenXRActionMap::remove_interaction_profile);
@@ -49,13 +55,41 @@ void OpenXRActionMap::_bind_methods() {
}
void OpenXRActionMap::set_action_sets(Array p_action_sets) {
- action_sets = p_action_sets;
+ action_sets.clear();
+
+ for (int i = 0; i < p_action_sets.size(); i++) {
+ Ref<OpenXRActionSet> action_set = p_action_sets[i];
+ if (action_set.is_valid() && action_sets.find(action_set) == -1) {
+ action_sets.push_back(action_set);
+ }
+ }
}
Array OpenXRActionMap::get_action_sets() const {
return action_sets;
}
+int OpenXRActionMap::get_action_set_count() const {
+ return action_sets.size();
+}
+
+Ref<OpenXRActionSet> OpenXRActionMap::find_action_set(String p_name) const {
+ for (int i = 0; i < action_sets.size(); i++) {
+ Ref<OpenXRActionSet> action_set = action_sets[i];
+ if (action_set->get_name() == p_name) {
+ return action_set;
+ }
+ }
+
+ return Ref<OpenXRActionSet>();
+}
+
+Ref<OpenXRActionSet> OpenXRActionMap::get_action_set(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx, action_sets.size(), Ref<OpenXRActionSet>());
+
+ return action_sets[p_idx];
+}
+
void OpenXRActionMap::add_action_set(Ref<OpenXRActionSet> p_action_set) {
ERR_FAIL_COND(p_action_set.is_null());
@@ -72,13 +106,41 @@ void OpenXRActionMap::remove_action_set(Ref<OpenXRActionSet> p_action_set) {
}
void OpenXRActionMap::set_interaction_profiles(Array p_interaction_profiles) {
- interaction_profiles = p_interaction_profiles;
+ interaction_profiles.clear();
+
+ for (int i = 0; i < p_interaction_profiles.size(); i++) {
+ Ref<OpenXRInteractionProfile> interaction_profile = p_interaction_profiles[i];
+ if (interaction_profile.is_valid() && interaction_profiles.find(interaction_profile) == -1) {
+ interaction_profiles.push_back(interaction_profile);
+ }
+ }
}
Array OpenXRActionMap::get_interaction_profiles() const {
return interaction_profiles;
}
+int OpenXRActionMap::get_interaction_profile_count() const {
+ return interaction_profiles.size();
+}
+
+Ref<OpenXRInteractionProfile> OpenXRActionMap::find_interaction_profile(String p_path) const {
+ for (int i = 0; i < interaction_profiles.size(); i++) {
+ Ref<OpenXRInteractionProfile> interaction_profile = interaction_profiles[i];
+ if (interaction_profile->get_interaction_profile_path() == p_path) {
+ return interaction_profile;
+ }
+ }
+
+ return Ref<OpenXRInteractionProfile>();
+}
+
+Ref<OpenXRInteractionProfile> OpenXRActionMap::get_interaction_profile(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx, interaction_profiles.size(), Ref<OpenXRInteractionProfile>());
+
+ return interaction_profiles[p_idx];
+}
+
void OpenXRActionMap::add_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile) {
ERR_FAIL_COND(p_interaction_profile.is_null());
@@ -165,7 +227,7 @@ void OpenXRActionMap::create_default_action_sets() {
profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click");
// wmr controller has no a/b/x/y buttons
profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
- profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); // OpenXR will conver float to bool
+ profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); // OpenXR will convert float to bool
profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); // OpenXR will convert bool to float
profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");
// primary on our wmr controller is our thumbstick, no touch
@@ -178,27 +240,6 @@ void OpenXRActionMap::create_default_action_sets() {
profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
add_interaction_profile(profile);
- // Create our HP MR controller profile
- profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/hp/mixed_reality_controller");
- profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
- profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
- profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
- // hpmr controllers have no select button we can use
- profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click");
- // hpmr controllers only register click, not touch, on our a/b/x/y buttons
- profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand
- profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand
- profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
- profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
- profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value");
- profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value");
- // primary on our hpmr controller is our thumbstick
- profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");
- profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");
- // No secondary on our hpmr controller
- profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
- add_interaction_profile(profile);
-
// Create our Meta touch controller profile
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/oculus/touch_controller");
profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
@@ -249,12 +290,185 @@ void OpenXRActionMap::create_default_action_sets() {
profile->add_new_binding(secondary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch");
profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
add_interaction_profile(profile);
+
+ // Note, the following profiles are all part of extensions.
+ // We include these regardless of whether the extension is active.
+ // We want our action map to be as complete as possible so our game is as portable as possible.
+ // It is very possible these will in due time become core.
+
+ // Create our HP MR controller profile
+ profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/hp/mixed_reality_controller");
+ profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
+ profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ // hpmr controllers have no select button we can use
+ profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click");
+ // hpmr controllers only register click, not touch, on our a/b/x/y buttons
+ profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand
+ profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand
+ profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
+ profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
+ profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value");
+ profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value");
+ // primary on our hpmr controller is our thumbstick
+ profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");
+ profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");
+ // No secondary on our hpmr controller
+ profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
+ add_interaction_profile(profile);
+
+ // Create our Samsung Odyssey controller profile,
+ // Note that this controller is only identified specifically on WMR, on SteamVR this is identified as a normal WMR controller.
+ profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/samsung/odyssey_controller");
+ profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
+ profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ // Odyssey controllers have no select button we can use
+ profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click");
+ // Odyssey controller has no a/b/x/y buttons
+ profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
+ profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
+ profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");
+ profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");
+ // primary on our Odyssey controller is our thumbstick, no touch
+ profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");
+ profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");
+ // secondary on our Odyssey controller is our trackpad
+ profile->add_new_binding(secondary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad");
+ profile->add_new_binding(secondary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click");
+ profile->add_new_binding(secondary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch");
+ profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
+ add_interaction_profile(profile);
+
+ // Create our Vive Cosmos controller
+ profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_cosmos_controller");
+ profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
+ profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click");
+ profile->add_new_binding(select_button, "/user/hand/left/input/system/click"); // we'll map system to select
+ profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand
+ profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand
+ profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
+ profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click");
+ profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");
+ profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");
+ // primary on our Cosmos controller is our thumbstick
+ profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");
+ profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");
+ profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch");
+ // No secondary on our cosmos controller
+ profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
+ add_interaction_profile(profile);
+
+ // Create our Vive Focus 3 controller
+ // Note, Vive Focus 3 currently is not yet supported as a stand alone device
+ // however HTC currently has a beta OpenXR runtime in testing we may support in the near future
+ profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_focus3_controller");
+ profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
+ profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click");
+ profile->add_new_binding(select_button, "/user/hand/left/input/system/click"); // we'll map system to select
+ profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand
+ profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand
+ profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
+ profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click");
+ profile->add_new_binding(trigger_touch, "/user/hand/left/input/trigger/touch,/user/hand/right/input/trigger/touch");
+ profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");
+ profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");
+ // primary on our Focus 3 controller is our thumbstick
+ profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");
+ profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");
+ profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch");
+ // We only have a thumb rest
+ profile->add_new_binding(secondary_touch, "/user/hand/left/input/thumbrest/touch,/user/hand/right/input/thumbrest/touch");
+ profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
+ add_interaction_profile(profile);
+
+ // Create our Huawei controller
+ profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/huawei/controller");
+ profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
+ profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(menu_button, "/user/hand/left/input/home/click,/user/hand/right/input/home/click");
+ profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
+ profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click");
+ // primary on our Huawei controller is our trackpad
+ profile->add_new_binding(primary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad");
+ profile->add_new_binding(primary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click");
+ profile->add_new_binding(primary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch");
+ profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
+ add_interaction_profile(profile);
}
void OpenXRActionMap::create_editor_action_sets() {
// TODO implement
}
+Ref<OpenXRAction> OpenXRActionMap::get_action(const String p_path) const {
+ PackedStringArray paths = p_path.split("/", false);
+ ERR_FAIL_COND_V(paths.size() != 2, Ref<OpenXRAction>());
+
+ Ref<OpenXRActionSet> action_set = find_action_set(paths[0]);
+ if (action_set.is_valid()) {
+ return action_set->get_action(paths[1]);
+ }
+
+ return Ref<OpenXRAction>();
+}
+
+void OpenXRActionMap::remove_action(const String p_path) {
+ Ref<OpenXRAction> action = get_action(p_path);
+ if (action.is_valid()) {
+ OpenXRActionSet *action_set = action->get_action_set();
+ if (action_set != nullptr) {
+ // Remove the action from this action set
+ action_set->remove_action(action);
+ }
+
+ for (int i = 0; i < interaction_profiles.size(); i++) {
+ Ref<OpenXRInteractionProfile> interaction_profile = interaction_profiles[i];
+
+ // Remove any bindings for this action
+ interaction_profile->remove_binding_for_action(action);
+ }
+ }
+}
+
+PackedStringArray OpenXRActionMap::get_top_level_paths(Ref<OpenXRAction> p_action) {
+ PackedStringArray arr;
+
+ for (int i = 0; i < interaction_profiles.size(); i++) {
+ Ref<OpenXRInteractionProfile> ip = interaction_profiles[i];
+ const OpenXRDefs::InteractionProfile *profile = OpenXRDefs::get_profile(ip->get_interaction_profile_path());
+
+ if (profile != nullptr) {
+ for (int j = 0; j < ip->get_binding_count(); j++) {
+ Ref<OpenXRIPBinding> binding = ip->get_binding(j);
+ if (binding->get_action() == p_action) {
+ PackedStringArray paths = binding->get_paths();
+
+ for (int k = 0; k < paths.size(); k++) {
+ const OpenXRDefs::IOPath *io_path = profile->get_io_path(paths[k]);
+ if (io_path != nullptr) {
+ String top_path = String(io_path->top_level_path->openxr_path);
+
+ if (!arr.has(top_path)) {
+ arr.push_back(top_path);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ print_line("Toplevel paths for", p_action->get_name_with_set(), "are", arr);
+
+ return arr;
+}
+
OpenXRActionMap::~OpenXRActionMap() {
action_sets.clear();
interaction_profiles.clear();
diff --git a/modules/openxr/action_map/openxr_action_map.h b/modules/openxr/action_map/openxr_action_map.h
index 866e170468..dcd8fc71aa 100644
--- a/modules/openxr/action_map/openxr_action_map.h
+++ b/modules/openxr/action_map/openxr_action_map.h
@@ -33,6 +33,7 @@
#include "core/io/resource.h"
+#include "openxr_action.h"
#include "openxr_action_set.h"
#include "openxr_interaction_profile.h"
@@ -47,20 +48,33 @@ protected:
static void _bind_methods();
public:
- void set_action_sets(Array p_action_sets);
- Array get_action_sets() const;
+ void set_action_sets(Array p_action_sets); // Set our actions sets by providing an array with action sets (for loading from resource)
+ Array get_action_sets() const; // Get our action sets as an array (for saving to resource)
- void add_action_set(Ref<OpenXRActionSet> p_action_set);
- void remove_action_set(Ref<OpenXRActionSet> p_action_set);
+ int get_action_set_count() const; // Retrieve the number of action sets we have
+ Ref<OpenXRActionSet> find_action_set(String p_name) const; // Find an action set by name
+ Ref<OpenXRActionSet> get_action_set(int p_idx) const; // Retrieve an action set by index
+ void add_action_set(Ref<OpenXRActionSet> p_action_set); // Add an action set to our action map
+ void remove_action_set(Ref<OpenXRActionSet> p_action_set); // Remove an action set from our action map
- void set_interaction_profiles(Array p_interaction_profiles);
- Array get_interaction_profiles() const;
+ void set_interaction_profiles(Array p_interaction_profiles); // Set our interaction profiles by providing an array (for loading from resource)
+ Array get_interaction_profiles() const; // Get our interaction profiles as an array (for saving to resource)
- void add_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile);
- void remove_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile);
+ int get_interaction_profile_count() const; // Retrieve the number of interaction profiles we have
+ Ref<OpenXRInteractionProfile> find_interaction_profile(String p_path) const; // Find an interaction profile by path
+ Ref<OpenXRInteractionProfile> get_interaction_profile(int p_idx) const; // Retrieve an interaction profile by index
+ void add_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile); // Add an interaction profile to our action map
+ void remove_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile); // remove an interaction profile from our action map
- void create_default_action_sets();
- void create_editor_action_sets();
+ void create_default_action_sets(); // Create our default action set for runtime
+ void create_editor_action_sets(); // Create our action set for the editor
+
+ // Helper functions for editor
+ Ref<OpenXRAction> get_action(const String p_path) const; // Retrieve an action using <action name>/<action> as our parameter
+ void remove_action(const String p_path); // Remove action from action set, also removes it from interaction profiles
+ PackedStringArray get_top_level_paths(Ref<OpenXRAction> p_action); // Determines the top level paths based on where an action is bound in interaction profiles
+
+ // TODO add validation to display in the interface that checks if we have action sets with the same name or if we have interaction profiles for the same path
~OpenXRActionMap();
};
diff --git a/modules/openxr/action_map/openxr_action_set.cpp b/modules/openxr/action_map/openxr_action_set.cpp
index 465a709b60..be45218300 100644
--- a/modules/openxr/action_map/openxr_action_set.cpp
+++ b/modules/openxr/action_map/openxr_action_set.cpp
@@ -39,6 +39,7 @@ void OpenXRActionSet::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_priority"), &OpenXRActionSet::get_priority);
ADD_PROPERTY(PropertyInfo(Variant::INT, "priority"), "set_priority", "get_priority");
+ ClassDB::bind_method(D_METHOD("get_action_count"), &OpenXRActionSet::get_action_count);
ClassDB::bind_method(D_METHOD("set_actions", "actions"), &OpenXRActionSet::set_actions);
ClassDB::bind_method(D_METHOD("get_actions"), &OpenXRActionSet::get_actions);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "actions", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRAction", PROPERTY_USAGE_NO_EDITOR), "set_actions", "get_actions");
@@ -75,18 +76,54 @@ int OpenXRActionSet::get_priority() const {
return priority;
}
+int OpenXRActionSet::get_action_count() const {
+ return actions.size();
+}
+
+void OpenXRActionSet::clear_actions() {
+ // Actions held within our action set should be released and destroyed but just in case they are still used some where else
+ for (int i = 0; i < actions.size(); i++) {
+ Ref<OpenXRAction> action = actions[i];
+ action->action_set = nullptr;
+ }
+ actions.clear();
+}
+
void OpenXRActionSet::set_actions(Array p_actions) {
- actions = p_actions;
+ // Any actions not retained in p_actions should be freed automatically, those held within our Array will have be relinked to our action set.
+ clear_actions();
+
+ for (int i = 0; i < p_actions.size(); i++) {
+ // add them anew so we verify our action_set pointer
+ add_action(p_actions[i]);
+ }
}
Array OpenXRActionSet::get_actions() const {
return actions;
}
+Ref<OpenXRAction> OpenXRActionSet::get_action(const String p_name) const {
+ for (int i = 0; i < actions.size(); i++) {
+ Ref<OpenXRAction> action = actions[i];
+ if (action->get_name() == p_name) {
+ return action;
+ }
+ }
+
+ return Ref<OpenXRAction>();
+}
+
void OpenXRActionSet::add_action(Ref<OpenXRAction> p_action) {
ERR_FAIL_COND(p_action.is_null());
if (actions.find(p_action) == -1) {
+ if (p_action->action_set && p_action->action_set != this) {
+ // action should only relate to our action set
+ p_action->action_set->remove_action(p_action);
+ }
+
+ p_action->action_set = this;
actions.push_back(p_action);
}
}
@@ -95,6 +132,9 @@ void OpenXRActionSet::remove_action(Ref<OpenXRAction> p_action) {
int idx = actions.find(p_action);
if (idx != -1) {
actions.remove_at(idx);
+
+ ERR_FAIL_COND_MSG(p_action->action_set != this, "Removing action that belongs to this action set but had incorrect action set pointer."); // this should never happen!
+ p_action->action_set = nullptr;
}
}
@@ -107,5 +147,5 @@ Ref<OpenXRAction> OpenXRActionSet::add_new_action(const char *p_name, const char
}
OpenXRActionSet::~OpenXRActionSet() {
- actions.clear();
+ clear_actions();
}
diff --git a/modules/openxr/action_map/openxr_action_set.h b/modules/openxr/action_map/openxr_action_set.h
index 012a088b1c..b1d7168894 100644
--- a/modules/openxr/action_map/openxr_action_set.h
+++ b/modules/openxr/action_map/openxr_action_set.h
@@ -43,26 +43,31 @@ private:
int priority = 0;
Array actions;
+ void clear_actions();
protected:
static void _bind_methods();
public:
- static Ref<OpenXRActionSet> new_action_set(const char *p_name, const char *p_localized_name, const int p_priority = 0);
+ static Ref<OpenXRActionSet> new_action_set(const char *p_name, const char *p_localized_name, const int p_priority = 0); // Helper function for adding and setting up an action set
- void set_localized_name(const String p_localized_name);
- String get_localized_name() const;
+ void set_localized_name(const String p_localized_name); // Set the localized name of this action set
+ String get_localized_name() const; // Get the localized name of this action set
- void set_priority(const int p_priority);
- int get_priority() const;
+ void set_priority(const int p_priority); // Set the priority of this action set
+ int get_priority() const; // Get the priority of this action set
- void set_actions(Array p_actions);
- Array get_actions() const;
+ int get_action_count() const; // Retrieve the number of actions in our action set
+ void set_actions(Array p_actions); // Set our actions using an array of actions (for loading a resource)
+ Array get_actions() const; // Get our actions as an array (for saving a resource)
- void add_action(Ref<OpenXRAction> p_action);
- void remove_action(Ref<OpenXRAction> p_action);
+ Ref<OpenXRAction> get_action(const String p_name) const; // Retrieve an action by name
+ void add_action(Ref<OpenXRAction> p_action); // Add a new action to our action set
+ void remove_action(Ref<OpenXRAction> p_action); // remove a action from our action set
- Ref<OpenXRAction> add_new_action(const char *p_name, const char *p_localized_name, const OpenXRAction::ActionType p_action_type, const char *p_toplevel_paths);
+ Ref<OpenXRAction> add_new_action(const char *p_name, const char *p_localized_name, const OpenXRAction::ActionType p_action_type, const char *p_toplevel_paths); // Helper function for adding and setting up an action
+
+ // TODO add validation to display in the interface that checks if we have duplicate action names within our action set
~OpenXRActionSet();
};
diff --git a/modules/openxr/action_map/openxr_defs.cpp b/modules/openxr/action_map/openxr_defs.cpp
new file mode 100644
index 0000000000..e10326449c
--- /dev/null
+++ b/modules/openxr/action_map/openxr_defs.cpp
@@ -0,0 +1,493 @@
+/*************************************************************************/
+/* openxr_defs.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "openxr_defs.h"
+
+// Our top level paths to which devices can be bound
+OpenXRDefs::TopLevelPath OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_TOP_LEVEL_PATH_MAX] = {
+ { "Left hand controller", "/user/hand/left" },
+ { "Right hand controller", "/user/hand/right" },
+};
+
+// Fallback Khronos simple controller
+OpenXRDefs::IOPath OpenXRDefs::simple_io_paths[] = {
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Select click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/select/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Select click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/select/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+};
+
+// Original HTC Vive wands
+OpenXRDefs::IOPath OpenXRDefs::vive_io_paths[] = {
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+};
+
+// Microsoft motion controller (original WMR controllers)
+OpenXRDefs::IOPath OpenXRDefs::motion_io_paths[] = {
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+};
+
+// HP MR controller (newer G2 controllers)
+OpenXRDefs::IOPath OpenXRDefs::hpmr_io_paths[] = {
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "X click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/x/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Y click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/y/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Squeeze", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Squeeze", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+};
+
+// Meta touch controller (original touch controllers, Quest 1 and Quest 2 controllers)
+OpenXRDefs::IOPath OpenXRDefs::touch_io_paths[] = {
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "X click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/x/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "X touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/x/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Y click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/y/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Y touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/y/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "A touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "B touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Squeeze", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Squeeze", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+};
+
+// Valve index controller
+OpenXRDefs::IOPath OpenXRDefs::index_io_paths[] = {
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+
+ { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "A touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/a/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "A touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "B touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/b/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "B touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Squeeze", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Squeeze", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Trackpad force", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/force", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Trackpad force", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/force", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+};
+
+// Samsung odyssey controller
+OpenXRDefs::IOPath OpenXRDefs::odyssey_io_paths[] = {
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+};
+
+// Vive Cosmos controller
+OpenXRDefs::IOPath OpenXRDefs::vive_cosmos_paths[] = {
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "X click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/x/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Y click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/y/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Shoulder click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/right/input/shoulder/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Shoulder click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/shoulder/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+};
+
+// Vive Focus 3 controller
+OpenXRDefs::IOPath OpenXRDefs::vive_focus3_paths[] = {
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "X click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/x/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Y click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/y/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/touch ", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Squeeze touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Squeeze touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Thumbrest touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbrest/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+};
+
+// Huawei controller
+OpenXRDefs::IOPath OpenXRDefs::huawei_controller_paths[] = {
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+
+ { "Home click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/home/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Home click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/home/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Back click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/back/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Back click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/back/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Volume up click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/volume_up/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Volume up click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/volume_up/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Volume down click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/volume_down/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Volume down click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/volume_down/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+};
+
+OpenXRDefs::InteractionProfile OpenXRDefs::available_interaction_profiles[] = {
+ {
+ "Simple controller", // display_name
+ "/interaction_profiles/khr/simple_controller", // openxr_path
+ simple_io_paths, // io_paths
+ sizeof(simple_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
+ },
+ {
+ "HTC Vive wand", // display_name
+ "/interaction_profiles/htc/vive_controller", // openxr_path
+ vive_io_paths, // io_paths
+ sizeof(vive_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
+ },
+ {
+ "MS Motion controller", // display_name
+ "/interaction_profiles/microsoft/motion_controller", // openxr_path
+ motion_io_paths, // io_paths
+ sizeof(motion_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
+ },
+ {
+ "HPMR controller", // display_name
+ "/interaction_profiles/hp/mixed_reality_controller", // openxr_path
+ hpmr_io_paths, // io_paths
+ sizeof(hpmr_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
+ },
+ {
+ "Touch controller", // display_name
+ "/interaction_profiles/oculus/touch_controller", // openxr_path
+ touch_io_paths, // io_paths
+ sizeof(touch_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
+ },
+ {
+ "Index controller", // display_name
+ "/interaction_profiles/valve/index_controller", // openxr_path
+ index_io_paths, // io_paths
+ sizeof(index_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
+ },
+ {
+ "Samsung Odyssey controller", // display_name
+ "/interaction_profiles/samsung/odyssey_controller", // openxr_path
+ odyssey_io_paths, // io_paths
+ sizeof(odyssey_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
+ },
+ {
+ "Vive Cosmos controller", // display_name
+ "/interaction_profiles/htc/vive_cosmos_controller", // openxr_path
+ vive_cosmos_paths, // io_paths
+ sizeof(vive_cosmos_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
+ },
+ {
+ "Vive Focus 3 controller", // display_name
+ "/interaction_profiles/htc/vive_focus3_controller", // openxr_path
+ vive_focus3_paths, // io_paths
+ sizeof(vive_focus3_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
+ },
+ {
+ "Huawei controller", // display_name
+ "/interaction_profiles/huawei/controller", // openxr_path
+ huawei_controller_paths, // io_paths
+ sizeof(huawei_controller_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
+ },
+};
+
+int OpenXRDefs::available_interaction_profile_count = sizeof(OpenXRDefs::available_interaction_profiles) / sizeof(OpenXRDefs::InteractionProfile);
+
+const OpenXRDefs::TopLevelPath *OpenXRDefs::get_top_level_path(const String p_top_level_path) {
+ for (int i = 0; i < OPENXR_TOP_LEVEL_PATH_MAX; i++) {
+ if (available_top_level_paths[i].openxr_path == p_top_level_path) {
+ return &OpenXRDefs::available_top_level_paths[i];
+ }
+ }
+
+ return nullptr;
+}
+
+const OpenXRDefs::InteractionProfile *OpenXRDefs::get_profile(const String p_interaction_profile_path) {
+ for (int i = 0; i < available_interaction_profile_count; i++) {
+ if (available_interaction_profiles[i].openxr_path == p_interaction_profile_path) {
+ return &available_interaction_profiles[i];
+ }
+ }
+
+ return nullptr;
+}
+
+const OpenXRDefs::IOPath *OpenXRDefs::InteractionProfile::get_io_path(const String p_io_path) const {
+ for (int i = 0; i < available_interaction_profiles[i].io_path_count; i++) {
+ if (io_paths[i].openxr_path == p_io_path) {
+ return &io_paths[i];
+ }
+ }
+
+ return nullptr;
+}
+
+const OpenXRDefs::IOPath *OpenXRDefs::get_io_path(const String p_interaction_profile_path, const String p_io_path) {
+ const OpenXRDefs::InteractionProfile *profile = OpenXRDefs::get_profile(p_interaction_profile_path);
+ if (profile != nullptr) {
+ return profile->get_io_path(p_io_path);
+ }
+
+ return nullptr;
+}
+
+PackedStringArray OpenXRDefs::get_interaction_profile_paths() {
+ PackedStringArray arr;
+
+ for (int i = 0; i < available_interaction_profile_count; i++) {
+ arr.push_back(available_interaction_profiles[i].openxr_path);
+ }
+
+ return arr;
+}
diff --git a/modules/openxr/action_map/openxr_defs.h b/modules/openxr/action_map/openxr_defs.h
new file mode 100644
index 0000000000..dbda4757f1
--- /dev/null
+++ b/modules/openxr/action_map/openxr_defs.h
@@ -0,0 +1,103 @@
+/*************************************************************************/
+/* openxr_defs.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef OPENXR_DEFS_H
+#define OPENXR_DEFS_H
+
+#include "openxr_action.h"
+
+///////////////////////////////////////////////////////////////////////////
+// Stores available interaction profiles
+//
+// OpenXR defines and hardcodes all the supported input devices and their
+// paths as part of the OpenXR spec. When support for new devices is
+// introduced this often starts life as extensions that need to be enabled
+// until they are adopted into the core. As there is no interface to
+// enumerate the possibly paths, and that any OpenXR runtime would likely
+// limit such enumeration to those input devices supported by that runtime
+// there is no other option than to hardcode this.
+//
+// Note on action type that automatic conversions between boolean and float
+// are supported but otherwise action types should match between action and
+// input/output paths.
+
+class OpenXRDefs {
+public:
+ enum TOP_LEVEL_PATH {
+ OPENXR_LEFT_HAND,
+ OPENXR_RIGHT_HAND,
+ OPENXR_TOP_LEVEL_PATH_MAX
+ };
+
+ struct TopLevelPath {
+ const char *display_name; // User friendly display name (i.e. Left controller)
+ const char *openxr_path; // Path in OpenXR (i.e. /user/hand/left)
+ };
+
+ struct IOPath {
+ const char *display_name; // User friendly display name (i.e. Grip pose (left controller))
+ const TopLevelPath *top_level_path; // Top level path identifying the usage of the device in relation to this input/output
+ const char *openxr_path; // Path in OpenXR (i.e. /user/hand/left/input/grip/pose)
+ const OpenXRAction::ActionType action_type; // Type of input/output
+ };
+
+ struct InteractionProfile {
+ const char *display_name; // User friendly display name (i.e. Simple controller)
+ const char *openxr_path; // Path in OpenXR (i.e. /interaction_profiles/khr/simple_controller)
+ const IOPath *io_paths; // Inputs and outputs for this device
+ const int io_path_count; // Number of inputs and outputs for this device
+
+ const IOPath *get_io_path(const String p_io_path) const;
+ };
+
+private:
+ static TopLevelPath available_top_level_paths[OPENXR_TOP_LEVEL_PATH_MAX];
+ static IOPath simple_io_paths[];
+ static IOPath vive_io_paths[];
+ static IOPath motion_io_paths[];
+ static IOPath hpmr_io_paths[];
+ static IOPath touch_io_paths[];
+ static IOPath index_io_paths[];
+ static IOPath odyssey_io_paths[];
+ static IOPath vive_cosmos_paths[];
+ static IOPath vive_focus3_paths[];
+ static IOPath huawei_controller_paths[];
+ static InteractionProfile available_interaction_profiles[];
+ static int available_interaction_profile_count;
+
+public:
+ static const TopLevelPath *get_top_level_path(const String p_top_level_path);
+ static const InteractionProfile *get_profile(const String p_interaction_profile_path);
+ static const IOPath *get_io_path(const String p_interaction_profile_path, const String p_io_path);
+
+ static PackedStringArray get_interaction_profile_paths();
+};
+
+#endif // !OPENXR_DEFS_H
diff --git a/modules/openxr/action_map/openxr_interaction_profile.cpp b/modules/openxr/action_map/openxr_interaction_profile.cpp
index bc33814f17..342c36cdff 100644
--- a/modules/openxr/action_map/openxr_interaction_profile.cpp
+++ b/modules/openxr/action_map/openxr_interaction_profile.cpp
@@ -35,9 +35,14 @@ void OpenXRIPBinding::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_action"), &OpenXRIPBinding::get_action);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "action", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRAction"), "set_action", "get_action");
+ ClassDB::bind_method(D_METHOD("get_path_count"), &OpenXRIPBinding::get_path_count);
ClassDB::bind_method(D_METHOD("set_paths", "paths"), &OpenXRIPBinding::set_paths);
ClassDB::bind_method(D_METHOD("get_paths"), &OpenXRIPBinding::get_paths);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "paths", PROPERTY_HINT_ARRAY_TYPE, "STRING"), "set_paths", "get_paths");
+
+ ClassDB::bind_method(D_METHOD("has_path"), &OpenXRIPBinding::has_path);
+ ClassDB::bind_method(D_METHOD("add_path", "path"), &OpenXRIPBinding::add_path);
+ ClassDB::bind_method(D_METHOD("remove_path", "path"), &OpenXRIPBinding::remove_path);
}
Ref<OpenXRIPBinding> OpenXRIPBinding::new_binding(const Ref<OpenXRAction> p_action, const char *p_paths) {
@@ -59,6 +64,10 @@ Ref<OpenXRAction> OpenXRIPBinding::get_action() const {
return action;
}
+int OpenXRIPBinding::get_path_count() const {
+ return paths.size();
+}
+
void OpenXRIPBinding::set_paths(const PackedStringArray p_paths) {
paths = p_paths;
}
@@ -71,6 +80,22 @@ void OpenXRIPBinding::parse_paths(const String p_paths) {
paths = p_paths.split(",", false);
}
+bool OpenXRIPBinding::has_path(const String p_path) const {
+ return paths.has(p_path);
+}
+
+void OpenXRIPBinding::add_path(const String p_path) {
+ if (!paths.has(p_path)) {
+ paths.push_back(p_path);
+ }
+}
+
+void OpenXRIPBinding::remove_path(const String p_path) {
+ if (paths.has(p_path)) {
+ paths.erase(p_path);
+ }
+}
+
OpenXRIPBinding::~OpenXRIPBinding() {
action.unref();
}
@@ -80,6 +105,8 @@ void OpenXRInteractionProfile::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_interaction_profile_path"), &OpenXRInteractionProfile::get_interaction_profile_path);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "interaction_profile_path"), "set_interaction_profile_path", "get_interaction_profile_path");
+ ClassDB::bind_method(D_METHOD("get_binding_count"), &OpenXRInteractionProfile::get_binding_count);
+ ClassDB::bind_method(D_METHOD("get_binding", "index"), &OpenXRInteractionProfile::get_binding);
ClassDB::bind_method(D_METHOD("set_bindings", "bindings"), &OpenXRInteractionProfile::set_bindings);
ClassDB::bind_method(D_METHOD("get_bindings"), &OpenXRInteractionProfile::get_bindings);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "bindings", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRIPBinding", PROPERTY_USAGE_NO_EDITOR), "set_bindings", "get_bindings");
@@ -101,18 +128,43 @@ String OpenXRInteractionProfile::get_interaction_profile_path() const {
return interaction_profile_path;
}
+int OpenXRInteractionProfile::get_binding_count() const {
+ return bindings.size();
+}
+
+Ref<OpenXRIPBinding> OpenXRInteractionProfile::get_binding(int p_index) const {
+ ERR_FAIL_INDEX_V(p_index, bindings.size(), Ref<OpenXRIPBinding>());
+
+ return bindings[p_index];
+}
+
void OpenXRInteractionProfile::set_bindings(Array p_bindings) {
bindings = p_bindings;
+
+ // TODO add check here that our bindings don't contain duplicate actions
}
Array OpenXRInteractionProfile::get_bindings() const {
return bindings;
}
+Ref<OpenXRIPBinding> OpenXRInteractionProfile::get_binding_for_action(const Ref<OpenXRAction> p_action) const {
+ for (int i = 0; i < bindings.size(); i++) {
+ Ref<OpenXRIPBinding> binding = bindings[i];
+ if (binding->get_action() == p_action) {
+ return binding;
+ }
+ }
+
+ return Ref<OpenXRIPBinding>();
+}
+
void OpenXRInteractionProfile::add_binding(Ref<OpenXRIPBinding> p_binding) {
ERR_FAIL_COND(p_binding.is_null());
if (bindings.find(p_binding) == -1) {
+ ERR_FAIL_COND_MSG(get_binding_for_action(p_binding->get_action()).is_valid(), "There is already a binding for this action in this interaction profile");
+
bindings.push_back(p_binding);
}
}
@@ -131,6 +183,15 @@ void OpenXRInteractionProfile::add_new_binding(const Ref<OpenXRAction> p_action,
add_binding(binding);
}
+void OpenXRInteractionProfile::remove_binding_for_action(const Ref<OpenXRAction> p_action) {
+ for (int i = bindings.size() - 1; i >= 0; i--) {
+ Ref<OpenXRIPBinding> binding = bindings[i];
+ if (binding->get_action() == p_action) {
+ remove_binding(binding);
+ }
+ }
+}
+
OpenXRInteractionProfile::~OpenXRInteractionProfile() {
bindings.clear();
}
diff --git a/modules/openxr/action_map/openxr_interaction_profile.h b/modules/openxr/action_map/openxr_interaction_profile.h
index abbc429e7d..46b1bda50f 100644
--- a/modules/openxr/action_map/openxr_interaction_profile.h
+++ b/modules/openxr/action_map/openxr_interaction_profile.h
@@ -34,6 +34,7 @@
#include "core/io/resource.h"
#include "openxr_action.h"
+#include "openxr_defs.h"
class OpenXRIPBinding : public Resource {
GDCLASS(OpenXRIPBinding, Resource);
@@ -46,15 +47,22 @@ protected:
static void _bind_methods();
public:
- static Ref<OpenXRIPBinding> new_binding(const Ref<OpenXRAction> p_action, const char *p_paths);
+ static Ref<OpenXRIPBinding> new_binding(const Ref<OpenXRAction> p_action, const char *p_paths); // Helper function for adding a new binding
- void set_action(const Ref<OpenXRAction> p_action);
- Ref<OpenXRAction> get_action() const;
+ void set_action(const Ref<OpenXRAction> p_action); // Set the action for this binding
+ Ref<OpenXRAction> get_action() const; // Get the action for this binding
- void set_paths(const PackedStringArray p_paths);
- PackedStringArray get_paths() const;
+ int get_path_count() const; // Get the number of io paths
+ void set_paths(const PackedStringArray p_paths); // Set our paths (for loading from resource)
+ PackedStringArray get_paths() const; // Get our paths (for saving to resource)
- void parse_paths(const String p_paths);
+ void parse_paths(const String p_paths); // Parse a comma separated string of io paths.
+
+ bool has_path(const String p_path) const; // Has this io path
+ void add_path(const String p_path); // Add an io path
+ void remove_path(const String p_path); // Remove an io path
+
+ // TODO add validation that we can display in the interface that checks if no two paths belong to the same top level path
~OpenXRIPBinding();
};
@@ -70,18 +78,22 @@ protected:
static void _bind_methods();
public:
- static Ref<OpenXRInteractionProfile> new_profile(const char *p_input_profile_path);
+ static Ref<OpenXRInteractionProfile> new_profile(const char *p_input_profile_path); // Helper function to create a new interaction profile
- void set_interaction_profile_path(const String p_input_profile_path);
- String get_interaction_profile_path() const;
+ void set_interaction_profile_path(const String p_input_profile_path); // Set our input profile path
+ String get_interaction_profile_path() const; // get our input profile path
- void set_bindings(Array p_bindings);
- Array get_bindings() const;
+ int get_binding_count() const; // Retrieve the number of bindings in this profile path
+ Ref<OpenXRIPBinding> get_binding(int p_index) const;
+ void set_bindings(Array p_bindings); // Set the bindings (for loading from a resource)
+ Array get_bindings() const; // Get the bindings (for saving to a resource)
- void add_binding(Ref<OpenXRIPBinding> p_binding);
- void remove_binding(Ref<OpenXRIPBinding> p_binding);
+ Ref<OpenXRIPBinding> get_binding_for_action(const Ref<OpenXRAction> p_action) const; // Get our binding record for a given action
+ void add_binding(Ref<OpenXRIPBinding> p_binding); // Add a binding object
+ void remove_binding(Ref<OpenXRIPBinding> p_binding); // Remove a binding object
- void add_new_binding(const Ref<OpenXRAction> p_action, const char *p_paths);
+ void add_new_binding(const Ref<OpenXRAction> p_action, const char *p_paths); // Create a new binding for this profile
+ void remove_binding_for_action(const Ref<OpenXRAction> p_action); // Remove all bindings for this action
~OpenXRInteractionProfile();
};
diff --git a/modules/openxr/doc_classes/OpenXRActionMap.xml b/modules/openxr/doc_classes/OpenXRActionMap.xml
index f1def8aad8..a29d10be41 100644
--- a/modules/openxr/doc_classes/OpenXRActionMap.xml
+++ b/modules/openxr/doc_classes/OpenXRActionMap.xml
@@ -6,7 +6,7 @@
<description>
OpenXR uses an action system similar to Godots Input map system to bind inputs and outputs on various types of XR controllers to named actions. OpenXR specifies more detail on these inputs and outputs than Godot supports.
Another important distinction is that OpenXR offers no control over these bindings. The bindings we register are suggestions, it is up to the XR runtime to offer users the ability to change these bindings. This allows the XR runtime to fill in the gaps if new hardware becomes available.
- The action map therefor needs to be loaded at startup and can't be changed afterwards. This resource is a container for the entire action map.
+ The action map therefore needs to be loaded at startup and can't be changed afterwards. This resource is a container for the entire action map.
</description>
<tutorials>
</tutorials>
@@ -31,6 +31,46 @@
Setup this action set with our default actions.
</description>
</method>
+ <method name="find_action_set" qualifiers="const">
+ <return type="OpenXRActionSet" />
+ <argument index="0" name="name" type="String" />
+ <description>
+ Retrieve an action set by name.
+ </description>
+ </method>
+ <method name="find_interaction_profile" qualifiers="const">
+ <return type="OpenXRInteractionProfile" />
+ <argument index="0" name="name" type="String" />
+ <description>
+ Find an interaction profile by its name (path).
+ </description>
+ </method>
+ <method name="get_action_set" qualifiers="const">
+ <return type="OpenXRActionSet" />
+ <argument index="0" name="idx" type="int" />
+ <description>
+ Retrieve the action set at this index.
+ </description>
+ </method>
+ <method name="get_action_set_count" qualifiers="const">
+ <return type="int" />
+ <description>
+ Retrieve the number of actions sets in our action map.
+ </description>
+ </method>
+ <method name="get_interaction_profile" qualifiers="const">
+ <return type="OpenXRInteractionProfile" />
+ <argument index="0" name="idx" type="int" />
+ <description>
+ Get the interaction profile at this index.
+ </description>
+ </method>
+ <method name="get_interaction_profile_count" qualifiers="const">
+ <return type="int" />
+ <description>
+ Retrieve the number of interaction profiles in our action map.
+ </description>
+ </method>
<method name="remove_action_set">
<return type="void" />
<argument index="0" name="action_set" type="OpenXRActionSet" />
@@ -48,8 +88,10 @@
</methods>
<members>
<member name="action_sets" type="Array" setter="set_action_sets" getter="get_action_sets" default="[]">
+ Collection of [OpenXRActionSet]s that are part of this action map.
</member>
<member name="interaction_profiles" type="Array" setter="set_interaction_profiles" getter="get_interaction_profiles" default="[]">
+ Collection of [OpenXRInteractionProfile]s that are part of this action map.
</member>
</members>
</class>
diff --git a/modules/openxr/doc_classes/OpenXRActionSet.xml b/modules/openxr/doc_classes/OpenXRActionSet.xml
index 5a87de463e..55cc0aaad4 100644
--- a/modules/openxr/doc_classes/OpenXRActionSet.xml
+++ b/modules/openxr/doc_classes/OpenXRActionSet.xml
@@ -5,8 +5,7 @@
</brief_description>
<description>
Action sets in OpenXR define a collection of actions that can be activated in unison. This allows games to easily change between different states that require different inputs or need to reinterpret inputs. For instance we could have an action set that is active when a menu is open, an action set that is active when the player is freely walking around and an action set that is active when the player is controlling a vehicle.
- Action sets can contain the same actions, or actions with the same name, if such action sets are active at the same time the action set with the highest priority defines which binding is active.
- Note that the name of the resource is used to identify the action set within OpenXR.
+ Action sets can contain the same action with the same name, if such action sets are active at the same time the action set with the highest priority defines which binding is active.
</description>
<tutorials>
</tutorials>
@@ -18,6 +17,12 @@
Add an action to this action set.
</description>
</method>
+ <method name="get_action_count" qualifiers="const">
+ <return type="int" />
+ <description>
+ Retrieve the number of actions in our action set.
+ </description>
+ </method>
<method name="remove_action">
<return type="void" />
<argument index="0" name="action" type="OpenXRAction" />
diff --git a/modules/openxr/doc_classes/OpenXRIPBinding.xml b/modules/openxr/doc_classes/OpenXRIPBinding.xml
index 3fdcde5eb5..9e1176874a 100644
--- a/modules/openxr/doc_classes/OpenXRIPBinding.xml
+++ b/modules/openxr/doc_classes/OpenXRIPBinding.xml
@@ -4,13 +4,42 @@
Defines a binding between an [OpenXRAction] and an XR input or output.
</brief_description>
<description>
- This binding resource binds an OpenXR action to inputs or outputs. As most controllers have left hand and right versions that are handled by the same interaction profile we can specify multiple bindings. For instance an action "Fire" could be bound to both "/user/hand/left/input/trigger" and "/user/hand/right/input/trigger".
+ This binding resource binds an [OpenXRAction] to inputs or outputs. As most controllers have left hand and right versions that are handled by the same interaction profile we can specify multiple bindings. For instance an action "Fire" could be bound to both "/user/hand/left/input/trigger" and "/user/hand/right/input/trigger".
</description>
<tutorials>
</tutorials>
+ <methods>
+ <method name="add_path">
+ <return type="void" />
+ <argument index="0" name="path" type="String" />
+ <description>
+ Add an input/output path to this binding.
+ </description>
+ </method>
+ <method name="get_path_count" qualifiers="const">
+ <return type="int" />
+ <description>
+ Get the number of input/output paths in this binding.
+ </description>
+ </method>
+ <method name="has_path" qualifiers="const">
+ <return type="bool" />
+ <argument index="0" name="arg0" type="String" />
+ <description>
+ Returns [code]true[/code] if this input/output path is part of this binding.
+ </description>
+ </method>
+ <method name="remove_path">
+ <return type="void" />
+ <argument index="0" name="path" type="String" />
+ <description>
+ Removes this input/output path from this binding.
+ </description>
+ </method>
+ </methods>
<members>
<member name="action" type="OpenXRAction" setter="set_action" getter="get_action">
- Action that is bound to these paths.
+ [OpenXRAction] that is bound to these paths.
</member>
<member name="paths" type="PackedStringArray" setter="set_paths" getter="get_paths" default="PackedStringArray()">
Paths that define the inputs or outputs bound on the device.
diff --git a/modules/openxr/doc_classes/OpenXRInteractionProfile.xml b/modules/openxr/doc_classes/OpenXRInteractionProfile.xml
index a8629caae4..71c0db44ed 100644
--- a/modules/openxr/doc_classes/OpenXRInteractionProfile.xml
+++ b/modules/openxr/doc_classes/OpenXRInteractionProfile.xml
@@ -9,6 +9,21 @@
</description>
<tutorials>
</tutorials>
+ <methods>
+ <method name="get_binding" qualifiers="const">
+ <return type="OpenXRIPBinding" />
+ <argument index="0" name="index" type="int" />
+ <description>
+ Retrieve the binding at this index.
+ </description>
+ </method>
+ <method name="get_binding_count" qualifiers="const">
+ <return type="int" />
+ <description>
+ Get the number of bindings in this interaction profile.
+ </description>
+ </method>
+ </methods>
<members>
<member name="bindings" type="Array" setter="set_bindings" getter="get_bindings" default="[]">
Action bindings for this interaction profile.
diff --git a/modules/openxr/editor/SCsub b/modules/openxr/editor/SCsub
new file mode 100644
index 0000000000..ccf67a80d0
--- /dev/null
+++ b/modules/openxr/editor/SCsub
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/openxr/editor/openxr_action_editor.cpp b/modules/openxr/editor/openxr_action_editor.cpp
new file mode 100644
index 0000000000..e2a4f67f16
--- /dev/null
+++ b/modules/openxr/editor/openxr_action_editor.cpp
@@ -0,0 +1,112 @@
+/*************************************************************************/
+/* openxr_action_editor.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "openxr_action_editor.h"
+
+void OpenXRActionEditor::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("remove", PropertyInfo(Variant::OBJECT, "action_editor")));
+}
+
+void OpenXRActionEditor::_theme_changed() {
+ rem_action->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+}
+
+void OpenXRActionEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ _theme_changed();
+ } break;
+ }
+}
+
+void OpenXRActionEditor::_on_action_name_changed(const String p_new_text) {
+ // TODO validate if entry is allowed
+
+ // If our localized name matches our action name, set this too
+ if (action->get_name() == action->get_localized_name()) {
+ action->set_localized_name(p_new_text);
+ action_localized_name->set_text(p_new_text);
+ }
+ action->set_name(p_new_text);
+}
+
+void OpenXRActionEditor::_on_action_localized_name_changed(const String p_new_text) {
+ action->set_localized_name(p_new_text);
+}
+
+void OpenXRActionEditor::_on_item_selected(int p_idx) {
+ ERR_FAIL_COND(p_idx < 0);
+ ERR_FAIL_COND(p_idx >= OpenXRAction::OPENXR_ACTION_MAX);
+
+ action->set_action_type(OpenXRAction::ActionType(p_idx));
+}
+
+void OpenXRActionEditor::_on_remove_action() {
+ emit_signal("remove", this);
+}
+
+OpenXRActionEditor::OpenXRActionEditor(Ref<OpenXRAction> p_action) {
+ action = p_action;
+
+ set_h_size_flags(Control::SIZE_EXPAND_FILL);
+
+ action_name = memnew(LineEdit);
+ action_name->set_text(action->get_name());
+ action_name->set_custom_minimum_size(Size2(150.0, 0.0));
+ action_name->connect("text_changed", callable_mp(this, &OpenXRActionEditor::_on_action_name_changed));
+ add_child(action_name);
+
+ action_localized_name = memnew(LineEdit);
+ action_localized_name->set_text(action->get_localized_name());
+ action_localized_name->set_custom_minimum_size(Size2(150.0, 0.0));
+ action_localized_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ action_localized_name->connect("text_changed", callable_mp(this, &OpenXRActionEditor::_on_action_localized_name_changed));
+ add_child(action_localized_name);
+
+ action_type = memnew(OptionButton);
+ action_type->add_item("Bool", OpenXRAction::OPENXR_ACTION_BOOL);
+ action_type->add_item("Float", OpenXRAction::OPENXR_ACTION_FLOAT);
+ action_type->add_item("Vector2", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ action_type->add_item("Pose", OpenXRAction::OPENXR_ACTION_POSE);
+ action_type->add_item("Haptic", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ action_type->select(int(action->get_action_type()));
+ action_type->set_custom_minimum_size(Size2(100.0, 0.0));
+ action_type->connect("item_selected", callable_mp(this, &OpenXRActionEditor::_on_item_selected));
+ add_child(action_type);
+
+ // maybe add dropdown to edit our toplevel paths, or do we deduce them from our suggested bindings?
+
+ rem_action = memnew(Button);
+ rem_action->set_tooltip(TTR("Remove action"));
+ rem_action->connect("pressed", callable_mp(this, &OpenXRActionEditor::_on_remove_action));
+ rem_action->set_flat(true);
+ add_child(rem_action);
+}
diff --git a/modules/openxr/editor/openxr_action_editor.h b/modules/openxr/editor/openxr_action_editor.h
new file mode 100644
index 0000000000..6e1b7ab779
--- /dev/null
+++ b/modules/openxr/editor/openxr_action_editor.h
@@ -0,0 +1,67 @@
+/*************************************************************************/
+/* openxr_action_editor.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef OPENXR_ACTION_EDITOR_H
+#define OPENXR_ACTION_EDITOR_H
+
+#include "../action_map/openxr_action.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
+#include "scene/gui/line_edit.h"
+#include "scene/gui/option_button.h"
+#include "scene/gui/text_edit.h"
+
+class OpenXRActionEditor : public HBoxContainer {
+ GDCLASS(OpenXRActionEditor, HBoxContainer);
+
+private:
+ Ref<OpenXRAction> action;
+
+ LineEdit *action_name = nullptr;
+ LineEdit *action_localized_name = nullptr;
+ OptionButton *action_type = nullptr;
+ Button *rem_action = nullptr;
+
+ void _theme_changed();
+ void _on_action_name_changed(const String p_new_text);
+ void _on_action_localized_name_changed(const String p_new_text);
+ void _on_item_selected(int p_idx);
+ void _on_remove_action();
+
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
+
+public:
+ Ref<OpenXRAction> get_action() { return action; };
+ OpenXRActionEditor(Ref<OpenXRAction> p_action);
+};
+
+#endif // !OPENXR_ACTION_EDITOR_H
diff --git a/modules/openxr/editor/openxr_action_map_editor.cpp b/modules/openxr/editor/openxr_action_map_editor.cpp
new file mode 100644
index 0000000000..6e9a2e1b61
--- /dev/null
+++ b/modules/openxr/editor/openxr_action_map_editor.cpp
@@ -0,0 +1,370 @@
+/*************************************************************************/
+/* openxr_action_map_editor.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "openxr_action_map_editor.h"
+
+#include "core/config/project_settings.h"
+#include "editor/editor_file_dialog.h"
+#include "editor/editor_node.h"
+#include "editor/editor_scale.h"
+#include "editor/editor_settings.h"
+
+// TODO implement redo/undo system
+
+void OpenXRActionMapEditor::_bind_methods() {
+ ClassDB::bind_method("_add_action_set_editor", &OpenXRActionMapEditor::_add_action_set_editor);
+ ClassDB::bind_method("_update_action_sets", &OpenXRActionMapEditor::_update_action_sets);
+
+ ClassDB::bind_method("_add_interaction_profile_editor", &OpenXRActionMapEditor::_add_interaction_profile_editor);
+ ClassDB::bind_method("_update_interaction_profiles", &OpenXRActionMapEditor::_update_interaction_profiles);
+
+ ClassDB::bind_method(D_METHOD("_add_action_set", "name"), &OpenXRActionMapEditor::_add_action_set);
+ ClassDB::bind_method(D_METHOD("_set_focus_on_action_set", "action_set"), &OpenXRActionMapEditor::_set_focus_on_action_set);
+ ClassDB::bind_method(D_METHOD("_remove_action_set", "name"), &OpenXRActionMapEditor::_remove_action_set);
+}
+
+void OpenXRActionMapEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ for (int i = 0; i < tabs->get_child_count(); i++) {
+ Control *tab = static_cast<Control *>(tabs->get_child(i));
+ if (tab) {
+ tab->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ }
+ }
+ } break;
+
+ case NOTIFICATION_READY: {
+ _update_action_sets();
+ _update_interaction_profiles();
+ } break;
+ }
+}
+
+OpenXRActionSetEditor *OpenXRActionMapEditor::_add_action_set_editor(Ref<OpenXRActionSet> p_action_set) {
+ ERR_FAIL_COND_V(p_action_set.is_null(), nullptr);
+
+ OpenXRActionSetEditor *action_set_editor = memnew(OpenXRActionSetEditor(action_map, p_action_set));
+ action_set_editor->connect("remove", callable_mp(this, &OpenXRActionMapEditor::_on_remove_action_set));
+ action_set_editor->connect("action_removed", callable_mp(this, &OpenXRActionMapEditor::_on_action_removed));
+ actionsets_vb->add_child(action_set_editor);
+
+ return action_set_editor;
+}
+
+void OpenXRActionMapEditor::_update_action_sets() {
+ // out with the old...
+ while (actionsets_vb->get_child_count() > 0) {
+ memdelete(actionsets_vb->get_child(0));
+ }
+
+ // in with the new...
+ if (action_map.is_valid()) {
+ Array action_sets = action_map->get_action_sets();
+ for (int i = 0; i < action_sets.size(); i++) {
+ Ref<OpenXRActionSet> action_set = action_sets[i];
+ _add_action_set_editor(action_set);
+ }
+ }
+}
+
+OpenXRInteractionProfileEditorBase *OpenXRActionMapEditor::_add_interaction_profile_editor(Ref<OpenXRInteractionProfile> p_interaction_profile) {
+ ERR_FAIL_COND_V(p_interaction_profile.is_null(), nullptr);
+
+ String profile_path = p_interaction_profile->get_interaction_profile_path();
+
+ // need to instance the correct editor for our profile
+ OpenXRInteractionProfileEditorBase *new_profile_editor = nullptr;
+ if (profile_path == "placeholder_text") {
+ // instance specific editor for this type
+ } else {
+ // instance generic editor
+ new_profile_editor = memnew(OpenXRInteractionProfileEditor(action_map, p_interaction_profile));
+ }
+
+ // now add it in..
+ ERR_FAIL_NULL_V(new_profile_editor, nullptr);
+ tabs->add_child(new_profile_editor);
+ new_profile_editor->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ tabs->set_tab_button_icon(tabs->get_tab_count() - 1, get_theme_icon(SNAME("close"), SNAME("TabBar")));
+
+ interaction_profiles.push_back(new_profile_editor);
+
+ return new_profile_editor;
+}
+
+void OpenXRActionMapEditor::_update_interaction_profiles() {
+ // out with the old...
+ while (interaction_profiles.size() > 0) {
+ Node *interaction_profile = interaction_profiles[0];
+ interaction_profiles.remove_at(0);
+
+ tabs->remove_child(interaction_profile);
+ interaction_profile->queue_delete();
+ }
+
+ // in with the new...
+ if (action_map.is_valid()) {
+ Array new_interaction_profiles = action_map->get_interaction_profiles();
+ for (int i = 0; i < new_interaction_profiles.size(); i++) {
+ Ref<OpenXRInteractionProfile> interaction_profile = new_interaction_profiles[i];
+ _add_interaction_profile_editor(interaction_profile);
+ }
+ }
+}
+
+OpenXRActionSetEditor *OpenXRActionMapEditor::_add_action_set(String p_name) {
+ ERR_FAIL_COND_V(action_map.is_null(), nullptr);
+ Ref<OpenXRActionSet> new_action_set;
+
+ // add our new action set
+ new_action_set.instantiate();
+ new_action_set->set_name(p_name);
+ new_action_set->set_localized_name(p_name);
+ action_map->add_action_set(new_action_set);
+
+ // update our editor right away
+ return _add_action_set_editor(new_action_set);
+}
+
+void OpenXRActionMapEditor::_remove_action_set(String p_name) {
+ ERR_FAIL_COND(action_map.is_null());
+ Ref<OpenXRActionSet> action_set = action_map->find_action_set(p_name);
+ ERR_FAIL_COND(action_set.is_null());
+
+ if (action_set->get_action_count() > 0) {
+ // we should remove these and add to our redo/undo step before calling _remove_action_set
+ WARN_PRINT("Action set still has associated actions before being removed!");
+ }
+
+ // now we remove it
+ action_map->remove_action_set(action_set);
+}
+
+void OpenXRActionMapEditor::_on_add_action_set() {
+ ERR_FAIL_COND(action_map.is_null());
+ String new_name = "New";
+ int count = 0;
+
+ while (action_map->find_action_set(new_name).is_valid()) {
+ new_name = "New_" + itos(count++);
+ }
+
+ OpenXRActionSetEditor *new_action_set_editor = _add_action_set(new_name);
+
+ // Make sure our action set is the current tab
+ tabs->set_current_tab(0);
+
+ call_deferred("_set_focus_on_action_set", new_action_set_editor);
+}
+
+void OpenXRActionMapEditor::_set_focus_on_action_set(OpenXRActionSetEditor *p_action_set_editor) {
+ // Scroll down to our new entry
+ actionsets_scroll->ensure_control_visible(p_action_set_editor);
+
+ // Set focus on this entry
+ p_action_set_editor->set_focus_on_entry();
+}
+
+void OpenXRActionMapEditor::_on_remove_action_set(Object *p_action_set_editor) {
+ ERR_FAIL_COND(action_map.is_null());
+
+ OpenXRActionSetEditor *action_set_editor = Object::cast_to<OpenXRActionSetEditor>(p_action_set_editor);
+ ERR_FAIL_NULL(action_set_editor);
+ ERR_FAIL_COND(action_set_editor->get_parent() != actionsets_vb);
+ Ref<OpenXRActionSet> action_set = action_set_editor->get_action_set();
+ ERR_FAIL_COND(action_set.is_null());
+
+ action_map->remove_action_set(action_set);
+ actionsets_vb->remove_child(action_set_editor);
+ action_set_editor->queue_delete();
+}
+
+void OpenXRActionMapEditor::_on_action_removed() {
+ // make sure our interaction profiles are updated
+ _update_interaction_profiles();
+}
+
+void OpenXRActionMapEditor::_on_add_interaction_profile() {
+ ERR_FAIL_COND(action_map.is_null());
+
+ PackedStringArray already_selected;
+
+ for (int i = 0; i < action_map->get_interaction_profile_count(); i++) {
+ already_selected.push_back(action_map->get_interaction_profile(i)->get_interaction_profile_path());
+ }
+
+ select_interaction_profile_dialog->open(already_selected);
+}
+
+void OpenXRActionMapEditor::_on_interaction_profile_selected(const String p_path) {
+ ERR_FAIL_COND(action_map.is_null());
+
+ Ref<OpenXRInteractionProfile> new_profile;
+ new_profile.instantiate();
+ new_profile->set_interaction_profile_path(p_path);
+ action_map->add_interaction_profile(new_profile);
+
+ _add_interaction_profile_editor(new_profile);
+
+ tabs->set_current_tab(tabs->get_tab_count() - 1);
+}
+
+void OpenXRActionMapEditor::_load_action_map(const String p_path, bool p_create_new_if_missing) {
+ action_map = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_IGNORE);
+ if (action_map.is_null()) {
+ if (p_create_new_if_missing) {
+ action_map.instantiate();
+ action_map->create_default_action_sets();
+ } else {
+ EditorNode::get_singleton()->show_warning(TTR("Invalid file, not an OpenXR action map."));
+
+ edited_path = "";
+ header_label->set_text("");
+ return;
+ }
+ }
+
+ edited_path = p_path;
+ header_label->set_text(TTR("OpenXR Action map:") + " " + p_path.get_file());
+}
+
+void OpenXRActionMapEditor::_on_save_action_map() {
+ Error err = ResourceSaver::save(edited_path, action_map);
+ if (err != OK) {
+ EditorNode::get_singleton()->show_warning(vformat(TTR("Error saving file: %s"), edited_path));
+ return;
+ }
+
+ _update_action_sets();
+ _update_interaction_profiles();
+}
+
+void OpenXRActionMapEditor::_on_reset_to_default_layout() {
+ // create a new one
+ action_map.unref();
+ action_map.instantiate();
+ action_map->create_default_action_sets();
+
+ _update_action_sets();
+ _update_interaction_profiles();
+}
+
+void OpenXRActionMapEditor::_on_tabs_tab_changed(int p_tab) {
+}
+
+void OpenXRActionMapEditor::_on_tab_button_pressed(int p_tab) {
+ OpenXRInteractionProfileEditorBase *profile_editor = static_cast<OpenXRInteractionProfileEditorBase *>(tabs->get_tab_control(p_tab));
+ ERR_FAIL_NULL(profile_editor);
+
+ Ref<OpenXRInteractionProfile> interaction_profile = profile_editor->get_interaction_profile();
+ ERR_FAIL_COND(interaction_profile.is_null());
+
+ action_map->remove_interaction_profile(interaction_profile);
+ tabs->remove_child(profile_editor);
+ profile_editor->queue_delete();
+}
+
+void OpenXRActionMapEditor::open_action_map(String p_path) {
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(this);
+
+ _load_action_map(p_path);
+
+ _update_action_sets();
+ _update_interaction_profiles();
+}
+
+OpenXRActionMapEditor::OpenXRActionMapEditor() {
+ set_custom_minimum_size(Size2(0.0, 300.0));
+
+ top_hb = memnew(HBoxContainer);
+ add_child(top_hb);
+
+ header_label = memnew(Label);
+ header_label->set_text(String(TTR("Action Map")));
+ header_label->set_clip_text(true);
+ header_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ top_hb->add_child(header_label);
+
+ add_action_set = memnew(Button);
+ add_action_set->set_text(TTR("Add Action Set"));
+ add_action_set->set_tooltip(TTR("Add an action set."));
+ add_action_set->connect("pressed", callable_mp(this, &OpenXRActionMapEditor::_on_add_action_set));
+ top_hb->add_child(add_action_set);
+
+ add_interaction_profile = memnew(Button);
+ add_interaction_profile->set_text(TTR("Add profile"));
+ add_interaction_profile->set_tooltip(TTR("Add an interaction profile."));
+ add_interaction_profile->connect("pressed", callable_mp(this, &OpenXRActionMapEditor::_on_add_interaction_profile));
+ top_hb->add_child(add_interaction_profile);
+
+ VSeparator *vseparator = memnew(VSeparator);
+ top_hb->add_child(vseparator);
+
+ save_as = memnew(Button);
+ save_as->set_text(TTR("Save"));
+ save_as->set_tooltip(TTR("Save this OpenXR action map."));
+ save_as->connect("pressed", callable_mp(this, &OpenXRActionMapEditor::_on_save_action_map));
+ top_hb->add_child(save_as);
+
+ _default = memnew(Button);
+ _default->set_text(TTR("Reset to Default"));
+ _default->set_tooltip(TTR("Reset to default OpenXR action map."));
+ _default->connect("pressed", callable_mp(this, &OpenXRActionMapEditor::_on_reset_to_default_layout));
+ top_hb->add_child(_default);
+
+ tabs = memnew(TabContainer);
+ tabs->set_h_size_flags(SIZE_EXPAND_FILL);
+ tabs->set_v_size_flags(SIZE_EXPAND_FILL);
+ tabs->connect("tab_changed", callable_mp(this, &OpenXRActionMapEditor::_on_tabs_tab_changed));
+ tabs->connect("tab_button_pressed", callable_mp(this, &OpenXRActionMapEditor::_on_tab_button_pressed));
+ add_child(tabs);
+
+ actionsets_scroll = memnew(ScrollContainer);
+ actionsets_scroll->set_h_size_flags(SIZE_EXPAND_FILL);
+ actionsets_scroll->set_v_size_flags(SIZE_EXPAND_FILL);
+ actionsets_scroll->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
+ tabs->add_child(actionsets_scroll);
+ actionsets_scroll->set_name(TTR("Action Sets"));
+
+ actionsets_vb = memnew(VBoxContainer);
+ actionsets_vb->set_h_size_flags(SIZE_EXPAND_FILL);
+ actionsets_scroll->add_child(actionsets_vb);
+
+ select_interaction_profile_dialog = memnew(OpenXRSelectInteractionProfileDialog);
+ select_interaction_profile_dialog->connect("interaction_profile_selected", callable_mp(this, &OpenXRActionMapEditor::_on_interaction_profile_selected));
+ add_child(select_interaction_profile_dialog);
+
+ _load_action_map(ProjectSettings::get_singleton()->get("xr/openxr/default_action_map"));
+}
+
+OpenXRActionMapEditor::~OpenXRActionMapEditor() {
+}
diff --git a/modules/openxr/editor/openxr_action_map_editor.h b/modules/openxr/editor/openxr_action_map_editor.h
new file mode 100644
index 0000000000..dfc941b500
--- /dev/null
+++ b/modules/openxr/editor/openxr_action_map_editor.h
@@ -0,0 +1,100 @@
+/*************************************************************************/
+/* openxr_action_map_editor.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef OPENXR_ACTION_MAP_EDITOR_H
+#define OPENXR_ACTION_MAP_EDITOR_H
+
+#include "../action_map/openxr_action_map.h"
+#include "../editor/openxr_action_set_editor.h"
+#include "../editor/openxr_interaction_profile_editor.h"
+#include "../editor/openxr_select_interaction_profile_dialog.h"
+
+#include "editor/editor_plugin.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
+#include "scene/gui/label.h"
+#include "scene/gui/scroll_container.h"
+#include "scene/gui/tab_container.h"
+
+class OpenXRActionMapEditor : public VBoxContainer {
+ GDCLASS(OpenXRActionMapEditor, VBoxContainer);
+
+private:
+ String edited_path;
+ Ref<OpenXRActionMap> action_map;
+ Vector<Node *> interaction_profiles;
+
+ HBoxContainer *top_hb = nullptr;
+ Label *header_label = nullptr;
+ Button *add_action_set = nullptr;
+ Button *add_interaction_profile = nullptr;
+ Button *load = nullptr;
+ Button *save_as = nullptr;
+ Button *_default = nullptr;
+ TabContainer *tabs = nullptr;
+ ScrollContainer *actionsets_scroll = nullptr;
+ VBoxContainer *actionsets_vb = nullptr;
+ OpenXRSelectInteractionProfileDialog *select_interaction_profile_dialog = nullptr;
+
+ OpenXRActionSetEditor *_add_action_set_editor(Ref<OpenXRActionSet> p_action_set);
+ void _update_action_sets();
+ OpenXRInteractionProfileEditorBase *_add_interaction_profile_editor(Ref<OpenXRInteractionProfile> p_interaction_profile);
+ void _update_interaction_profiles();
+
+ OpenXRActionSetEditor *_add_action_set(String p_name);
+ void _remove_action_set(String p_name);
+
+ void _on_add_action_set();
+ void _set_focus_on_action_set(OpenXRActionSetEditor *p_action_set_editor);
+ void _on_remove_action_set(Object *p_action_set_editor);
+ void _on_action_removed();
+
+ void _on_add_interaction_profile();
+ void _on_interaction_profile_selected(const String p_path);
+
+ void _load_action_map(const String p_path, bool p_create_new_if_missing = false);
+ void _on_save_action_map();
+ void _on_reset_to_default_layout();
+
+ void _on_tabs_tab_changed(int p_tab);
+ void _on_tab_button_pressed(int p_tab);
+
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
+
+public:
+ void open_action_map(String p_path);
+
+ OpenXRActionMapEditor();
+ ~OpenXRActionMapEditor();
+};
+
+#endif // !OPENXR_ACTION_MAP_EDITOR_H
diff --git a/modules/openxr/editor/openxr_action_set_editor.cpp b/modules/openxr/editor/openxr_action_set_editor.cpp
new file mode 100644
index 0000000000..7bf8557c5b
--- /dev/null
+++ b/modules/openxr/editor/openxr_action_set_editor.cpp
@@ -0,0 +1,218 @@
+/*************************************************************************/
+/* openxr_action_set_editor.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "openxr_action_set_editor.h"
+#include "openxr_action_editor.h"
+
+void OpenXRActionSetEditor::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("remove", PropertyInfo(Variant::OBJECT, "action_set_editor")));
+ ADD_SIGNAL(MethodInfo("action_removed"));
+}
+
+void OpenXRActionSetEditor::_set_fold_icon() {
+ if (is_expanded) {
+ fold_btn->set_icon(get_theme_icon(SNAME("GuiTreeArrowDown"), SNAME("EditorIcons")));
+ } else {
+ fold_btn->set_icon(get_theme_icon(SNAME("GuiTreeArrowRight"), SNAME("EditorIcons")));
+ }
+}
+
+void OpenXRActionSetEditor::_theme_changed() {
+ _set_fold_icon();
+ add_action->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
+ rem_action_set->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+}
+
+void OpenXRActionSetEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ _theme_changed();
+ panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TabContainer")));
+ } break;
+ }
+}
+
+OpenXRActionEditor *OpenXRActionSetEditor::_add_action_editor(Ref<OpenXRAction> p_action) {
+ OpenXRActionEditor *action_editor = memnew(OpenXRActionEditor(p_action));
+ action_editor->connect("remove", callable_mp(this, &OpenXRActionSetEditor::_on_remove_action));
+ actions_vb->add_child(action_editor);
+
+ return action_editor;
+}
+
+void OpenXRActionSetEditor::_update_actions() {
+ // out with the old...
+ while (actions_vb->get_child_count() > 0) {
+ memdelete(actions_vb->get_child(0));
+ }
+
+ // in with the new...
+ Array actions = action_set->get_actions();
+ for (int i = 0; i < actions.size(); i++) {
+ Ref<OpenXRAction> action = actions[i];
+ _add_action_editor(action);
+ }
+}
+
+void OpenXRActionSetEditor::_on_toggle_expand() {
+ is_expanded = !is_expanded;
+ actions_vb->set_visible(is_expanded);
+ _set_fold_icon();
+}
+
+void OpenXRActionSetEditor::_on_action_set_name_changed(const String p_new_text) {
+ // TODO validate if entry is allowed
+
+ // If our localized name matches our action set name, set this too
+ if (action_set->get_name() == action_set->get_localized_name()) {
+ action_set->set_localized_name(p_new_text);
+ action_set_localized_name->set_text(p_new_text);
+ }
+ action_set->set_name(p_new_text);
+}
+
+void OpenXRActionSetEditor::_on_action_set_localized_name_changed(const String p_new_text) {
+ action_set->set_localized_name(p_new_text);
+}
+
+void OpenXRActionSetEditor::_on_action_set_priority_changed(const String p_new_text) {
+ int64_t value = p_new_text.to_int();
+
+ action_set->set_priority(value);
+}
+
+void OpenXRActionSetEditor::_on_add_action() {
+ Ref<OpenXRAction> new_action;
+
+ new_action.instantiate();
+ new_action->set_name("New");
+ new_action->set_localized_name("New");
+ action_set->add_action(new_action);
+
+ _add_action_editor(new_action);
+
+ // TODO handle focus
+}
+
+void OpenXRActionSetEditor::_on_remove_action_set() {
+ emit_signal("remove", this);
+}
+
+void OpenXRActionSetEditor::_on_remove_action(Object *p_action_editor) {
+ OpenXRActionEditor *action_editor = Object::cast_to<OpenXRActionEditor>(p_action_editor);
+ ERR_FAIL_NULL(action_editor);
+ ERR_FAIL_COND(action_editor->get_parent() != actions_vb);
+ Ref<OpenXRAction> action = action_editor->get_action();
+ ERR_FAIL_COND(action.is_null());
+
+ // TODO add undo/redo action
+
+ // TODO find where this action is used by our interaction profiles and remove it there
+
+ // And remove it....
+ action_map->remove_action(action->get_name_with_set()); // remove it from the set and any interaction profile it relates to
+ actions_vb->remove_child(action_editor);
+ action_editor->queue_delete();
+
+ // Let action map editor know so we can update our interaction profiles
+ emit_signal("action_removed");
+}
+
+void OpenXRActionSetEditor::set_focus_on_entry() {
+ ERR_FAIL_NULL(action_set_name);
+ action_set_name->grab_focus();
+}
+
+OpenXRActionSetEditor::OpenXRActionSetEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRActionSet> p_action_set) {
+ action_map = p_action_map;
+ action_set = p_action_set;
+
+ set_h_size_flags(Control::SIZE_EXPAND_FILL);
+
+ panel = memnew(PanelContainer);
+ panel->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ add_child(panel);
+
+ HBoxContainer *panel_hb = memnew(HBoxContainer);
+ panel_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ panel->add_child(panel_hb);
+
+ fold_btn = memnew(Button);
+ fold_btn->set_v_size_flags(Control::SIZE_SHRINK_BEGIN);
+ fold_btn->connect("pressed", callable_mp(this, &OpenXRActionSetEditor::_on_toggle_expand));
+ fold_btn->set_flat(true);
+ panel_hb->add_child(fold_btn);
+
+ main_vb = memnew(VBoxContainer);
+ main_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ panel_hb->add_child(main_vb);
+
+ action_set_hb = memnew(HBoxContainer);
+ action_set_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ main_vb->add_child(action_set_hb);
+
+ action_set_name = memnew(LineEdit);
+ action_set_name->set_text(action_set->get_name());
+ action_set_name->set_custom_minimum_size(Size2(150.0, 0.0));
+ action_set_name->connect("text_changed", callable_mp(this, &OpenXRActionSetEditor::_on_action_set_name_changed));
+ action_set_hb->add_child(action_set_name);
+
+ action_set_localized_name = memnew(LineEdit);
+ action_set_localized_name->set_text(action_set->get_localized_name());
+ action_set_localized_name->set_custom_minimum_size(Size2(150.0, 0.0));
+ action_set_localized_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ action_set_localized_name->connect("text_changed", callable_mp(this, &OpenXRActionSetEditor::_on_action_set_localized_name_changed));
+ action_set_hb->add_child(action_set_localized_name);
+
+ action_set_priority = memnew(TextEdit);
+ action_set_priority->set_text(itos(action_set->get_priority()));
+ action_set_priority->set_custom_minimum_size(Size2(50.0, 0.0));
+ action_set_priority->connect("text_changed", callable_mp(this, &OpenXRActionSetEditor::_on_action_set_priority_changed));
+ action_set_hb->add_child(action_set_priority);
+
+ add_action = memnew(Button);
+ add_action->set_tooltip("Add Action.");
+ add_action->connect("pressed", callable_mp(this, &OpenXRActionSetEditor::_on_add_action));
+ add_action->set_flat(true);
+ action_set_hb->add_child(add_action);
+
+ rem_action_set = memnew(Button);
+ rem_action_set->set_tooltip("Remove Action Set.");
+ rem_action_set->connect("pressed", callable_mp(this, &OpenXRActionSetEditor::_on_remove_action_set));
+ rem_action_set->set_flat(true);
+ action_set_hb->add_child(rem_action_set);
+
+ actions_vb = memnew(VBoxContainer);
+ actions_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ main_vb->add_child(actions_vb);
+
+ _update_actions();
+}
diff --git a/modules/openxr/editor/openxr_action_set_editor.h b/modules/openxr/editor/openxr_action_set_editor.h
new file mode 100644
index 0000000000..f3960dcbf9
--- /dev/null
+++ b/modules/openxr/editor/openxr_action_set_editor.h
@@ -0,0 +1,88 @@
+/*************************************************************************/
+/* openxr_action_set_editor.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef OPENXR_ACTION_SET_EDITOR_H
+#define OPENXR_ACTION_SET_EDITOR_H
+
+#include "../action_map/openxr_action_map.h"
+#include "../action_map/openxr_action_set.h"
+#include "openxr_action_editor.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
+#include "scene/gui/line_edit.h"
+#include "scene/gui/panel_container.h"
+#include "scene/gui/text_edit.h"
+
+class OpenXRActionSetEditor : public HBoxContainer {
+ GDCLASS(OpenXRActionSetEditor, HBoxContainer);
+
+private:
+ Ref<OpenXRActionMap> action_map;
+ Ref<OpenXRActionSet> action_set;
+
+ bool is_expanded = true;
+
+ PanelContainer *panel = nullptr;
+ Button *fold_btn = nullptr;
+ VBoxContainer *main_vb = nullptr;
+ HBoxContainer *action_set_hb = nullptr;
+ LineEdit *action_set_name = nullptr;
+ LineEdit *action_set_localized_name = nullptr;
+ TextEdit *action_set_priority = nullptr;
+ Button *add_action = nullptr;
+ Button *rem_action_set = nullptr;
+ VBoxContainer *actions_vb = nullptr;
+
+ void _set_fold_icon();
+ void _theme_changed();
+ OpenXRActionEditor *_add_action_editor(Ref<OpenXRAction> p_action);
+ void _update_actions();
+
+ void _on_toggle_expand();
+ void _on_action_set_name_changed(const String p_new_text);
+ void _on_action_set_localized_name_changed(const String p_new_text);
+ void _on_action_set_priority_changed(const String p_new_text);
+ void _on_add_action();
+ void _on_remove_action_set();
+
+ void _on_remove_action(Object *p_action_editor);
+
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
+
+public:
+ Ref<OpenXRActionSet> get_action_set() { return action_set; };
+ void set_focus_on_entry();
+
+ OpenXRActionSetEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRActionSet> p_action_set);
+};
+
+#endif // !OPENXR_ACTION_SET_EDITOR_H
diff --git a/modules/fbx/data/fbx_bone.cpp b/modules/openxr/editor/openxr_editor_plugin.cpp
index 72aba20fd4..b87b538511 100644
--- a/modules/fbx/data/fbx_bone.cpp
+++ b/modules/openxr/editor/openxr_editor_plugin.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* fbx_bone.cpp */
+/* openxr_editor_plugin.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,29 +28,31 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "fbx_bone.h"
+#include "openxr_editor_plugin.h"
-#include "fbx_node.h"
-#include "import_state.h"
+#include "../action_map/openxr_action_map.h"
+#include "editor/editor_node.h"
-Ref<FBXNode> FBXSkinDeformer::get_link(const ImportState &state) const {
- print_verbose("bone name: " + bone->bone_name);
-
- // safe for when deformers must be polyfilled when skin has different count of binds to bones in the scene ;)
- if (!cluster) {
- return nullptr;
+void OpenXREditorPlugin::edit(Object *p_node) {
+ if (Object::cast_to<OpenXRActionMap>(p_node)) {
+ String path = Object::cast_to<OpenXRActionMap>(p_node)->get_path();
+ if (path.is_resource_file()) {
+ action_map_editor->open_action_map(path);
+ }
}
+}
- ERR_FAIL_COND_V_MSG(cluster->TargetNode() == nullptr, nullptr, "bone has invalid target node");
+bool OpenXREditorPlugin::handles(Object *p_node) const {
+ return (Object::cast_to<OpenXRActionMap>(p_node) != nullptr);
+}
- Ref<FBXNode> link_node;
- uint64_t id = cluster->TargetNode()->ID();
- if (state.fbx_target_map.has(id)) {
- link_node = state.fbx_target_map[id];
- } else {
- print_error("link node not found for " + itos(id));
- }
+void OpenXREditorPlugin::make_visible(bool p_visible) {
+}
+
+OpenXREditorPlugin::OpenXREditorPlugin() {
+ action_map_editor = memnew(OpenXRActionMapEditor);
+ EditorNode::get_singleton()->add_bottom_panel_item(TTR("OpenXR Action Map"), action_map_editor);
+}
- // the node in space this is for, like if it's FOR a target.
- return link_node;
+OpenXREditorPlugin::~OpenXREditorPlugin() {
}
diff --git a/modules/fbx/data/fbx_skeleton.h b/modules/openxr/editor/openxr_editor_plugin.h
index e615d0f5e3..af8ee7d54c 100644
--- a/modules/fbx/data/fbx_skeleton.h
+++ b/modules/openxr/editor/openxr_editor_plugin.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* fbx_skeleton.h */
+/* openxr_editor_plugin.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,26 +28,26 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef FBX_SKELETON_H
-#define FBX_SKELETON_H
+#ifndef OPENXR_EDITOR_PLUGIN_H
+#define OPENXR_EDITOR_PLUGIN_H
-#include "fbx_bone.h"
-#include "fbx_node.h"
-#include "model_abstraction.h"
+#include "editor/editor_plugin.h"
+#include "openxr_action_map_editor.h"
-#include "core/object/ref_counted.h"
-#include "scene/3d/skeleton_3d.h"
+class OpenXREditorPlugin : public EditorPlugin {
+ GDCLASS(OpenXREditorPlugin, EditorPlugin);
-struct FBXNode;
-struct ImportState;
-struct FBXBone;
+ OpenXRActionMapEditor *action_map_editor = nullptr;
-struct FBXSkeleton : RefCounted {
- Ref<FBXNode> fbx_node = Ref<FBXNode>();
- Vector<Ref<FBXBone>> skeleton_bones = Vector<Ref<FBXBone>>();
- Skeleton3D *skeleton = nullptr;
+public:
+ virtual String get_name() const override { return "OpenXRPlugin"; }
+ bool has_main_screen() const override { return false; }
+ virtual void edit(Object *p_node) override;
+ virtual bool handles(Object *p_node) const override;
+ virtual void make_visible(bool p_visible) override;
- void init_skeleton(const ImportState &state);
+ OpenXREditorPlugin();
+ ~OpenXREditorPlugin();
};
-#endif // FBX_SKELETON_H
+#endif // !OPENXR_EDITOR_PLUGIN_H
diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.cpp b/modules/openxr/editor/openxr_interaction_profile_editor.cpp
new file mode 100644
index 0000000000..24ac5494dd
--- /dev/null
+++ b/modules/openxr/editor/openxr_interaction_profile_editor.cpp
@@ -0,0 +1,274 @@
+/*************************************************************************/
+/* openxr_interaction_profile_editor.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "openxr_interaction_profile_editor.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
+#include "scene/gui/label.h"
+#include "scene/gui/line_edit.h"
+#include "scene/gui/panel_container.h"
+#include "scene/gui/separator.h"
+#include "scene/gui/text_edit.h"
+
+///////////////////////////////////////////////////////////////////////////
+// Interaction profile editor base
+
+void OpenXRInteractionProfileEditorBase::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_add_binding", "action", "path"), &OpenXRInteractionProfileEditorBase::_add_binding);
+ ClassDB::bind_method(D_METHOD("_remove_binding", "action", "path"), &OpenXRInteractionProfileEditorBase::_remove_binding);
+ ClassDB::bind_method(D_METHOD("_update_interaction_profile"), &OpenXRInteractionProfileEditorBase::_update_interaction_profile);
+}
+
+void OpenXRInteractionProfileEditorBase::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ _update_interaction_profile();
+ } break;
+
+ case NOTIFICATION_THEME_CHANGED: {
+ _theme_changed();
+ } break;
+ }
+}
+
+void OpenXRInteractionProfileEditorBase::_add_binding(const String p_action, const String p_path) {
+ ERR_FAIL_COND(action_map.is_null());
+ ERR_FAIL_COND(interaction_profile.is_null());
+
+ Ref<OpenXRAction> action = action_map->get_action(p_action);
+ ERR_FAIL_COND(action.is_null());
+
+ Ref<OpenXRIPBinding> binding = interaction_profile->get_binding_for_action(action);
+ if (binding.is_null()) {
+ // create a new binding
+ binding.instantiate();
+ binding->set_action(action);
+ interaction_profile->add_binding(binding);
+ }
+
+ binding->add_path(p_path);
+
+ // Update our toplevel paths
+ action->set_toplevel_paths(action_map->get_top_level_paths(action));
+
+ call_deferred("_update_interaction_profile");
+}
+
+void OpenXRInteractionProfileEditorBase::_remove_binding(const String p_action, const String p_path) {
+ ERR_FAIL_COND(action_map.is_null());
+ ERR_FAIL_COND(interaction_profile.is_null());
+
+ Ref<OpenXRAction> action = action_map->get_action(p_action);
+ ERR_FAIL_COND(action.is_null());
+
+ Ref<OpenXRIPBinding> binding = interaction_profile->get_binding_for_action(action);
+ if (binding.is_valid()) {
+ binding->remove_path(p_path);
+
+ if (binding->get_path_count() == 0) {
+ interaction_profile->remove_binding(binding);
+ }
+
+ // Update our toplevel paths
+ action->set_toplevel_paths(action_map->get_top_level_paths(action));
+
+ call_deferred("_update_interaction_profile");
+ }
+}
+
+OpenXRInteractionProfileEditorBase::OpenXRInteractionProfileEditorBase(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile) {
+ action_map = p_action_map;
+ interaction_profile = p_interaction_profile;
+ String profile_path = interaction_profile->get_interaction_profile_path();
+ String profile_name = profile_path;
+
+ profile_def = OpenXRDefs::get_profile(profile_path);
+ if (profile_def != nullptr) {
+ profile_name = profile_def->display_name;
+ }
+
+ set_name(profile_name);
+ set_h_size_flags(SIZE_EXPAND_FILL);
+ set_v_size_flags(SIZE_EXPAND_FILL);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Default interaction profile editor
+
+void OpenXRInteractionProfileEditor::select_action_for(const String p_io_path) {
+ selecting_for_io_path = p_io_path;
+ select_action_dialog->open();
+}
+
+void OpenXRInteractionProfileEditor::action_selected(const String p_action) {
+ _add_binding(p_action, selecting_for_io_path);
+ selecting_for_io_path = "";
+}
+
+void OpenXRInteractionProfileEditor::_add_io_path(VBoxContainer *p_container, const OpenXRDefs::IOPath *p_io_path) {
+ HBoxContainer *path_hb = memnew(HBoxContainer);
+ path_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ p_container->add_child(path_hb);
+
+ Label *path_label = memnew(Label);
+ path_label->set_text(p_io_path->display_name);
+ path_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ path_hb->add_child(path_label);
+
+ Label *type_label = memnew(Label);
+ switch (p_io_path->action_type) {
+ case OpenXRAction::OPENXR_ACTION_BOOL: {
+ type_label->set_text(TTR("Boolean"));
+ } break;
+ case OpenXRAction::OPENXR_ACTION_FLOAT: {
+ type_label->set_text(TTR("Float"));
+ } break;
+ case OpenXRAction::OPENXR_ACTION_VECTOR2: {
+ type_label->set_text(TTR("Vector2"));
+ } break;
+ case OpenXRAction::OPENXR_ACTION_POSE: {
+ type_label->set_text(TTR("Pose"));
+ } break;
+ case OpenXRAction::OPENXR_ACTION_HAPTIC: {
+ type_label->set_text(TTR("Haptic"));
+ } break;
+ default: {
+ type_label->set_text(TTR("Unknown"));
+ } break;
+ }
+ type_label->set_custom_minimum_size(Size2(50.0, 0.0));
+ path_hb->add_child(type_label);
+
+ Button *path_add = memnew(Button);
+ path_add->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
+ path_add->set_flat(true);
+ Vector<Variant> add_binds;
+ add_binds.push_back(String(p_io_path->openxr_path));
+ path_add->connect("pressed", callable_mp(this, &OpenXRInteractionProfileEditor::select_action_for), add_binds);
+ path_hb->add_child(path_add);
+
+ if (interaction_profile.is_valid()) {
+ String io_path = String(p_io_path->openxr_path);
+ Array bindings = interaction_profile->get_bindings();
+ for (int i = 0; i < bindings.size(); i++) {
+ Ref<OpenXRIPBinding> binding = bindings[i];
+ if (binding->has_path(io_path)) {
+ Ref<OpenXRAction> action = binding->get_action();
+
+ HBoxContainer *action_hb = memnew(HBoxContainer);
+ action_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ p_container->add_child(action_hb);
+
+ Control *indent_node = memnew(Control);
+ indent_node->set_custom_minimum_size(Size2(10.0, 0.0));
+ action_hb->add_child(indent_node);
+
+ Label *action_label = memnew(Label);
+ action_label->set_text(action->get_name_with_set() + ": " + action->get_localized_name());
+ action_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ action_hb->add_child(action_label);
+
+ Button *action_rem = memnew(Button);
+ action_rem->set_flat(true);
+ action_rem->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+ Vector<Variant> remove_binds;
+ remove_binds.push_back(action->get_name_with_set());
+ remove_binds.push_back(String(p_io_path->openxr_path));
+ action_rem->connect("pressed", callable_mp((OpenXRInteractionProfileEditorBase *)this, &OpenXRInteractionProfileEditorBase::_remove_binding), remove_binds);
+ action_hb->add_child(action_rem);
+ }
+ }
+ }
+}
+
+void OpenXRInteractionProfileEditor::_update_interaction_profile() {
+ ERR_FAIL_NULL(profile_def);
+
+ // out with the old...
+ while (main_hb->get_child_count() > 0) {
+ memdelete(main_hb->get_child(0));
+ }
+
+ // in with the new...
+
+ // Determine toplevel paths
+ Vector<const OpenXRDefs::TopLevelPath *> top_level_paths;
+ for (int i = 0; i < profile_def->io_path_count; i++) {
+ const OpenXRDefs::IOPath *io_path = &profile_def->io_paths[i];
+
+ if (!top_level_paths.has(io_path->top_level_path)) {
+ top_level_paths.push_back(io_path->top_level_path);
+ }
+ }
+
+ for (int i = 0; i < top_level_paths.size(); i++) {
+ PanelContainer *panel = memnew(PanelContainer);
+ panel->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ main_hb->add_child(panel);
+ panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TabContainer")));
+
+ VBoxContainer *container = memnew(VBoxContainer);
+ panel->add_child(container);
+
+ Label *label = memnew(Label);
+ label->set_text(top_level_paths[i]->display_name);
+ container->add_child(label);
+
+ for (int j = 0; j < profile_def->io_path_count; j++) {
+ const OpenXRDefs::IOPath *io_path = &profile_def->io_paths[j];
+ if (io_path->top_level_path == top_level_paths[i]) {
+ _add_io_path(container, io_path);
+ }
+ }
+ }
+}
+
+void OpenXRInteractionProfileEditor::_theme_changed() {
+ for (int i = 0; i < main_hb->get_child_count(); i++) {
+ Control *panel = static_cast<Control *>(main_hb->get_child(i));
+ if (panel) {
+ panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TabContainer")));
+ }
+ }
+}
+
+OpenXRInteractionProfileEditor::OpenXRInteractionProfileEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile) :
+ OpenXRInteractionProfileEditorBase(p_action_map, p_interaction_profile) {
+ // TODO background of scrollbox should be darker with our VBoxContainers we're adding in _update_interaction_profile the normal color
+
+ main_hb = memnew(HBoxContainer);
+ add_child(main_hb);
+
+ select_action_dialog = memnew(OpenXRSelectActionDialog(p_action_map));
+ select_action_dialog->connect("action_selected", callable_mp(this, &OpenXRInteractionProfileEditor::action_selected));
+ add_child(select_action_dialog);
+
+ _update_interaction_profile();
+}
diff --git a/modules/fbx/tools/validation_tools.h b/modules/openxr/editor/openxr_interaction_profile_editor.h
index 69a2673197..f50da1a003 100644
--- a/modules/fbx/tools/validation_tools.h
+++ b/modules/openxr/editor/openxr_interaction_profile_editor.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* validation_tools.h */
+/* openxr_interaction_profile_editor.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,65 +28,56 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef FBX_VALIDATION_TOOLS_H
-#define FBX_VALIDATION_TOOLS_H
+#ifndef OPENXR_INTERACTION_PROFILE_EDITOR_H
+#define OPENXR_INTERACTION_PROFILE_EDITOR_H
-#ifdef TOOLS_ENABLED
+#include "../action_map/openxr_action_map.h"
+#include "../action_map/openxr_defs.h"
+#include "../action_map/openxr_interaction_profile.h"
+#include "scene/gui/scroll_container.h"
-#include "core/io/file_access.h"
-#include "core/string/print_string.h"
-#include "core/templates/local_vector.h"
-#include "core/templates/map.h"
+#include "openxr_select_action_dialog.h"
+
+class OpenXRInteractionProfileEditorBase : public ScrollContainer {
+ GDCLASS(OpenXRInteractionProfileEditorBase, ScrollContainer);
-class ValidationTracker {
protected:
- struct Entries {
- Map<String, LocalVector<String>> validation_entries = Map<String, LocalVector<String>>();
-
- // for printing our CSV to dump validation problems of files
- // later we can make some agnostic tooling for this but this is fine for the time being.
- void add_validation_error(String asset_path, String message);
- void print_to_csv() {
- print_verbose("Exporting assset validation log please wait");
- String massive_log_file;
-
- String csv_header = "file_path, error message, extra data\n";
- massive_log_file += csv_header;
-
- for (const KeyValue<String, LocalVector<String>> &element : validation_entries) {
- for (unsigned int x = 0; x < element.value.size(); x++) {
- const String &line_entry = element.key + ", " + element.value[x].c_escape() + "\n";
- massive_log_file += line_entry;
- }
- }
-
- String path = "asset_validation_errors.csv";
- Error err;
- FileAccess *file = FileAccess::open(path, FileAccess::WRITE, &err);
- if (!file || err) {
- if (file) {
- memdelete(file);
- }
- print_error("ValidationTracker Error - failed to create file - path: %s\n" + path);
- return;
- }
-
- file->store_string(massive_log_file);
- if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
- print_error("ValidationTracker Error - failed to write to file - path: %s\n" + path);
- }
- file->close();
- memdelete(file);
- }
- };
- // asset path, error messages
- static Entries *entries_singleton;
+ Ref<OpenXRInteractionProfile> interaction_profile;
+ Ref<OpenXRActionMap> action_map;
+
+ static void _bind_methods();
+ void _notification(int p_what);
+
+ const OpenXRDefs::InteractionProfile *profile_def = nullptr;
+
+public:
+ Ref<OpenXRInteractionProfile> get_interaction_profile() { return interaction_profile; }
+
+ virtual void _update_interaction_profile() {}
+ virtual void _theme_changed() {}
+ void _add_binding(const String p_action, const String p_path);
+ void _remove_binding(const String p_action, const String p_path);
+
+ OpenXRInteractionProfileEditorBase(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile);
+};
+
+class OpenXRInteractionProfileEditor : public OpenXRInteractionProfileEditorBase {
+ GDCLASS(OpenXRInteractionProfileEditor, OpenXRInteractionProfileEditorBase);
+
+private:
+ String selecting_for_io_path;
+ HBoxContainer *main_hb = nullptr;
+ OpenXRSelectActionDialog *select_action_dialog = nullptr;
+
+ void _add_io_path(VBoxContainer *p_container, const OpenXRDefs::IOPath *p_io_path);
public:
- static Entries *get_singleton() {
- return entries_singleton;
- }
+ void select_action_for(const String p_io_path);
+ void action_selected(const String p_action);
+
+ virtual void _update_interaction_profile() override;
+ virtual void _theme_changed() override;
+ OpenXRInteractionProfileEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile);
};
-#endif // TOOLS_ENABLED
-#endif // FBX_VALIDATION_TOOLS_H
+#endif // !OPENXR_INTERACTION_PROFILE_EDITOR_H
diff --git a/modules/openxr/editor/openxr_select_action_dialog.cpp b/modules/openxr/editor/openxr_select_action_dialog.cpp
new file mode 100644
index 0000000000..c2a2965200
--- /dev/null
+++ b/modules/openxr/editor/openxr_select_action_dialog.cpp
@@ -0,0 +1,135 @@
+/*************************************************************************/
+/* openxr_select_action_dialog.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "openxr_select_action_dialog.h"
+#include "editor/editor_node.h"
+
+void OpenXRSelectActionDialog::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("action_selected", PropertyInfo(Variant::STRING, "action")));
+}
+
+void OpenXRSelectActionDialog::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ scroll->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ } break;
+ }
+}
+
+void OpenXRSelectActionDialog::_on_select_action(const String p_action) {
+ if (selected_action != "") {
+ NodePath button_path = action_buttons[selected_action];
+ Button *button = static_cast<Button *>(get_node(button_path));
+ if (button != nullptr) {
+ button->set_flat(true);
+ }
+ }
+
+ selected_action = p_action;
+
+ if (selected_action != "") {
+ NodePath button_path = action_buttons[selected_action];
+ Button *button = static_cast<Button *>(get_node(button_path));
+ if (button != nullptr) {
+ button->set_flat(false);
+ }
+ }
+}
+
+void OpenXRSelectActionDialog::open() {
+ ERR_FAIL_COND(action_map.is_null());
+
+ // out with the old...
+ while (main_vb->get_child_count() > 0) {
+ memdelete(main_vb->get_child(0));
+ }
+
+ selected_action = "";
+ action_buttons.clear();
+
+ Array action_sets = action_map->get_action_sets();
+ for (int i = 0; i < action_sets.size(); i++) {
+ Ref<OpenXRActionSet> action_set = action_sets[i];
+
+ Label *action_set_label = memnew(Label);
+ action_set_label->set_text(action_set->get_localized_name());
+ main_vb->add_child(action_set_label);
+
+ Array actions = action_set->get_actions();
+ for (int j = 0; j < actions.size(); j++) {
+ Ref<OpenXRAction> action = actions[j];
+
+ HBoxContainer *action_hb = memnew(HBoxContainer);
+ main_vb->add_child(action_hb);
+
+ Control *indent_node = memnew(Control);
+ indent_node->set_custom_minimum_size(Size2(10.0, 0.0));
+ action_hb->add_child(indent_node);
+
+ Button *action_button = memnew(Button);
+ String action_name = action->get_name_with_set();
+ Vector<Variant> binds;
+ binds.push_back(action_name);
+ action_button->set_flat(true);
+ action_button->set_text(action->get_name() + ": " + action->get_localized_name());
+ action_button->connect("pressed", callable_mp(this, &OpenXRSelectActionDialog::_on_select_action), binds);
+ action_hb->add_child(action_button);
+
+ action_buttons[action_name] = action_button->get_path();
+ }
+ }
+
+ popup_centered();
+}
+
+void OpenXRSelectActionDialog::ok_pressed() {
+ if (selected_action == "") {
+ return;
+ }
+
+ emit_signal("action_selected", selected_action);
+
+ hide();
+}
+
+OpenXRSelectActionDialog::OpenXRSelectActionDialog(Ref<OpenXRActionMap> p_action_map) {
+ action_map = p_action_map;
+
+ set_title(TTR("Select an action"));
+
+ scroll = memnew(ScrollContainer);
+ scroll->set_custom_minimum_size(Size2(600.0, 400.0));
+ add_child(scroll);
+
+ main_vb = memnew(VBoxContainer);
+ main_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ scroll->add_child(main_vb);
+}
diff --git a/modules/fbx/data/fbx_node.h b/modules/openxr/editor/openxr_select_action_dialog.h
index 7a4139dcdf..ea2c30373b 100644
--- a/modules/fbx/data/fbx_node.h
+++ b/modules/openxr/editor/openxr_select_action_dialog.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* fbx_node.h */
+/* openxr_select_action_dialog.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,36 +28,40 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef FBX_NODE_H
-#define FBX_NODE_H
+#ifndef OPENXR_SELECT_ACTION_DIALOG_H
+#define OPENXR_SELECT_ACTION_DIALOG_H
-#include "fbx_skeleton.h"
-#include "model_abstraction.h"
-#include "pivot_transform.h"
+#include "../action_map/openxr_action_map.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
+#include "scene/gui/dialogs.h"
+#include "scene/gui/label.h"
+#include "scene/gui/line_edit.h"
+#include "scene/gui/scroll_container.h"
+#include "scene/gui/separator.h"
+#include "scene/gui/text_edit.h"
-#include "fbx_parser/FBXDocument.h"
+class OpenXRSelectActionDialog : public ConfirmationDialog {
+ GDCLASS(OpenXRSelectActionDialog, ConfirmationDialog);
-class Node3D;
-struct PivotTransform;
+private:
+ Ref<OpenXRActionMap> action_map;
+ String selected_action;
+ Dictionary action_buttons;
-struct FBXNode : RefCounted, ModelAbstraction {
- uint64_t current_node_id = 0;
- String node_name = String();
- Node3D *godot_node = nullptr;
+ VBoxContainer *main_vb = nullptr;
+ ScrollContainer *scroll = nullptr;
- // used to parent the skeleton once the tree is built.
- Ref<FBXSkeleton> skeleton_node = Ref<FBXSkeleton>();
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
- void set_parent(Ref<FBXNode> p_parent) {
- fbx_parent = p_parent;
- }
+public:
+ void _on_select_action(const String p_action);
+ void open();
+ virtual void ok_pressed() override;
- void set_pivot_transform(Ref<PivotTransform> p_pivot_transform) {
- pivot_transform = p_pivot_transform;
- }
-
- Ref<PivotTransform> pivot_transform = Ref<PivotTransform>(); // local and global xform data
- Ref<FBXNode> fbx_parent = Ref<FBXNode>(); // parent node
+ OpenXRSelectActionDialog(Ref<OpenXRActionMap> p_action_map);
};
-#endif // FBX_NODE_H
+#endif // !OPENXR_SELECT_ACTION_DIALOG_H
diff --git a/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp b/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp
new file mode 100644
index 0000000000..12b110f146
--- /dev/null
+++ b/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp
@@ -0,0 +1,125 @@
+/*************************************************************************/
+/* openxr_select_interaction_profile_dialog.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "openxr_select_interaction_profile_dialog.h"
+
+void OpenXRSelectInteractionProfileDialog::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("interaction_profile_selected", PropertyInfo(Variant::STRING, "interaction_profile")));
+}
+
+void OpenXRSelectInteractionProfileDialog::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ scroll->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ } break;
+ }
+}
+
+void OpenXRSelectInteractionProfileDialog::_on_select_interaction_profile(const String p_interaction_profile) {
+ if (selected_interaction_profile != "") {
+ NodePath button_path = ip_buttons[selected_interaction_profile];
+ Button *button = static_cast<Button *>(get_node(button_path));
+ if (button != nullptr) {
+ button->set_flat(true);
+ }
+ }
+
+ selected_interaction_profile = p_interaction_profile;
+
+ if (selected_interaction_profile != "") {
+ NodePath button_path = ip_buttons[selected_interaction_profile];
+ Button *button = static_cast<Button *>(get_node(button_path));
+ if (button != nullptr) {
+ button->set_flat(false);
+ }
+ }
+}
+
+void OpenXRSelectInteractionProfileDialog::open(PackedStringArray p_do_not_include) {
+ int available_count = 0;
+
+ // out with the old...
+ while (main_vb->get_child_count() > 0) {
+ memdelete(main_vb->get_child(0));
+ }
+
+ selected_interaction_profile = "";
+ ip_buttons.clear();
+
+ // in with the new
+ PackedStringArray interaction_profiles = OpenXRDefs::get_interaction_profile_paths();
+ for (int i = 0; i < interaction_profiles.size(); i++) {
+ String path = interaction_profiles[i];
+ if (!p_do_not_include.has(path)) {
+ Button *ip_button = memnew(Button);
+ Vector<Variant> binds;
+ binds.push_back(path);
+ ip_button->set_flat(true);
+ ip_button->set_text(OpenXRDefs::get_profile(path)->display_name);
+ ip_button->connect("pressed", callable_mp(this, &OpenXRSelectInteractionProfileDialog::_on_select_interaction_profile), binds);
+ main_vb->add_child(ip_button);
+
+ ip_buttons[path] = ip_button->get_path();
+ available_count++;
+ }
+ }
+
+ if (available_count == 0) {
+ // give warning that we have all profiles selected
+
+ } else {
+ // TODO maybe if we only have one, auto select it?
+
+ popup_centered();
+ }
+}
+
+void OpenXRSelectInteractionProfileDialog::ok_pressed() {
+ if (selected_interaction_profile == "") {
+ return;
+ }
+
+ emit_signal("interaction_profile_selected", selected_interaction_profile);
+
+ hide();
+}
+
+OpenXRSelectInteractionProfileDialog::OpenXRSelectInteractionProfileDialog() {
+ set_title("Select an interaction profile");
+
+ scroll = memnew(ScrollContainer);
+ scroll->set_custom_minimum_size(Size2(600.0, 400.0));
+ add_child(scroll);
+
+ main_vb = memnew(VBoxContainer);
+ // main_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ scroll->add_child(main_vb);
+}
diff --git a/modules/openxr/editor/openxr_select_interaction_profile_dialog.h b/modules/openxr/editor/openxr_select_interaction_profile_dialog.h
new file mode 100644
index 0000000000..d177861ff3
--- /dev/null
+++ b/modules/openxr/editor/openxr_select_interaction_profile_dialog.h
@@ -0,0 +1,66 @@
+/*************************************************************************/
+/* openxr_select_interaction_profile_dialog.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef OPENXR_SELECT_INTERACTION_PROFILE_DIALOG_H
+#define OPENXR_SELECT_INTERACTION_PROFILE_DIALOG_H
+
+#include "../action_map/openxr_defs.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
+#include "scene/gui/dialogs.h"
+#include "scene/gui/label.h"
+#include "scene/gui/line_edit.h"
+#include "scene/gui/scroll_container.h"
+#include "scene/gui/separator.h"
+#include "scene/gui/text_edit.h"
+
+class OpenXRSelectInteractionProfileDialog : public ConfirmationDialog {
+ GDCLASS(OpenXRSelectInteractionProfileDialog, ConfirmationDialog);
+
+private:
+ String selected_interaction_profile;
+ Dictionary ip_buttons;
+
+ VBoxContainer *main_vb = nullptr;
+ ScrollContainer *scroll = nullptr;
+
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
+
+public:
+ void _on_select_interaction_profile(const String p_interaction_profile);
+ void open(PackedStringArray p_do_not_include);
+ virtual void ok_pressed() override;
+
+ OpenXRSelectInteractionProfileDialog();
+};
+
+#endif // !OPENXR_SELECT_INTERACTION_PROFILE_DIALOG_H
diff --git a/modules/openxr/extensions/openxr_extension_wrapper.h b/modules/openxr/extensions/openxr_extension_wrapper.h
index 5242ee6063..f3064041b8 100644
--- a/modules/openxr/extensions/openxr_extension_wrapper.h
+++ b/modules/openxr/extensions/openxr_extension_wrapper.h
@@ -40,10 +40,11 @@
#include <openxr/openxr.h>
class OpenXRAPI;
+class OpenXRActionMap;
class OpenXRExtensionWrapper {
protected:
- OpenXRAPI *openxr_api;
+ OpenXRAPI *openxr_api = nullptr;
// Store extension we require.
// If bool pointer is a nullptr this means this extension is mandatory and initialisation will fail if it is not available
diff --git a/modules/openxr/extensions/openxr_vulkan_extension.cpp b/modules/openxr/extensions/openxr_vulkan_extension.cpp
index c7c840fdf3..1eb7635a82 100644
--- a/modules/openxr/extensions/openxr_vulkan_extension.cpp
+++ b/modules/openxr/extensions/openxr_vulkan_extension.cpp
@@ -30,10 +30,11 @@
#include "core/string/print_string.h"
-#include "modules/openxr/extensions/openxr_vulkan_extension.h"
-#include "modules/openxr/openxr_api.h"
-#include "modules/openxr/openxr_util.h"
+#include "../extensions/openxr_vulkan_extension.h"
+#include "../openxr_api.h"
+#include "../openxr_util.h"
#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
+#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
#include "servers/rendering/rendering_server_globals.h"
#include "servers/rendering_server.h"
@@ -439,7 +440,7 @@ bool OpenXRVulkanExtension::copy_render_target_to_image(RID p_from_render_target
ERR_FAIL_COND_V(p_from_render_target.is_null(), false);
ERR_FAIL_NULL_V(RendererStorageRD::base_singleton, false);
- RID source_image = RendererStorageRD::base_singleton->render_target_get_rd_texture(p_from_render_target);
+ RID source_image = RendererRD::TextureStorage::get_singleton()->render_target_get_rd_texture(p_from_render_target);
ERR_FAIL_COND_V(source_image.is_null(), false);
RID depth_image; // TODO implement
diff --git a/modules/openxr/extensions/openxr_vulkan_extension.h b/modules/openxr/extensions/openxr_vulkan_extension.h
index cf55ae264f..1e34fe1f80 100644
--- a/modules/openxr/extensions/openxr_vulkan_extension.h
+++ b/modules/openxr/extensions/openxr_vulkan_extension.h
@@ -78,11 +78,11 @@ private:
bool check_graphics_api_support(XrVersion p_desired_version);
- VkInstance vulkan_instance;
- VkPhysicalDevice vulkan_physical_device;
- VkDevice vulkan_device;
- uint32_t vulkan_queue_family_index;
- uint32_t vulkan_queue_index;
+ VkInstance vulkan_instance = nullptr;
+ VkPhysicalDevice vulkan_physical_device = nullptr;
+ VkDevice vulkan_device = nullptr;
+ uint32_t vulkan_queue_family_index = 0;
+ uint32_t vulkan_queue_index = 0;
XrResult xrGetVulkanGraphicsRequirements2KHR(XrInstance p_instance, XrSystemId p_system_id, XrGraphicsRequirementsVulkanKHR *p_graphics_requirements);
XrResult xrCreateVulkanInstanceKHR(XrInstance p_instance, const XrVulkanInstanceCreateInfoKHR *p_create_info, VkInstance *r_vulkan_instance, VkResult *r_vulkan_result);
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index 4d533337f3..2e9be48f01 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -48,40 +48,14 @@
#include "extensions/openxr_vulkan_extension.h"
#endif
-#include "modules/openxr/openxr_interface.h"
+#include "openxr_interface.h"
OpenXRAPI *OpenXRAPI::singleton = nullptr;
-void OpenXRAPI::setup_global_defs() {
- // As OpenXRAPI is not constructed if OpenXR is not enabled, we register our project and editor settings here
-
- // Project settings
- GLOBAL_DEF_BASIC("xr/openxr/enabled", false);
- GLOBAL_DEF_BASIC("xr/openxr/default_action_map", "res://default_action_map.tres");
- ProjectSettings::get_singleton()->set_custom_property_info("xr/openxr/default_action_map", PropertyInfo(Variant::STRING, "xr/openxr/default_action_map", PROPERTY_HINT_FILE, "*.tres"));
-
- GLOBAL_DEF_BASIC("xr/openxr/form_factor", "0");
- ProjectSettings::get_singleton()->set_custom_property_info("xr/openxr/form_factor", PropertyInfo(Variant::INT, "xr/openxr/form_factor", PROPERTY_HINT_ENUM, "Head mounted,Handheld"));
-
- GLOBAL_DEF_BASIC("xr/openxr/view_configuration", "1");
- ProjectSettings::get_singleton()->set_custom_property_info("xr/openxr/view_configuration", PropertyInfo(Variant::INT, "xr/openxr/view_configuration", PROPERTY_HINT_ENUM, "Mono,Stereo")); // "Mono,Stereo,Quad,Observer"
-
- GLOBAL_DEF_BASIC("xr/openxr/reference_space", "1");
- ProjectSettings::get_singleton()->set_custom_property_info("xr/openxr/reference_space", PropertyInfo(Variant::INT, "xr/openxr/reference_space", PROPERTY_HINT_ENUM, "Local,Stage"));
-
-#ifdef TOOLS_ENABLED
- // Disabled for now, using XR inside of the editor we'll be working on during the coming months.
-
- // editor settings (it seems we're too early in the process when setting up rendering, to access editor settings...)
- // EDITOR_DEF_RST("xr/openxr/in_editor", false);
- // GLOBAL_DEF("xr/openxr/in_editor", false);
-#endif
-}
-
-bool OpenXRAPI::openxr_is_enabled() {
+bool OpenXRAPI::openxr_is_enabled(bool p_check_run_in_editor) {
// @TODO we need an overrule switch so we can force enable openxr, i.e run "godot --openxr_enabled"
- if (Engine::get_singleton()->is_editor_hint()) {
+ if (Engine::get_singleton()->is_editor_hint() && p_check_run_in_editor) {
#ifdef TOOLS_ENABLED
// Disabled for now, using XR inside of the editor we'll be working on during the coming months.
return false;
@@ -99,17 +73,7 @@ bool OpenXRAPI::openxr_is_enabled() {
}
OpenXRAPI *OpenXRAPI::get_singleton() {
- if (singleton != nullptr) {
- // already constructed, return our singleton
- return singleton;
- } else if (openxr_is_enabled()) {
- // construct our singleton and return it
- singleton = memnew(OpenXRAPI);
- return singleton;
- } else {
- // not enabled, don't instantiate, return nullptr
- return nullptr;
- }
+ return singleton;
}
String OpenXRAPI::get_default_action_map_resource_name() {
@@ -136,7 +100,7 @@ String OpenXRAPI::get_error_string(XrResult result) {
}
String OpenXRAPI::get_swapchain_format_name(int64_t p_swapchain_format) const {
- // This is rendering engine dependend...
+ // This is rendering engine dependent...
if (graphics_extension) {
return graphics_extension->get_swapchain_format_name(p_swapchain_format);
}
@@ -145,7 +109,7 @@ String OpenXRAPI::get_swapchain_format_name(int64_t p_swapchain_format) const {
}
bool OpenXRAPI::load_layer_properties() {
- // This queries additional layers that are available and can be initialised when we create our OpenXR instance
+ // This queries additional layers that are available and can be initialized when we create our OpenXR instance
if (layer_properties != nullptr) {
// already retrieved this
return true;
@@ -175,7 +139,7 @@ bool OpenXRAPI::load_layer_properties() {
}
bool OpenXRAPI::load_supported_extensions() {
- // This queries supported extensions that are available and can be initialised when we create our OpenXR instance
+ // This queries supported extensions that are available and can be initialized when we create our OpenXR instance
if (supported_extensions != nullptr) {
// already retrieved this
@@ -208,11 +172,18 @@ bool OpenXRAPI::load_supported_extensions() {
bool OpenXRAPI::is_extension_supported(const char *p_extension) const {
for (uint32_t i = 0; i < num_supported_extensions; i++) {
- if (strcmp(supported_extensions[i].extensionName, p_extension)) {
+ if (strcmp(supported_extensions[i].extensionName, p_extension) == 0) {
+#ifdef DEBUG
+ print_line("OpenXR: requested extension", p_extension, "is supported");
+#endif
return true;
}
}
+#ifdef DEBUG
+ print_line("OpenXR: requested extension", p_extension, "is not supported");
+#endif
+
return false;
}
@@ -243,6 +214,14 @@ bool OpenXRAPI::create_instance() {
}
}
+ // Add optional extensions for controllers that may be supported.
+ // Overkill to create extension classes for this.
+ requested_extensions[XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME] = &ext_hp_mixed_reality_available;
+ requested_extensions[XR_EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME] = &ext_samsung_odyssey_available;
+ requested_extensions[XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME] = &ext_vive_cosmos_available;
+ requested_extensions[XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME] = &ext_vive_focus3_available;
+ requested_extensions[XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME] = &ext_huawei_controller_available;
+
// Check which extensions are supported
enabled_extensions.clear();
for (auto &requested_extension : requested_extensions) {
@@ -375,7 +354,7 @@ bool OpenXRAPI::get_system_info() {
}
bool OpenXRAPI::load_supported_view_configuration_types() {
- // This queries the supported configuration types, likely there will only be one chosing between Mono (phone AR) and Stereo (HMDs)
+ // This queries the supported configuration types, likely there will only be one choosing between Mono (phone AR) and Stereo (HMDs)
ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false);
@@ -444,7 +423,7 @@ bool OpenXRAPI::load_supported_view_configuration_views(XrViewConfigurationType
for (uint32_t i = 0; i < view_count; i++) {
view_configuration_views[i].type = XR_TYPE_VIEW_CONFIGURATION_VIEW;
- view_configuration_views[i].next = NULL;
+ view_configuration_views[i].next = nullptr;
}
result = xrEnumerateViewConfigurationViews(instance, system_id, p_configuration_type, view_count, &view_count, view_configuration_views);
@@ -716,10 +695,10 @@ bool OpenXRAPI::create_main_swapchain() {
for (uint32_t i = 0; i < view_count; i++) {
views[i].type = XR_TYPE_VIEW;
- views[i].next = NULL;
+ views[i].next = nullptr;
projection_views[i].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW;
- projection_views[i].next = NULL;
+ projection_views[i].next = nullptr;
projection_views[i].subImage.swapchain = swapchain;
projection_views[i].subImage.imageArrayIndex = i;
projection_views[i].subImage.imageRect.offset.x = 0;
@@ -1010,7 +989,7 @@ bool OpenXRAPI::is_running() {
return running;
}
-bool OpenXRAPI::initialise(const String &p_rendering_driver) {
+bool OpenXRAPI::initialize(const String &p_rendering_driver) {
ERR_FAIL_COND_V_MSG(instance != XR_NULL_HANDLE, false, "OpenXR instance was already created");
if (p_rendering_driver == "vulkan") {
@@ -1034,7 +1013,7 @@ bool OpenXRAPI::initialise(const String &p_rendering_driver) {
ERR_FAIL_V_MSG(false, "OpenXR: Unsupported rendering device.");
}
- // initialise
+ // initialize
if (!load_layer_properties()) {
destroy_instance();
return false;
@@ -1068,7 +1047,7 @@ bool OpenXRAPI::initialise(const String &p_rendering_driver) {
return true;
}
-bool OpenXRAPI::initialise_session() {
+bool OpenXRAPI::initialize_session() {
if (!create_session()) {
destroy_session();
return false;
@@ -1117,7 +1096,7 @@ Size2 OpenXRAPI::get_recommended_target_size() {
return target_size;
}
-XRPose::TrackingConfidence OpenXRAPI::get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity) {
+XRPose::TrackingConfidence OpenXRAPI::get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, const Vector3 &r_angular_velocity) {
XrResult result;
ERR_FAIL_COND_V(!running, XRPose::XR_TRACKING_CONFIDENCE_NONE);
@@ -1183,7 +1162,7 @@ bool OpenXRAPI::get_view_transform(uint32_t p_view, Transform3D &r_transform) {
}
// we don't have valid view info
- if (views == NULL || !view_pose_valid) {
+ if (views == nullptr || !view_pose_valid) {
return false;
}
@@ -1203,7 +1182,7 @@ bool OpenXRAPI::get_view_projection(uint32_t p_view, double p_z_near, double p_z
}
// we don't have valid view info
- if (views == NULL || !view_pose_valid) {
+ if (views == nullptr || !view_pose_valid) {
return false;
}
@@ -1599,7 +1578,7 @@ void OpenXRAPI::end_frame() {
OpenXRAPI::OpenXRAPI() {
// OpenXRAPI is only constructed if OpenXR is enabled.
- // It will be constructed when the rendering device first accesses OpenXR (be it the Vulkan or OpenGL rendering system)
+ singleton = this;
if (Engine::get_singleton()->is_editor_hint()) {
// Enabled OpenXR in the editor? Adjust our settings for the editor
@@ -1656,7 +1635,7 @@ OpenXRAPI::OpenXRAPI() {
frame_state.predictedDisplayPeriod = 0;
#ifdef ANDROID_ENABLED
- // our android wrapper will initialise our android loader at this point
+ // our android wrapper will initialize our android loader at this point
register_extension_wrapper(memnew(OpenXRAndroidExtension(this)));
#endif
}
@@ -1683,6 +1662,8 @@ OpenXRAPI::~OpenXRAPI() {
memfree(layer_properties);
layer_properties = nullptr;
}
+
+ singleton = nullptr;
}
Transform3D OpenXRAPI::transform_from_pose(const XrPosef &p_pose) {
@@ -2316,7 +2297,7 @@ Vector2 OpenXRAPI::get_action_vector2(RID p_action, RID p_tracker) {
return result_state.isActive ? Vector2(result_state.currentState.x, result_state.currentState.y) : Vector2();
}
-XRPose::TrackingConfidence OpenXRAPI::get_action_pose(RID p_action, RID p_tracker, Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity) {
+XRPose::TrackingConfidence OpenXRAPI::get_action_pose(RID p_action, RID p_tracker, Transform3D &r_transform, Vector3 &r_linear_velocity, const Vector3 &r_angular_velocity) {
ERR_FAIL_COND_V(session == XR_NULL_HANDLE, XRPose::XR_TRACKING_CONFIDENCE_NONE);
Action *action = action_owner.get_or_null(p_action);
ERR_FAIL_NULL_V(action, XRPose::XR_TRACKING_CONFIDENCE_NONE);
diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h
index e20826c849..702f6b9b1d 100644
--- a/modules/openxr/openxr_api.h
+++ b/modules/openxr/openxr_api.h
@@ -75,6 +75,12 @@ private:
Vector<OpenXRExtensionWrapper *> registered_extension_wrappers;
Vector<const char *> enabled_extensions;
+ bool ext_hp_mixed_reality_available = false;
+ bool ext_samsung_odyssey_available = false;
+ bool ext_vive_cosmos_available = false;
+ bool ext_vive_focus3_available = false;
+ bool ext_huawei_controller_available = false;
+
// composition layer providers
Vector<OpenXRCompositionLayerProvider *> composition_layer_providers;
@@ -98,9 +104,9 @@ private:
// state
XrInstance instance = XR_NULL_HANDLE;
- XrSystemId system_id;
+ XrSystemId system_id = 0;
String system_name;
- uint32_t vendor_id;
+ uint32_t vendor_id = 0;
XrSystemTrackingProperties tracking_properties;
XrSession session = XR_NULL_HANDLE;
XrSessionState session_state = XR_SESSION_STATE_UNKNOWN;
@@ -222,8 +228,7 @@ protected:
void parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_linear_velocity, Vector3 r_angular_velocity);
public:
- static void setup_global_defs();
- static bool openxr_is_enabled();
+ static bool openxr_is_enabled(bool p_check_run_in_editor = true);
static OpenXRAPI *get_singleton();
String get_error_string(XrResult result);
@@ -234,15 +239,15 @@ public:
bool is_initialized();
bool is_running();
- bool initialise(const String &p_rendering_driver);
- bool initialise_session();
+ bool initialize(const String &p_rendering_driver);
+ bool initialize_session();
void finish();
XrTime get_next_frame_time() { return frame_state.predictedDisplayTime + frame_state.predictedDisplayPeriod; };
bool can_render() { return instance != XR_NULL_HANDLE && session != XR_NULL_HANDLE && running && view_pose_valid && frame_state.shouldRender; };
Size2 get_recommended_target_size();
- XRPose::TrackingConfidence get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity);
+ XRPose::TrackingConfidence get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, const Vector3 &r_angular_velocity);
bool get_view_transform(uint32_t p_view, Transform3D &r_transform);
bool get_view_projection(uint32_t p_view, double p_z_near, double p_z_far, CameraMatrix &p_camera_matrix);
bool process();
@@ -280,7 +285,7 @@ public:
bool get_action_bool(RID p_action, RID p_tracker);
float get_action_float(RID p_action, RID p_tracker);
Vector2 get_action_vector2(RID p_action, RID p_tracker);
- XRPose::TrackingConfidence get_action_pose(RID p_action, RID p_tracker, Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity);
+ XRPose::TrackingConfidence get_action_pose(RID p_action, RID p_tracker, Transform3D &r_transform, Vector3 &r_linear_velocity, const Vector3 &r_angular_velocity);
bool trigger_haptic_pulse(RID p_action, RID p_tracker, float p_frequency, float p_amplitude, XrDuration p_duration_ns);
OpenXRAPI();
diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp
index 39f9153f0d..41ce8c019e 100644
--- a/modules/openxr/openxr_interface.cpp
+++ b/modules/openxr/openxr_interface.cpp
@@ -384,7 +384,7 @@ void OpenXRInterface::handle_tracker(Tracker *p_tracker) {
// profiles are suggested bindings for controller types we know about. OpenXR runtimes can stray away from these
// and rebind them or even offer bindings to controllers that are not known to us.
- // We don't really have a consistant way to detect whether a controller is active however as long as it is
+ // We don't really have a consistent way to detect whether a controller is active however as long as it is
// unbound it seems to be unavailable, so far unknown controller seem to mimic one of the profiles we've
// supplied.
if (p_tracker->interaction_profile.is_null()) {
@@ -466,7 +466,7 @@ void OpenXRInterface::free_interaction_profiles() {
interaction_profiles.clear();
}
-bool OpenXRInterface::initialise_on_startup() const {
+bool OpenXRInterface::initialize_on_startup() const {
if (openxr_api == nullptr) {
return false;
} else if (!openxr_api->is_initialized()) {
@@ -495,7 +495,7 @@ bool OpenXRInterface::initialize() {
// load up our action sets before setting up our session, note that our profiles are suggestions, OpenXR takes ownership of (re)binding
_load_action_map();
- if (!openxr_api->initialise_session()) {
+ if (!openxr_api->initialize_session()) {
return false;
}
diff --git a/modules/openxr/openxr_interface.h b/modules/openxr/openxr_interface.h
index 421838e445..a223acfed0 100644
--- a/modules/openxr/openxr_interface.h
+++ b/modules/openxr/openxr_interface.h
@@ -106,7 +106,7 @@ public:
virtual PackedStringArray get_suggested_tracker_names() const override;
virtual TrackingStatus get_tracking_status() const override;
- bool initialise_on_startup() const;
+ bool initialize_on_startup() const;
virtual bool is_initialized() const override;
virtual bool initialize() override;
virtual void uninitialize() override;
diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp
index 7a74c8c089..c765f169dc 100644
--- a/modules/openxr/register_types.cpp
+++ b/modules/openxr/register_types.cpp
@@ -38,44 +38,73 @@
#include "action_map/openxr_action_set.h"
#include "action_map/openxr_interaction_profile.h"
-OpenXRAPI *openxr_api = nullptr;
-Ref<OpenXRInterface> openxr_interface;
+#ifdef TOOLS_ENABLED
-void preregister_openxr_types() {
- // For now we create our openxr device here. If we merge it with openxr_interface we'll create that here soon.
+#include "editor/editor_node.h"
+#include "editor/openxr_editor_plugin.h"
- OpenXRAPI::setup_global_defs();
- openxr_api = OpenXRAPI::get_singleton();
- if (openxr_api) {
- if (!openxr_api->initialise(Main::get_rendering_driver_name())) {
- return;
- }
+static void _editor_init() {
+ if (OpenXRAPI::openxr_is_enabled(false)) {
+ // Only add our OpenXR action map editor if OpenXR is enabled for our project
+
+ OpenXREditorPlugin *openxr_plugin = memnew(OpenXREditorPlugin());
+ EditorNode::get_singleton()->add_editor_plugin(openxr_plugin);
}
}
-void register_openxr_types() {
- GDREGISTER_CLASS(OpenXRInterface);
+#endif
- GDREGISTER_CLASS(OpenXRAction);
- GDREGISTER_CLASS(OpenXRActionSet);
- GDREGISTER_CLASS(OpenXRActionMap);
- GDREGISTER_CLASS(OpenXRIPBinding);
- GDREGISTER_CLASS(OpenXRInteractionProfile);
+static OpenXRAPI *openxr_api = nullptr;
+static Ref<OpenXRInterface> openxr_interface;
- XRServer *xr_server = XRServer::get_singleton();
- if (xr_server) {
- openxr_interface.instantiate();
- xr_server->add_interface(openxr_interface);
+void initialize_openxr_module(ModuleInitializationLevel p_level) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) {
+ // For now we create our openxr device here. If we merge it with openxr_interface we'll create that here soon.
- if (openxr_interface->initialise_on_startup()) {
- openxr_interface->initialize();
+ if (OpenXRAPI::openxr_is_enabled()) {
+ openxr_api = memnew(OpenXRAPI);
+ ERR_FAIL_NULL(openxr_api);
+
+ if (!openxr_api->initialize(Main::get_rendering_driver_name())) {
+ memdelete(openxr_api);
+ openxr_api = nullptr;
+ return;
+ }
}
}
+
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
+ GDREGISTER_CLASS(OpenXRInterface);
+
+ GDREGISTER_CLASS(OpenXRAction);
+ GDREGISTER_CLASS(OpenXRActionSet);
+ GDREGISTER_CLASS(OpenXRActionMap);
+ GDREGISTER_CLASS(OpenXRIPBinding);
+ GDREGISTER_CLASS(OpenXRInteractionProfile);
+
+ XRServer *xr_server = XRServer::get_singleton();
+ if (xr_server) {
+ openxr_interface.instantiate();
+ xr_server->add_interface(openxr_interface);
+
+ if (openxr_interface->initialize_on_startup()) {
+ openxr_interface->initialize();
+ }
+ }
+
+#ifdef TOOLS_ENABLED
+ EditorNode::add_init_callback(_editor_init);
+#endif
+ }
}
-void unregister_openxr_types() {
+void uninitialize_openxr_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
if (openxr_interface.is_valid()) {
- // uninitialise just in case
+ // uninitialize just in case
if (openxr_interface->is_initialized()) {
openxr_interface->uninitialize();
}
@@ -96,5 +125,6 @@ void unregister_openxr_types() {
if (openxr_api) {
openxr_api->finish();
memdelete(openxr_api);
+ openxr_api = nullptr;
}
}
diff --git a/modules/openxr/register_types.h b/modules/openxr/register_types.h
index fb42770750..1b3d98422d 100644
--- a/modules/openxr/register_types.h
+++ b/modules/openxr/register_types.h
@@ -33,8 +33,9 @@
#define MODULE_OPENXR_HAS_PREREGISTER
-void preregister_openxr_types();
-void register_openxr_types();
-void unregister_openxr_types();
+#include "modules/register_module_types.h"
+
+void initialize_openxr_module(ModuleInitializationLevel p_level);
+void uninitialize_openxr_module(ModuleInitializationLevel p_level);
#endif // OPENXR_REGISTER_TYPES_H
diff --git a/modules/raycast/raycast_occlusion_cull.cpp b/modules/raycast/raycast_occlusion_cull.cpp
index 2e0d17fb28..1550f0ef8b 100644
--- a/modules/raycast/raycast_occlusion_cull.cpp
+++ b/modules/raycast/raycast_occlusion_cull.cpp
@@ -85,7 +85,7 @@ void RaycastOcclusionCull::RaycastHZBuffer::update_camera_rays(const Transform3D
td.z_near = p_cam_projection.get_z_near();
td.z_far = p_cam_projection.get_z_far() * 1.05f;
td.camera_pos = p_cam_transform.origin;
- td.camera_dir = -p_cam_transform.basis.get_axis(2);
+ td.camera_dir = -p_cam_transform.basis.get_column(2);
td.camera_orthogonal = p_cam_orthogonal;
CameraMatrix inv_camera_matrix = p_cam_projection.inverse();
@@ -548,7 +548,7 @@ void RaycastOcclusionCull::buffer_update(RID p_buffer, const Transform3D &p_cam_
buffer.update_camera_rays(p_cam_transform, p_cam_projection, p_cam_orthogonal, p_thread_pool);
scenario.raycast(buffer.camera_rays, buffer.camera_ray_masks.ptr(), buffer.camera_rays_tile_count, p_thread_pool);
- buffer.sort_rays(-p_cam_transform.basis.get_axis(2), p_cam_orthogonal);
+ buffer.sort_rays(-p_cam_transform.basis.get_column(2), p_cam_orthogonal);
buffer.update_mips();
}
diff --git a/modules/raycast/raycast_occlusion_cull.h b/modules/raycast/raycast_occlusion_cull.h
index a22e52dd17..8453c5341d 100644
--- a/modules/raycast/raycast_occlusion_cull.h
+++ b/modules/raycast/raycast_occlusion_cull.h
@@ -115,7 +115,7 @@ private:
struct Scenario {
struct RaycastThreadData {
- CameraRayTile *rays;
+ CameraRayTile *rays = nullptr;
const uint32_t *masks;
};
@@ -124,7 +124,7 @@ private:
uint32_t vertex_count;
Transform3D xform;
const Vector3 *read;
- Vector3 *write;
+ Vector3 *write = nullptr;
};
Thread *commit_thread = nullptr;
diff --git a/modules/raycast/register_types.cpp b/modules/raycast/register_types.cpp
index 053039a85b..42de1d971d 100644
--- a/modules/raycast/register_types.cpp
+++ b/modules/raycast/register_types.cpp
@@ -36,7 +36,11 @@
RaycastOcclusionCull *raycast_occlusion_cull = nullptr;
-void register_raycast_types() {
+void initialize_raycast_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
#ifdef TOOLS_ENABLED
LightmapRaycasterEmbree::make_default_raycaster();
StaticRaycasterEmbree::make_default_raycaster();
@@ -44,7 +48,11 @@ void register_raycast_types() {
raycast_occlusion_cull = memnew(RaycastOcclusionCull);
}
-void unregister_raycast_types() {
+void uninitialize_raycast_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
if (raycast_occlusion_cull) {
memdelete(raycast_occlusion_cull);
}
diff --git a/modules/raycast/register_types.h b/modules/raycast/register_types.h
index 0abc5eb63a..a917285390 100644
--- a/modules/raycast/register_types.h
+++ b/modules/raycast/register_types.h
@@ -28,5 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-void register_raycast_types();
-void unregister_raycast_types();
+#include "modules/register_module_types.h"
+
+void initialize_raycast_module(ModuleInitializationLevel p_level);
+void uninitialize_raycast_module(ModuleInitializationLevel p_level);
diff --git a/modules/regex/regex.h b/modules/regex/regex.h
index a745c50a58..e7221f4070 100644
--- a/modules/regex/regex.h
+++ b/modules/regex/regex.h
@@ -71,7 +71,7 @@ public:
class RegEx : public RefCounted {
GDCLASS(RegEx, RefCounted);
- void *general_ctx;
+ void *general_ctx = nullptr;
void *code = nullptr;
String pattern;
diff --git a/modules/regex/register_types.cpp b/modules/regex/register_types.cpp
index 9289a724d8..2103c57f77 100644
--- a/modules/regex/register_types.cpp
+++ b/modules/regex/register_types.cpp
@@ -32,10 +32,17 @@
#include "core/object/class_db.h"
#include "regex.h"
-void register_regex_types() {
+void initialize_regex_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
GDREGISTER_CLASS(RegExMatch);
GDREGISTER_CLASS(RegEx);
}
-void unregister_regex_types() {
+void uninitialize_regex_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
diff --git a/modules/regex/register_types.h b/modules/regex/register_types.h
index b2d5009ef4..c3edf23562 100644
--- a/modules/regex/register_types.h
+++ b/modules/regex/register_types.h
@@ -31,7 +31,9 @@
#ifndef REGEX_REGISTER_TYPES_H
#define REGEX_REGISTER_TYPES_H
-void register_regex_types();
-void unregister_regex_types();
+#include "modules/register_module_types.h"
+
+void initialize_regex_module(ModuleInitializationLevel p_level);
+void uninitialize_regex_module(ModuleInitializationLevel p_level);
#endif // REGEX_REGISTER_TYPES_H
diff --git a/modules/register_module_types.h b/modules/register_module_types.h
index bc9aeb31ab..cfd1b355d4 100644
--- a/modules/register_module_types.h
+++ b/modules/register_module_types.h
@@ -31,8 +31,16 @@
#ifndef REGISTER_MODULE_TYPES_H
#define REGISTER_MODULE_TYPES_H
-void preregister_module_types();
-void register_module_types();
-void unregister_module_types();
+#include "core/extension/gdnative_interface.h"
+
+enum ModuleInitializationLevel {
+ MODULE_INITIALIZATION_LEVEL_CORE = GDNATIVE_INITIALIZATION_CORE,
+ MODULE_INITIALIZATION_LEVEL_SERVERS = GDNATIVE_INITIALIZATION_SERVERS,
+ MODULE_INITIALIZATION_LEVEL_SCENE = GDNATIVE_INITIALIZATION_SCENE,
+ MODULE_INITIALIZATION_LEVEL_EDITOR = GDNATIVE_INITIALIZATION_EDITOR
+};
+
+void initialize_modules(ModuleInitializationLevel p_level);
+void uninitialize_modules(ModuleInitializationLevel p_level);
#endif // REGISTER_MODULE_TYPES_H
diff --git a/modules/squish/register_types.cpp b/modules/squish/register_types.cpp
index 1dc2e11ab9..a80419e0eb 100644
--- a/modules/squish/register_types.cpp
+++ b/modules/squish/register_types.cpp
@@ -32,8 +32,16 @@
#include "image_decompress_squish.h"
-void register_squish_types() {
+void initialize_squish_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
Image::_image_decompress_bc = image_decompress_squish;
}
-void unregister_squish_types() {}
+void uninitialize_squish_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+}
diff --git a/modules/squish/register_types.h b/modules/squish/register_types.h
index ed1c6b0716..5e9a4dfd50 100644
--- a/modules/squish/register_types.h
+++ b/modules/squish/register_types.h
@@ -31,7 +31,9 @@
#ifndef SQUISH_REGISTER_TYPES_H
#define SQUISH_REGISTER_TYPES_H
-void register_squish_types();
-void unregister_squish_types();
+#include "modules/register_module_types.h"
+
+void initialize_squish_module(ModuleInitializationLevel p_level);
+void uninitialize_squish_module(ModuleInitializationLevel p_level);
#endif // SQUISH_REGISTER_TYPES_H
diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp
index 79ef2de929..7fe2e589b1 100644
--- a/modules/svg/image_loader_svg.cpp
+++ b/modules/svg/image_loader_svg.cpp
@@ -136,7 +136,7 @@ void ImageLoaderSVG::get_recognized_extensions(List<String> *p_extensions) const
p_extensions->push_back("svg");
}
-Error ImageLoaderSVG::load_image(Ref<Image> p_image, FileAccess *p_fileaccess, bool p_force_linear, float p_scale) {
+Error ImageLoaderSVG::load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, bool p_force_linear, float p_scale) {
String svg = p_fileaccess->get_as_utf8_string();
create_image_from_string(p_image, svg, p_scale, false, false);
ERR_FAIL_COND_V(p_image->is_empty(), FAILED);
diff --git a/modules/svg/image_loader_svg.h b/modules/svg/image_loader_svg.h
index d0bd71d92d..94c17fda43 100644
--- a/modules/svg/image_loader_svg.h
+++ b/modules/svg/image_loader_svg.h
@@ -42,7 +42,7 @@ public:
void set_replace_colors(Dictionary p_replace_colors) { replace_colors = p_replace_colors; }
void create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, bool p_convert_color);
- virtual Error load_image(Ref<Image> p_image, FileAccess *p_fileaccess, bool p_force_linear, float p_scale) override;
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, bool p_force_linear, float p_scale) override;
virtual void get_recognized_extensions(List<String> *p_extensions) const override;
};
diff --git a/modules/svg/register_types.cpp b/modules/svg/register_types.cpp
index a4341c6f1e..5b4d1d31ca 100644
--- a/modules/svg/register_types.cpp
+++ b/modules/svg/register_types.cpp
@@ -36,16 +36,24 @@
static ImageLoaderSVG *image_loader_svg = nullptr;
-void register_svg_types() {
+void initialize_svg_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw;
- if (tvg::Initializer::init(tvgEngine, 0) != tvg::Result::Success) {
+ if (tvg::Initializer::init(tvgEngine, 1) != tvg::Result::Success) {
return;
}
image_loader_svg = memnew(ImageLoaderSVG);
ImageLoader::add_image_format_loader(image_loader_svg);
}
-void unregister_svg_types() {
+void uninitialize_svg_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
if (!image_loader_svg) {
return;
}
diff --git a/modules/svg/register_types.h b/modules/svg/register_types.h
index 11fd9e7007..66f3e94600 100644
--- a/modules/svg/register_types.h
+++ b/modules/svg/register_types.h
@@ -31,7 +31,9 @@
#ifndef SVG_REGISTER_TYPES_H
#define SVG_REGISTER_TYPES_H
-void register_svg_types();
-void unregister_svg_types();
+#include "modules/register_module_types.h"
+
+void initialize_svg_module(ModuleInitializationLevel p_level);
+void uninitialize_svg_module(ModuleInitializationLevel p_level);
#endif // SVG_REGISTER_TYPES_H
diff --git a/modules/text_server_adv/.gitignore b/modules/text_server_adv/.gitignore
new file mode 100644
index 0000000000..15cc38b59c
--- /dev/null
+++ b/modules/text_server_adv/.gitignore
@@ -0,0 +1,2 @@
+# Godot-cpp headers
+gdextension_build/godot-cpp
diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub
index 5e5c284b57..525d4d3efb 100644
--- a/modules/text_server_adv/SCsub
+++ b/modules/text_server_adv/SCsub
@@ -37,7 +37,7 @@ def make_icu_data(target, source, env):
thirdparty_obj = []
freetype_enabled = env.module_check_dependencies("text_server_adv", ["freetype"], True)
-msdngen_enabled = env.module_check_dependencies("text_server_adv", ["msdfgen"], True)
+msdfgen_enabled = env.module_check_dependencies("text_server_adv", ["msdfgen"], True)
if env["builtin_harfbuzz"]:
env_harfbuzz = env_modules.Clone()
@@ -103,6 +103,7 @@ if env["builtin_harfbuzz"]:
"src/hb-subset-cff2.cc",
"src/hb-subset-input.cc",
"src/hb-subset-plan.cc",
+ "src/hb-subset-repacker.cc",
"src/hb-subset.cc",
"src/hb-ucd.cc",
"src/hb-unicode.cc",
@@ -116,20 +117,25 @@ if env["builtin_harfbuzz"]:
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
- env_harfbuzz.Append(
- CPPPATH=[
- "#thirdparty/harfbuzz/src",
- "#thirdparty/icu4c/common/",
- ]
- )
+ env_harfbuzz.Append(CPPPATH=["#thirdparty/harfbuzz/src"])
+
+ env_harfbuzz.Append(CCFLAGS=["-DHAVE_ICU"])
+ if env["builtin_icu"]:
+ env_harfbuzz.Append(CPPPATH=["#thirdparty/icu4c/common/"])
+ env_harfbuzz.Append(CCFLAGS=["-DU_HAVE_LIB_SUFFIX=1", "-DU_LIB_SUFFIX_C_NAME=_godot", "-DHAVE_ICU_BUILTIN"])
if freetype_enabled:
env_harfbuzz.Append(
- CPPPATH=[
- "#thirdparty/freetype/include",
- "#thirdparty/graphite/include",
+ CCFLAGS=[
+ "-DHAVE_FREETYPE",
+ "-DHAVE_GRAPHITE2",
]
)
+ if env["builtin_freetype"]:
+ env_harfbuzz.Append(CPPPATH=["#thirdparty/freetype/include"])
+ if env["builtin_graphite"]:
+ env_harfbuzz.Append(CPPPATH=["#thirdparty/graphite/include"])
+ env_harfbuzz.Append(CCFLAGS=["-DGRAPHITE2_STATIC"])
if env["platform"] == "android" or env["platform"] == "linuxbsd":
env_harfbuzz.Append(CCFLAGS=["-DHAVE_PTHREAD"])
@@ -140,21 +146,7 @@ if env["builtin_harfbuzz"]:
else:
env_harfbuzz.Append(CCFLAGS=["-DHB_NO_MT"])
- env_harfbuzz.Append(
- CCFLAGS=[
- "-DHAVE_ICU_BUILTIN",
- "-DHAVE_ICU",
- ]
- )
-
- if freetype_enabled:
- env_harfbuzz.Append(
- CCFLAGS=[
- "-DHAVE_FREETYPE",
- "-DHAVE_GRAPHITE2",
- "-DGRAPHITE2_STATIC",
- ]
- )
+ env_text_server_adv.Append(CPPPATH=["#thirdparty/harfbuzz/src"])
lib = env_harfbuzz.add_library("harfbuzz_builtin", thirdparty_sources)
thirdparty_obj += lib
@@ -455,6 +447,7 @@ if env["builtin_icu"]:
if env_icu["tools"]:
env_icu.Depends("#thirdparty/icu4c/icudata.gen.h", "#thirdparty/icu4c/" + icu_data_name)
env_icu.Command("#thirdparty/icu4c/icudata.gen.h", "#thirdparty/icu4c/" + icu_data_name, make_icu_data)
+ env_text_server_adv.Append(CPPPATH=["#thirdparty/icu4c/"])
else:
thirdparty_sources += ["icu_data/icudata_stub.cpp"]
@@ -471,14 +464,23 @@ if env["builtin_icu"]:
"-DUCONFIG_NO_FILE_IO",
"-DUCONFIG_NO_TRANSLITERATION",
"-DPKGDATA_MODE=static",
+ "-DU_ENABLE_DYLOAD=0",
+ "-DU_HAVE_LIB_SUFFIX=1",
+ "-DU_LIB_SUFFIX_C_NAME=_godot",
"-DICU_DATA_NAME=" + icu_data_name,
]
)
env_text_server_adv.Append(
CXXFLAGS=[
+ "-DU_HAVE_LIB_SUFFIX=1",
+ "-DU_LIB_SUFFIX_C_NAME=_godot",
"-DICU_DATA_NAME=" + icu_data_name,
]
)
+ if env_text_server_adv["tools"]:
+ env_text_server_adv.Append(CXXFLAGS=["-DICU_STATIC_DATA"])
+
+ env_text_server_adv.Append(CPPPATH=["#thirdparty/icu4c/common/"])
lib = env_icu.add_library("icu_builtin", thirdparty_sources)
thirdparty_obj += lib
@@ -501,30 +503,14 @@ if env["builtin_icu"]:
module_obj = []
-if env_text_server_adv["tools"]:
- env_text_server_adv.Append(CXXFLAGS=["-DICU_STATIC_DATA"])
+if env["builtin_msdfgen"] and msdfgen_enabled:
+ env_text_server_adv.Append(CPPPATH=["#thirdparty/msdfgen"])
-env_text_server_adv.Append(
- CPPPATH=[
- "#thirdparty/harfbuzz/src",
- "#thirdparty/icu4c/common/",
- ]
-)
+if env["builtin_freetype"] and freetype_enabled:
+ env_text_server_adv.Append(CPPPATH=["#thirdparty/freetype/include"])
-if msdngen_enabled:
- env_text_server_adv.Append(
- CPPPATH=[
- "#thirdparty/msdfgen",
- ]
- )
-
-if freetype_enabled:
- env_text_server_adv.Append(
- CPPPATH=[
- "#thirdparty/freetype/include",
- "#thirdparty/graphite/include",
- ]
- )
+if env["builtin_graphite"] and freetype_enabled:
+ env_text_server_adv.Append(CPPPATH=["#thirdparty/graphite/include"])
env_text_server_adv.add_source_files(module_obj, "*.cpp")
env.modules_sources += module_obj
diff --git a/modules/text_server_adv/doc_classes/TextServerAdvanced.xml b/modules/text_server_adv/doc_classes/TextServerAdvanced.xml
index bf86eb6406..91dde65cb8 100644
--- a/modules/text_server_adv/doc_classes/TextServerAdvanced.xml
+++ b/modules/text_server_adv/doc_classes/TextServerAdvanced.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TextServerAdvanced" inherits="TextServer" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="TextServerAdvanced" inherits="TextServerExtension" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Text Server using HarfBuzz, ICU and SIL Graphite to support BiDi, complex text layouts and contextual OpenType features.
</brief_description>
diff --git a/modules/text_server_adv/gdextension_build/SConstruct b/modules/text_server_adv/gdextension_build/SConstruct
new file mode 100644
index 0000000000..1c38398c88
--- /dev/null
+++ b/modules/text_server_adv/gdextension_build/SConstruct
@@ -0,0 +1,645 @@
+#!/usr/bin/env python
+import atexit
+import os
+import sys
+import methods
+import time
+
+# For the reference:
+# - CCFLAGS are compilation flags shared between C and C++
+# - CFLAGS are for C-specific compilation flags
+# - CXXFLAGS are for C++-specific compilation flags
+# - CPPFLAGS are for pre-processor flags
+# - CPPDEFINES are for pre-processor defines
+# - LINKFLAGS are for linking flags
+
+time_at_start = time.time()
+
+env = SConscript("./godot-cpp/SConstruct")
+env.__class__.disable_warnings = methods.disable_warnings
+
+opts = Variables([], ARGUMENTS)
+opts.Add(BoolVariable("freetype_enabled", "Use FreeType library", True))
+opts.Add(BoolVariable("msdfgen_enabled", "Use MSDFgen library (require FreeType)", True))
+opts.Add(BoolVariable("graphite_enabled", "Use Graphite library (require FreeType)", True))
+opts.Add(BoolVariable("static_icu_data", "Use built-in ICU data", True))
+opts.Add(BoolVariable("verbose", "Enable verbose output for the compilation", False))
+
+opts.Update(env)
+
+if not env["verbose"]:
+ methods.no_verbose(sys, env)
+
+if env["platform"] == "windows" and not env["use_mingw"]:
+ env.AppendUnique(CCFLAGS=["/utf-8"]) # Force to use Unicode encoding.
+
+# MSDFGEN
+if env["msdfgen_enabled"] and env["freetype_enabled"]:
+ env_msdfgen = env.Clone()
+ env_msdfgen.disable_warnings()
+
+ thirdparty_msdfgen_dir = "../../../thirdparty/msdfgen/"
+ thirdparty_msdfgen_sources = [
+ "core/Contour.cpp",
+ "core/EdgeHolder.cpp",
+ "core/MSDFErrorCorrection.cpp",
+ "core/Projection.cpp",
+ "core/Scanline.cpp",
+ "core/Shape.cpp",
+ "core/SignedDistance.cpp",
+ "core/Vector2.cpp",
+ "core/contour-combiners.cpp",
+ "core/edge-coloring.cpp",
+ "core/edge-segments.cpp",
+ "core/edge-selectors.cpp",
+ "core/equation-solver.cpp",
+ "core/msdf-error-correction.cpp",
+ "core/msdfgen.cpp",
+ "core/rasterization.cpp",
+ "core/render-sdf.cpp",
+ "core/sdf-error-estimation.cpp",
+ "core/shape-description.cpp",
+ ]
+ thirdparty_msdfgen_sources = [thirdparty_msdfgen_dir + file for file in thirdparty_msdfgen_sources]
+
+ env_msdfgen.Append(CPPPATH=["../../../thirdparty/freetype/include", "../../../thirdparty/msdfgen"])
+ env.Append(CPPPATH=["../../../thirdparty/msdfgen"])
+ env.Append(CPPDEFINES=["MODULE_MSDFGEN_ENABLED"])
+
+ lib = env_msdfgen.Library(
+ f'msdfgen_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}',
+ thirdparty_msdfgen_sources,
+ )
+ env.Append(LIBS=[lib])
+
+# FreeType
+if env["freetype_enabled"]:
+ env_freetype = env.Clone()
+ env_freetype.disable_warnings()
+
+ thirdparty_freetype_dir = "../../../thirdparty/freetype/"
+ thirdparty_freetype_sources = [
+ "src/autofit/autofit.c",
+ "src/base/ftbase.c",
+ "src/base/ftbbox.c",
+ "src/base/ftbdf.c",
+ "src/base/ftbitmap.c",
+ "src/base/ftcid.c",
+ "src/base/ftdebug.c",
+ "src/base/ftfstype.c",
+ "src/base/ftgasp.c",
+ "src/base/ftglyph.c",
+ "src/base/ftgxval.c",
+ "src/base/ftinit.c",
+ "src/base/ftmm.c",
+ "src/base/ftotval.c",
+ "src/base/ftpatent.c",
+ "src/base/ftpfr.c",
+ "src/base/ftstroke.c",
+ "src/base/ftsynth.c",
+ "src/base/ftsystem.c",
+ "src/base/fttype1.c",
+ "src/base/ftwinfnt.c",
+ "src/bdf/bdf.c",
+ "src/bzip2/ftbzip2.c",
+ "src/cache/ftcache.c",
+ "src/cff/cff.c",
+ "src/cid/type1cid.c",
+ "src/gxvalid/gxvalid.c",
+ "src/gzip/ftgzip.c",
+ "src/lzw/ftlzw.c",
+ "src/otvalid/otvalid.c",
+ "src/pcf/pcf.c",
+ "src/pfr/pfr.c",
+ "src/psaux/psaux.c",
+ "src/pshinter/pshinter.c",
+ "src/psnames/psnames.c",
+ "src/raster/raster.c",
+ "src/sdf/sdf.c",
+ "src/smooth/smooth.c",
+ "src/truetype/truetype.c",
+ "src/type1/type1.c",
+ "src/type42/type42.c",
+ "src/winfonts/winfnt.c",
+ "src/sfnt/sfnt.c",
+ ]
+ thirdparty_freetype_sources = [thirdparty_freetype_dir + file for file in thirdparty_freetype_sources]
+
+ thirdparty_png_dir = "../../../thirdparty/libpng/"
+ thirdparty_png_sources = [
+ "png.c",
+ "pngerror.c",
+ "pngget.c",
+ "pngmem.c",
+ "pngpread.c",
+ "pngread.c",
+ "pngrio.c",
+ "pngrtran.c",
+ "pngrutil.c",
+ "pngset.c",
+ "pngtrans.c",
+ "pngwio.c",
+ "pngwrite.c",
+ "pngwtran.c",
+ "pngwutil.c",
+ ]
+ thirdparty_freetype_sources += [thirdparty_png_dir + file for file in thirdparty_png_sources]
+
+ thirdparty_zlib_dir = "../../../thirdparty/zlib/"
+ thirdparty_zlib_sources = [
+ "adler32.c",
+ "compress.c",
+ "crc32.c",
+ "deflate.c",
+ "infback.c",
+ "inffast.c",
+ "inflate.c",
+ "inftrees.c",
+ "trees.c",
+ "uncompr.c",
+ "zutil.c",
+ ]
+ thirdparty_freetype_sources += [thirdparty_zlib_dir + file for file in thirdparty_zlib_sources]
+
+ env_freetype.Append(CPPPATH=[thirdparty_freetype_dir + "/include", thirdparty_zlib_dir, thirdparty_png_dir])
+ env.Append(CPPPATH=[thirdparty_freetype_dir + "/include"])
+
+ env_freetype.Append(CPPDEFINES=["FT2_BUILD_LIBRARY", "FT_CONFIG_OPTION_USE_PNG", ("PNG_ARM_NEON_OPT", 0)])
+ if env["target"] == "debug":
+ env_freetype.Append(CPPDEFINES=["ZLIB_DEBUG"])
+
+ env.Append(CPPDEFINES=["MODULE_FREETYPE_ENABLED"])
+
+ lib = env_freetype.Library(
+ f'freetype_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}',
+ thirdparty_freetype_sources,
+ )
+ env.Append(LIBS=[lib])
+
+# HarfBuzz
+env_harfbuzz = env.Clone()
+env_harfbuzz.disable_warnings()
+
+thirdparty_harfbuzz_dir = "../../../thirdparty/harfbuzz/"
+thirdparty_harfbuzz_sources = [
+ "src/hb-aat-layout.cc",
+ "src/hb-aat-map.cc",
+ "src/hb-blob.cc",
+ "src/hb-buffer-serialize.cc",
+ "src/hb-buffer-verify.cc",
+ "src/hb-buffer.cc",
+ "src/hb-common.cc",
+ #'src/hb-coretext.cc',
+ #'src/hb-directwrite.cc',
+ "src/hb-draw.cc",
+ "src/hb-face.cc",
+ "src/hb-fallback-shape.cc",
+ "src/hb-font.cc",
+ #'src/hb-gdi.cc',
+ #'src/hb-glib.cc',
+ #'src/hb-gobject-structs.cc',
+ "src/hb-icu.cc",
+ "src/hb-map.cc",
+ "src/hb-number.cc",
+ "src/hb-ot-cff1-table.cc",
+ "src/hb-ot-cff2-table.cc",
+ "src/hb-ot-color.cc",
+ "src/hb-ot-face.cc",
+ "src/hb-ot-font.cc",
+ "src/hb-ot-layout.cc",
+ "src/hb-ot-map.cc",
+ "src/hb-ot-math.cc",
+ "src/hb-ot-meta.cc",
+ "src/hb-ot-metrics.cc",
+ "src/hb-ot-name.cc",
+ "src/hb-ot-shape-complex-arabic.cc",
+ "src/hb-ot-shape-complex-default.cc",
+ "src/hb-ot-shape-complex-hangul.cc",
+ "src/hb-ot-shape-complex-hebrew.cc",
+ "src/hb-ot-shape-complex-indic-table.cc",
+ "src/hb-ot-shape-complex-indic.cc",
+ "src/hb-ot-shape-complex-khmer.cc",
+ "src/hb-ot-shape-complex-myanmar.cc",
+ "src/hb-ot-shape-complex-syllabic.cc",
+ "src/hb-ot-shape-complex-thai.cc",
+ "src/hb-ot-shape-complex-use.cc",
+ "src/hb-ot-shape-complex-vowel-constraints.cc",
+ "src/hb-ot-shape-fallback.cc",
+ "src/hb-ot-shape-normalize.cc",
+ "src/hb-ot-shape.cc",
+ "src/hb-ot-tag.cc",
+ "src/hb-ot-var.cc",
+ "src/hb-set.cc",
+ "src/hb-shape-plan.cc",
+ "src/hb-shape.cc",
+ "src/hb-shaper.cc",
+ "src/hb-static.cc",
+ "src/hb-style.cc",
+ "src/hb-subset-cff-common.cc",
+ "src/hb-subset-cff1.cc",
+ "src/hb-subset-cff2.cc",
+ "src/hb-subset-input.cc",
+ "src/hb-subset-plan.cc",
+ "src/hb-subset.cc",
+ "src/hb-ucd.cc",
+ "src/hb-unicode.cc",
+ #'src/hb-uniscribe.cc'
+]
+
+if env["freetype_enabled"]:
+ thirdparty_harfbuzz_sources += [
+ "src/hb-ft.cc",
+ "src/hb-graphite2.cc",
+ ]
+thirdparty_harfbuzz_sources = [thirdparty_harfbuzz_dir + file for file in thirdparty_harfbuzz_sources]
+
+env_harfbuzz.Append(
+ CPPPATH=[
+ "../../../thirdparty/harfbuzz/src",
+ "../../../thirdparty/icu4c/common/",
+ ]
+)
+
+if env["freetype_enabled"]:
+ env_harfbuzz.Append(
+ CPPPATH=[
+ "../../../thirdparty/freetype/include",
+ "../../../thirdparty/graphite/include",
+ ]
+ )
+
+if env["platform"] == "android" or env["platform"] == "linuxbsd":
+ env_harfbuzz.Append(CCFLAGS=["-DHAVE_PTHREAD"])
+
+env_harfbuzz.Append(
+ CCFLAGS=[
+ "-DU_HAVE_LIB_SUFFIX=1",
+ "-DU_LIB_SUFFIX_C_NAME=_godot",
+ "-DHAVE_ICU_BUILTIN",
+ "-DHAVE_ICU",
+ ]
+)
+
+if env["freetype_enabled"]:
+ env_harfbuzz.Append(
+ CCFLAGS=[
+ "-DHAVE_FREETYPE",
+ "-DHAVE_GRAPHITE2",
+ "-DGRAPHITE2_STATIC",
+ ]
+ )
+
+env.Append(CPPPATH=["../../../thirdparty/harfbuzz/src"])
+
+lib = env_harfbuzz.Library(
+ f'harfbuzz_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}',
+ thirdparty_harfbuzz_sources,
+)
+env.Prepend(LIBS=[lib])
+
+# Graphite
+if env["graphite_enabled"] and env["freetype_enabled"]:
+ env_graphite = env.Clone()
+ env_graphite.disable_warnings()
+
+ thirdparty_graphite_dir = "../../../thirdparty/graphite/"
+ thirdparty_graphite_sources = [
+ "src/gr_char_info.cpp",
+ "src/gr_face.cpp",
+ "src/gr_features.cpp",
+ "src/gr_font.cpp",
+ "src/gr_logging.cpp",
+ "src/gr_segment.cpp",
+ "src/gr_slot.cpp",
+ "src/CmapCache.cpp",
+ "src/Code.cpp",
+ "src/Collider.cpp",
+ "src/Decompressor.cpp",
+ "src/Face.cpp",
+ #'src/FileFace.cpp',
+ "src/FeatureMap.cpp",
+ "src/Font.cpp",
+ "src/GlyphCache.cpp",
+ "src/GlyphFace.cpp",
+ "src/Intervals.cpp",
+ "src/Justifier.cpp",
+ "src/NameTable.cpp",
+ "src/Pass.cpp",
+ "src/Position.cpp",
+ "src/Segment.cpp",
+ "src/Silf.cpp",
+ "src/Slot.cpp",
+ "src/Sparse.cpp",
+ "src/TtfUtil.cpp",
+ "src/UtfCodec.cpp",
+ "src/FileFace.cpp",
+ "src/json.cpp",
+ ]
+ if env["platform"] != "windows" or env["use_mingw"]:
+ thirdparty_graphite_sources += ["src/direct_machine.cpp"]
+ else:
+ thirdparty_graphite_sources += ["src/call_machine.cpp"]
+
+ thirdparty_graphite_sources = [thirdparty_graphite_dir + file for file in thirdparty_graphite_sources]
+
+ env_graphite.Append(CPPPATH=["../../../thirdparty/graphite/src", "../../../thirdparty/graphite/include"])
+ env_graphite.Append(
+ CCFLAGS=[
+ "-DGRAPHITE2_STATIC",
+ "-DGRAPHITE2_NTRACING",
+ "-DGRAPHITE2_NFILEFACE",
+ ]
+ )
+
+ lib = env_graphite.Library(
+ f'graphite_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}',
+ thirdparty_graphite_sources,
+ )
+ env.Append(LIBS=[lib])
+
+# ICU
+env_icu = env.Clone()
+env_icu.disable_warnings()
+
+thirdparty_icu_dir = "../../../thirdparty/icu4c/"
+thirdparty_icu_sources = [
+ "common/appendable.cpp",
+ "common/bmpset.cpp",
+ "common/brkeng.cpp",
+ "common/brkiter.cpp",
+ "common/bytesinkutil.cpp",
+ "common/bytestream.cpp",
+ "common/bytestrie.cpp",
+ "common/bytestriebuilder.cpp",
+ "common/bytestrieiterator.cpp",
+ "common/caniter.cpp",
+ "common/characterproperties.cpp",
+ "common/chariter.cpp",
+ "common/charstr.cpp",
+ "common/cmemory.cpp",
+ "common/cstr.cpp",
+ "common/cstring.cpp",
+ "common/cwchar.cpp",
+ "common/dictbe.cpp",
+ "common/dictionarydata.cpp",
+ "common/dtintrv.cpp",
+ "common/edits.cpp",
+ "common/emojiprops.cpp",
+ "common/errorcode.cpp",
+ "common/filteredbrk.cpp",
+ "common/filterednormalizer2.cpp",
+ "common/icudataver.cpp",
+ "common/icuplug.cpp",
+ "common/loadednormalizer2impl.cpp",
+ "common/localebuilder.cpp",
+ "common/localematcher.cpp",
+ "common/localeprioritylist.cpp",
+ "common/locavailable.cpp",
+ "common/locbased.cpp",
+ "common/locdispnames.cpp",
+ "common/locdistance.cpp",
+ "common/locdspnm.cpp",
+ "common/locid.cpp",
+ "common/loclikely.cpp",
+ "common/loclikelysubtags.cpp",
+ "common/locmap.cpp",
+ "common/locresdata.cpp",
+ "common/locutil.cpp",
+ "common/lsr.cpp",
+ "common/lstmbe.cpp",
+ "common/messagepattern.cpp",
+ "common/normalizer2.cpp",
+ "common/normalizer2impl.cpp",
+ "common/normlzr.cpp",
+ "common/parsepos.cpp",
+ "common/patternprops.cpp",
+ "common/pluralmap.cpp",
+ "common/propname.cpp",
+ "common/propsvec.cpp",
+ "common/punycode.cpp",
+ "common/putil.cpp",
+ "common/rbbi.cpp",
+ "common/rbbi_cache.cpp",
+ "common/rbbidata.cpp",
+ "common/rbbinode.cpp",
+ "common/rbbirb.cpp",
+ "common/rbbiscan.cpp",
+ "common/rbbisetb.cpp",
+ "common/rbbistbl.cpp",
+ "common/rbbitblb.cpp",
+ "common/resbund.cpp",
+ "common/resbund_cnv.cpp",
+ "common/resource.cpp",
+ "common/restrace.cpp",
+ "common/ruleiter.cpp",
+ "common/schriter.cpp",
+ "common/serv.cpp",
+ "common/servlk.cpp",
+ "common/servlkf.cpp",
+ "common/servls.cpp",
+ "common/servnotf.cpp",
+ "common/servrbf.cpp",
+ "common/servslkf.cpp",
+ "common/sharedobject.cpp",
+ "common/simpleformatter.cpp",
+ "common/static_unicode_sets.cpp",
+ "common/stringpiece.cpp",
+ "common/stringtriebuilder.cpp",
+ "common/uarrsort.cpp",
+ "common/ubidi.cpp",
+ "common/ubidi_props.cpp",
+ "common/ubidiln.cpp",
+ "common/ubiditransform.cpp",
+ "common/ubidiwrt.cpp",
+ "common/ubrk.cpp",
+ "common/ucase.cpp",
+ "common/ucasemap.cpp",
+ "common/ucasemap_titlecase_brkiter.cpp",
+ "common/ucat.cpp",
+ "common/uchar.cpp",
+ "common/ucharstrie.cpp",
+ "common/ucharstriebuilder.cpp",
+ "common/ucharstrieiterator.cpp",
+ "common/uchriter.cpp",
+ "common/ucln_cmn.cpp",
+ "common/ucmndata.cpp",
+ "common/ucnv.cpp",
+ "common/ucnv2022.cpp",
+ "common/ucnv_bld.cpp",
+ "common/ucnv_cb.cpp",
+ "common/ucnv_cnv.cpp",
+ "common/ucnv_ct.cpp",
+ "common/ucnv_err.cpp",
+ "common/ucnv_ext.cpp",
+ "common/ucnv_io.cpp",
+ "common/ucnv_lmb.cpp",
+ "common/ucnv_set.cpp",
+ "common/ucnv_u16.cpp",
+ "common/ucnv_u32.cpp",
+ "common/ucnv_u7.cpp",
+ "common/ucnv_u8.cpp",
+ "common/ucnvbocu.cpp",
+ "common/ucnvdisp.cpp",
+ "common/ucnvhz.cpp",
+ "common/ucnvisci.cpp",
+ "common/ucnvlat1.cpp",
+ "common/ucnvmbcs.cpp",
+ "common/ucnvscsu.cpp",
+ "common/ucnvsel.cpp",
+ "common/ucol_swp.cpp",
+ "common/ucptrie.cpp",
+ "common/ucurr.cpp",
+ "common/udata.cpp",
+ "common/udatamem.cpp",
+ "common/udataswp.cpp",
+ "common/uenum.cpp",
+ "common/uhash.cpp",
+ "common/uhash_us.cpp",
+ "common/uidna.cpp",
+ "common/uinit.cpp",
+ "common/uinvchar.cpp",
+ "common/uiter.cpp",
+ "common/ulist.cpp",
+ "common/uloc.cpp",
+ "common/uloc_keytype.cpp",
+ "common/uloc_tag.cpp",
+ "common/umapfile.cpp",
+ "common/umath.cpp",
+ "common/umutablecptrie.cpp",
+ "common/umutex.cpp",
+ "common/unames.cpp",
+ "common/unifiedcache.cpp",
+ "common/unifilt.cpp",
+ "common/unifunct.cpp",
+ "common/uniset.cpp",
+ "common/uniset_closure.cpp",
+ "common/uniset_props.cpp",
+ "common/unisetspan.cpp",
+ "common/unistr.cpp",
+ "common/unistr_case.cpp",
+ "common/unistr_case_locale.cpp",
+ "common/unistr_cnv.cpp",
+ "common/unistr_props.cpp",
+ "common/unistr_titlecase_brkiter.cpp",
+ "common/unorm.cpp",
+ "common/unormcmp.cpp",
+ "common/uobject.cpp",
+ "common/uprops.cpp",
+ "common/ures_cnv.cpp",
+ "common/uresbund.cpp",
+ "common/uresdata.cpp",
+ "common/usc_impl.cpp",
+ "common/uscript.cpp",
+ "common/uscript_props.cpp",
+ "common/uset.cpp",
+ "common/uset_props.cpp",
+ "common/usetiter.cpp",
+ # "common/ushape.cpp",
+ "common/usprep.cpp",
+ "common/ustack.cpp",
+ "common/ustr_cnv.cpp",
+ "common/ustr_titlecase_brkiter.cpp",
+ "common/ustr_wcs.cpp",
+ "common/ustrcase.cpp",
+ "common/ustrcase_locale.cpp",
+ "common/ustrenum.cpp",
+ "common/ustrfmt.cpp",
+ "common/ustring.cpp",
+ "common/ustrtrns.cpp",
+ "common/utext.cpp",
+ "common/utf_impl.cpp",
+ "common/util.cpp",
+ "common/util_props.cpp",
+ "common/utrace.cpp",
+ "common/utrie.cpp",
+ "common/utrie2.cpp",
+ "common/utrie2_builder.cpp",
+ "common/utrie_swap.cpp",
+ "common/uts46.cpp",
+ "common/utypes.cpp",
+ "common/uvector.cpp",
+ "common/uvectr32.cpp",
+ "common/uvectr64.cpp",
+ "common/wintz.cpp",
+]
+thirdparty_icu_sources = [thirdparty_icu_dir + file for file in thirdparty_icu_sources]
+
+icu_data_name = "icudt70l.dat"
+
+if env["static_icu_data"]:
+ env_icu.Depends("../../../thirdparty/icu4c/icudata.gen.h", "../../../thirdparty/icu4c/" + icu_data_name)
+ env_icu.Command(
+ "../../../thirdparty/icu4c/icudata.gen.h", "../../../thirdparty/icu4c/" + icu_data_name, methods.make_icu_data
+ )
+ env.Append(CXXFLAGS=["-DICU_STATIC_DATA"])
+ env.Append(CPPPATH=["../../../thirdparty/icu4c/"])
+else:
+ thirdparty_sources += ["../icu_data/icudata_stub.cpp"]
+
+env_icu.Append(CPPPATH=["../../../thirdparty/icu4c/common/"])
+env_icu.Append(
+ CXXFLAGS=[
+ "-DU_STATIC_IMPLEMENTATION",
+ "-DU_COMMON_IMPLEMENTATION",
+ "-DUCONFIG_NO_COLLATION",
+ "-DUCONFIG_NO_CONVERSION",
+ "-DUCONFIG_NO_FORMATTING",
+ "-DUCONFIG_NO_SERVICE",
+ "-DUCONFIG_NO_IDNA",
+ "-DUCONFIG_NO_FILE_IO",
+ "-DUCONFIG_NO_TRANSLITERATION",
+ "-DPKGDATA_MODE=static",
+ "-DU_ENABLE_DYLOAD=0",
+ "-DU_HAVE_LIB_SUFFIX=1",
+ "-DU_LIB_SUFFIX_C_NAME=_godot",
+ "-DICU_DATA_NAME=" + icu_data_name,
+ ]
+)
+env.Append(
+ CXXFLAGS=[
+ "-DU_HAVE_LIB_SUFFIX=1",
+ "-DU_LIB_SUFFIX_C_NAME=_godot",
+ "-DICU_DATA_NAME=" + icu_data_name,
+ ]
+)
+env.Append(CPPPATH=["../../../thirdparty/icu4c/common/"])
+
+if env["platform"] == "windows":
+ env.Append(LIBS=["advapi32"])
+
+lib = env_icu.Library(
+ f'icu_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}', thirdparty_icu_sources
+)
+env.Append(LIBS=[lib])
+
+env.Append(CPPDEFINES=["GDEXTENSION"])
+env.Append(CPPPATH=["../"])
+sources = Glob("../*.cpp")
+
+if env["platform"] == "osx":
+ methods.write_osx_plist(
+ f'./bin/libtextserver_advanced.osx.{env["target"]}.framework',
+ f'libtextserver_advanced.osx.{env["target"]}',
+ "org.godotengine.textserver_advanced",
+ "ICU / HarfBuzz / Graphite Text Server",
+ )
+ library = env.SharedLibrary(
+ f'./bin/libtextserver_advanced.osx.{env["target"]}.framework/libtextserver_advanced.osx.{env["target"]}',
+ source=sources,
+ )
+else:
+ library = env.SharedLibrary(
+ f'./bin/libtextserver_advanced.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["SHLIBSUFFIX"]}',
+ source=sources,
+ )
+
+Default(library)
+
+
+def print_elapsed_time():
+ elapsed_time_sec = round(time.time() - time_at_start, 3)
+ time_ms = round((elapsed_time_sec % 1) * 1000)
+ print("[Time elapsed: {}.{:03}]".format(time.strftime("%H:%M:%S", time.gmtime(elapsed_time_sec)), time_ms))
+
+
+atexit.register(print_elapsed_time)
diff --git a/modules/text_server_adv/gdextension_build/methods.py b/modules/text_server_adv/gdextension_build/methods.py
new file mode 100644
index 0000000000..d404f2851e
--- /dev/null
+++ b/modules/text_server_adv/gdextension_build/methods.py
@@ -0,0 +1,130 @@
+import os
+import sys
+
+
+def no_verbose(sys, env):
+ colors = {}
+
+ # Colors are disabled in non-TTY environments such as pipes. This means
+ # that if output is redirected to a file, it will not contain color codes
+ if sys.stdout.isatty():
+ colors["blue"] = "\033[0;94m"
+ colors["bold_blue"] = "\033[1;94m"
+ colors["reset"] = "\033[0m"
+ else:
+ colors["blue"] = ""
+ colors["bold_blue"] = ""
+ colors["reset"] = ""
+
+ # There is a space before "..." to ensure that source file names can be
+ # Ctrl + clicked in the VS Code terminal.
+ compile_source_message = "{}Compiling {}$SOURCE{} ...{}".format(
+ colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
+ )
+ java_compile_source_message = "{}Compiling {}$SOURCE{} ...{}".format(
+ colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
+ )
+ compile_shared_source_message = "{}Compiling shared {}$SOURCE{} ...{}".format(
+ colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
+ )
+ link_program_message = "{}Linking Program {}$TARGET{} ...{}".format(
+ colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
+ )
+ link_library_message = "{}Linking Static Library {}$TARGET{} ...{}".format(
+ colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
+ )
+ ranlib_library_message = "{}Ranlib Library {}$TARGET{} ...{}".format(
+ colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
+ )
+ link_shared_library_message = "{}Linking Shared Library {}$TARGET{} ...{}".format(
+ colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
+ )
+ java_library_message = "{}Creating Java Archive {}$TARGET{} ...{}".format(
+ colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
+ )
+
+ env.Append(CXXCOMSTR=[compile_source_message])
+ env.Append(CCCOMSTR=[compile_source_message])
+ env.Append(SHCCCOMSTR=[compile_shared_source_message])
+ env.Append(SHCXXCOMSTR=[compile_shared_source_message])
+ env.Append(ARCOMSTR=[link_library_message])
+ env.Append(RANLIBCOMSTR=[ranlib_library_message])
+ env.Append(SHLINKCOMSTR=[link_shared_library_message])
+ env.Append(LINKCOMSTR=[link_program_message])
+ env.Append(JARCOMSTR=[java_library_message])
+ env.Append(JAVACCOMSTR=[java_compile_source_message])
+
+
+def disable_warnings(self):
+ # 'self' is the environment
+ if self["platform"] == "windows" and not self["use_mingw"]:
+ # We have to remove existing warning level defines before appending /w,
+ # otherwise we get: "warning D9025 : overriding '/W3' with '/w'"
+ warn_flags = ["/Wall", "/W4", "/W3", "/W2", "/W1", "/WX"]
+ self.Append(CCFLAGS=["/w"])
+ self.Append(CFLAGS=["/w"])
+ self.Append(CXXFLAGS=["/w"])
+ self["CCFLAGS"] = [x for x in self["CCFLAGS"] if not x in warn_flags]
+ self["CFLAGS"] = [x for x in self["CFLAGS"] if not x in warn_flags]
+ self["CXXFLAGS"] = [x for x in self["CXXFLAGS"] if not x in warn_flags]
+ else:
+ self.Append(CCFLAGS=["-w"])
+ self.Append(CFLAGS=["-w"])
+ self.Append(CXXFLAGS=["-w"])
+
+
+def make_icu_data(target, source, env):
+ dst = target[0].srcnode().abspath
+ g = open(dst, "w", encoding="utf-8")
+
+ g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
+ g.write("/* (C) 2016 and later: Unicode, Inc. and others. */\n")
+ g.write("/* License & terms of use: https://www.unicode.org/copyright.html */\n")
+ g.write("#ifndef _ICU_DATA_H\n")
+ g.write("#define _ICU_DATA_H\n")
+ g.write('#include "unicode/utypes.h"\n')
+ g.write('#include "unicode/udata.h"\n')
+ g.write('#include "unicode/uversion.h"\n')
+
+ f = open(source[0].srcnode().abspath, "rb")
+ buf = f.read()
+
+ g.write('extern "C" U_EXPORT const size_t U_ICUDATA_SIZE = ' + str(len(buf)) + ";\n")
+ g.write('extern "C" U_EXPORT const unsigned char U_ICUDATA_ENTRY_POINT[] = {\n')
+ for i in range(len(buf)):
+ g.write("\t" + str(buf[i]) + ",\n")
+
+ g.write("};\n")
+ g.write("#endif")
+
+
+def write_osx_plist(target, binary_name, identifier, name):
+ os.makedirs(f"{target}/Resourece/", exist_ok=True)
+ f = open(f"{target}/Resourece/Info.plist", "w")
+
+ f.write(f'<?xml version="1.0" encoding="UTF-8"?>\n')
+ f.write(f'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n')
+ f.write(f'<plist version="1.0">\n')
+ f.write(f"<dict>\n")
+ f.write(f"\t<key>CFBundleExecutable</key>\n")
+ f.write(f"\t<string>{binary_name}</string>\n")
+ f.write(f"\t<key>CFBundleIdentifier</key>\n")
+ f.write(f"\t<string>{identifier}</string>\n")
+ f.write(f"\t<key>CFBundleInfoDictionaryVersion</key>\n")
+ f.write(f"\t<string>6.0</string>\n")
+ f.write(f"\t<key>CFBundleName</key>\n")
+ f.write(f"\t<string>{name}</string>\n")
+ f.write(f"\t<key>CFBundlePackageType</key>\n")
+ f.write(f"\t<string>FMWK</string>\n")
+ f.write(f"\t<key>CFBundleShortVersionString</key>\n")
+ f.write(f"\t<string>1.0.0</string>\n")
+ f.write(f"\t<key>CFBundleSupportedPlatforms</key>\n")
+ f.write(f"\t<array>\n")
+ f.write(f"\t\t<string>MacOSX</string>\n")
+ f.write(f"\t</array>\n")
+ f.write(f"\t<key>CFBundleVersion</key>\n")
+ f.write(f"\t<string>1.0.0</string>\n")
+ f.write(f"\t<key>LSMinimumSystemVersion</key>\n")
+ f.write(f"\t<string>10.14</string>\n")
+ f.write(f"</dict>\n")
+ f.write(f"</plist>\n")
diff --git a/modules/text_server_adv/gdextension_build/text_server_adv.gdextension b/modules/text_server_adv/gdextension_build/text_server_adv.gdextension
new file mode 100644
index 0000000000..5956476a5e
--- /dev/null
+++ b/modules/text_server_adv/gdextension_build/text_server_adv.gdextension
@@ -0,0 +1,12 @@
+[configuration]
+
+entry_symbol = "textserver_advanced_init"
+
+[libraries]
+
+linux.64.debug = "bin/libtextserver_advanced.linux.debug.64.so"
+linux.64.release = "bin/libtextserver_advanced.linux.release.64.so"
+windows.64.debug = "bin/libtextserver_advanced.windows.debug.64.dll"
+windows.64.release = "bin/libtextserver_advanced.windows.release.64.dll"
+macos.debug = "bin/libtextserver_advanced.osx.debug.framework"
+macos.release = "bin/libtextserver_advanced.osx.release.framework"
diff --git a/modules/text_server_adv/register_types.cpp b/modules/text_server_adv/register_types.cpp
index d2dbfa045b..6a26584506 100644
--- a/modules/text_server_adv/register_types.cpp
+++ b/modules/text_server_adv/register_types.cpp
@@ -32,17 +32,46 @@
#include "text_server_adv.h"
-void preregister_text_server_adv_types() {
+void initialize_text_server_adv_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SERVERS) {
+ return;
+ }
+
GDREGISTER_CLASS(TextServerAdvanced);
- if (TextServerManager::get_singleton()) {
+ TextServerManager *tsman = TextServerManager::get_singleton();
+ if (tsman) {
Ref<TextServerAdvanced> ts;
ts.instantiate();
- TextServerManager::get_singleton()->add_interface(ts);
+ tsman->add_interface(ts);
}
}
-void register_text_server_adv_types() {
+void uninitialize_text_server_adv_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SERVERS) {
+ return;
+ }
}
-void unregister_text_server_adv_types() {
+#ifdef GDEXTENSION
+
+#include <godot_cpp/core/class_db.hpp>
+#include <godot_cpp/core/defs.hpp>
+#include <godot_cpp/core/memory.hpp>
+
+using namespace godot;
+
+extern "C" {
+
+GDNativeBool GDN_EXPORT textserver_advanced_init(const GDNativeInterface *p_interface, const GDNativeExtensionClassLibraryPtr p_library, GDNativeInitialization *r_initialization) {
+ GDExtensionBinding::InitObject init_obj(p_interface, p_library, r_initialization);
+
+ init_obj.register_initializer(&initialize_text_server_adv_module);
+ init_obj.register_terminator(&uninitialize_text_server_adv_module);
+ init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SERVERS);
+
+ return init_obj.init();
}
+
+} // ! extern "C"
+
+#endif // ! GDEXTENSION
diff --git a/modules/text_server_adv/register_types.h b/modules/text_server_adv/register_types.h
index d2b49fce6e..dfe20c860c 100644
--- a/modules/text_server_adv/register_types.h
+++ b/modules/text_server_adv/register_types.h
@@ -31,10 +31,14 @@
#ifndef TEXT_SERVER_ADV_REGISTER_TYPES_H
#define TEXT_SERVER_ADV_REGISTER_TYPES_H
-#define MODULE_TEXT_SERVER_ADV_HAS_PREREGISTER
+#ifdef GDEXTENSION
+#include <godot_cpp/core/class_db.hpp>
+using namespace godot;
+#else
+#include "modules/register_module_types.h"
+#endif
-void preregister_text_server_adv_types();
-void register_text_server_adv_types();
-void unregister_text_server_adv_types();
+void initialize_text_server_adv_module(ModuleInitializationLevel p_level);
+void uninitialize_text_server_adv_module(ModuleInitializationLevel p_level);
#endif // TEXT_SERVER_ADV_REGISTER_TYPES_H
diff --git a/modules/text_server_adv/script_iterator.cpp b/modules/text_server_adv/script_iterator.cpp
index 06e934c67d..3331254b20 100644
--- a/modules/text_server_adv/script_iterator.cpp
+++ b/modules/text_server_adv/script_iterator.cpp
@@ -51,7 +51,7 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length
}
int paren_size = PAREN_STACK_DEPTH;
- ParenStackEntry *paren_stack = (ParenStackEntry *)memalloc(paren_size * sizeof(ParenStackEntry));
+ ParenStackEntry *paren_stack = static_cast<ParenStackEntry *>(memalloc(paren_size * sizeof(ParenStackEntry)));
int script_start;
int script_end = p_start;
@@ -77,7 +77,7 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length
if (unlikely(paren_sp >= paren_size)) {
// If the stack is full, allocate more space to handle deeply nested parentheses. This is unlikely to happen with any real text.
paren_size += PAREN_STACK_DEPTH;
- paren_stack = (ParenStackEntry *)memrealloc(paren_stack, paren_size * sizeof(ParenStackEntry));
+ paren_stack = static_cast<ParenStackEntry *>(memrealloc(paren_stack, paren_size * sizeof(ParenStackEntry)));
}
paren_stack[paren_sp].pair_index = ch;
paren_stack[paren_sp].script_code = script_code;
diff --git a/modules/text_server_adv/script_iterator.h b/modules/text_server_adv/script_iterator.h
index 1e11b51521..2bd045b91a 100644
--- a/modules/text_server_adv/script_iterator.h
+++ b/modules/text_server_adv/script_iterator.h
@@ -31,7 +31,22 @@
#ifndef SCRIPT_ITERATOR_H
#define SCRIPT_ITERATOR_H
-#include "servers/text_server.h"
+#ifdef GDEXTENSION
+
+// Headers for building as GDExtension plug-in.
+#include <godot_cpp/godot.hpp>
+#include <godot_cpp/templates/vector.hpp>
+#include <godot_cpp/variant/string.hpp>
+
+using namespace godot;
+
+#else
+
+// Headers for building as built-in module.
+#include "core/string/ustring.h"
+#include "core/templates/vector.h"
+
+#endif
#include <unicode/uchar.h>
#include <unicode/uloc.h>
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 7fd9cd42ed..ba249aff7a 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -30,15 +30,37 @@
#include "text_server_adv.h"
+#ifdef GDEXTENSION
+// Headers for building as GDExtension plug-in.
+
+#include <godot_cpp/classes/file.hpp>
+#include <godot_cpp/classes/rendering_server.hpp>
+#include <godot_cpp/classes/translation_server.hpp>
+#include <godot_cpp/core/error_macros.hpp>
+
+using namespace godot;
+
+#else
+// Headers for building as built-in module.
+
+#include "core/core_bind.h"
#include "core/error/error_macros.h"
#include "core/string/print_string.h"
#include "core/string/translation.h"
+#include "modules/modules_enabled.gen.h" // For freetype, msdfgen.
+
+using namespace core_bind;
+
+#endif
+
+// Built-in ICU data.
+
#ifdef ICU_STATIC_DATA
-#include "thirdparty/icu4c/icudata.gen.h"
+#include "icudata.gen.h"
#endif
-#include "modules/modules_enabled.gen.h" // For freetype, msdfgen.
+// Thirdparty headers.
#ifdef MODULE_MSDFGEN_ENABLED
#include "core/ShapeDistanceFinder.h"
@@ -67,20 +89,20 @@ TextServerAdvanced::bmp_font_t *TextServerAdvanced::_bmp_font_create(TextServerA
}
void TextServerAdvanced::_bmp_font_destroy(void *p_data) {
- bmp_font_t *bm_font = reinterpret_cast<bmp_font_t *>(p_data);
+ bmp_font_t *bm_font = static_cast<bmp_font_t *>(p_data);
memdelete(bm_font);
}
hb_bool_t TextServerAdvanced::_bmp_get_nominal_glyph(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_unicode, hb_codepoint_t *r_glyph, void *p_user_data) {
- const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data);
+ const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return false;
}
if (!bm_font->face->glyph_map.has(p_unicode)) {
- if (bm_font->face->glyph_map.has(0xF000u + p_unicode)) {
- *r_glyph = 0xF000u + p_unicode;
+ if (bm_font->face->glyph_map.has(0xf000u + p_unicode)) {
+ *r_glyph = 0xf000u + p_unicode;
return true;
} else {
return false;
@@ -92,7 +114,7 @@ hb_bool_t TextServerAdvanced::_bmp_get_nominal_glyph(hb_font_t *p_font, void *p_
}
hb_position_t TextServerAdvanced::_bmp_get_glyph_h_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) {
- const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data);
+ const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return 0;
@@ -106,7 +128,7 @@ hb_position_t TextServerAdvanced::_bmp_get_glyph_h_advance(hb_font_t *p_font, vo
}
hb_position_t TextServerAdvanced::_bmp_get_glyph_v_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) {
- const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data);
+ const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return 0;
@@ -120,7 +142,7 @@ hb_position_t TextServerAdvanced::_bmp_get_glyph_v_advance(hb_font_t *p_font, vo
}
hb_position_t TextServerAdvanced::_bmp_get_glyph_h_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data) {
- const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data);
+ const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return 0;
@@ -134,7 +156,7 @@ hb_position_t TextServerAdvanced::_bmp_get_glyph_h_kerning(hb_font_t *p_font, vo
}
hb_bool_t TextServerAdvanced::_bmp_get_glyph_v_origin(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_position_t *r_x, hb_position_t *r_y, void *p_user_data) {
- const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data);
+ const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return false;
@@ -151,7 +173,7 @@ hb_bool_t TextServerAdvanced::_bmp_get_glyph_v_origin(hb_font_t *p_font, void *p
}
hb_bool_t TextServerAdvanced::_bmp_get_glyph_extents(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_glyph_extents_t *r_extents, void *p_user_data) {
- const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data);
+ const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return false;
@@ -170,7 +192,7 @@ hb_bool_t TextServerAdvanced::_bmp_get_glyph_extents(hb_font_t *p_font, void *p_
}
hb_bool_t TextServerAdvanced::_bmp_get_font_h_extents(hb_font_t *p_font, void *p_font_data, hb_font_extents_t *r_metrics, void *p_user_data) {
- const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data);
+ const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return false;
@@ -305,22 +327,52 @@ _FORCE_INLINE_ bool is_connected_to_prev(char32_t p_chr, char32_t p_pchr) {
/*************************************************************************/
-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 | FEATURE_FONT_VARIABLE | FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION;
-
bool TextServerAdvanced::has_feature(Feature p_feature) const {
- return (interface_features & p_feature) == p_feature;
+ switch (p_feature) {
+ case FEATURE_SIMPLE_LAYOUT:
+ case FEATURE_BIDI_LAYOUT:
+ case FEATURE_VERTICAL_LAYOUT:
+ case FEATURE_SHAPING:
+ case FEATURE_KASHIDA_JUSTIFICATION:
+ case FEATURE_BREAK_ITERATORS:
+ case FEATURE_FONT_BITMAP:
+#ifdef MODULE_FREETYPE_ENABLED
+ case FEATURE_FONT_DYNAMIC:
+#endif
+#ifdef MODULE_MSDFGEN_ENABLED
+ case FEATURE_FONT_MSDF:
+#endif
+ case FEATURE_FONT_VARIABLE:
+ case FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION:
+ case FEATURE_USE_SUPPORT_DATA:
+ return true;
+ default: {
+ }
+ }
+ return false;
}
String TextServerAdvanced::get_name() const {
- return interface_name;
+#ifdef GDEXTENSION
+ return "ICU / HarfBuzz / Graphite (GDExtension)";
+#else
+ return "ICU / HarfBuzz / Graphite (Built-in)";
+#endif
}
-uint32_t TextServerAdvanced::get_features() const {
+int64_t TextServerAdvanced::get_features() const {
+ int64_t interface_features = FEATURE_SIMPLE_LAYOUT | FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_FONT_BITMAP | FEATURE_FONT_VARIABLE | FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION | FEATURE_USE_SUPPORT_DATA;
+#ifdef MODULE_FREETYPE_ENABLED
+ interface_features |= FEATURE_FONT_DYNAMIC;
+#endif
+#ifdef MODULE_MSDFGEN_ENABLED
+ interface_features |= FEATURE_FONT_MSDF;
+#endif
+
return interface_features;
}
-void TextServerAdvanced::free(RID p_rid) {
+void TextServerAdvanced::free_rid(const RID &p_rid) {
_THREAD_SAFE_METHOD_
if (font_owner.owns(p_rid)) {
FontDataAdvanced *fd = font_owner.get_or_null(p_rid);
@@ -333,7 +385,7 @@ void TextServerAdvanced::free(RID p_rid) {
}
}
-bool TextServerAdvanced::has(RID p_rid) {
+bool TextServerAdvanced::has(const RID &p_rid) {
_THREAD_SAFE_METHOD_
return font_owner.owns(p_rid) || shaped_owner.owns(p_rid);
}
@@ -342,43 +394,35 @@ bool TextServerAdvanced::load_support_data(const String &p_filename) {
_THREAD_SAFE_METHOD_
#ifdef ICU_STATIC_DATA
- if (icu_data == nullptr) {
+ if (!icu_data_loaded) {
UErrorCode err = U_ZERO_ERROR;
u_init(&err); // Do not check for errors, since we only load part of the data.
- icu_data = (uint8_t *)&U_ICUDATA_ENTRY_POINT;
+ icu_data_loaded = true;
}
#else
- if (icu_data == nullptr) {
+ if (!icu_data_loaded) {
String filename = (p_filename.is_empty()) ? String("res://") + _MKSTR(ICU_DATA_NAME) : p_filename;
- FileAccess *f = FileAccess::open(filename, FileAccess::READ);
- if (!f) {
+ Ref<File> f;
+ f.instantiate();
+ if (f->open(filename, File::READ) != OK) {
return false;
}
-
- UErrorCode err = U_ZERO_ERROR;
-
- // ICU data found.
uint64_t len = f->get_length();
- icu_data = (uint8_t *)memalloc(len);
- f->get_buffer(icu_data, len);
- f->close();
- memdelete(f);
+ PackedByteArray icu_data = f->get_buffer(len);
- udata_setCommonData(icu_data, &err);
+ UErrorCode err = U_ZERO_ERROR;
+ udata_setCommonData(icu_data.ptr(), &err);
if (U_FAILURE(err)) {
- memfree(icu_data);
- icu_data = nullptr;
ERR_FAIL_V_MSG(false, u_errorName(err));
}
err = U_ZERO_ERROR;
u_init(&err);
if (U_FAILURE(err)) {
- memfree(icu_data);
- icu_data = nullptr;
ERR_FAIL_V_MSG(false, u_errorName(err));
}
+ icu_data_loaded = true;
}
#endif
return true;
@@ -405,15 +449,19 @@ bool TextServerAdvanced::save_support_data(const String &p_filename) const {
#ifdef ICU_STATIC_DATA
// Store data to the res file if it's available.
- FileAccess *f = FileAccess::open(p_filename, FileAccess::WRITE);
- if (!f) {
+
+ Ref<File> f;
+ f.instantiate();
+ if (f->open(p_filename, File::WRITE) != OK) {
return false;
}
- f->store_buffer(U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE);
- f->close();
- memdelete(f);
- return true;
+ PackedByteArray icu_data;
+ icu_data.resize(U_ICUDATA_SIZE);
+ memcpy(icu_data.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE);
+ f->store_buffer(icu_data);
+
+ return true;
#else
return false;
#endif
@@ -428,256 +476,262 @@ bool TextServerAdvanced::is_locale_right_to_left(const String &p_locale) const {
}
}
+_FORCE_INLINE_ void TextServerAdvanced::_insert_feature(const StringName &p_name, int32_t p_tag) {
+ feature_sets.insert(p_name, p_tag);
+ feature_sets_inv.insert(p_tag, p_name);
+}
+
void TextServerAdvanced::_insert_feature_sets() {
// Registered OpenType feature tags.
- feature_sets.insert("access_all_alternates", HB_TAG('a', 'a', 'l', 't'));
- feature_sets.insert("above_base_forms", HB_TAG('a', 'b', 'v', 'f'));
- feature_sets.insert("above_base_mark_positioning", HB_TAG('a', 'b', 'v', 'm'));
- feature_sets.insert("above_base_substitutions", HB_TAG('a', 'b', 'v', 's'));
- feature_sets.insert("alternative_fractions", HB_TAG('a', 'f', 'r', 'c'));
- feature_sets.insert("akhands", HB_TAG('a', 'k', 'h', 'n'));
- feature_sets.insert("below_base_forms", HB_TAG('b', 'l', 'w', 'f'));
- feature_sets.insert("below_base_mark_positioning", HB_TAG('b', 'l', 'w', 'm'));
- feature_sets.insert("below_base_substitutions", HB_TAG('b', 'l', 'w', 's'));
- feature_sets.insert("contextual_alternates", HB_TAG('c', 'a', 'l', 't'));
- feature_sets.insert("case_sensitive_forms", HB_TAG('c', 'a', 's', 'e'));
- feature_sets.insert("glyph_composition", HB_TAG('c', 'c', 'm', 'p'));
- feature_sets.insert("conjunct_form_after_ro", HB_TAG('c', 'f', 'a', 'r'));
- feature_sets.insert("conjunct_forms", HB_TAG('c', 'j', 'c', 't'));
- feature_sets.insert("contextual_ligatures", HB_TAG('c', 'l', 'i', 'g'));
- feature_sets.insert("centered_cjk_punctuation", HB_TAG('c', 'p', 'c', 't'));
- feature_sets.insert("capital_spacing", HB_TAG('c', 'p', 's', 'p'));
- feature_sets.insert("contextual_swash", HB_TAG('c', 's', 'w', 'h'));
- feature_sets.insert("cursive_positioning", HB_TAG('c', 'u', 'r', 's'));
- feature_sets.insert("character_variant_01", HB_TAG('c', 'v', '0', '1'));
- feature_sets.insert("character_variant_02", HB_TAG('c', 'v', '0', '2'));
- feature_sets.insert("character_variant_03", HB_TAG('c', 'v', '0', '3'));
- feature_sets.insert("character_variant_04", HB_TAG('c', 'v', '0', '4'));
- feature_sets.insert("character_variant_05", HB_TAG('c', 'v', '0', '5'));
- feature_sets.insert("character_variant_06", HB_TAG('c', 'v', '0', '6'));
- feature_sets.insert("character_variant_07", HB_TAG('c', 'v', '0', '7'));
- feature_sets.insert("character_variant_08", HB_TAG('c', 'v', '0', '8'));
- feature_sets.insert("character_variant_09", HB_TAG('c', 'v', '0', '9'));
- feature_sets.insert("character_variant_10", HB_TAG('c', 'v', '1', '0'));
- feature_sets.insert("character_variant_11", HB_TAG('c', 'v', '1', '1'));
- feature_sets.insert("character_variant_12", HB_TAG('c', 'v', '1', '2'));
- feature_sets.insert("character_variant_13", HB_TAG('c', 'v', '1', '3'));
- feature_sets.insert("character_variant_14", HB_TAG('c', 'v', '1', '4'));
- feature_sets.insert("character_variant_15", HB_TAG('c', 'v', '1', '5'));
- feature_sets.insert("character_variant_16", HB_TAG('c', 'v', '1', '6'));
- feature_sets.insert("character_variant_17", HB_TAG('c', 'v', '1', '7'));
- feature_sets.insert("character_variant_18", HB_TAG('c', 'v', '1', '8'));
- feature_sets.insert("character_variant_19", HB_TAG('c', 'v', '1', '9'));
- feature_sets.insert("character_variant_20", HB_TAG('c', 'v', '2', '0'));
- feature_sets.insert("character_variant_21", HB_TAG('c', 'v', '2', '1'));
- feature_sets.insert("character_variant_22", HB_TAG('c', 'v', '2', '2'));
- feature_sets.insert("character_variant_23", HB_TAG('c', 'v', '2', '3'));
- feature_sets.insert("character_variant_24", HB_TAG('c', 'v', '2', '4'));
- feature_sets.insert("character_variant_25", HB_TAG('c', 'v', '2', '5'));
- feature_sets.insert("character_variant_26", HB_TAG('c', 'v', '2', '6'));
- feature_sets.insert("character_variant_27", HB_TAG('c', 'v', '2', '7'));
- feature_sets.insert("character_variant_28", HB_TAG('c', 'v', '2', '8'));
- feature_sets.insert("character_variant_29", HB_TAG('c', 'v', '2', '9'));
- feature_sets.insert("character_variant_30", HB_TAG('c', 'v', '3', '0'));
- feature_sets.insert("character_variant_31", HB_TAG('c', 'v', '3', '1'));
- feature_sets.insert("character_variant_32", HB_TAG('c', 'v', '3', '2'));
- feature_sets.insert("character_variant_33", HB_TAG('c', 'v', '3', '3'));
- feature_sets.insert("character_variant_34", HB_TAG('c', 'v', '3', '4'));
- feature_sets.insert("character_variant_35", HB_TAG('c', 'v', '3', '5'));
- feature_sets.insert("character_variant_36", HB_TAG('c', 'v', '3', '6'));
- feature_sets.insert("character_variant_37", HB_TAG('c', 'v', '3', '7'));
- feature_sets.insert("character_variant_38", HB_TAG('c', 'v', '3', '8'));
- feature_sets.insert("character_variant_39", HB_TAG('c', 'v', '3', '9'));
- feature_sets.insert("character_variant_40", HB_TAG('c', 'v', '4', '0'));
- feature_sets.insert("character_variant_41", HB_TAG('c', 'v', '4', '1'));
- feature_sets.insert("character_variant_42", HB_TAG('c', 'v', '4', '2'));
- feature_sets.insert("character_variant_43", HB_TAG('c', 'v', '4', '3'));
- feature_sets.insert("character_variant_44", HB_TAG('c', 'v', '4', '4'));
- feature_sets.insert("character_variant_45", HB_TAG('c', 'v', '4', '5'));
- feature_sets.insert("character_variant_46", HB_TAG('c', 'v', '4', '6'));
- feature_sets.insert("character_variant_47", HB_TAG('c', 'v', '4', '7'));
- feature_sets.insert("character_variant_48", HB_TAG('c', 'v', '4', '8'));
- feature_sets.insert("character_variant_49", HB_TAG('c', 'v', '4', '9'));
- feature_sets.insert("character_variant_50", HB_TAG('c', 'v', '5', '0'));
- feature_sets.insert("character_variant_51", HB_TAG('c', 'v', '5', '1'));
- feature_sets.insert("character_variant_52", HB_TAG('c', 'v', '5', '2'));
- feature_sets.insert("character_variant_53", HB_TAG('c', 'v', '5', '3'));
- feature_sets.insert("character_variant_54", HB_TAG('c', 'v', '5', '4'));
- feature_sets.insert("character_variant_55", HB_TAG('c', 'v', '5', '5'));
- feature_sets.insert("character_variant_56", HB_TAG('c', 'v', '5', '6'));
- feature_sets.insert("character_variant_57", HB_TAG('c', 'v', '5', '7'));
- feature_sets.insert("character_variant_58", HB_TAG('c', 'v', '5', '8'));
- feature_sets.insert("character_variant_59", HB_TAG('c', 'v', '5', '9'));
- feature_sets.insert("character_variant_60", HB_TAG('c', 'v', '6', '0'));
- feature_sets.insert("character_variant_61", HB_TAG('c', 'v', '6', '1'));
- feature_sets.insert("character_variant_62", HB_TAG('c', 'v', '6', '2'));
- feature_sets.insert("character_variant_63", HB_TAG('c', 'v', '6', '3'));
- feature_sets.insert("character_variant_64", HB_TAG('c', 'v', '6', '4'));
- feature_sets.insert("character_variant_65", HB_TAG('c', 'v', '6', '5'));
- feature_sets.insert("character_variant_66", HB_TAG('c', 'v', '6', '6'));
- feature_sets.insert("character_variant_67", HB_TAG('c', 'v', '6', '7'));
- feature_sets.insert("character_variant_68", HB_TAG('c', 'v', '6', '8'));
- feature_sets.insert("character_variant_69", HB_TAG('c', 'v', '6', '9'));
- feature_sets.insert("character_variant_70", HB_TAG('c', 'v', '7', '0'));
- feature_sets.insert("character_variant_71", HB_TAG('c', 'v', '7', '1'));
- feature_sets.insert("character_variant_72", HB_TAG('c', 'v', '7', '2'));
- feature_sets.insert("character_variant_73", HB_TAG('c', 'v', '7', '3'));
- feature_sets.insert("character_variant_74", HB_TAG('c', 'v', '7', '4'));
- feature_sets.insert("character_variant_75", HB_TAG('c', 'v', '7', '5'));
- feature_sets.insert("character_variant_76", HB_TAG('c', 'v', '7', '6'));
- feature_sets.insert("character_variant_77", HB_TAG('c', 'v', '7', '7'));
- feature_sets.insert("character_variant_78", HB_TAG('c', 'v', '7', '8'));
- feature_sets.insert("character_variant_79", HB_TAG('c', 'v', '7', '9'));
- feature_sets.insert("character_variant_80", HB_TAG('c', 'v', '8', '0'));
- feature_sets.insert("character_variant_81", HB_TAG('c', 'v', '8', '1'));
- feature_sets.insert("character_variant_82", HB_TAG('c', 'v', '8', '2'));
- feature_sets.insert("character_variant_83", HB_TAG('c', 'v', '8', '3'));
- feature_sets.insert("character_variant_84", HB_TAG('c', 'v', '8', '4'));
- feature_sets.insert("character_variant_85", HB_TAG('c', 'v', '8', '5'));
- feature_sets.insert("character_variant_86", HB_TAG('c', 'v', '8', '6'));
- feature_sets.insert("character_variant_87", HB_TAG('c', 'v', '8', '7'));
- feature_sets.insert("character_variant_88", HB_TAG('c', 'v', '8', '8'));
- feature_sets.insert("character_variant_89", HB_TAG('c', 'v', '8', '9'));
- feature_sets.insert("character_variant_90", HB_TAG('c', 'v', '9', '0'));
- feature_sets.insert("character_variant_91", HB_TAG('c', 'v', '9', '1'));
- feature_sets.insert("character_variant_92", HB_TAG('c', 'v', '9', '2'));
- feature_sets.insert("character_variant_93", HB_TAG('c', 'v', '9', '3'));
- feature_sets.insert("character_variant_94", HB_TAG('c', 'v', '9', '4'));
- feature_sets.insert("character_variant_95", HB_TAG('c', 'v', '9', '5'));
- feature_sets.insert("character_variant_96", HB_TAG('c', 'v', '9', '6'));
- feature_sets.insert("character_variant_97", HB_TAG('c', 'v', '9', '7'));
- feature_sets.insert("character_variant_98", HB_TAG('c', 'v', '9', '8'));
- feature_sets.insert("character_variant_99", HB_TAG('c', 'v', '9', '9'));
- feature_sets.insert("petite_capitals_from_capitals", HB_TAG('c', '2', 'p', 'c'));
- feature_sets.insert("small_capitals_from_capitals", HB_TAG('c', '2', 's', 'c'));
- feature_sets.insert("distances", HB_TAG('d', 'i', 's', 't'));
- feature_sets.insert("discretionary_ligatures", HB_TAG('d', 'l', 'i', 'g'));
- feature_sets.insert("denominators", HB_TAG('d', 'n', 'o', 'm'));
- feature_sets.insert("dotless_forms", HB_TAG('d', 't', 'l', 's'));
- feature_sets.insert("expert_forms", HB_TAG('e', 'x', 'p', 't'));
- feature_sets.insert("final_glyph_on_line_alternates", HB_TAG('f', 'a', 'l', 't'));
- feature_sets.insert("terminal_forms_2", HB_TAG('f', 'i', 'n', '2'));
- feature_sets.insert("terminal_forms_3", HB_TAG('f', 'i', 'n', '3'));
- feature_sets.insert("terminal_forms", HB_TAG('f', 'i', 'n', 'a'));
- feature_sets.insert("flattened_accent_forms", HB_TAG('f', 'l', 'a', 'c'));
- feature_sets.insert("fractions", HB_TAG('f', 'r', 'a', 'c'));
- feature_sets.insert("full_widths", HB_TAG('f', 'w', 'i', 'd'));
- feature_sets.insert("half_forms", HB_TAG('h', 'a', 'l', 'f'));
- feature_sets.insert("halant_forms", HB_TAG('h', 'a', 'l', 'n'));
- feature_sets.insert("alternate_half_widths", HB_TAG('h', 'a', 'l', 't'));
- feature_sets.insert("historical_forms", HB_TAG('h', 'i', 's', 't'));
- feature_sets.insert("horizontal_kana_alternates", HB_TAG('h', 'k', 'n', 'a'));
- feature_sets.insert("historical_ligatures", HB_TAG('h', 'l', 'i', 'g'));
- feature_sets.insert("hangul", HB_TAG('h', 'n', 'g', 'l'));
- feature_sets.insert("hojo_kanji_forms", HB_TAG('h', 'o', 'j', 'o'));
- feature_sets.insert("half_widths", HB_TAG('h', 'w', 'i', 'd'));
- feature_sets.insert("initial_forms", HB_TAG('i', 'n', 'i', 't'));
- feature_sets.insert("isolated_forms", HB_TAG('i', 's', 'o', 'l'));
- feature_sets.insert("italics", HB_TAG('i', 't', 'a', 'l'));
- feature_sets.insert("justification_alternates", HB_TAG('j', 'a', 'l', 't'));
- feature_sets.insert("jis78_forms", HB_TAG('j', 'p', '7', '8'));
- feature_sets.insert("jis83_forms", HB_TAG('j', 'p', '8', '3'));
- feature_sets.insert("jis90_forms", HB_TAG('j', 'p', '9', '0'));
- feature_sets.insert("jis2004_forms", HB_TAG('j', 'p', '0', '4'));
- feature_sets.insert("kerning", HB_TAG('k', 'e', 'r', 'n'));
- feature_sets.insert("left_bounds", HB_TAG('l', 'f', 'b', 'd'));
- feature_sets.insert("standard_ligatures", HB_TAG('l', 'i', 'g', 'a'));
- feature_sets.insert("leading_jamo_forms", HB_TAG('l', 'j', 'm', 'o'));
- feature_sets.insert("lining_figures", HB_TAG('l', 'n', 'u', 'm'));
- feature_sets.insert("localized_forms", HB_TAG('l', 'o', 'c', 'l'));
- feature_sets.insert("left_to_right_alternates", HB_TAG('l', 't', 'r', 'a'));
- feature_sets.insert("left_to_right_mirrored_forms", HB_TAG('l', 't', 'r', 'm'));
- feature_sets.insert("mark_positioning", HB_TAG('m', 'a', 'r', 'k'));
- feature_sets.insert("medial_forms_2", HB_TAG('m', 'e', 'd', '2'));
- feature_sets.insert("medial_forms", HB_TAG('m', 'e', 'd', 'i'));
- feature_sets.insert("mathematical_greek", HB_TAG('m', 'g', 'r', 'k'));
- feature_sets.insert("mark_to_mark_positioning", HB_TAG('m', 'k', 'm', 'k'));
- feature_sets.insert("mark_positioning_via_substitution", HB_TAG('m', 's', 'e', 't'));
- feature_sets.insert("alternate_annotation_forms", HB_TAG('n', 'a', 'l', 't'));
- feature_sets.insert("nlc_kanji_forms", HB_TAG('n', 'l', 'c', 'k'));
- feature_sets.insert("nukta_forms", HB_TAG('n', 'u', 'k', 't'));
- feature_sets.insert("numerators", HB_TAG('n', 'u', 'm', 'r'));
- feature_sets.insert("oldstyle_figures", HB_TAG('o', 'n', 'u', 'm'));
- feature_sets.insert("optical_bounds", HB_TAG('o', 'p', 'b', 'd'));
- feature_sets.insert("ordinals", HB_TAG('o', 'r', 'd', 'n'));
- feature_sets.insert("ornaments", HB_TAG('o', 'r', 'n', 'm'));
- feature_sets.insert("proportional_alternate_widths", HB_TAG('p', 'a', 'l', 't'));
- feature_sets.insert("petite_capitals", HB_TAG('p', 'c', 'a', 'p'));
- feature_sets.insert("proportional_kana", HB_TAG('p', 'k', 'n', 'a'));
- feature_sets.insert("proportional_figures", HB_TAG('p', 'n', 'u', 'm'));
- feature_sets.insert("pre_base_forms", HB_TAG('p', 'r', 'e', 'f'));
- feature_sets.insert("pre_base_substitutions", HB_TAG('p', 'r', 'e', 's'));
- feature_sets.insert("post_base_forms", HB_TAG('p', 's', 't', 'f'));
- feature_sets.insert("post_base_substitutions", HB_TAG('p', 's', 't', 's'));
- feature_sets.insert("proportional_widths", HB_TAG('p', 'w', 'i', 'd'));
- feature_sets.insert("quarter_widths", HB_TAG('q', 'w', 'i', 'd'));
- feature_sets.insert("randomize", HB_TAG('r', 'a', 'n', 'd'));
- feature_sets.insert("required_contextual_alternates", HB_TAG('r', 'c', 'l', 't'));
- feature_sets.insert("rakar_forms", HB_TAG('r', 'k', 'r', 'f'));
- feature_sets.insert("required_ligatures", HB_TAG('r', 'l', 'i', 'g'));
- feature_sets.insert("reph_forms", HB_TAG('r', 'p', 'h', 'f'));
- feature_sets.insert("right_bounds", HB_TAG('r', 't', 'b', 'd'));
- feature_sets.insert("right_to_left_alternates", HB_TAG('r', 't', 'l', 'a'));
- feature_sets.insert("right_to_left_mirrored_forms", HB_TAG('r', 't', 'l', 'm'));
- feature_sets.insert("ruby_notation_forms", HB_TAG('r', 'u', 'b', 'y'));
- feature_sets.insert("required_variation_alternates", HB_TAG('r', 'v', 'r', 'n'));
- feature_sets.insert("stylistic_alternates", HB_TAG('s', 'a', 'l', 't'));
- feature_sets.insert("scientific_inferiors", HB_TAG('s', 'i', 'n', 'f'));
- feature_sets.insert("optical_size", HB_TAG('s', 'i', 'z', 'e'));
- feature_sets.insert("small_capitals", HB_TAG('s', 'm', 'c', 'p'));
- feature_sets.insert("simplified_forms", HB_TAG('s', 'm', 'p', 'l'));
- feature_sets.insert("stylistic_set_01", HB_TAG('s', 's', '0', '1'));
- feature_sets.insert("stylistic_set_02", HB_TAG('s', 's', '0', '2'));
- feature_sets.insert("stylistic_set_03", HB_TAG('s', 's', '0', '3'));
- feature_sets.insert("stylistic_set_04", HB_TAG('s', 's', '0', '4'));
- feature_sets.insert("stylistic_set_05", HB_TAG('s', 's', '0', '5'));
- feature_sets.insert("stylistic_set_06", HB_TAG('s', 's', '0', '6'));
- feature_sets.insert("stylistic_set_07", HB_TAG('s', 's', '0', '7'));
- feature_sets.insert("stylistic_set_08", HB_TAG('s', 's', '0', '8'));
- feature_sets.insert("stylistic_set_09", HB_TAG('s', 's', '0', '9'));
- feature_sets.insert("stylistic_set_10", HB_TAG('s', 's', '1', '0'));
- feature_sets.insert("stylistic_set_11", HB_TAG('s', 's', '1', '1'));
- feature_sets.insert("stylistic_set_12", HB_TAG('s', 's', '1', '2'));
- feature_sets.insert("stylistic_set_13", HB_TAG('s', 's', '1', '3'));
- feature_sets.insert("stylistic_set_14", HB_TAG('s', 's', '1', '4'));
- feature_sets.insert("stylistic_set_15", HB_TAG('s', 's', '1', '5'));
- feature_sets.insert("stylistic_set_16", HB_TAG('s', 's', '1', '6'));
- feature_sets.insert("stylistic_set_17", HB_TAG('s', 's', '1', '7'));
- feature_sets.insert("stylistic_set_18", HB_TAG('s', 's', '1', '8'));
- feature_sets.insert("stylistic_set_19", HB_TAG('s', 's', '1', '9'));
- feature_sets.insert("stylistic_set_20", HB_TAG('s', 's', '2', '0'));
- feature_sets.insert("math_script_style_alternates", HB_TAG('s', 's', 't', 'y'));
- feature_sets.insert("stretching_glyph_decomposition", HB_TAG('s', 't', 'c', 'h'));
- feature_sets.insert("subscript", HB_TAG('s', 'u', 'b', 's'));
- feature_sets.insert("superscript", HB_TAG('s', 'u', 'p', 's'));
- feature_sets.insert("swash", HB_TAG('s', 'w', 's', 'h'));
- feature_sets.insert("titling", HB_TAG('t', 'i', 't', 'l'));
- feature_sets.insert("trailing_jamo_forms", HB_TAG('t', 'j', 'm', 'o'));
- feature_sets.insert("traditional_name_forms", HB_TAG('t', 'n', 'a', 'm'));
- feature_sets.insert("tabular_figures", HB_TAG('t', 'n', 'u', 'm'));
- feature_sets.insert("traditional_forms", HB_TAG('t', 'r', 'a', 'd'));
- feature_sets.insert("third_widths", HB_TAG('t', 'w', 'i', 'd'));
- feature_sets.insert("unicase", HB_TAG('u', 'n', 'i', 'c'));
- feature_sets.insert("alternate_vertical_metrics", HB_TAG('v', 'a', 'l', 't'));
- feature_sets.insert("vattu_variants", HB_TAG('v', 'a', 't', 'u'));
- feature_sets.insert("vertical_writing", HB_TAG('v', 'e', 'r', 't'));
- feature_sets.insert("alternate_vertical_half_metrics", HB_TAG('v', 'h', 'a', 'l'));
- feature_sets.insert("vowel_jamo_forms", HB_TAG('v', 'j', 'm', 'o'));
- feature_sets.insert("vertical_kana_alternates", HB_TAG('v', 'k', 'n', 'a'));
- feature_sets.insert("vertical_kerning", HB_TAG('v', 'k', 'r', 'n'));
- feature_sets.insert("proportional_alternate_vertical_metrics", HB_TAG('v', 'p', 'a', 'l'));
- feature_sets.insert("vertical_alternates_and_rotation", HB_TAG('v', 'r', 't', '2'));
- feature_sets.insert("vertical_alternates_for_rotation", HB_TAG('v', 'r', 't', 'r'));
- feature_sets.insert("slashed_zero", HB_TAG('z', 'e', 'r', 'o'));
+ _insert_feature("access_all_alternates", HB_TAG('a', 'a', 'l', 't'));
+ _insert_feature("above_base_forms", HB_TAG('a', 'b', 'v', 'f'));
+ _insert_feature("above_base_mark_positioning", HB_TAG('a', 'b', 'v', 'm'));
+ _insert_feature("above_base_substitutions", HB_TAG('a', 'b', 'v', 's'));
+ _insert_feature("alternative_fractions", HB_TAG('a', 'f', 'r', 'c'));
+ _insert_feature("akhands", HB_TAG('a', 'k', 'h', 'n'));
+ _insert_feature("below_base_forms", HB_TAG('b', 'l', 'w', 'f'));
+ _insert_feature("below_base_mark_positioning", HB_TAG('b', 'l', 'w', 'm'));
+ _insert_feature("below_base_substitutions", HB_TAG('b', 'l', 'w', 's'));
+ _insert_feature("contextual_alternates", HB_TAG('c', 'a', 'l', 't'));
+ _insert_feature("case_sensitive_forms", HB_TAG('c', 'a', 's', 'e'));
+ _insert_feature("glyph_composition", HB_TAG('c', 'c', 'm', 'p'));
+ _insert_feature("conjunct_form_after_ro", HB_TAG('c', 'f', 'a', 'r'));
+ _insert_feature("conjunct_forms", HB_TAG('c', 'j', 'c', 't'));
+ _insert_feature("contextual_ligatures", HB_TAG('c', 'l', 'i', 'g'));
+ _insert_feature("centered_cjk_punctuation", HB_TAG('c', 'p', 'c', 't'));
+ _insert_feature("capital_spacing", HB_TAG('c', 'p', 's', 'p'));
+ _insert_feature("contextual_swash", HB_TAG('c', 's', 'w', 'h'));
+ _insert_feature("cursive_positioning", HB_TAG('c', 'u', 'r', 's'));
+ _insert_feature("character_variant_01", HB_TAG('c', 'v', '0', '1'));
+ _insert_feature("character_variant_02", HB_TAG('c', 'v', '0', '2'));
+ _insert_feature("character_variant_03", HB_TAG('c', 'v', '0', '3'));
+ _insert_feature("character_variant_04", HB_TAG('c', 'v', '0', '4'));
+ _insert_feature("character_variant_05", HB_TAG('c', 'v', '0', '5'));
+ _insert_feature("character_variant_06", HB_TAG('c', 'v', '0', '6'));
+ _insert_feature("character_variant_07", HB_TAG('c', 'v', '0', '7'));
+ _insert_feature("character_variant_08", HB_TAG('c', 'v', '0', '8'));
+ _insert_feature("character_variant_09", HB_TAG('c', 'v', '0', '9'));
+ _insert_feature("character_variant_10", HB_TAG('c', 'v', '1', '0'));
+ _insert_feature("character_variant_11", HB_TAG('c', 'v', '1', '1'));
+ _insert_feature("character_variant_12", HB_TAG('c', 'v', '1', '2'));
+ _insert_feature("character_variant_13", HB_TAG('c', 'v', '1', '3'));
+ _insert_feature("character_variant_14", HB_TAG('c', 'v', '1', '4'));
+ _insert_feature("character_variant_15", HB_TAG('c', 'v', '1', '5'));
+ _insert_feature("character_variant_16", HB_TAG('c', 'v', '1', '6'));
+ _insert_feature("character_variant_17", HB_TAG('c', 'v', '1', '7'));
+ _insert_feature("character_variant_18", HB_TAG('c', 'v', '1', '8'));
+ _insert_feature("character_variant_19", HB_TAG('c', 'v', '1', '9'));
+ _insert_feature("character_variant_20", HB_TAG('c', 'v', '2', '0'));
+ _insert_feature("character_variant_21", HB_TAG('c', 'v', '2', '1'));
+ _insert_feature("character_variant_22", HB_TAG('c', 'v', '2', '2'));
+ _insert_feature("character_variant_23", HB_TAG('c', 'v', '2', '3'));
+ _insert_feature("character_variant_24", HB_TAG('c', 'v', '2', '4'));
+ _insert_feature("character_variant_25", HB_TAG('c', 'v', '2', '5'));
+ _insert_feature("character_variant_26", HB_TAG('c', 'v', '2', '6'));
+ _insert_feature("character_variant_27", HB_TAG('c', 'v', '2', '7'));
+ _insert_feature("character_variant_28", HB_TAG('c', 'v', '2', '8'));
+ _insert_feature("character_variant_29", HB_TAG('c', 'v', '2', '9'));
+ _insert_feature("character_variant_30", HB_TAG('c', 'v', '3', '0'));
+ _insert_feature("character_variant_31", HB_TAG('c', 'v', '3', '1'));
+ _insert_feature("character_variant_32", HB_TAG('c', 'v', '3', '2'));
+ _insert_feature("character_variant_33", HB_TAG('c', 'v', '3', '3'));
+ _insert_feature("character_variant_34", HB_TAG('c', 'v', '3', '4'));
+ _insert_feature("character_variant_35", HB_TAG('c', 'v', '3', '5'));
+ _insert_feature("character_variant_36", HB_TAG('c', 'v', '3', '6'));
+ _insert_feature("character_variant_37", HB_TAG('c', 'v', '3', '7'));
+ _insert_feature("character_variant_38", HB_TAG('c', 'v', '3', '8'));
+ _insert_feature("character_variant_39", HB_TAG('c', 'v', '3', '9'));
+ _insert_feature("character_variant_40", HB_TAG('c', 'v', '4', '0'));
+ _insert_feature("character_variant_41", HB_TAG('c', 'v', '4', '1'));
+ _insert_feature("character_variant_42", HB_TAG('c', 'v', '4', '2'));
+ _insert_feature("character_variant_43", HB_TAG('c', 'v', '4', '3'));
+ _insert_feature("character_variant_44", HB_TAG('c', 'v', '4', '4'));
+ _insert_feature("character_variant_45", HB_TAG('c', 'v', '4', '5'));
+ _insert_feature("character_variant_46", HB_TAG('c', 'v', '4', '6'));
+ _insert_feature("character_variant_47", HB_TAG('c', 'v', '4', '7'));
+ _insert_feature("character_variant_48", HB_TAG('c', 'v', '4', '8'));
+ _insert_feature("character_variant_49", HB_TAG('c', 'v', '4', '9'));
+ _insert_feature("character_variant_50", HB_TAG('c', 'v', '5', '0'));
+ _insert_feature("character_variant_51", HB_TAG('c', 'v', '5', '1'));
+ _insert_feature("character_variant_52", HB_TAG('c', 'v', '5', '2'));
+ _insert_feature("character_variant_53", HB_TAG('c', 'v', '5', '3'));
+ _insert_feature("character_variant_54", HB_TAG('c', 'v', '5', '4'));
+ _insert_feature("character_variant_55", HB_TAG('c', 'v', '5', '5'));
+ _insert_feature("character_variant_56", HB_TAG('c', 'v', '5', '6'));
+ _insert_feature("character_variant_57", HB_TAG('c', 'v', '5', '7'));
+ _insert_feature("character_variant_58", HB_TAG('c', 'v', '5', '8'));
+ _insert_feature("character_variant_59", HB_TAG('c', 'v', '5', '9'));
+ _insert_feature("character_variant_60", HB_TAG('c', 'v', '6', '0'));
+ _insert_feature("character_variant_61", HB_TAG('c', 'v', '6', '1'));
+ _insert_feature("character_variant_62", HB_TAG('c', 'v', '6', '2'));
+ _insert_feature("character_variant_63", HB_TAG('c', 'v', '6', '3'));
+ _insert_feature("character_variant_64", HB_TAG('c', 'v', '6', '4'));
+ _insert_feature("character_variant_65", HB_TAG('c', 'v', '6', '5'));
+ _insert_feature("character_variant_66", HB_TAG('c', 'v', '6', '6'));
+ _insert_feature("character_variant_67", HB_TAG('c', 'v', '6', '7'));
+ _insert_feature("character_variant_68", HB_TAG('c', 'v', '6', '8'));
+ _insert_feature("character_variant_69", HB_TAG('c', 'v', '6', '9'));
+ _insert_feature("character_variant_70", HB_TAG('c', 'v', '7', '0'));
+ _insert_feature("character_variant_71", HB_TAG('c', 'v', '7', '1'));
+ _insert_feature("character_variant_72", HB_TAG('c', 'v', '7', '2'));
+ _insert_feature("character_variant_73", HB_TAG('c', 'v', '7', '3'));
+ _insert_feature("character_variant_74", HB_TAG('c', 'v', '7', '4'));
+ _insert_feature("character_variant_75", HB_TAG('c', 'v', '7', '5'));
+ _insert_feature("character_variant_76", HB_TAG('c', 'v', '7', '6'));
+ _insert_feature("character_variant_77", HB_TAG('c', 'v', '7', '7'));
+ _insert_feature("character_variant_78", HB_TAG('c', 'v', '7', '8'));
+ _insert_feature("character_variant_79", HB_TAG('c', 'v', '7', '9'));
+ _insert_feature("character_variant_80", HB_TAG('c', 'v', '8', '0'));
+ _insert_feature("character_variant_81", HB_TAG('c', 'v', '8', '1'));
+ _insert_feature("character_variant_82", HB_TAG('c', 'v', '8', '2'));
+ _insert_feature("character_variant_83", HB_TAG('c', 'v', '8', '3'));
+ _insert_feature("character_variant_84", HB_TAG('c', 'v', '8', '4'));
+ _insert_feature("character_variant_85", HB_TAG('c', 'v', '8', '5'));
+ _insert_feature("character_variant_86", HB_TAG('c', 'v', '8', '6'));
+ _insert_feature("character_variant_87", HB_TAG('c', 'v', '8', '7'));
+ _insert_feature("character_variant_88", HB_TAG('c', 'v', '8', '8'));
+ _insert_feature("character_variant_89", HB_TAG('c', 'v', '8', '9'));
+ _insert_feature("character_variant_90", HB_TAG('c', 'v', '9', '0'));
+ _insert_feature("character_variant_91", HB_TAG('c', 'v', '9', '1'));
+ _insert_feature("character_variant_92", HB_TAG('c', 'v', '9', '2'));
+ _insert_feature("character_variant_93", HB_TAG('c', 'v', '9', '3'));
+ _insert_feature("character_variant_94", HB_TAG('c', 'v', '9', '4'));
+ _insert_feature("character_variant_95", HB_TAG('c', 'v', '9', '5'));
+ _insert_feature("character_variant_96", HB_TAG('c', 'v', '9', '6'));
+ _insert_feature("character_variant_97", HB_TAG('c', 'v', '9', '7'));
+ _insert_feature("character_variant_98", HB_TAG('c', 'v', '9', '8'));
+ _insert_feature("character_variant_99", HB_TAG('c', 'v', '9', '9'));
+ _insert_feature("petite_capitals_from_capitals", HB_TAG('c', '2', 'p', 'c'));
+ _insert_feature("small_capitals_from_capitals", HB_TAG('c', '2', 's', 'c'));
+ _insert_feature("distances", HB_TAG('d', 'i', 's', 't'));
+ _insert_feature("discretionary_ligatures", HB_TAG('d', 'l', 'i', 'g'));
+ _insert_feature("denominators", HB_TAG('d', 'n', 'o', 'm'));
+ _insert_feature("dotless_forms", HB_TAG('d', 't', 'l', 's'));
+ _insert_feature("expert_forms", HB_TAG('e', 'x', 'p', 't'));
+ _insert_feature("final_glyph_on_line_alternates", HB_TAG('f', 'a', 'l', 't'));
+ _insert_feature("terminal_forms_2", HB_TAG('f', 'i', 'n', '2'));
+ _insert_feature("terminal_forms_3", HB_TAG('f', 'i', 'n', '3'));
+ _insert_feature("terminal_forms", HB_TAG('f', 'i', 'n', 'a'));
+ _insert_feature("flattened_accent_forms", HB_TAG('f', 'l', 'a', 'c'));
+ _insert_feature("fractions", HB_TAG('f', 'r', 'a', 'c'));
+ _insert_feature("full_widths", HB_TAG('f', 'w', 'i', 'd'));
+ _insert_feature("half_forms", HB_TAG('h', 'a', 'l', 'f'));
+ _insert_feature("halant_forms", HB_TAG('h', 'a', 'l', 'n'));
+ _insert_feature("alternate_half_widths", HB_TAG('h', 'a', 'l', 't'));
+ _insert_feature("historical_forms", HB_TAG('h', 'i', 's', 't'));
+ _insert_feature("horizontal_kana_alternates", HB_TAG('h', 'k', 'n', 'a'));
+ _insert_feature("historical_ligatures", HB_TAG('h', 'l', 'i', 'g'));
+ _insert_feature("hangul", HB_TAG('h', 'n', 'g', 'l'));
+ _insert_feature("hojo_kanji_forms", HB_TAG('h', 'o', 'j', 'o'));
+ _insert_feature("half_widths", HB_TAG('h', 'w', 'i', 'd'));
+ _insert_feature("initial_forms", HB_TAG('i', 'n', 'i', 't'));
+ _insert_feature("isolated_forms", HB_TAG('i', 's', 'o', 'l'));
+ _insert_feature("italics", HB_TAG('i', 't', 'a', 'l'));
+ _insert_feature("justification_alternates", HB_TAG('j', 'a', 'l', 't'));
+ _insert_feature("jis78_forms", HB_TAG('j', 'p', '7', '8'));
+ _insert_feature("jis83_forms", HB_TAG('j', 'p', '8', '3'));
+ _insert_feature("jis90_forms", HB_TAG('j', 'p', '9', '0'));
+ _insert_feature("jis2004_forms", HB_TAG('j', 'p', '0', '4'));
+ _insert_feature("kerning", HB_TAG('k', 'e', 'r', 'n'));
+ _insert_feature("left_bounds", HB_TAG('l', 'f', 'b', 'd'));
+ _insert_feature("standard_ligatures", HB_TAG('l', 'i', 'g', 'a'));
+ _insert_feature("leading_jamo_forms", HB_TAG('l', 'j', 'm', 'o'));
+ _insert_feature("lining_figures", HB_TAG('l', 'n', 'u', 'm'));
+ _insert_feature("localized_forms", HB_TAG('l', 'o', 'c', 'l'));
+ _insert_feature("left_to_right_alternates", HB_TAG('l', 't', 'r', 'a'));
+ _insert_feature("left_to_right_mirrored_forms", HB_TAG('l', 't', 'r', 'm'));
+ _insert_feature("mark_positioning", HB_TAG('m', 'a', 'r', 'k'));
+ _insert_feature("medial_forms_2", HB_TAG('m', 'e', 'd', '2'));
+ _insert_feature("medial_forms", HB_TAG('m', 'e', 'd', 'i'));
+ _insert_feature("mathematical_greek", HB_TAG('m', 'g', 'r', 'k'));
+ _insert_feature("mark_to_mark_positioning", HB_TAG('m', 'k', 'm', 'k'));
+ _insert_feature("mark_positioning_via_substitution", HB_TAG('m', 's', 'e', 't'));
+ _insert_feature("alternate_annotation_forms", HB_TAG('n', 'a', 'l', 't'));
+ _insert_feature("nlc_kanji_forms", HB_TAG('n', 'l', 'c', 'k'));
+ _insert_feature("nukta_forms", HB_TAG('n', 'u', 'k', 't'));
+ _insert_feature("numerators", HB_TAG('n', 'u', 'm', 'r'));
+ _insert_feature("oldstyle_figures", HB_TAG('o', 'n', 'u', 'm'));
+ _insert_feature("optical_bounds", HB_TAG('o', 'p', 'b', 'd'));
+ _insert_feature("ordinals", HB_TAG('o', 'r', 'd', 'n'));
+ _insert_feature("ornaments", HB_TAG('o', 'r', 'n', 'm'));
+ _insert_feature("proportional_alternate_widths", HB_TAG('p', 'a', 'l', 't'));
+ _insert_feature("petite_capitals", HB_TAG('p', 'c', 'a', 'p'));
+ _insert_feature("proportional_kana", HB_TAG('p', 'k', 'n', 'a'));
+ _insert_feature("proportional_figures", HB_TAG('p', 'n', 'u', 'm'));
+ _insert_feature("pre_base_forms", HB_TAG('p', 'r', 'e', 'f'));
+ _insert_feature("pre_base_substitutions", HB_TAG('p', 'r', 'e', 's'));
+ _insert_feature("post_base_forms", HB_TAG('p', 's', 't', 'f'));
+ _insert_feature("post_base_substitutions", HB_TAG('p', 's', 't', 's'));
+ _insert_feature("proportional_widths", HB_TAG('p', 'w', 'i', 'd'));
+ _insert_feature("quarter_widths", HB_TAG('q', 'w', 'i', 'd'));
+ _insert_feature("randomize", HB_TAG('r', 'a', 'n', 'd'));
+ _insert_feature("required_contextual_alternates", HB_TAG('r', 'c', 'l', 't'));
+ _insert_feature("rakar_forms", HB_TAG('r', 'k', 'r', 'f'));
+ _insert_feature("required_ligatures", HB_TAG('r', 'l', 'i', 'g'));
+ _insert_feature("reph_forms", HB_TAG('r', 'p', 'h', 'f'));
+ _insert_feature("right_bounds", HB_TAG('r', 't', 'b', 'd'));
+ _insert_feature("right_to_left_alternates", HB_TAG('r', 't', 'l', 'a'));
+ _insert_feature("right_to_left_mirrored_forms", HB_TAG('r', 't', 'l', 'm'));
+ _insert_feature("ruby_notation_forms", HB_TAG('r', 'u', 'b', 'y'));
+ _insert_feature("required_variation_alternates", HB_TAG('r', 'v', 'r', 'n'));
+ _insert_feature("stylistic_alternates", HB_TAG('s', 'a', 'l', 't'));
+ _insert_feature("scientific_inferiors", HB_TAG('s', 'i', 'n', 'f'));
+ _insert_feature("optical_size", HB_TAG('s', 'i', 'z', 'e'));
+ _insert_feature("small_capitals", HB_TAG('s', 'm', 'c', 'p'));
+ _insert_feature("simplified_forms", HB_TAG('s', 'm', 'p', 'l'));
+ _insert_feature("stylistic_set_01", HB_TAG('s', 's', '0', '1'));
+ _insert_feature("stylistic_set_02", HB_TAG('s', 's', '0', '2'));
+ _insert_feature("stylistic_set_03", HB_TAG('s', 's', '0', '3'));
+ _insert_feature("stylistic_set_04", HB_TAG('s', 's', '0', '4'));
+ _insert_feature("stylistic_set_05", HB_TAG('s', 's', '0', '5'));
+ _insert_feature("stylistic_set_06", HB_TAG('s', 's', '0', '6'));
+ _insert_feature("stylistic_set_07", HB_TAG('s', 's', '0', '7'));
+ _insert_feature("stylistic_set_08", HB_TAG('s', 's', '0', '8'));
+ _insert_feature("stylistic_set_09", HB_TAG('s', 's', '0', '9'));
+ _insert_feature("stylistic_set_10", HB_TAG('s', 's', '1', '0'));
+ _insert_feature("stylistic_set_11", HB_TAG('s', 's', '1', '1'));
+ _insert_feature("stylistic_set_12", HB_TAG('s', 's', '1', '2'));
+ _insert_feature("stylistic_set_13", HB_TAG('s', 's', '1', '3'));
+ _insert_feature("stylistic_set_14", HB_TAG('s', 's', '1', '4'));
+ _insert_feature("stylistic_set_15", HB_TAG('s', 's', '1', '5'));
+ _insert_feature("stylistic_set_16", HB_TAG('s', 's', '1', '6'));
+ _insert_feature("stylistic_set_17", HB_TAG('s', 's', '1', '7'));
+ _insert_feature("stylistic_set_18", HB_TAG('s', 's', '1', '8'));
+ _insert_feature("stylistic_set_19", HB_TAG('s', 's', '1', '9'));
+ _insert_feature("stylistic_set_20", HB_TAG('s', 's', '2', '0'));
+ _insert_feature("math_script_style_alternates", HB_TAG('s', 's', 't', 'y'));
+ _insert_feature("stretching_glyph_decomposition", HB_TAG('s', 't', 'c', 'h'));
+ _insert_feature("subscript", HB_TAG('s', 'u', 'b', 's'));
+ _insert_feature("superscript", HB_TAG('s', 'u', 'p', 's'));
+ _insert_feature("swash", HB_TAG('s', 'w', 's', 'h'));
+ _insert_feature("titling", HB_TAG('t', 'i', 't', 'l'));
+ _insert_feature("trailing_jamo_forms", HB_TAG('t', 'j', 'm', 'o'));
+ _insert_feature("traditional_name_forms", HB_TAG('t', 'n', 'a', 'm'));
+ _insert_feature("tabular_figures", HB_TAG('t', 'n', 'u', 'm'));
+ _insert_feature("traditional_forms", HB_TAG('t', 'r', 'a', 'd'));
+ _insert_feature("third_widths", HB_TAG('t', 'w', 'i', 'd'));
+ _insert_feature("unicase", HB_TAG('u', 'n', 'i', 'c'));
+ _insert_feature("alternate_vertical_metrics", HB_TAG('v', 'a', 'l', 't'));
+ _insert_feature("vattu_variants", HB_TAG('v', 'a', 't', 'u'));
+ _insert_feature("vertical_writing", HB_TAG('v', 'e', 'r', 't'));
+ _insert_feature("alternate_vertical_half_metrics", HB_TAG('v', 'h', 'a', 'l'));
+ _insert_feature("vowel_jamo_forms", HB_TAG('v', 'j', 'm', 'o'));
+ _insert_feature("vertical_kana_alternates", HB_TAG('v', 'k', 'n', 'a'));
+ _insert_feature("vertical_kerning", HB_TAG('v', 'k', 'r', 'n'));
+ _insert_feature("proportional_alternate_vertical_metrics", HB_TAG('v', 'p', 'a', 'l'));
+ _insert_feature("vertical_alternates_and_rotation", HB_TAG('v', 'r', 't', '2'));
+ _insert_feature("vertical_alternates_for_rotation", HB_TAG('v', 'r', 't', 'r'));
+ _insert_feature("slashed_zero", HB_TAG('z', 'e', 'r', 'o'));
+
// Registered OpenType variation tag.
- feature_sets.insert("italic", HB_TAG('i', 't', 'a', 'l'));
- feature_sets.insert("optical_size", HB_TAG('o', 'p', 's', 'z'));
- feature_sets.insert("slant", HB_TAG('s', 'l', 'n', 't'));
- feature_sets.insert("width", HB_TAG('w', 'd', 't', 'h'));
- feature_sets.insert("weight", HB_TAG('w', 'g', 'h', 't'));
+ _insert_feature("italic", HB_TAG('i', 't', 'a', 'l'));
+ _insert_feature("optical_size", HB_TAG('o', 'p', 's', 'z'));
+ _insert_feature("slant", HB_TAG('s', 'l', 'n', 't'));
+ _insert_feature("width", HB_TAG('w', 'd', 't', 'h'));
+ _insert_feature("weight", HB_TAG('w', 'g', 'h', 't'));
}
-int32_t TextServerAdvanced::name_to_tag(const String &p_name) const {
+int64_t TextServerAdvanced::name_to_tag(const String &p_name) const {
if (feature_sets.has(p_name)) {
return feature_sets[p_name];
}
@@ -686,11 +740,9 @@ int32_t TextServerAdvanced::name_to_tag(const String &p_name) const {
return hb_tag_from_string(p_name.replace("custom_", "").ascii().get_data(), -1);
}
-String TextServerAdvanced::tag_to_name(int32_t p_tag) const {
- for (const KeyValue<StringName, int32_t> &E : feature_sets) {
- if (E.value == p_tag) {
- return E.key;
- }
+String TextServerAdvanced::tag_to_name(int64_t p_tag) const {
+ if (feature_sets_inv.has(p_tag)) {
+ return feature_sets_inv[p_tag];
}
// No readable name, use tag string.
@@ -714,12 +766,6 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_
for (int i = 0; i < p_data->textures.size(); i++) {
const FontTexture &ct = p_data->textures[i];
- if (RenderingServer::get_singleton() != nullptr) {
- if (ct.texture->get_format() != p_image_format) {
- continue;
- }
- }
-
if (mw > ct.texture_w || mh > ct.texture_h) { // Too big for this texture.
continue;
}
@@ -728,7 +774,7 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_
continue;
}
- ret.y = 0x7FFFFFFF;
+ ret.y = 0x7fffffff;
ret.x = 0;
for (int j = 0; j < ct.texture_w - mw; j++) {
@@ -747,7 +793,7 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_
}
}
- if (ret.y == 0x7FFFFFFF || ret.y + mh > ct.texture_h) {
+ if (ret.y == 0x7fffffff || ret.y + mh > ct.texture_h) {
continue; // Fail, could not fit it here.
}
@@ -761,19 +807,31 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_
ret.y = 0;
int texsize = MAX(p_data->size.x * p_data->oversampling * 8, 256);
- if (mw > texsize) {
- texsize = mw; // Special case, adapt to it?
- }
- if (mh > texsize) {
- texsize = mh; // Special case, adapt to it?
- }
+#ifdef GDEXTENSION
+ texsize = Math::next_power_of_2(texsize);
+#else
texsize = next_power_of_2(texsize);
+#endif
if (p_msdf) {
texsize = MIN(texsize, 2048);
} else {
texsize = MIN(texsize, 1024);
}
+ if (mw > texsize) { // Special case, adapt to it?
+#ifdef GDEXTENSION
+ texsize = Math::next_power_of_2(mw);
+#else
+ texsize = next_power_of_2(mw);
+#endif
+ }
+ if (mh > texsize) { // Special case, adapt to it?
+#ifdef GDEXTENSION
+ texsize = Math::next_power_of_2(mh);
+#else
+ texsize = next_power_of_2(mh);
+#endif
+ }
FontTexture tex;
tex.texture_w = texsize;
@@ -804,8 +862,9 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_
}
}
tex.offsets.resize(texsize);
+ int32_t *offw = tex.offsets.ptrw();
for (int i = 0; i < texsize; i++) { // Zero offsets.
- tex.offsets.write[i] = 0;
+ offw[i] = 0;
}
p_data->textures.push_back(tex);
@@ -819,8 +878,8 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_
struct MSContext {
msdfgen::Point2 position;
- msdfgen::Shape *shape;
- msdfgen::Contour *contour;
+ msdfgen::Shape *shape = nullptr;
+ msdfgen::Contour *contour = nullptr;
};
class DistancePixelConversion {
@@ -849,7 +908,7 @@ static msdfgen::Point2 ft_point2(const FT_Vector &vector) {
}
static int ft_move_to(const FT_Vector *to, void *user) {
- MSContext *context = reinterpret_cast<MSContext *>(user);
+ MSContext *context = static_cast<MSContext *>(user);
if (!(context->contour && context->contour->edges.empty())) {
context->contour = &context->shape->addContour();
}
@@ -858,7 +917,7 @@ static int ft_move_to(const FT_Vector *to, void *user) {
}
static int ft_line_to(const FT_Vector *to, void *user) {
- MSContext *context = reinterpret_cast<MSContext *>(user);
+ MSContext *context = static_cast<MSContext *>(user);
msdfgen::Point2 endpoint = ft_point2(*to);
if (endpoint != context->position) {
context->contour->addEdge(new msdfgen::LinearSegment(context->position, endpoint));
@@ -868,21 +927,21 @@ static int ft_line_to(const FT_Vector *to, void *user) {
}
static int ft_conic_to(const FT_Vector *control, const FT_Vector *to, void *user) {
- MSContext *context = reinterpret_cast<MSContext *>(user);
+ MSContext *context = static_cast<MSContext *>(user);
context->contour->addEdge(new msdfgen::QuadraticSegment(context->position, ft_point2(*control), ft_point2(*to)));
context->position = ft_point2(*to);
return 0;
}
static int ft_cubic_to(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) {
- MSContext *context = reinterpret_cast<MSContext *>(user);
+ MSContext *context = static_cast<MSContext *>(user);
context->contour->addEdge(new msdfgen::CubicSegment(context->position, ft_point2(*control1), ft_point2(*control2), ft_point2(*to)));
context->position = ft_point2(*to);
return 0;
}
void TextServerAdvanced::_generateMTSDF_threaded(uint32_t y, void *p_td) const {
- MSDFThreadData *td = (MSDFThreadData *)p_td;
+ MSDFThreadData *td = static_cast<MSDFThreadData *>(p_td);
msdfgen::ShapeDistanceFinder<msdfgen::OverlappingContourCombiner<msdfgen::MultiAndTrueDistanceSelector>> distanceFinder(*td->shape);
int row = td->shape->inverseYAxis ? td->output->height() - y - 1 : y;
@@ -935,11 +994,11 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(
int w = (bounds.r - bounds.l);
int h = (bounds.t - bounds.b);
- int mw = w + p_rect_margin * 2;
- int mh = h + p_rect_margin * 2;
+ int mw = w + p_rect_margin * 4;
+ int mh = h + p_rect_margin * 4;
- ERR_FAIL_COND_V(mw > 1024, FontGlyph());
- ERR_FAIL_COND_V(mh > 1024, FontGlyph());
+ ERR_FAIL_COND_V(mw > 4096, FontGlyph());
+ ERR_FAIL_COND_V(mh > 4096, FontGlyph());
FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, 4, Image::FORMAT_RGBA8, mw, mh, true);
ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());
@@ -970,7 +1029,7 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
- int ofs = ((i + tex_pos.y + p_rect_margin) * tex.texture_w + j + tex_pos.x + p_rect_margin) * 4;
+ int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * 4;
ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), FontGlyph());
wr[ofs + 0] = (uint8_t)(CLAMP(image(j, i)[0] * 256.f, 0.f, 255.f));
wr[ofs + 1] = (uint8_t)(CLAMP(image(j, i)[1] * 256.f, 0.f, 255.f));
@@ -980,28 +1039,19 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(
}
}
- // Blit to image and texture.
- {
- if (RenderingServer::get_singleton() != nullptr) {
- Ref<Image> img = memnew(Image(tex.texture_w, tex.texture_h, 0, Image::FORMAT_RGBA8, tex.imgdata));
- if (tex.texture.is_null()) {
- tex.texture.instantiate();
- tex.texture->create_from_image(img);
- } else {
- tex.texture->update(img);
- }
- }
- }
+ tex.dirty = true;
// Update height array.
+ int32_t *offw = tex.offsets.ptrw();
for (int k = tex_pos.x; k < tex_pos.x + mw; k++) {
- tex.offsets.write[k] = tex_pos.y + mh;
+ offw[k] = tex_pos.y + mh;
}
chr.texture_idx = tex_pos.index;
- chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w, h);
- chr.rect.position = Vector2(bounds.l, -bounds.t);
+ chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w + p_rect_margin * 2, h + p_rect_margin * 2);
+ chr.rect.position = Vector2(bounds.l - p_rect_margin, -bounds.t - p_rect_margin);
+
chr.rect.size = chr.uv_rect.size;
}
return chr;
@@ -1013,11 +1063,11 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma
int w = bitmap.width;
int h = bitmap.rows;
- int mw = w + p_rect_margin * 2;
- int mh = h + p_rect_margin * 2;
+ int mw = w + p_rect_margin * 4;
+ int mh = h + p_rect_margin * 4;
- ERR_FAIL_COND_V(mw > 1024, FontGlyph());
- ERR_FAIL_COND_V(mh > 1024, FontGlyph());
+ ERR_FAIL_COND_V(mw > 4096, FontGlyph());
+ ERR_FAIL_COND_V(mh > 4096, FontGlyph());
int color_size = bitmap.pixel_mode == FT_PIXEL_MODE_BGRA ? 4 : 2;
Image::Format require_format = color_size == 4 ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8;
@@ -1034,7 +1084,7 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
- int ofs = ((i + tex_pos.y + p_rect_margin) * tex.texture_w + j + tex_pos.x + p_rect_margin) * color_size;
+ int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * color_size;
ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), FontGlyph());
switch (bitmap.pixel_mode) {
case FT_PIXEL_MODE_MONO: {
@@ -1055,30 +1105,19 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma
wr[ofs + 3] = bitmap.buffer[ofs_color + 3];
} break;
default:
- ERR_FAIL_V_MSG(FontGlyph(), "Font uses unsupported pixel format: " + itos(bitmap.pixel_mode) + ".");
+ ERR_FAIL_V_MSG(FontGlyph(), "Font uses unsupported pixel format: " + String::num_int64(bitmap.pixel_mode) + ".");
break;
}
}
}
}
- // Blit to image and texture.
- {
- if (RenderingServer::get_singleton() != nullptr) {
- Ref<Image> img = memnew(Image(tex.texture_w, tex.texture_h, 0, require_format, tex.imgdata));
-
- if (tex.texture.is_null()) {
- tex.texture.instantiate();
- tex.texture->create_from_image(img);
- } else {
- tex.texture->update(img);
- }
- }
- }
+ tex.dirty = true;
// Update height array.
+ int32_t *offw = tex.offsets.ptrw();
for (int k = tex_pos.x; k < tex_pos.x + mw; k++) {
- tex.offsets.write[k] = tex_pos.y + mh;
+ offw[k] = tex_pos.y + mh;
}
FontGlyph chr;
@@ -1086,8 +1125,8 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma
chr.texture_idx = tex_pos.index;
chr.found = true;
- chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w, h);
- chr.rect.position = Vector2(xofs, -yofs) * p_data->scale / p_data->oversampling;
+ chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w + p_rect_margin * 2, h + p_rect_margin * 2);
+ chr.rect.position = Vector2(xofs - p_rect_margin, -yofs - p_rect_margin) * p_data->scale / p_data->oversampling;
chr.rect.size = chr.uv_rect.size * p_data->scale / p_data->oversampling;
return chr;
}
@@ -1100,7 +1139,7 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma
_FORCE_INLINE_ bool TextServerAdvanced::_ensure_glyph(FontDataAdvanced *p_font_data, const Vector2i &p_size, int32_t p_glyph) const {
ERR_FAIL_COND_V(!_ensure_cache_for_size(p_font_data, p_size), false);
- int32_t glyph_index = p_glyph & 0xFFFFFF; // Remove subpixel shifts.
+ int32_t glyph_index = p_glyph & 0xffffff; // Remove subpixel shifts.
FontDataForSizeAdvanced *fd = p_font_data->cache[p_size];
if (fd->glyph_map.has(p_glyph)) {
@@ -1187,7 +1226,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_glyph(FontDataAdvanced *p_font_d
}
} else {
FT_Stroker stroker;
- if (FT_Stroker_New(library, &stroker) != 0) {
+ if (FT_Stroker_New(ft_library, &stroker) != 0) {
fd->glyph_map[p_glyph] = FontGlyph();
ERR_FAIL_V_MSG(false, "FreeType: Failed to load glyph stroker.");
}
@@ -1233,8 +1272,8 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced
// Init dynamic font.
#ifdef MODULE_FREETYPE_ENABLED
int error = 0;
- if (!library) {
- error = FT_Init_FreeType(&library);
+ if (!ft_library) {
+ error = FT_Init_FreeType(&ft_library);
ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
}
@@ -1249,7 +1288,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced
fargs.memory_size = p_font_data->data_size;
fargs.flags = FT_OPEN_MEMORY;
fargs.stream = &fd->stream;
- error = FT_Open_Face(library, &fargs, 0, &fd->face);
+ error = FT_Open_Face(ft_library, &fargs, 0, &fd->face);
if (error) {
FT_Done_Face(fd->face);
fd->face = nullptr;
@@ -1257,9 +1296,9 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced
}
if (p_font_data->msdf) {
- fd->oversampling = 1.0f;
+ fd->oversampling = 1.0;
fd->size.x = p_font_data->msdf_source_size;
- } else if (p_font_data->oversampling <= 0.0f) {
+ } else if (p_font_data->oversampling <= 0.0) {
fd->oversampling = font_get_global_oversampling();
} else {
fd->oversampling = p_font_data->oversampling;
@@ -1268,19 +1307,19 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced
if (FT_HAS_COLOR(fd->face) && fd->face->num_fixed_sizes > 0) {
int best_match = 0;
int diff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[0].width));
- fd->scale = float(fd->size.x * fd->oversampling) / fd->face->available_sizes[0].width;
+ fd->scale = double(fd->size.x * fd->oversampling) / fd->face->available_sizes[0].width;
for (int i = 1; i < fd->face->num_fixed_sizes; i++) {
int ndiff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[i].width));
if (ndiff < diff) {
best_match = i;
diff = ndiff;
- fd->scale = float(fd->size.x * fd->oversampling) / fd->face->available_sizes[i].width;
+ fd->scale = double(fd->size.x * fd->oversampling) / fd->face->available_sizes[i].width;
}
}
FT_Select_Size(fd->face, best_match);
} else {
- FT_Set_Pixel_Sizes(fd->face, 0, float(fd->size.x * fd->oversampling));
- fd->scale = ((float)fd->size.x * fd->oversampling) / (float)fd->face->size->metrics.y_ppem;
+ FT_Set_Pixel_Sizes(fd->face, 0, double(fd->size.x * fd->oversampling));
+ fd->scale = ((double)fd->size.x * fd->oversampling) / (double)fd->face->size->metrics.y_ppem;
}
fd->hb_handle = hb_ft_font_create(fd->face, nullptr);
@@ -1290,6 +1329,8 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced
fd->underline_position = (-FT_MulFix(fd->face->underline_position, fd->face->size->metrics.y_scale) / 64.0) / fd->oversampling * fd->scale;
fd->underline_thickness = (FT_MulFix(fd->face->underline_thickness, fd->face->size->metrics.y_scale) / 64.0) / fd->oversampling * fd->scale;
+ hb_font_set_synthetic_slant(fd->hb_handle, p_font_data->transform.columns[0][1]);
+
if (!p_font_data->face_init) {
// Get style flags and name.
if (fd->face->family_name != nullptr) {
@@ -1573,7 +1614,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced
for (FT_UInt i = 0; i < amaster->num_axis; i++) {
p_font_data->supported_varaitions[(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);
+ FT_Done_MM_Var(ft_library, amaster);
}
p_font_data->face_init = true;
}
@@ -1595,17 +1636,17 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced
// Reset to default.
var.tag = amaster->axis[i].tag;
- var.value = (double)amaster->axis[i].def / 65536.f;
+ var.value = (double)amaster->axis[i].def / 65536.0;
coords.write[i] = amaster->axis[i].def;
if (p_font_data->variation_coordinates.has(var.tag)) {
var.value = p_font_data->variation_coordinates[var.tag];
- coords.write[i] = CLAMP(var.value * 65536.f, amaster->axis[i].minimum, amaster->axis[i].maximum);
+ coords.write[i] = CLAMP(var.value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum);
}
if (p_font_data->variation_coordinates.has(tag_to_name(var.tag))) {
var.value = p_font_data->variation_coordinates[tag_to_name(var.tag)];
- coords.write[i] = CLAMP(var.value * 65536.f, amaster->axis[i].minimum, amaster->axis[i].maximum);
+ coords.write[i] = CLAMP(var.value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum);
}
hb_vars.push_back(var);
@@ -1613,7 +1654,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced
FT_Set_Var_Design_Coordinates(fd->face, coords.size(), coords.ptrw());
hb_font_set_variations(fd->hb_handle, hb_vars.is_empty() ? nullptr : &hb_vars[0], hb_vars.size());
- FT_Done_MM_Var(library, amaster);
+ FT_Done_MM_Var(ft_library, amaster);
}
#else
ERR_FAIL_V_MSG(false, "FreeType: Can't load dynamic font, engine is compiled without FreeType support!");
@@ -1637,7 +1678,7 @@ _FORCE_INLINE_ void TextServerAdvanced::_font_clear_cache(FontDataAdvanced *p_fo
p_font_data->supported_scripts.clear();
}
-hb_font_t *TextServerAdvanced::_font_get_hb_handle(RID p_font_rid, int p_size) const {
+hb_font_t *TextServerAdvanced::_font_get_hb_handle(const RID &p_font_rid, int64_t p_size) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, nullptr);
@@ -1655,7 +1696,7 @@ RID TextServerAdvanced::create_font() {
return font_owner.make_rid(fd);
}
-void TextServerAdvanced::font_set_data(RID p_font_rid, const PackedByteArray &p_data) {
+void TextServerAdvanced::font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1666,18 +1707,18 @@ void TextServerAdvanced::font_set_data(RID p_font_rid, const PackedByteArray &p_
fd->data_size = fd->data.size();
}
-void TextServerAdvanced::font_set_data_ptr(RID p_font_rid, const uint8_t *p_data_ptr, size_t p_data_size) {
+void TextServerAdvanced::font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
_font_clear_cache(fd);
- fd->data.clear();
+ fd->data.resize(0);
fd->data_ptr = p_data_ptr;
fd->data_size = p_data_size;
}
-void TextServerAdvanced::font_set_style(RID p_font_rid, uint32_t /*FontStyle*/ p_style) {
+void TextServerAdvanced::font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1687,7 +1728,7 @@ void TextServerAdvanced::font_set_style(RID p_font_rid, uint32_t /*FontStyle*/ p
fd->style_flags = p_style;
}
-uint32_t /*FontStyle*/ TextServerAdvanced::font_get_style(RID p_font_rid) const {
+int64_t /*FontStyle*/ TextServerAdvanced::font_get_style(const RID &p_font_rid) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0);
@@ -1697,7 +1738,7 @@ uint32_t /*FontStyle*/ TextServerAdvanced::font_get_style(RID p_font_rid) const
return fd->style_flags;
}
-void TextServerAdvanced::font_set_style_name(RID p_font_rid, const String &p_name) {
+void TextServerAdvanced::font_set_style_name(const RID &p_font_rid, const String &p_name) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1707,7 +1748,7 @@ void TextServerAdvanced::font_set_style_name(RID p_font_rid, const String &p_nam
fd->style_name = p_name;
}
-String TextServerAdvanced::font_get_style_name(RID p_font_rid) const {
+String TextServerAdvanced::font_get_style_name(const RID &p_font_rid) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, String());
@@ -1717,7 +1758,7 @@ String TextServerAdvanced::font_get_style_name(RID p_font_rid) const {
return fd->style_name;
}
-void TextServerAdvanced::font_set_name(RID p_font_rid, const String &p_name) {
+void TextServerAdvanced::font_set_name(const RID &p_font_rid, const String &p_name) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1727,7 +1768,7 @@ void TextServerAdvanced::font_set_name(RID p_font_rid, const String &p_name) {
fd->font_name = p_name;
}
-String TextServerAdvanced::font_get_name(RID p_font_rid) const {
+String TextServerAdvanced::font_get_name(const RID &p_font_rid) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, String());
@@ -1737,7 +1778,7 @@ String TextServerAdvanced::font_get_name(RID p_font_rid) const {
return fd->font_name;
}
-void TextServerAdvanced::font_set_antialiased(RID p_font_rid, bool p_antialiased) {
+void TextServerAdvanced::font_set_antialiased(const RID &p_font_rid, bool p_antialiased) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1748,7 +1789,7 @@ void TextServerAdvanced::font_set_antialiased(RID p_font_rid, bool p_antialiased
}
}
-bool TextServerAdvanced::font_is_antialiased(RID p_font_rid) const {
+bool TextServerAdvanced::font_is_antialiased(const RID &p_font_rid) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -1756,7 +1797,30 @@ bool TextServerAdvanced::font_is_antialiased(RID p_font_rid) const {
return fd->antialiased;
}
-void TextServerAdvanced::font_set_multichannel_signed_distance_field(RID p_font_rid, bool p_msdf) {
+void TextServerAdvanced::font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ if (fd->mipmaps != p_generate_mipmaps) {
+ for (KeyValue<Vector2i, FontDataForSizeAdvanced *> &E : fd->cache) {
+ for (int i = 0; i < E.value->textures.size(); i++) {
+ E.value->textures.write[i].dirty = true;
+ }
+ }
+ fd->mipmaps = p_generate_mipmaps;
+ }
+}
+
+bool TextServerAdvanced::font_get_generate_mipmaps(const RID &p_font_rid) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, false);
+
+ MutexLock lock(fd->mutex);
+ return fd->mipmaps;
+}
+
+void TextServerAdvanced::font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1767,7 +1831,7 @@ void TextServerAdvanced::font_set_multichannel_signed_distance_field(RID p_font_
}
}
-bool TextServerAdvanced::font_is_multichannel_signed_distance_field(RID p_font_rid) const {
+bool TextServerAdvanced::font_is_multichannel_signed_distance_field(const RID &p_font_rid) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -1775,7 +1839,7 @@ bool TextServerAdvanced::font_is_multichannel_signed_distance_field(RID p_font_r
return fd->msdf;
}
-void TextServerAdvanced::font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pixel_range) {
+void TextServerAdvanced::font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1786,7 +1850,7 @@ void TextServerAdvanced::font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pi
}
}
-int TextServerAdvanced::font_get_msdf_pixel_range(RID p_font_rid) const {
+int64_t TextServerAdvanced::font_get_msdf_pixel_range(const RID &p_font_rid) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -1794,7 +1858,7 @@ int TextServerAdvanced::font_get_msdf_pixel_range(RID p_font_rid) const {
return fd->msdf_range;
}
-void TextServerAdvanced::font_set_msdf_size(RID p_font_rid, int p_msdf_size) {
+void TextServerAdvanced::font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1805,7 +1869,7 @@ void TextServerAdvanced::font_set_msdf_size(RID p_font_rid, int p_msdf_size) {
}
}
-int TextServerAdvanced::font_get_msdf_size(RID p_font_rid) const {
+int64_t TextServerAdvanced::font_get_msdf_size(const RID &p_font_rid) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -1813,17 +1877,15 @@ int TextServerAdvanced::font_get_msdf_size(RID p_font_rid) const {
return fd->msdf_source_size;
}
-void TextServerAdvanced::font_set_fixed_size(RID p_font_rid, int p_fixed_size) {
+void TextServerAdvanced::font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
- if (fd->fixed_size != p_fixed_size) {
- fd->fixed_size = p_fixed_size;
- }
+ fd->fixed_size = p_fixed_size;
}
-int TextServerAdvanced::font_get_fixed_size(RID p_font_rid) const {
+int64_t TextServerAdvanced::font_get_fixed_size(const RID &p_font_rid) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -1831,7 +1893,7 @@ int TextServerAdvanced::font_get_fixed_size(RID p_font_rid) const {
return fd->fixed_size;
}
-void TextServerAdvanced::font_set_force_autohinter(RID p_font_rid, bool p_force_autohinter) {
+void TextServerAdvanced::font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1842,7 +1904,7 @@ void TextServerAdvanced::font_set_force_autohinter(RID p_font_rid, bool p_force_
}
}
-bool TextServerAdvanced::font_is_force_autohinter(RID p_font_rid) const {
+bool TextServerAdvanced::font_is_force_autohinter(const RID &p_font_rid) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -1850,7 +1912,7 @@ bool TextServerAdvanced::font_is_force_autohinter(RID p_font_rid) const {
return fd->force_autohinter;
}
-void TextServerAdvanced::font_set_hinting(RID p_font_rid, TextServer::Hinting p_hinting) {
+void TextServerAdvanced::font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1861,7 +1923,7 @@ void TextServerAdvanced::font_set_hinting(RID p_font_rid, TextServer::Hinting p_
}
}
-TextServer::Hinting TextServerAdvanced::font_get_hinting(RID p_font_rid) const {
+TextServer::Hinting TextServerAdvanced::font_get_hinting(const RID &p_font_rid) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, HINTING_NONE);
@@ -1869,17 +1931,15 @@ TextServer::Hinting TextServerAdvanced::font_get_hinting(RID p_font_rid) const {
return fd->hinting;
}
-void TextServerAdvanced::font_set_subpixel_positioning(RID p_font_rid, TextServer::SubpixelPositioning p_subpixel) {
+void TextServerAdvanced::font_set_subpixel_positioning(const RID &p_font_rid, TextServer::SubpixelPositioning p_subpixel) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
- if (fd->subpixel_positioning != p_subpixel) {
- fd->subpixel_positioning = p_subpixel;
- }
+ fd->subpixel_positioning = p_subpixel;
}
-TextServer::SubpixelPositioning TextServerAdvanced::font_get_subpixel_positioning(RID p_font_rid) const {
+TextServer::SubpixelPositioning TextServerAdvanced::font_get_subpixel_positioning(const RID &p_font_rid) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, SUBPIXEL_POSITIONING_DISABLED);
@@ -1887,7 +1947,7 @@ TextServer::SubpixelPositioning TextServerAdvanced::font_get_subpixel_positionin
return fd->subpixel_positioning;
}
-void TextServerAdvanced::font_set_embolden(RID p_font_rid, float p_strength) {
+void TextServerAdvanced::font_set_embolden(const RID &p_font_rid, double p_strength) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1898,15 +1958,15 @@ void TextServerAdvanced::font_set_embolden(RID p_font_rid, float p_strength) {
}
}
-float TextServerAdvanced::font_get_embolden(RID p_font_rid) const {
+double TextServerAdvanced::font_get_embolden(const RID &p_font_rid) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, 0.f);
+ ERR_FAIL_COND_V(!fd, 0.0);
MutexLock lock(fd->mutex);
return fd->embolden;
}
-void TextServerAdvanced::font_set_transform(RID p_font_rid, Transform2D p_transform) {
+void TextServerAdvanced::font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1917,7 +1977,7 @@ void TextServerAdvanced::font_set_transform(RID p_font_rid, Transform2D p_transf
}
}
-Transform2D TextServerAdvanced::font_get_transform(RID p_font_rid) const {
+Transform2D TextServerAdvanced::font_get_transform(const RID &p_font_rid) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Transform2D());
@@ -1925,7 +1985,7 @@ Transform2D TextServerAdvanced::font_get_transform(RID p_font_rid) const {
return fd->transform;
}
-void TextServerAdvanced::font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) {
+void TextServerAdvanced::font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1936,7 +1996,7 @@ void TextServerAdvanced::font_set_variation_coordinates(RID p_font_rid, const Di
}
}
-Dictionary TextServerAdvanced::font_get_variation_coordinates(RID p_font_rid) const {
+Dictionary TextServerAdvanced::font_get_variation_coordinates(const RID &p_font_rid) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Dictionary());
@@ -1944,7 +2004,7 @@ Dictionary TextServerAdvanced::font_get_variation_coordinates(RID p_font_rid) co
return fd->variation_coordinates;
}
-void TextServerAdvanced::font_set_oversampling(RID p_font_rid, float p_oversampling) {
+void TextServerAdvanced::font_set_oversampling(const RID &p_font_rid, double p_oversampling) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1955,27 +2015,27 @@ void TextServerAdvanced::font_set_oversampling(RID p_font_rid, float p_oversampl
}
}
-float TextServerAdvanced::font_get_oversampling(RID p_font_rid) const {
+double TextServerAdvanced::font_get_oversampling(const RID &p_font_rid) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, 0.f);
+ ERR_FAIL_COND_V(!fd, 0.0);
MutexLock lock(fd->mutex);
return fd->oversampling;
}
-Array TextServerAdvanced::font_get_size_cache_list(RID p_font_rid) const {
+Array TextServerAdvanced::font_get_size_cache_list(const RID &p_font_rid) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Array());
MutexLock lock(fd->mutex);
Array ret;
- for (const Map<Vector2i, FontDataForSizeAdvanced *>::Element *E = fd->cache.front(); E; E = E->next()) {
- ret.push_back(E->key());
+ for (const KeyValue<Vector2i, FontDataForSizeAdvanced *> &E : fd->cache) {
+ ret.push_back(E.key);
}
return ret;
}
-void TextServerAdvanced::font_clear_size_cache(RID p_font_rid) {
+void TextServerAdvanced::font_clear_size_cache(const RID &p_font_rid) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1986,7 +2046,7 @@ void TextServerAdvanced::font_clear_size_cache(RID p_font_rid) {
fd->cache.clear();
}
-void TextServerAdvanced::font_remove_size_cache(RID p_font_rid, const Vector2i &p_size) {
+void TextServerAdvanced::font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1997,7 +2057,7 @@ void TextServerAdvanced::font_remove_size_cache(RID p_font_rid, const Vector2i &
}
}
-void TextServerAdvanced::font_set_ascent(RID p_font_rid, int p_size, float p_ascent) {
+void TextServerAdvanced::font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2008,23 +2068,23 @@ void TextServerAdvanced::font_set_ascent(RID p_font_rid, int p_size, float p_asc
fd->cache[size]->ascent = p_ascent;
}
-float TextServerAdvanced::font_get_ascent(RID p_font_rid, int p_size) const {
+double TextServerAdvanced::font_get_ascent(const RID &p_font_rid, int64_t p_size) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, 0.f);
+ ERR_FAIL_COND_V(!fd, 0.0);
MutexLock lock(fd->mutex);
Vector2i size = _get_size(fd, p_size);
- ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0);
if (fd->msdf) {
- return fd->cache[size]->ascent * (float)p_size / (float)fd->msdf_source_size;
+ return fd->cache[size]->ascent * (double)p_size / (double)fd->msdf_source_size;
} else {
return fd->cache[size]->ascent;
}
}
-void TextServerAdvanced::font_set_descent(RID p_font_rid, int p_size, float p_descent) {
+void TextServerAdvanced::font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2034,23 +2094,23 @@ void TextServerAdvanced::font_set_descent(RID p_font_rid, int p_size, float p_de
fd->cache[size]->descent = p_descent;
}
-float TextServerAdvanced::font_get_descent(RID p_font_rid, int p_size) const {
+double TextServerAdvanced::font_get_descent(const RID &p_font_rid, int64_t p_size) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, 0.f);
+ ERR_FAIL_COND_V(!fd, 0.0);
MutexLock lock(fd->mutex);
Vector2i size = _get_size(fd, p_size);
- ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0);
if (fd->msdf) {
- return fd->cache[size]->descent * (float)p_size / (float)fd->msdf_source_size;
+ return fd->cache[size]->descent * (double)p_size / (double)fd->msdf_source_size;
} else {
return fd->cache[size]->descent;
}
}
-void TextServerAdvanced::font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) {
+void TextServerAdvanced::font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2061,23 +2121,23 @@ void TextServerAdvanced::font_set_underline_position(RID p_font_rid, int p_size,
fd->cache[size]->underline_position = p_underline_position;
}
-float TextServerAdvanced::font_get_underline_position(RID p_font_rid, int p_size) const {
+double TextServerAdvanced::font_get_underline_position(const RID &p_font_rid, int64_t p_size) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, 0.f);
+ ERR_FAIL_COND_V(!fd, 0.0);
MutexLock lock(fd->mutex);
Vector2i size = _get_size(fd, p_size);
- ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0);
if (fd->msdf) {
- return fd->cache[size]->underline_position * (float)p_size / (float)fd->msdf_source_size;
+ return fd->cache[size]->underline_position * (double)p_size / (double)fd->msdf_source_size;
} else {
return fd->cache[size]->underline_position;
}
}
-void TextServerAdvanced::font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) {
+void TextServerAdvanced::font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2088,23 +2148,23 @@ void TextServerAdvanced::font_set_underline_thickness(RID p_font_rid, int p_size
fd->cache[size]->underline_thickness = p_underline_thickness;
}
-float TextServerAdvanced::font_get_underline_thickness(RID p_font_rid, int p_size) const {
+double TextServerAdvanced::font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, 0.f);
+ ERR_FAIL_COND_V(!fd, 0.0);
MutexLock lock(fd->mutex);
Vector2i size = _get_size(fd, p_size);
- ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0);
if (fd->msdf) {
- return fd->cache[size]->underline_thickness * (float)p_size / (float)fd->msdf_source_size;
+ return fd->cache[size]->underline_thickness * (double)p_size / (double)fd->msdf_source_size;
} else {
return fd->cache[size]->underline_thickness;
}
}
-void TextServerAdvanced::font_set_scale(RID p_font_rid, int p_size, float p_scale) {
+void TextServerAdvanced::font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2115,23 +2175,23 @@ void TextServerAdvanced::font_set_scale(RID p_font_rid, int p_size, float p_scal
fd->cache[size]->scale = p_scale;
}
-float TextServerAdvanced::font_get_scale(RID p_font_rid, int p_size) const {
+double TextServerAdvanced::font_get_scale(const RID &p_font_rid, int64_t p_size) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, 0.f);
+ ERR_FAIL_COND_V(!fd, 0.0);
MutexLock lock(fd->mutex);
Vector2i size = _get_size(fd, p_size);
- ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0);
if (fd->msdf) {
- return fd->cache[size]->scale * (float)p_size / (float)fd->msdf_source_size;
+ return fd->cache[size]->scale * (double)p_size / (double)fd->msdf_source_size;
} else {
return fd->cache[size]->scale / fd->cache[size]->oversampling;
}
}
-void TextServerAdvanced::font_set_spacing(RID p_font_rid, int p_size, TextServer::SpacingType p_spacing, int p_value) {
+void TextServerAdvanced::font_set_spacing(const RID &p_font_rid, int64_t p_size, TextServer::SpacingType p_spacing, int64_t p_value) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2147,12 +2207,12 @@ void TextServerAdvanced::font_set_spacing(RID p_font_rid, int p_size, TextServer
fd->cache[size]->spacing_space = p_value;
} break;
default: {
- ERR_FAIL_MSG("Invalid spacing type: " + itos(p_spacing));
+ ERR_FAIL_MSG("Invalid spacing type: " + String::num_int64(p_spacing));
} break;
}
}
-int TextServerAdvanced::font_get_spacing(RID p_font_rid, int p_size, TextServer::SpacingType p_spacing) const {
+int64_t TextServerAdvanced::font_get_spacing(const RID &p_font_rid, int64_t p_size, TextServer::SpacingType p_spacing) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0);
@@ -2164,26 +2224,26 @@ int TextServerAdvanced::font_get_spacing(RID p_font_rid, int p_size, TextServer:
switch (p_spacing) {
case TextServer::SPACING_GLYPH: {
if (fd->msdf) {
- return fd->cache[size]->spacing_glyph * (float)p_size / (float)fd->msdf_source_size;
+ return fd->cache[size]->spacing_glyph * (double)p_size / (double)fd->msdf_source_size;
} else {
return fd->cache[size]->spacing_glyph;
}
} break;
case TextServer::SPACING_SPACE: {
if (fd->msdf) {
- return fd->cache[size]->spacing_space * (float)p_size / (float)fd->msdf_source_size;
+ return fd->cache[size]->spacing_space * (double)p_size / (double)fd->msdf_source_size;
} else {
return fd->cache[size]->spacing_space;
}
} break;
default: {
- ERR_FAIL_V_MSG(0, "Invalid spacing type: " + itos(p_spacing));
+ ERR_FAIL_V_MSG(0, "Invalid spacing type: " + String::num_int64(p_spacing));
} break;
}
return 0;
}
-int TextServerAdvanced::font_get_texture_count(RID p_font_rid, const Vector2i &p_size) const {
+int64_t TextServerAdvanced::font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0);
@@ -2195,7 +2255,7 @@ int TextServerAdvanced::font_get_texture_count(RID p_font_rid, const Vector2i &p
return fd->cache[size]->textures.size();
}
-void TextServerAdvanced::font_clear_textures(RID p_font_rid, const Vector2i &p_size) {
+void TextServerAdvanced::font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -2205,7 +2265,7 @@ void TextServerAdvanced::font_clear_textures(RID p_font_rid, const Vector2i &p_s
fd->cache[size]->textures.clear();
}
-void TextServerAdvanced::font_remove_texture(RID p_font_rid, const Vector2i &p_size, int p_texture_index) {
+void TextServerAdvanced::font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2217,7 +2277,7 @@ void TextServerAdvanced::font_remove_texture(RID p_font_rid, const Vector2i &p_s
fd->cache[size]->textures.remove_at(p_texture_index);
}
-void TextServerAdvanced::font_set_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) {
+void TextServerAdvanced::font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
ERR_FAIL_COND(p_image.is_null());
@@ -2237,13 +2297,20 @@ void TextServerAdvanced::font_set_texture_image(RID p_font_rid, const Vector2i &
tex.texture_h = p_image->get_height();
tex.format = p_image->get_format();
- Ref<Image> img = memnew(Image(tex.texture_w, tex.texture_h, 0, tex.format, tex.imgdata));
+ Ref<Image> img;
+ img.instantiate();
+ img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ if (fd->mipmaps) {
+ img->generate_mipmaps();
+ }
+
tex.texture = Ref<ImageTexture>();
tex.texture.instantiate();
tex.texture->create_from_image(img);
+ tex.dirty = false;
}
-Ref<Image> TextServerAdvanced::font_get_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const {
+Ref<Image> TextServerAdvanced::font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Ref<Image>());
@@ -2252,13 +2319,15 @@ Ref<Image> TextServerAdvanced::font_get_texture_image(RID p_font_rid, const Vect
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Ref<Image>());
ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), Ref<Image>());
- const FontTexture &tex = fd->cache[size]->textures.write[p_texture_index];
- Ref<Image> img = memnew(Image(tex.texture_w, tex.texture_h, 0, tex.format, tex.imgdata));
+ const FontTexture &tex = fd->cache[size]->textures[p_texture_index];
+ Ref<Image> img;
+ img.instantiate();
+ img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
return img;
}
-void TextServerAdvanced::font_set_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) {
+void TextServerAdvanced::font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2274,7 +2343,7 @@ void TextServerAdvanced::font_set_texture_offsets(RID p_font_rid, const Vector2i
tex.offsets = p_offset;
}
-PackedInt32Array TextServerAdvanced::font_get_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const {
+PackedInt32Array TextServerAdvanced::font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, PackedInt32Array());
@@ -2283,11 +2352,11 @@ PackedInt32Array TextServerAdvanced::font_get_texture_offsets(RID p_font_rid, co
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), PackedInt32Array());
ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), PackedInt32Array());
- const FontTexture &tex = fd->cache[size]->textures.write[p_texture_index];
+ const FontTexture &tex = fd->cache[size]->textures[p_texture_index];
return tex.offsets;
}
-Array TextServerAdvanced::font_get_glyph_list(RID p_font_rid, const Vector2i &p_size) const {
+Array TextServerAdvanced::font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Array());
@@ -2304,7 +2373,7 @@ Array TextServerAdvanced::font_get_glyph_list(RID p_font_rid, const Vector2i &p_
return ret;
}
-void TextServerAdvanced::font_clear_glyphs(RID p_font_rid, const Vector2i &p_size) {
+void TextServerAdvanced::font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2315,7 +2384,7 @@ void TextServerAdvanced::font_clear_glyphs(RID p_font_rid, const Vector2i &p_siz
fd->cache[size]->glyph_map.clear();
}
-void TextServerAdvanced::font_remove_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) {
+void TextServerAdvanced::font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2326,7 +2395,7 @@ void TextServerAdvanced::font_remove_glyph(RID p_font_rid, const Vector2i &p_siz
fd->cache[size]->glyph_map.erase(p_glyph);
}
-float TextServerAdvanced::_get_extra_advance(RID p_font_rid, int p_font_size) const {
+double TextServerAdvanced::_get_extra_advance(RID p_font_rid, int p_font_size) const {
const FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0.0);
@@ -2334,13 +2403,13 @@ float TextServerAdvanced::_get_extra_advance(RID p_font_rid, int p_font_size) co
Vector2i size = _get_size(fd, p_font_size);
if (fd->embolden != 0.0) {
- return fd->embolden * float(size.x) / 64.0;
+ return fd->embolden * double(size.x) / 64.0;
} else {
return 0.0;
}
}
-Vector2 TextServerAdvanced::font_get_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph) const {
+Vector2 TextServerAdvanced::font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector2());
@@ -2356,11 +2425,11 @@ Vector2 TextServerAdvanced::font_get_glyph_advance(RID p_font_rid, int p_size, i
Vector2 ea;
if (fd->embolden != 0.0) {
- ea.x = fd->embolden * float(size.x) / 64.0;
+ ea.x = fd->embolden * double(size.x) / 64.0;
}
if (fd->msdf) {
- return (gl[p_glyph].advance + ea) * (float)p_size / (float)fd->msdf_source_size;
+ return (gl[p_glyph].advance + ea) * (double)p_size / (double)fd->msdf_source_size;
} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_DISABLED) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x > SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
return (gl[p_glyph].advance + ea).round();
} else {
@@ -2368,7 +2437,7 @@ Vector2 TextServerAdvanced::font_get_glyph_advance(RID p_font_rid, int p_size, i
}
}
-void TextServerAdvanced::font_set_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph, const Vector2 &p_advance) {
+void TextServerAdvanced::font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2383,7 +2452,7 @@ void TextServerAdvanced::font_set_glyph_advance(RID p_font_rid, int p_size, int3
gl[p_glyph].found = true;
}
-Vector2 TextServerAdvanced::font_get_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
+Vector2 TextServerAdvanced::font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector2());
@@ -2398,13 +2467,13 @@ Vector2 TextServerAdvanced::font_get_glyph_offset(RID p_font_rid, const Vector2i
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
if (fd->msdf) {
- return gl[p_glyph].rect.position * (float)p_size.x / (float)fd->msdf_source_size;
+ return gl[p_glyph].rect.position * (double)p_size.x / (double)fd->msdf_source_size;
} else {
return gl[p_glyph].rect.position;
}
}
-void TextServerAdvanced::font_set_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) {
+void TextServerAdvanced::font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2419,7 +2488,7 @@ void TextServerAdvanced::font_set_glyph_offset(RID p_font_rid, const Vector2i &p
gl[p_glyph].found = true;
}
-Vector2 TextServerAdvanced::font_get_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
+Vector2 TextServerAdvanced::font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector2());
@@ -2434,13 +2503,13 @@ Vector2 TextServerAdvanced::font_get_glyph_size(RID p_font_rid, const Vector2i &
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
if (fd->msdf) {
- return gl[p_glyph].rect.size * (float)p_size.x / (float)fd->msdf_source_size;
+ return gl[p_glyph].rect.size * (double)p_size.x / (double)fd->msdf_source_size;
} else {
return gl[p_glyph].rect.size;
}
}
-void TextServerAdvanced::font_set_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) {
+void TextServerAdvanced::font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2455,7 +2524,7 @@ void TextServerAdvanced::font_set_glyph_size(RID p_font_rid, const Vector2i &p_s
gl[p_glyph].found = true;
}
-Rect2 TextServerAdvanced::font_get_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
+Rect2 TextServerAdvanced::font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Rect2());
@@ -2471,7 +2540,7 @@ Rect2 TextServerAdvanced::font_get_glyph_uv_rect(RID p_font_rid, const Vector2i
return gl[p_glyph].uv_rect;
}
-void TextServerAdvanced::font_set_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) {
+void TextServerAdvanced::font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2486,7 +2555,7 @@ void TextServerAdvanced::font_set_glyph_uv_rect(RID p_font_rid, const Vector2i &
gl[p_glyph].found = true;
}
-int TextServerAdvanced::font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
+int64_t TextServerAdvanced::font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, -1);
@@ -2502,7 +2571,7 @@ int TextServerAdvanced::font_get_glyph_texture_idx(RID p_font_rid, const Vector2
return gl[p_glyph].texture_idx;
}
-void TextServerAdvanced::font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) {
+void TextServerAdvanced::font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2517,7 +2586,87 @@ void TextServerAdvanced::font_set_glyph_texture_idx(RID p_font_rid, const Vector
gl[p_glyph].found = true;
}
-Dictionary TextServerAdvanced::font_get_glyph_contours(RID p_font_rid, int p_size, int32_t p_index) const {
+RID TextServerAdvanced::font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, RID());
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), RID());
+ if (!_ensure_glyph(fd, size, p_glyph)) {
+ return RID(); // Invalid or non graphicl glyph, do not display errors.
+ }
+
+ const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
+ ERR_FAIL_COND_V(gl[p_glyph].texture_idx < -1 || gl[p_glyph].texture_idx >= fd->cache[size]->textures.size(), RID());
+
+ if (RenderingServer::get_singleton() != nullptr) {
+ if (gl[p_glyph].texture_idx != -1) {
+ if (fd->cache[size]->textures[gl[p_glyph].texture_idx].dirty) {
+ FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph].texture_idx];
+ Ref<Image> img;
+ img.instantiate();
+ img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ if (fd->mipmaps) {
+ img->generate_mipmaps();
+ }
+ if (tex.texture.is_null()) {
+ tex.texture.instantiate();
+ tex.texture->create_from_image(img);
+ } else {
+ tex.texture->update(img);
+ }
+ tex.dirty = false;
+ }
+ return fd->cache[size]->textures[gl[p_glyph].texture_idx].texture->get_rid();
+ }
+ }
+
+ return RID();
+}
+
+Size2 TextServerAdvanced::font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, Size2());
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Size2());
+ if (!_ensure_glyph(fd, size, p_glyph)) {
+ return Size2(); // Invalid or non graphicl glyph, do not display errors.
+ }
+
+ const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
+ ERR_FAIL_COND_V(gl[p_glyph].texture_idx < -1 || gl[p_glyph].texture_idx >= fd->cache[size]->textures.size(), Size2());
+
+ if (RenderingServer::get_singleton() != nullptr) {
+ if (gl[p_glyph].texture_idx != -1) {
+ if (fd->cache[size]->textures[gl[p_glyph].texture_idx].dirty) {
+ FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph].texture_idx];
+ Ref<Image> img;
+ img.instantiate();
+ img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ if (fd->mipmaps) {
+ img->generate_mipmaps();
+ }
+ if (tex.texture.is_null()) {
+ tex.texture.instantiate();
+ tex.texture->create_from_image(img);
+ } else {
+ tex.texture->update(img);
+ }
+ tex.dirty = false;
+ }
+ return fd->cache[size]->textures[gl[p_glyph].texture_idx].texture->get_size();
+ }
+ }
+
+ return Size2();
+}
+
+Dictionary TextServerAdvanced::font_get_glyph_contours(const RID &p_font_rid, int64_t p_size, int64_t p_index) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Dictionary());
@@ -2526,20 +2675,19 @@ Dictionary TextServerAdvanced::font_get_glyph_contours(RID p_font_rid, int p_siz
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary());
- Vector<Vector3> points;
- Vector<int32_t> contours;
- bool orientation;
#ifdef MODULE_FREETYPE_ENABLED
- int error = FT_Load_Glyph(fd->cache[size]->face, p_index, FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
- ERR_FAIL_COND_V(error, Dictionary());
+ PackedVector3Array points;
+ PackedInt32Array contours;
+
+ int32_t index = p_index & 0xffffff; // Remove subpixel shifts.
- points.clear();
- contours.clear();
+ int error = FT_Load_Glyph(fd->cache[size]->face, index, FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
+ ERR_FAIL_COND_V(error, Dictionary());
- float h = fd->cache[size]->ascent;
- float scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale;
+ double h = fd->cache[size]->ascent;
+ double scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale;
if (fd->msdf) {
- scale = scale * (float)p_size / (float)fd->msdf_source_size;
+ scale = scale * (double)p_size / (double)fd->msdf_source_size;
}
for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_points; i++) {
points.push_back(Vector3(fd->cache[size]->face->glyph->outline.points[i].x * scale, h - fd->cache[size]->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fd->cache[size]->face->glyph->outline.tags[i])));
@@ -2547,19 +2695,19 @@ Dictionary TextServerAdvanced::font_get_glyph_contours(RID p_font_rid, int p_siz
for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_contours; i++) {
contours.push_back(fd->cache[size]->face->glyph->outline.contours[i]);
}
- orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);
-#else
- return Dictionary();
-#endif
+ bool orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);
Dictionary out;
out["points"] = points;
out["contours"] = contours;
out["orientation"] = orientation;
return out;
+#else
+ return Dictionary();
+#endif
}
-Array TextServerAdvanced::font_get_kerning_list(RID p_font_rid, int p_size) const {
+Array TextServerAdvanced::font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Array());
@@ -2569,13 +2717,13 @@ Array TextServerAdvanced::font_get_kerning_list(RID p_font_rid, int p_size) cons
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Array());
Array ret;
- for (const Map<Vector2i, Vector2>::Element *E = fd->cache[size]->kerning_map.front(); E; E = E->next()) {
- ret.push_back(E->key());
+ for (const KeyValue<Vector2i, FontDataForSizeAdvanced *> &E : fd->cache) {
+ ret.push_back(E.key);
}
return ret;
}
-void TextServerAdvanced::font_clear_kerning_map(RID p_font_rid, int p_size) {
+void TextServerAdvanced::font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2586,7 +2734,7 @@ void TextServerAdvanced::font_clear_kerning_map(RID p_font_rid, int p_size) {
fd->cache[size]->kerning_map.clear();
}
-void TextServerAdvanced::font_remove_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) {
+void TextServerAdvanced::font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2597,7 +2745,7 @@ void TextServerAdvanced::font_remove_kerning(RID p_font_rid, int p_size, const V
fd->cache[size]->kerning_map.erase(p_glyph_pair);
}
-void TextServerAdvanced::font_set_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) {
+void TextServerAdvanced::font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2608,7 +2756,7 @@ void TextServerAdvanced::font_set_kerning(RID p_font_rid, int p_size, const Vect
fd->cache[size]->kerning_map[p_glyph_pair] = p_kerning;
}
-Vector2 TextServerAdvanced::font_get_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) const {
+Vector2 TextServerAdvanced::font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector2());
@@ -2621,7 +2769,7 @@ Vector2 TextServerAdvanced::font_get_kerning(RID p_font_rid, int p_size, const V
if (kern.has(p_glyph_pair)) {
if (fd->msdf) {
- return kern[p_glyph_pair] * (float)p_size / (float)fd->msdf_source_size;
+ return kern[p_glyph_pair] * (double)p_size / (double)fd->msdf_source_size;
} else {
return kern[p_glyph_pair];
}
@@ -2631,7 +2779,7 @@ Vector2 TextServerAdvanced::font_get_kerning(RID p_font_rid, int p_size, const V
FT_Vector delta;
FT_Get_Kerning(fd->cache[size]->face, p_glyph_pair.x, p_glyph_pair.y, FT_KERNING_DEFAULT, &delta);
if (fd->msdf) {
- return Vector2(delta.x, delta.y) * (float)p_size / (float)fd->msdf_source_size;
+ return Vector2(delta.x, delta.y) * (double)p_size / (double)fd->msdf_source_size;
} else {
return Vector2(delta.x, delta.y);
}
@@ -2641,7 +2789,7 @@ Vector2 TextServerAdvanced::font_get_kerning(RID p_font_rid, int p_size, const V
return Vector2();
}
-int32_t TextServerAdvanced::font_get_glyph_index(RID p_font_rid, int p_size, char32_t p_char, char32_t p_variation_selector) const {
+int64_t TextServerAdvanced::font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0);
ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), 0, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + ".");
@@ -2659,14 +2807,14 @@ int32_t TextServerAdvanced::font_get_glyph_index(RID p_font_rid, int p_size, cha
return FT_Get_Char_Index(fd->cache[size]->face, p_char);
}
} else {
- return (int32_t)p_char;
+ return (int64_t)p_char;
}
#else
- return (int32_t)p_char;
+ return (int64_t)p_char;
#endif
}
-bool TextServerAdvanced::font_has_char(RID p_font_rid, char32_t p_char) const {
+bool TextServerAdvanced::font_has_char(const RID &p_font_rid, int64_t p_char) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), false, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + ".");
@@ -2685,7 +2833,7 @@ bool TextServerAdvanced::font_has_char(RID p_font_rid, char32_t p_char) const {
return (at_size) ? at_size->glyph_map.has((int32_t)p_char) : false;
}
-String TextServerAdvanced::font_get_supported_chars(RID p_font_rid) const {
+String TextServerAdvanced::font_get_supported_chars(const RID &p_font_rid) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, String());
@@ -2702,7 +2850,7 @@ String TextServerAdvanced::font_get_supported_chars(RID p_font_rid) const {
FT_ULong charcode = FT_Get_First_Char(at_size->face, &gindex);
while (gindex != 0) {
if (charcode != 0) {
- chars += char32_t(charcode);
+ chars = chars + String::chr(charcode);
}
charcode = FT_Get_Next_Char(at_size->face, charcode, &gindex);
}
@@ -2713,13 +2861,13 @@ String TextServerAdvanced::font_get_supported_chars(RID p_font_rid) const {
const HashMap<int32_t, FontGlyph> &gl = at_size->glyph_map;
const int32_t *E = nullptr;
while ((E = gl.next(E))) {
- chars += char32_t(*E);
+ chars = chars + String::chr(*E);
}
}
return chars;
}
-void TextServerAdvanced::font_render_range(RID p_font_rid, const Vector2i &p_size, char32_t p_start, char32_t p_end) {
+void TextServerAdvanced::font_render_range(const RID &p_font_rid, const Vector2i &p_size, int64_t p_start, int64_t p_end) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
ERR_FAIL_COND_MSG((p_start >= 0xd800 && p_start <= 0xdfff) || (p_start > 0x10ffff), "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_start, 16) + ".");
@@ -2728,7 +2876,7 @@ void TextServerAdvanced::font_render_range(RID p_font_rid, const Vector2i &p_siz
MutexLock lock(fd->mutex);
Vector2i size = _get_size_outline(fd, p_size);
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
- for (char32_t i = p_start; i <= p_end; i++) {
+ for (int64_t i = p_start; i <= p_end; i++) {
#ifdef MODULE_FREETYPE_ENABLED
int32_t idx = FT_Get_Char_Index(fd->cache[size]->face, i);
if (fd->cache[size]->face) {
@@ -2752,7 +2900,7 @@ void TextServerAdvanced::font_render_range(RID p_font_rid, const Vector2i &p_siz
}
}
-void TextServerAdvanced::font_render_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_index) {
+void TextServerAdvanced::font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2760,7 +2908,7 @@ void TextServerAdvanced::font_render_glyph(RID p_font_rid, const Vector2i &p_siz
Vector2i size = _get_size_outline(fd, p_size);
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
#ifdef MODULE_FREETYPE_ENABLED
- int32_t idx = p_index;
+ int32_t idx = p_index & 0xffffff; // Remove subpixel shifts.
if (fd->cache[size]->face) {
if (fd->msdf) {
_ensure_glyph(fd, size, (int32_t)idx);
@@ -2781,7 +2929,7 @@ void TextServerAdvanced::font_render_glyph(RID p_font_rid, const Vector2i &p_siz
#endif
}
-void TextServerAdvanced::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color) const {
+void TextServerAdvanced::font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2789,7 +2937,7 @@ void TextServerAdvanced::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_siz
Vector2i size = _get_size(fd, p_size);
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
- int32_t index = p_index;
+ int32_t index = p_index & 0xffffff; // Remove subpixel shifts.
#ifdef MODULE_FREETYPE_ENABLED
if (!fd->msdf && fd->cache[size]->face) {
@@ -2819,11 +2967,27 @@ void TextServerAdvanced::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_siz
}
#endif
if (RenderingServer::get_singleton() != nullptr) {
+ if (fd->cache[size]->textures[gl.texture_idx].dirty) {
+ FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
+ Ref<Image> img;
+ img.instantiate();
+ img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ if (fd->mipmaps) {
+ img->generate_mipmaps();
+ }
+ if (tex.texture.is_null()) {
+ tex.texture.instantiate();
+ tex.texture->create_from_image(img);
+ } else {
+ tex.texture->update(img);
+ }
+ tex.dirty = false;
+ }
RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid();
if (fd->msdf) {
Point2 cpos = p_pos;
- cpos += gl.rect.position * (float)p_size / (float)fd->msdf_source_size;
- Size2 csize = gl.rect.size * (float)p_size / (float)fd->msdf_source_size;
+ cpos += gl.rect.position * (double)p_size / (double)fd->msdf_source_size;
+ Size2 csize = gl.rect.size * (double)p_size / (double)fd->msdf_source_size;
RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range);
} else {
Point2 cpos = p_pos;
@@ -2844,7 +3008,7 @@ void TextServerAdvanced::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_siz
}
}
-void TextServerAdvanced::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color) const {
+void TextServerAdvanced::font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2852,7 +3016,7 @@ void TextServerAdvanced::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, i
Vector2i size = _get_size_outline(fd, Vector2i(p_size, p_outline_size));
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
- int32_t index = p_index;
+ int32_t index = p_index & 0xffffff; // Remove subpixel shifts.
#ifdef MODULE_FREETYPE_ENABLED
if (!fd->msdf && fd->cache[size]->face) {
@@ -2882,11 +3046,27 @@ void TextServerAdvanced::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, i
}
#endif
if (RenderingServer::get_singleton() != nullptr) {
+ if (fd->cache[size]->textures[gl.texture_idx].dirty) {
+ FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
+ Ref<Image> img;
+ img.instantiate();
+ img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ if (fd->mipmaps) {
+ img->generate_mipmaps();
+ }
+ if (tex.texture.is_null()) {
+ tex.texture.instantiate();
+ tex.texture->create_from_image(img);
+ } else {
+ tex.texture->update(img);
+ }
+ tex.dirty = false;
+ }
RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid();
if (fd->msdf) {
Point2 cpos = p_pos;
- cpos += gl.rect.position * (float)p_size / (float)fd->msdf_source_size;
- Size2 csize = gl.rect.size * (float)p_size / (float)fd->msdf_source_size;
+ cpos += gl.rect.position * (double)p_size / (double)fd->msdf_source_size;
+ Size2 csize = gl.rect.size * (double)p_size / (double)fd->msdf_source_size;
RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, p_outline_size * 2, fd->msdf_range);
} else {
Point2 cpos = p_pos;
@@ -2907,7 +3087,7 @@ void TextServerAdvanced::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, i
}
}
-bool TextServerAdvanced::font_is_language_supported(RID p_font_rid, const String &p_language) const {
+bool TextServerAdvanced::font_is_language_supported(const RID &p_font_rid, const String &p_language) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -2919,7 +3099,7 @@ bool TextServerAdvanced::font_is_language_supported(RID p_font_rid, const String
}
}
-void TextServerAdvanced::font_set_language_support_override(RID p_font_rid, const String &p_language, bool p_supported) {
+void TextServerAdvanced::font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2927,7 +3107,7 @@ void TextServerAdvanced::font_set_language_support_override(RID p_font_rid, cons
fd->language_support_overrides[p_language] = p_supported;
}
-bool TextServerAdvanced::font_get_language_support_override(RID p_font_rid, const String &p_language) {
+bool TextServerAdvanced::font_get_language_support_override(const RID &p_font_rid, const String &p_language) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -2935,7 +3115,7 @@ bool TextServerAdvanced::font_get_language_support_override(RID p_font_rid, cons
return fd->language_support_overrides[p_language];
}
-void TextServerAdvanced::font_remove_language_support_override(RID p_font_rid, const String &p_language) {
+void TextServerAdvanced::font_remove_language_support_override(const RID &p_font_rid, const String &p_language) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2943,19 +3123,19 @@ void TextServerAdvanced::font_remove_language_support_override(RID p_font_rid, c
fd->language_support_overrides.erase(p_language);
}
-Vector<String> TextServerAdvanced::font_get_language_support_overrides(RID p_font_rid) {
+PackedStringArray TextServerAdvanced::font_get_language_support_overrides(const RID &p_font_rid) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, Vector<String>());
+ ERR_FAIL_COND_V(!fd, PackedStringArray());
MutexLock lock(fd->mutex);
- Vector<String> out;
+ PackedStringArray out;
for (const KeyValue<String, bool> &E : fd->language_support_overrides) {
out.push_back(E.key);
}
return out;
}
-bool TextServerAdvanced::font_is_script_supported(RID p_font_rid, const String &p_script) const {
+bool TextServerAdvanced::font_is_script_supported(const RID &p_font_rid, const String &p_script) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -2969,7 +3149,7 @@ bool TextServerAdvanced::font_is_script_supported(RID p_font_rid, const String &
}
}
-void TextServerAdvanced::font_set_script_support_override(RID p_font_rid, const String &p_script, bool p_supported) {
+void TextServerAdvanced::font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2977,7 +3157,7 @@ void TextServerAdvanced::font_set_script_support_override(RID p_font_rid, const
fd->script_support_overrides[p_script] = p_supported;
}
-bool TextServerAdvanced::font_get_script_support_override(RID p_font_rid, const String &p_script) {
+bool TextServerAdvanced::font_get_script_support_override(const RID &p_font_rid, const String &p_script) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -2985,7 +3165,7 @@ bool TextServerAdvanced::font_get_script_support_override(RID p_font_rid, const
return fd->script_support_overrides[p_script];
}
-void TextServerAdvanced::font_remove_script_support_override(RID p_font_rid, const String &p_script) {
+void TextServerAdvanced::font_remove_script_support_override(const RID &p_font_rid, const String &p_script) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2993,19 +3173,19 @@ void TextServerAdvanced::font_remove_script_support_override(RID p_font_rid, con
fd->script_support_overrides.erase(p_script);
}
-Vector<String> TextServerAdvanced::font_get_script_support_overrides(RID p_font_rid) {
+PackedStringArray TextServerAdvanced::font_get_script_support_overrides(const RID &p_font_rid) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, Vector<String>());
+ ERR_FAIL_COND_V(!fd, PackedStringArray());
MutexLock lock(fd->mutex);
- Vector<String> out;
- for (const Map<String, bool>::Element *E = fd->script_support_overrides.front(); E; E = E->next()) {
- out.push_back(E->key());
+ PackedStringArray out;
+ for (const KeyValue<String, bool> &E : fd->script_support_overrides) {
+ out.push_back(E.key);
}
return out;
}
-void TextServerAdvanced::font_set_opentype_feature_overrides(RID p_font_rid, const Dictionary &p_overrides) {
+void TextServerAdvanced::font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -3015,7 +3195,7 @@ void TextServerAdvanced::font_set_opentype_feature_overrides(RID p_font_rid, con
fd->feature_overrides = p_overrides;
}
-Dictionary TextServerAdvanced::font_get_opentype_feature_overrides(RID p_font_rid) const {
+Dictionary TextServerAdvanced::font_get_opentype_feature_overrides(const RID &p_font_rid) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Dictionary());
@@ -3023,7 +3203,7 @@ Dictionary TextServerAdvanced::font_get_opentype_feature_overrides(RID p_font_ri
return fd->feature_overrides;
}
-Dictionary TextServerAdvanced::font_supported_feature_list(RID p_font_rid) const {
+Dictionary TextServerAdvanced::font_supported_feature_list(const RID &p_font_rid) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Dictionary());
@@ -3033,7 +3213,7 @@ Dictionary TextServerAdvanced::font_supported_feature_list(RID p_font_rid) const
return fd->supported_features;
}
-Dictionary TextServerAdvanced::font_supported_variation_list(RID p_font_rid) const {
+Dictionary TextServerAdvanced::font_supported_variation_list(const RID &p_font_rid) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Dictionary());
@@ -3043,11 +3223,11 @@ Dictionary TextServerAdvanced::font_supported_variation_list(RID p_font_rid) con
return fd->supported_varaitions;
}
-float TextServerAdvanced::font_get_global_oversampling() const {
+double TextServerAdvanced::font_get_global_oversampling() const {
return oversampling;
}
-void TextServerAdvanced::font_set_global_oversampling(float p_oversampling) {
+void TextServerAdvanced::font_set_global_oversampling(double p_oversampling) {
_THREAD_SAFE_METHOD_
if (oversampling != p_oversampling) {
oversampling = p_oversampling;
@@ -3075,10 +3255,23 @@ void TextServerAdvanced::font_set_global_oversampling(float p_oversampling) {
/* Shaped text buffer interface */
/*************************************************************************/
-int TextServerAdvanced::_convert_pos(const ShapedTextDataAdvanced *p_sd, int p_pos) const {
- int32_t limit = p_pos;
+int64_t TextServerAdvanced::_convert_pos(const String &p_utf32, const Char16String &p_utf16, int64_t p_pos) const {
+ int64_t limit = p_pos;
+ if (p_utf32.length() != p_utf16.length()) {
+ const UChar *data = p_utf16.ptr();
+ for (int i = 0; i < p_pos; i++) {
+ if (U16_IS_LEAD(data[i])) {
+ limit--;
+ }
+ }
+ }
+ return limit;
+}
+
+int64_t TextServerAdvanced::_convert_pos(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const {
+ int64_t limit = p_pos;
if (p_sd->text.length() != p_sd->utf16.length()) {
- const UChar *data = p_sd->utf16.ptr();
+ const UChar *data = p_sd->utf16.get_data();
for (int i = 0; i < p_pos; i++) {
if (U16_IS_LEAD(data[i])) {
limit--;
@@ -3088,11 +3281,11 @@ int TextServerAdvanced::_convert_pos(const ShapedTextDataAdvanced *p_sd, int p_p
return limit;
}
-int TextServerAdvanced::_convert_pos_inv(const ShapedTextDataAdvanced *p_sd, int p_pos) const {
- int32_t limit = p_pos;
+int64_t TextServerAdvanced::_convert_pos_inv(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const {
+ int64_t limit = p_pos;
if (p_sd->text.length() != p_sd->utf16.length()) {
for (int i = 0; i < p_pos; i++) {
- if (p_sd->text[i] > 0xFFFF) {
+ if (p_sd->text[i] > 0xffff) {
limit++;
}
}
@@ -3106,11 +3299,11 @@ void TextServerAdvanced::invalidate(TextServerAdvanced::ShapedTextDataAdvanced *
p_shaped->line_breaks_valid = false;
p_shaped->justification_ops_valid = false;
p_shaped->text_trimmed = false;
- p_shaped->ascent = 0.f;
- p_shaped->descent = 0.f;
- p_shaped->width = 0.f;
- p_shaped->upos = 0.f;
- p_shaped->uthk = 0.f;
+ p_shaped->ascent = 0.0;
+ p_shaped->descent = 0.0;
+ p_shaped->width = 0.0;
+ p_shaped->upos = 0.0;
+ p_shaped->uthk = 0.0;
p_shaped->glyphs.clear();
p_shaped->glyphs_logical.clear();
p_shaped->overrun_trim_data = TrimData();
@@ -3161,7 +3354,7 @@ RID TextServerAdvanced::create_shaped_text(TextServer::Direction p_direction, Te
return shaped_owner.make_rid(sd);
}
-void TextServerAdvanced::shaped_text_clear(RID p_shaped) {
+void TextServerAdvanced::shaped_text_clear(const RID &p_shaped) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
@@ -3176,7 +3369,7 @@ void TextServerAdvanced::shaped_text_clear(RID p_shaped) {
invalidate(sd, true);
}
-void TextServerAdvanced::shaped_text_set_direction(RID p_shaped, TextServer::Direction p_direction) {
+void TextServerAdvanced::shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
@@ -3190,7 +3383,7 @@ void TextServerAdvanced::shaped_text_set_direction(RID p_shaped, TextServer::Dir
}
}
-TextServer::Direction TextServerAdvanced::shaped_text_get_direction(RID p_shaped) const {
+TextServer::Direction TextServerAdvanced::shaped_text_get_direction(const RID &p_shaped) const {
const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, TextServer::DIRECTION_LTR);
@@ -3198,7 +3391,7 @@ TextServer::Direction TextServerAdvanced::shaped_text_get_direction(RID p_shaped
return sd->direction;
}
-TextServer::Direction TextServerAdvanced::shaped_text_get_inferred_direction(RID p_shaped) const {
+TextServer::Direction TextServerAdvanced::shaped_text_get_inferred_direction(const RID &p_shaped) const {
const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, TextServer::DIRECTION_LTR);
@@ -3206,7 +3399,7 @@ TextServer::Direction TextServerAdvanced::shaped_text_get_inferred_direction(RID
return sd->para_direction;
}
-void TextServerAdvanced::shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) {
+void TextServerAdvanced::shaped_text_set_custom_punctuation(const RID &p_shaped, const String &p_punct) {
_THREAD_SAFE_METHOD_
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
@@ -3220,14 +3413,14 @@ void TextServerAdvanced::shaped_text_set_custom_punctuation(RID p_shaped, const
}
}
-String TextServerAdvanced::shaped_text_get_custom_punctuation(RID p_shaped) const {
+String TextServerAdvanced::shaped_text_get_custom_punctuation(const RID &p_shaped) const {
_THREAD_SAFE_METHOD_
const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, String());
return sd->custom_punct;
}
-void TextServerAdvanced::shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) {
+void TextServerAdvanced::shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
@@ -3237,12 +3430,14 @@ void TextServerAdvanced::shaped_text_set_bidi_override(RID p_shaped, const Array
}
sd->bidi_override.clear();
for (int i = 0; i < p_override.size(); i++) {
- sd->bidi_override.push_back(p_override[i]);
+ if (p_override[i].get_type() == Variant::VECTOR2I) {
+ sd->bidi_override.push_back(p_override[i]);
+ }
}
invalidate(sd, false);
}
-void TextServerAdvanced::shaped_text_set_orientation(RID p_shaped, TextServer::Orientation p_orientation) {
+void TextServerAdvanced::shaped_text_set_orientation(const RID &p_shaped, TextServer::Orientation p_orientation) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
@@ -3256,7 +3451,7 @@ void TextServerAdvanced::shaped_text_set_orientation(RID p_shaped, TextServer::O
}
}
-void TextServerAdvanced::shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) {
+void TextServerAdvanced::shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
@@ -3268,7 +3463,7 @@ void TextServerAdvanced::shaped_text_set_preserve_invalid(RID p_shaped, bool p_e
}
}
-bool TextServerAdvanced::shaped_text_get_preserve_invalid(RID p_shaped) const {
+bool TextServerAdvanced::shaped_text_get_preserve_invalid(const RID &p_shaped) const {
const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -3276,7 +3471,7 @@ bool TextServerAdvanced::shaped_text_get_preserve_invalid(RID p_shaped) const {
return sd->preserve_invalid;
}
-void TextServerAdvanced::shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) {
+void TextServerAdvanced::shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
@@ -3290,7 +3485,7 @@ void TextServerAdvanced::shaped_text_set_preserve_control(RID p_shaped, bool p_e
}
}
-bool TextServerAdvanced::shaped_text_get_preserve_control(RID p_shaped) const {
+bool TextServerAdvanced::shaped_text_get_preserve_control(const RID &p_shaped) const {
const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -3298,7 +3493,7 @@ bool TextServerAdvanced::shaped_text_get_preserve_control(RID p_shaped) const {
return sd->preserve_control;
}
-TextServer::Orientation TextServerAdvanced::shaped_text_get_orientation(RID p_shaped) const {
+TextServer::Orientation TextServerAdvanced::shaped_text_get_orientation(const RID &p_shaped) const {
const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, TextServer::ORIENTATION_HORIZONTAL);
@@ -3306,25 +3501,25 @@ TextServer::Orientation TextServerAdvanced::shaped_text_get_orientation(RID p_sh
return sd->orientation;
}
-int TextServerAdvanced::shaped_get_span_count(RID p_shaped) const {
+int64_t TextServerAdvanced::shaped_get_span_count(const RID &p_shaped) const {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0);
return sd->spans.size();
}
-Variant TextServerAdvanced::shaped_get_span_meta(RID p_shaped, int p_index) const {
+Variant TextServerAdvanced::shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, Variant());
ERR_FAIL_INDEX_V(p_index, sd->spans.size(), Variant());
return sd->spans[p_index].meta;
}
-void TextServerAdvanced::shaped_set_span_update_font(RID p_shaped, int p_index, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features) {
+void TextServerAdvanced::shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
ERR_FAIL_INDEX(p_index, sd->spans.size());
- ShapedTextDataAdvanced::Span &span = sd->spans.write[p_index];
+ ShapedTextDataAdvanced::Span &span = sd->spans.ptrw()[p_index];
bool changed = (span.font_size != p_size) || (span.features != p_opentype_features) || (p_fonts.size() != span.fonts.size());
if (!changed) {
for (int i = 0; i < p_fonts.size(); i++) {
@@ -3340,7 +3535,7 @@ void TextServerAdvanced::shaped_set_span_update_font(RID p_shaped, int p_index,
}
}
-bool TextServerAdvanced::shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) {
+bool TextServerAdvanced::shaped_text_add_string(const RID &p_shaped, const String &p_text, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
ERR_FAIL_COND_V(p_size <= 0, false);
@@ -3368,14 +3563,14 @@ bool TextServerAdvanced::shaped_text_add_string(RID p_shaped, const String &p_te
span.meta = p_meta;
sd->spans.push_back(span);
- sd->text += p_text;
+ sd->text = sd->text + p_text;
sd->end += p_text.length();
invalidate(sd, true);
return true;
}
-bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align, int p_length) {
+bool TextServerAdvanced::shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, int64_t p_length) {
_THREAD_SAFE_METHOD_
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -3397,7 +3592,7 @@ bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, con
obj.pos = span.start;
sd->spans.push_back(span);
- sd->text += String::chr(0xfffc).repeat(p_length);
+ sd->text = sd->text + String::chr(0xfffc).repeat(p_length);
sd->end += p_length;
sd->objects[p_key] = obj;
invalidate(sd, true);
@@ -3405,7 +3600,7 @@ bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, con
return true;
}
-bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align) {
+bool TextServerAdvanced::shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -3459,8 +3654,8 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
if (sd->orientation == ORIENTATION_HORIZONTAL) {
sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y);
} else {
- sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
- sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
+ sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));
+ sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));
}
}
sd->width += gl.advance * gl.repeat;
@@ -3473,8 +3668,8 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
void TextServerAdvanced::_realign(ShapedTextDataAdvanced *p_sd) const {
// Align embedded objects to baseline.
- float full_ascent = p_sd->ascent;
- float full_descent = p_sd->descent;
+ double full_ascent = p_sd->ascent;
+ double full_descent = p_sd->descent;
for (KeyValue<Variant, ShapedTextDataAdvanced::EmbeddedObject> &E : p_sd->objects) {
if ((E.value.pos >= p_sd->start) && (E.value.pos < p_sd->end)) {
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
@@ -3540,7 +3735,7 @@ void TextServerAdvanced::_realign(ShapedTextDataAdvanced *p_sd) const {
p_sd->descent = full_descent;
}
-RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_length) const {
+RID TextServerAdvanced::shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const {
const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, RID());
@@ -3571,7 +3766,7 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
return shaped_owner.make_rid(new_sd);
}
-bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const ShapedTextDataAdvanced *p_sd, int p_start, int p_length) const {
+bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_length) const {
if (p_new_sd->valid) {
return true;
}
@@ -3661,8 +3856,8 @@ bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const S
if (p_new_sd->orientation == ORIENTATION_HORIZONTAL) {
p_new_sd->ascent = MAX(p_new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y);
} else {
- p_new_sd->ascent = MAX(p_new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
- p_new_sd->descent = MAX(p_new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
+ p_new_sd->ascent = MAX(p_new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));
+ p_new_sd->descent = MAX(p_new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));
}
}
p_new_sd->width += gl.advance * gl.repeat;
@@ -3680,7 +3875,7 @@ bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const S
return true;
}
-RID TextServerAdvanced::shaped_text_get_parent(RID p_shaped) const {
+RID TextServerAdvanced::shaped_text_get_parent(const RID &p_shaped) const {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, RID());
@@ -3688,9 +3883,9 @@ RID TextServerAdvanced::shaped_text_get_parent(RID p_shaped) const {
return sd->parent;
}
-float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t /*JustificationFlag*/ p_jst_flags) {
+double TextServerAdvanced::shaped_text_fit_to_width(const RID &p_shaped, double p_width, int64_t /*JustificationFlag*/ p_jst_flags) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
- ERR_FAIL_COND_V(!sd, 0.f);
+ ERR_FAIL_COND_V(!sd, 0.0);
MutexLock lock(sd->mutex);
if (!sd->valid) {
@@ -3729,7 +3924,7 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width,
}
}
- float justification_width;
+ double justification_width;
if ((p_jst_flags & JUSTIFICATION_CONSTRAIN_ELLIPSIS) == JUSTIFICATION_CONSTRAIN_ELLIPSIS) {
if (sd->overrun_trim_data.trim_pos >= 0) {
if (sd->para_direction == DIRECTION_RTL) {
@@ -3785,7 +3980,7 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width,
}
if ((elongation_count > 0) && ((p_jst_flags & JUSTIFICATION_KASHIDA) == JUSTIFICATION_KASHIDA)) {
- float delta_width_per_kashida = (p_width - justification_width) / elongation_count;
+ double delta_width_per_kashida = (p_width - justification_width) / elongation_count;
for (int i = start_pos; i <= end_pos; i++) {
Glyph &gl = sd->glyphs.write[i];
if (gl.count > 0) {
@@ -3805,17 +4000,17 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width,
}
}
}
- float adv_remain = 0;
if ((space_count > 0) && ((p_jst_flags & JUSTIFICATION_WORD_BOUND) == JUSTIFICATION_WORD_BOUND)) {
- float delta_width_per_space = (p_width - justification_width) / space_count;
+ double delta_width_per_space = (p_width - justification_width) / space_count;
+ double adv_remain = 0;
for (int i = start_pos; i <= end_pos; i++) {
Glyph &gl = sd->glyphs.write[i];
if (gl.count > 0) {
if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) {
- float old_adv = gl.advance;
- float new_advance;
+ double old_adv = gl.advance;
+ double new_advance;
if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {
- new_advance = MAX(gl.advance + delta_width_per_space, 0.f);
+ new_advance = MAX(gl.advance + delta_width_per_space, 0.0);
} else {
new_advance = MAX(gl.advance + delta_width_per_space, 0.1 * gl.font_size);
}
@@ -3845,9 +4040,9 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width,
return Math::ceil(justification_width);
}
-float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) {
+double TextServerAdvanced::shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
- ERR_FAIL_COND_V(!sd, 0.f);
+ ERR_FAIL_COND_V(!sd, 0.0);
MutexLock lock(sd->mutex);
if (!sd->valid) {
@@ -3859,12 +4054,12 @@ float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const PackedFloat3
for (int i = 0; i < p_tab_stops.size(); i++) {
if (p_tab_stops[i] <= 0) {
- return 0.f;
+ return 0.0;
}
}
int tab_index = 0;
- float off = 0.f;
+ double off = 0.0;
int start, end, delta;
if (sd->para_direction == DIRECTION_LTR) {
@@ -3881,7 +4076,7 @@ float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const PackedFloat3
for (int i = start; i != end; i += delta) {
if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
- float tab_off = 0.f;
+ double tab_off = 0.0;
while (tab_off <= off) {
tab_off += p_tab_stops[tab_index];
tab_index++;
@@ -3889,7 +4084,7 @@ float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const PackedFloat3
tab_index = 0;
}
}
- float old_adv = gl[i].advance;
+ double old_adv = gl[i].advance;
gl[i].advance = tab_off - off;
sd->width += gl[i].advance - old_adv;
off = 0;
@@ -3898,10 +4093,10 @@ float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const PackedFloat3
off += gl[i].advance * gl[i].repeat;
}
- return 0.f;
+ return 0.0;
}
-void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint16_t p_trim_flags) {
+void TextServerAdvanced::shaped_text_overrun_trim_to_width(const RID &p_shaped_line, double p_width, int64_t p_trim_flags) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped_line);
ERR_FAIL_COND_MSG(!sd, "ShapedTextDataAdvanced invalid.");
@@ -3947,20 +4142,20 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
// Find usable fonts, if fonts from the last glyph do not have required chars.
RID dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;
if (!font_has_char(dot_gl_font_rid, '.')) {
- const Vector<RID> &fonts = spans[spans.size() - 1].fonts;
- for (const RID &font : fonts) {
- if (font_has_char(font, '.')) {
- dot_gl_font_rid = font;
+ const Array &fonts = spans[spans.size() - 1].fonts;
+ for (int i = 0; i < fonts.size(); i++) {
+ if (font_has_char(fonts[i], '.')) {
+ dot_gl_font_rid = fonts[i];
break;
}
}
}
RID whitespace_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;
if (!font_has_char(whitespace_gl_font_rid, '.')) {
- const Vector<RID> &fonts = spans[spans.size() - 1].fonts;
- for (const RID &font : fonts) {
- if (font_has_char(font, ' ')) {
- whitespace_gl_font_rid = font;
+ const Array &fonts = spans[spans.size() - 1].fonts;
+ for (int i = 0; i < fonts.size(); i++) {
+ if (font_has_char(fonts[i], ' ')) {
+ whitespace_gl_font_rid = fonts[i];
break;
}
}
@@ -3977,7 +4172,7 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
}
int ell_min_characters = 6;
- float width = sd->width;
+ double width = sd->width;
bool is_rtl = sd->para_direction == DIRECTION_RTL;
@@ -4063,7 +4258,7 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
}
}
-int TextServerAdvanced::shaped_text_get_trim_pos(RID p_shaped) const {
+int64_t TextServerAdvanced::shaped_text_get_trim_pos(const RID &p_shaped) const {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataAdvanced invalid.");
@@ -4071,7 +4266,7 @@ int TextServerAdvanced::shaped_text_get_trim_pos(RID p_shaped) const {
return sd->overrun_trim_data.trim_pos;
}
-int TextServerAdvanced::shaped_text_get_ellipsis_pos(RID p_shaped) const {
+int64_t TextServerAdvanced::shaped_text_get_ellipsis_pos(const RID &p_shaped) const {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataAdvanced invalid.");
@@ -4079,7 +4274,7 @@ int TextServerAdvanced::shaped_text_get_ellipsis_pos(RID p_shaped) const {
return sd->overrun_trim_data.ellipsis_pos;
}
-const Glyph *TextServerAdvanced::shaped_text_get_ellipsis_glyphs(RID p_shaped) const {
+const Glyph *TextServerAdvanced::shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V_MSG(!sd, nullptr, "ShapedTextDataAdvanced invalid.");
@@ -4087,7 +4282,7 @@ const Glyph *TextServerAdvanced::shaped_text_get_ellipsis_glyphs(RID p_shaped) c
return sd->overrun_trim_data.ellipsis_glyph_buf.ptr();
}
-int TextServerAdvanced::shaped_text_get_ellipsis_glyph_count(RID p_shaped) const {
+int64_t TextServerAdvanced::shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V_MSG(!sd, 0, "ShapedTextDataAdvanced invalid.");
@@ -4095,7 +4290,7 @@ int TextServerAdvanced::shaped_text_get_ellipsis_glyph_count(RID p_shaped) const
return sd->overrun_trim_data.ellipsis_glyph_buf.size();
}
-bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
+bool TextServerAdvanced::shaped_text_update_breaks(const RID &p_shaped) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -4108,7 +4303,7 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
return true; // Nothing to do.
}
- const UChar *data = sd->utf16.ptr();
+ const UChar *data = sd->utf16.get_data();
if (!sd->break_ops_valid) {
sd->breaks.clear();
@@ -4171,7 +4366,7 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
sd_glyphs[i].flags |= GRAPHEME_IS_SPACE;
}
if (c_punct_size == 0) {
- if (u_ispunct(c) && c != 0x005F) {
+ if (u_ispunct(c) && c != 0x005f) {
sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION;
}
} else {
@@ -4237,10 +4432,10 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
return sd->line_breaks_valid;
}
-_FORCE_INLINE_ int _generate_kashida_justification_opportunies(const String &p_data, int p_start, int p_end) {
- int kashida_pos = -1;
+_FORCE_INLINE_ int64_t _generate_kashida_justification_opportunies(const String &p_data, int64_t p_start, int64_t p_end) {
+ int64_t kashida_pos = -1;
int8_t priority = 100;
- int i = p_start;
+ int64_t i = p_start;
char32_t pc = 0;
@@ -4256,7 +4451,7 @@ _FORCE_INLINE_ int _generate_kashida_justification_opportunies(const String &p_d
priority = 0;
}
if (priority >= 1 && i < p_end - 1) {
- if (is_seen_sad(c) && (p_data[i + 1] != 0x200C)) {
+ if (is_seen_sad(c) && (p_data[i + 1] != 0x200c)) {
kashida_pos = i;
priority = 1;
}
@@ -4312,7 +4507,7 @@ _FORCE_INLINE_ int _generate_kashida_justification_opportunies(const String &p_d
return kashida_pos;
}
-bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
+bool TextServerAdvanced::shaped_text_update_justification_ops(const RID &p_shaped) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -4328,8 +4523,8 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
return true; // Nothing to do.
}
- const UChar *data = sd->utf16.ptr();
- int32_t data_size = sd->utf16.length();
+ const UChar *data = sd->utf16.get_data();
+ int data_size = sd->utf16.length();
if (!sd->js_ops_valid) {
sd->jstops.clear();
@@ -4459,7 +4654,7 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
return sd->justification_ops_valid;
}
-Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, RID p_font, int p_font_size) {
+Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, const RID &p_font, int64_t p_font_size) {
hb_font_t *hb_font = _font_get_hb_handle(p_font, p_font_size);
bool subpos = (font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_ONE_HALF) || (font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_AUTO && p_font_size <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE);
ERR_FAIL_COND_V(hb_font == nullptr, Glyph());
@@ -4487,7 +4682,7 @@ Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char
gl.font_size = p_font_size;
if (glyph_count > 0) {
- float scale = font_get_scale(p_font, p_font_size);
+ double scale = font_get_scale(p_font, p_font_size);
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
if (subpos) {
gl.advance = glyph_pos[0].x_advance / (64.0 / scale) + _get_extra_advance(p_font, p_font_size);
@@ -4515,16 +4710,18 @@ Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char
}
_FORCE_INLINE_ void TextServerAdvanced::_add_featuers(const Dictionary &p_source, Vector<hb_feature_t> &r_ftrs) {
- for (const Variant *ftr = p_source.next(nullptr); ftr != nullptr; ftr = p_source.next(ftr)) {
- int32_t values = p_source[*ftr];
- if (values >= 0) {
+ Array keys = p_source.keys();
+ Array values = p_source.values();
+ for (int i = 0; i < keys.size(); i++) {
+ int32_t value = values[i];
+ if (value >= 0) {
hb_feature_t feature;
- if (ftr->get_type() == Variant::STRING) {
- feature.tag = name_to_tag(*ftr);
+ if (keys[i].get_type() == Variant::STRING) {
+ feature.tag = name_to_tag(keys[i]);
} else {
- feature.tag = *ftr;
+ feature.tag = keys[i];
}
- feature.value = values;
+ feature.value = value;
feature.start = 0;
feature.end = -1;
r_ftrs.push_back(feature);
@@ -4532,7 +4729,7 @@ _FORCE_INLINE_ void TextServerAdvanced::_add_featuers(const Dictionary &p_source
}
}
-void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_start, int32_t p_end, hb_script_t p_script, hb_direction_t p_direction, Vector<RID> p_fonts, int p_span, int p_fb_index) {
+void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_end, hb_script_t p_script, hb_direction_t p_direction, Array p_fonts, int64_t p_span, int64_t p_fb_index) {
int fs = p_sd->spans[p_span].font_size;
if (p_fb_index >= p_fonts.size()) {
// Add fallback glyphs.
@@ -4553,8 +4750,8 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
p_sd->ascent = MAX(p_sd->ascent, get_hex_code_box_size(fs, gl.index).y);
} else {
gl.advance = get_hex_code_box_size(fs, gl.index).y;
- p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5f));
- p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5f));
+ p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5));
+ p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5));
}
p_sd->width += gl.advance;
@@ -4565,11 +4762,13 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
}
RID f = p_fonts[p_fb_index];
+ FontDataAdvanced *fd = font_owner.get_or_null(f);
+ Vector2i fss = _get_size(fd, fs);
hb_font_t *hb_font = _font_get_hb_handle(f, fs);
- float scale = font_get_scale(f, fs);
- float sp_sp = font_get_spacing(f, fs, SPACING_SPACE);
- float sp_gl = font_get_spacing(f, fs, SPACING_GLYPH);
- float ea = _get_extra_advance(f, fs);
+ double scale = font_get_scale(f, fs);
+ double sp_sp = font_get_spacing(f, fs, SPACING_SPACE);
+ double sp_gl = font_get_spacing(f, fs, SPACING_GLYPH);
+ double ea = _get_extra_advance(f, fs);
bool subpos = (font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_ONE_HALF) || (font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_AUTO && fs <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE);
ERR_FAIL_COND(hb_font == nullptr);
@@ -4646,6 +4845,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
gl.index = glyph_info[i].codepoint;
if (gl.index != 0) {
+ _ensure_glyph(fd, fss, gl.index);
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
if (subpos) {
gl.advance = glyph_pos[i].x_advance / (64.0 / scale) + ea;
@@ -4703,7 +4903,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
p_sd->ascent = MAX(p_sd->ascent, -w[i + j].y_off);
p_sd->descent = MAX(p_sd->descent, w[i + j].y_off);
} else {
- float gla = Math::round(font_get_glyph_advance(f, fs, w[i + j].index).x * 0.5);
+ double gla = Math::round(font_get_glyph_advance(f, fs, w[i + j].index).x * 0.5);
p_sd->ascent = MAX(p_sd->ascent, gla);
p_sd->descent = MAX(p_sd->descent, gla);
}
@@ -4733,7 +4933,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
}
}
-bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
+bool TextServerAdvanced::shaped_text_shape(const RID &p_shaped) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -4757,7 +4957,7 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
}
sd->utf16 = sd->text.utf16();
- const UChar *data = sd->utf16.ptr();
+ const UChar *data = sd->utf16.get_data();
// Create script iterator.
if (sd->script_iter == nullptr) {
@@ -4876,9 +5076,9 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
}
sd->glyphs.push_back(gl);
} else {
- Vector<RID> fonts;
- Vector<RID> fonts_scr_only;
- Vector<RID> fonts_no_match;
+ Array fonts;
+ Array fonts_scr_only;
+ Array fonts_no_match;
int font_count = span.fonts.size();
for (int l = 0; l < font_count; l++) {
if (font_is_script_supported(span.fonts[l], script)) {
@@ -4906,7 +5106,7 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
return sd->valid;
}
-bool TextServerAdvanced::shaped_text_is_ready(RID p_shaped) const {
+bool TextServerAdvanced::shaped_text_is_ready(const RID &p_shaped) const {
const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -4914,7 +5114,7 @@ bool TextServerAdvanced::shaped_text_is_ready(RID p_shaped) const {
return sd->valid;
}
-const Glyph *TextServerAdvanced::shaped_text_get_glyphs(RID p_shaped) const {
+const Glyph *TextServerAdvanced::shaped_text_get_glyphs(const RID &p_shaped) const {
const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, nullptr);
@@ -4925,7 +5125,7 @@ const Glyph *TextServerAdvanced::shaped_text_get_glyphs(RID p_shaped) const {
return sd->glyphs.ptr();
}
-int TextServerAdvanced::shaped_text_get_glyph_count(RID p_shaped) const {
+int64_t TextServerAdvanced::shaped_text_get_glyph_count(const RID &p_shaped) const {
const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0);
@@ -4936,7 +5136,7 @@ int TextServerAdvanced::shaped_text_get_glyph_count(RID p_shaped) const {
return sd->glyphs.size();
}
-const Glyph *TextServerAdvanced::shaped_text_sort_logical(RID p_shaped) {
+const Glyph *TextServerAdvanced::shaped_text_sort_logical(const RID &p_shaped) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, nullptr);
@@ -4954,7 +5154,7 @@ const Glyph *TextServerAdvanced::shaped_text_sort_logical(RID p_shaped) {
return sd->glyphs_logical.ptr();
}
-Vector2i TextServerAdvanced::shaped_text_get_range(RID p_shaped) const {
+Vector2i TextServerAdvanced::shaped_text_get_range(const RID &p_shaped) const {
const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, Vector2i());
@@ -4962,7 +5162,7 @@ Vector2i TextServerAdvanced::shaped_text_get_range(RID p_shaped) const {
return Vector2(sd->start, sd->end);
}
-Array TextServerAdvanced::shaped_text_get_objects(RID p_shaped) const {
+Array TextServerAdvanced::shaped_text_get_objects(const RID &p_shaped) const {
Array ret;
const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, ret);
@@ -4975,7 +5175,7 @@ Array TextServerAdvanced::shaped_text_get_objects(RID p_shaped) const {
return ret;
}
-Rect2 TextServerAdvanced::shaped_text_get_object_rect(RID p_shaped, Variant p_key) const {
+Rect2 TextServerAdvanced::shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const {
const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, Rect2());
@@ -4987,7 +5187,7 @@ Rect2 TextServerAdvanced::shaped_text_get_object_rect(RID p_shaped, Variant p_ke
return sd->objects[p_key].rect;
}
-Size2 TextServerAdvanced::shaped_text_get_size(RID p_shaped) const {
+Size2 TextServerAdvanced::shaped_text_get_size(const RID &p_shaped) const {
const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, Size2());
@@ -5002,9 +5202,9 @@ Size2 TextServerAdvanced::shaped_text_get_size(RID p_shaped) const {
}
}
-float TextServerAdvanced::shaped_text_get_ascent(RID p_shaped) const {
+double TextServerAdvanced::shaped_text_get_ascent(const RID &p_shaped) const {
const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
- ERR_FAIL_COND_V(!sd, 0.f);
+ ERR_FAIL_COND_V(!sd, 0.0);
MutexLock lock(sd->mutex);
if (!sd->valid) {
@@ -5013,9 +5213,9 @@ float TextServerAdvanced::shaped_text_get_ascent(RID p_shaped) const {
return sd->ascent;
}
-float TextServerAdvanced::shaped_text_get_descent(RID p_shaped) const {
+double TextServerAdvanced::shaped_text_get_descent(const RID &p_shaped) const {
const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
- ERR_FAIL_COND_V(!sd, 0.f);
+ ERR_FAIL_COND_V(!sd, 0.0);
MutexLock lock(sd->mutex);
if (!sd->valid) {
@@ -5024,9 +5224,9 @@ float TextServerAdvanced::shaped_text_get_descent(RID p_shaped) const {
return sd->descent;
}
-float TextServerAdvanced::shaped_text_get_width(RID p_shaped) const {
+double TextServerAdvanced::shaped_text_get_width(const RID &p_shaped) const {
const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
- ERR_FAIL_COND_V(!sd, 0.f);
+ ERR_FAIL_COND_V(!sd, 0.0);
MutexLock lock(sd->mutex);
if (!sd->valid) {
@@ -5035,9 +5235,9 @@ float TextServerAdvanced::shaped_text_get_width(RID p_shaped) const {
return Math::ceil(sd->text_trimmed ? sd->width_trimmed : sd->width);
}
-float TextServerAdvanced::shaped_text_get_underline_position(RID p_shaped) const {
+double TextServerAdvanced::shaped_text_get_underline_position(const RID &p_shaped) const {
const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
- ERR_FAIL_COND_V(!sd, 0.f);
+ ERR_FAIL_COND_V(!sd, 0.0);
MutexLock lock(sd->mutex);
if (!sd->valid) {
@@ -5047,9 +5247,9 @@ float TextServerAdvanced::shaped_text_get_underline_position(RID p_shaped) const
return sd->upos;
}
-float TextServerAdvanced::shaped_text_get_underline_thickness(RID p_shaped) const {
+double TextServerAdvanced::shaped_text_get_underline_thickness(const RID &p_shaped) const {
const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
- ERR_FAIL_COND_V(!sd, 0.f);
+ ERR_FAIL_COND_V(!sd, 0.0);
MutexLock lock(sd->mutex);
if (!sd->valid) {
@@ -5246,7 +5446,7 @@ String TextServerAdvanced::format_number(const String &p_string, const String &p
res.replace("e", num_systems[i].exp);
res.replace("E", num_systems[i].exp);
char32_t *data = res.ptrw();
- for (int j = 0; j < res.size(); j++) {
+ for (int j = 0; j < res.length(); j++) {
if (data[j] >= 0x30 && data[j] <= 0x39) {
data[j] = num_systems[i].digits[data[j] - 0x30];
} else if (data[j] == '.' || data[j] == ',') {
@@ -5270,7 +5470,7 @@ String TextServerAdvanced::parse_number(const String &p_string, const String &p_
}
res.replace(num_systems[i].exp, "e");
char32_t *data = res.ptrw();
- for (int j = 0; j < res.size(); j++) {
+ for (int j = 0; j < res.length(); j++) {
if (data[j] == num_systems[i].digits[10]) {
data[j] = '.';
} else {
@@ -5312,13 +5512,13 @@ String TextServerAdvanced::strip_diacritics(const String &p_string) const {
Char16String utf16 = p_string.utf16();
// Normalize.
- Char16String normalized;
+ Vector<char16_t> normalized;
err = U_ZERO_ERROR;
- int32_t len = unorm2_normalize(unorm, utf16.ptr(), -1, nullptr, 0, &err);
+ int32_t len = unorm2_normalize(unorm, utf16.get_data(), -1, nullptr, 0, &err);
ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, TextServer::strip_diacritics(p_string), u_errorName(err));
normalized.resize(len);
err = U_ZERO_ERROR;
- unorm2_normalize(unorm, utf16.ptr(), -1, normalized.ptrw(), len, &err);
+ unorm2_normalize(unorm, utf16.get_data(), -1, normalized.ptrw(), len, &err);
ERR_FAIL_COND_V_MSG(U_FAILURE(err), TextServer::strip_diacritics(p_string), u_errorName(err));
// Convert back to UTF-32.
@@ -5328,7 +5528,7 @@ String TextServerAdvanced::strip_diacritics(const String &p_string) const {
String result;
for (int i = 0; i < normalized_string.length(); i++) {
if (u_getCombiningClass(normalized_string[i]) == 0) {
- result += normalized_string[i];
+ result = result + normalized_string[i];
}
}
return result;
@@ -5338,13 +5538,13 @@ String TextServerAdvanced::string_to_upper(const String &p_string, const String
// Convert to UTF-16.
Char16String utf16 = p_string.utf16();
- Char16String upper;
+ Vector<char16_t> upper;
UErrorCode err = U_ZERO_ERROR;
- int32_t len = u_strToUpper(nullptr, 0, utf16.ptr(), -1, p_language.ascii().get_data(), &err);
+ int32_t len = u_strToUpper(nullptr, 0, utf16.get_data(), -1, p_language.ascii().get_data(), &err);
ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, p_string, u_errorName(err));
upper.resize(len);
err = U_ZERO_ERROR;
- u_strToUpper(upper.ptrw(), len, utf16.ptr(), -1, p_language.ascii().get_data(), &err);
+ u_strToUpper(upper.ptrw(), len, utf16.get_data(), -1, p_language.ascii().get_data(), &err);
ERR_FAIL_COND_V_MSG(U_FAILURE(err), p_string, u_errorName(err));
// Convert back to UTF-32.
@@ -5355,19 +5555,66 @@ String TextServerAdvanced::string_to_lower(const String &p_string, const String
// Convert to UTF-16.
Char16String utf16 = p_string.utf16();
- Char16String lower;
+ Vector<char16_t> lower;
UErrorCode err = U_ZERO_ERROR;
- int32_t len = u_strToLower(nullptr, 0, utf16.ptr(), -1, p_language.ascii().get_data(), &err);
+ int32_t len = u_strToLower(nullptr, 0, utf16.get_data(), -1, p_language.ascii().get_data(), &err);
ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, p_string, u_errorName(err));
lower.resize(len);
err = U_ZERO_ERROR;
- u_strToLower(lower.ptrw(), len, utf16.ptr(), -1, p_language.ascii().get_data(), &err);
+ u_strToLower(lower.ptrw(), len, utf16.get_data(), -1, p_language.ascii().get_data(), &err);
ERR_FAIL_COND_V_MSG(U_FAILURE(err), p_string, u_errorName(err));
// Convert back to UTF-32.
return String::utf16(lower.ptr(), len);
}
+PackedInt32Array TextServerAdvanced::string_get_word_breaks(const String &p_string, const String &p_language) const {
+ // Convert to UTF-16.
+ Char16String utf16 = p_string.utf16();
+
+ Set<int> breaks;
+ UErrorCode err = U_ZERO_ERROR;
+ UBreakIterator *bi = ubrk_open(UBRK_LINE, p_language.ascii().get_data(), (const UChar *)utf16.ptr(), utf16.length(), &err);
+ if (U_FAILURE(err)) {
+ // No data loaded - use fallback.
+ for (int i = 0; i < p_string.length(); i++) {
+ char32_t c = p_string[i];
+ if (is_whitespace(c) || is_linebreak(c)) {
+ breaks.insert(i);
+ }
+ }
+ } else {
+ while (ubrk_next(bi) != UBRK_DONE) {
+ int pos = _convert_pos(p_string, utf16, ubrk_current(bi)) - 1;
+ if (pos != p_string.length() - 1) {
+ breaks.insert(pos);
+ }
+ }
+ }
+ ubrk_close(bi);
+
+ PackedInt32Array ret;
+ for (int i = 0; i < p_string.length(); i++) {
+ char32_t c = p_string[i];
+ if (c == 0xfffc) {
+ continue;
+ }
+ if (u_ispunct(c) && c != 0x005F) {
+ ret.push_back(i);
+ continue;
+ }
+ if (is_underscore(c)) {
+ ret.push_back(i);
+ continue;
+ }
+ if (breaks.has(i)) {
+ ret.push_back(i);
+ continue;
+ }
+ }
+ return ret;
+}
+
TextServerAdvanced::TextServerAdvanced() {
_insert_num_systems_lang();
_insert_feature_sets();
@@ -5376,14 +5623,8 @@ TextServerAdvanced::TextServerAdvanced() {
TextServerAdvanced::~TextServerAdvanced() {
_bmp_free_font_funcs();
- if (library != nullptr) {
- FT_Done_FreeType(library);
+ if (ft_library != nullptr) {
+ FT_Done_FreeType(ft_library);
}
u_cleanup();
-#ifndef ICU_STATIC_DATA
- if (icu_data != nullptr) {
- memfree(icu_data);
- icu_data = nullptr;
- }
-#endif
}
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index e5958fc162..1b4293aa72 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -36,13 +36,61 @@
/* shaping and advanced font features support. */
/*************************************************************************/
-#include "servers/text_server.h"
+#ifdef GDEXTENSION
+// Headers for building as GDExtension plug-in.
+
+#include <godot_cpp/godot.hpp>
+
+#include <godot_cpp/core/class_db.hpp>
+#include <godot_cpp/core/mutex_lock.hpp>
+
+#include <godot_cpp/variant/array.hpp>
+#include <godot_cpp/variant/dictionary.hpp>
+#include <godot_cpp/variant/packed_int32_array.hpp>
+#include <godot_cpp/variant/packed_string_array.hpp>
+#include <godot_cpp/variant/packed_vector2_array.hpp>
+#include <godot_cpp/variant/rect2.hpp>
+#include <godot_cpp/variant/rid.hpp>
+#include <godot_cpp/variant/string.hpp>
+#include <godot_cpp/variant/vector2.hpp>
+#include <godot_cpp/variant/vector2i.hpp>
+
+#include <godot_cpp/classes/text_server.hpp>
+#include <godot_cpp/classes/text_server_extension.hpp>
+#include <godot_cpp/classes/text_server_manager.hpp>
+
+#include <godot_cpp/classes/caret_info.hpp>
+#include <godot_cpp/classes/global_constants_binds.hpp>
+#include <godot_cpp/classes/glyph.hpp>
+#include <godot_cpp/classes/image.hpp>
+#include <godot_cpp/classes/image_texture.hpp>
+#include <godot_cpp/classes/ref.hpp>
+
+#include <godot_cpp/templates/hash_map.hpp>
+#include <godot_cpp/templates/map.hpp>
+#include <godot_cpp/templates/rid_owner.hpp>
+#include <godot_cpp/templates/set.hpp>
+#include <godot_cpp/templates/thread_work_pool.hpp>
+#include <godot_cpp/templates/vector.hpp>
+
+using namespace godot;
+
+#else
+// Headers for building as built-in module.
#include "core/templates/rid_owner.h"
#include "core/templates/thread_work_pool.h"
#include "scene/resources/texture.h"
+#include "servers/text/text_server_extension.h"
+
+#include "modules/modules_enabled.gen.h" // For freetype, msdfgen.
+
+#endif
+
#include "script_iterator.h"
+// Thirdparty headers.
+
#include <unicode/ubidi.h>
#include <unicode/ubrk.h>
#include <unicode/uchar.h>
@@ -55,8 +103,6 @@
#include <unicode/ustring.h>
#include <unicode/utypes.h>
-#include "modules/modules_enabled.gen.h" // For freetype, msdfgen.
-
#ifdef MODULE_FREETYPE_ENABLED
#include <ft2build.h>
#include FT_FREETYPE_H
@@ -73,12 +119,11 @@
#include <hb-icu.h>
#include <hb.h>
-class TextServerAdvanced : public TextServer {
- GDCLASS(TextServerAdvanced, TextServer);
- _THREAD_SAFE_CLASS_
+/*************************************************************************/
- static String interface_name;
- static uint32_t interface_features;
+class TextServerAdvanced : public TextServerExtension {
+ GDCLASS(TextServerAdvanced, TextServerExtension);
+ _THREAD_SAFE_CLASS_
struct NumSystemData {
Set<StringName> lang;
@@ -89,21 +134,23 @@ class TextServerAdvanced : public TextServer {
Vector<NumSystemData> num_systems;
Map<StringName, int32_t> feature_sets;
+ Map<int32_t, StringName> feature_sets_inv;
void _insert_num_systems_lang();
void _insert_feature_sets();
+ _FORCE_INLINE_ void _insert_feature(const StringName &p_name, int32_t p_tag);
// ICU support data.
- uint8_t *icu_data = nullptr;
+ bool icu_data_loaded = false;
// Font cache data.
#ifdef MODULE_FREETYPE_ENABLED
- mutable FT_Library library = nullptr;
+ mutable FT_Library ft_library = nullptr;
#endif
- const int rect_range = 2;
+ const int rect_range = 1;
struct FontTexture {
Image::Format format;
@@ -112,6 +159,7 @@ class TextServerAdvanced : public TextServer {
int texture_h = 0;
PackedInt32Array offsets;
Ref<ImageTexture> texture;
+ bool dirty = true;
};
struct FontTexturePosition {
@@ -129,12 +177,12 @@ class TextServerAdvanced : public TextServer {
};
struct FontDataForSizeAdvanced {
- float ascent = 0.f;
- float descent = 0.f;
- float underline_position = 0.f;
- float underline_thickness = 0.f;
- float scale = 1.f;
- float oversampling = 1.f;
+ double ascent = 0.0;
+ double descent = 0.0;
+ double underline_position = 0.0;
+ double underline_thickness = 0.0;
+ double scale = 1.0;
+ double oversampling = 1.0;
int spacing_glyph = 0;
int spacing_space = 0;
@@ -168,6 +216,7 @@ class TextServerAdvanced : public TextServer {
Mutex mutex;
bool antialiased = true;
+ bool mipmaps = false;
bool msdf = false;
int msdf_range = 14;
int msdf_source_size = 48;
@@ -176,8 +225,8 @@ class TextServerAdvanced : public TextServer {
TextServer::Hinting hinting = TextServer::HINTING_LIGHT;
TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO;
Dictionary variation_coordinates;
- float oversampling = 0.f;
- float embolden = 0.f;
+ double oversampling = 0.0;
+ double embolden = 0.0;
Transform2D transform;
uint32_t style_flags = 0;
@@ -203,8 +252,8 @@ class TextServerAdvanced : public TextServer {
~FontDataAdvanced() {
work_pool.finish();
- for (const Map<Vector2i, FontDataForSizeAdvanced *>::Element *E = cache.front(); E; E = E->next()) {
- memdelete(E->get());
+ for (const KeyValue<Vector2i, FontDataForSizeAdvanced *> &E : cache) {
+ memdelete(E.value);
}
cache.clear();
}
@@ -242,16 +291,34 @@ class TextServerAdvanced : public TextServer {
}
}
- _FORCE_INLINE_ float _get_extra_advance(RID p_font_rid, int p_font_size) const;
+ _FORCE_INLINE_ double _get_extra_advance(RID p_font_rid, int p_font_size) const;
// Shaped text cache data.
+ struct TrimData {
+ int trim_pos = -1;
+ int ellipsis_pos = -1;
+ Vector<Glyph> ellipsis_glyph_buf;
+ };
+
+ struct ShapedTextDataAdvanced {
+ Mutex mutex;
+
+ /* Source data */
+ RID parent; // Substring parent ShapedTextData.
+
+ int start = 0; // Substring start offset in the parent string.
+ int end = 0; // Substring end offset in the parent string.
+
+ String text;
+ String custom_punct;
+ TextServer::Direction direction = DIRECTION_LTR; // Desired text direction.
+ TextServer::Orientation orientation = ORIENTATION_HORIZONTAL;
- struct ShapedTextDataAdvanced : public ShapedTextData {
struct Span {
int start = -1;
int end = -1;
- Vector<RID> fonts;
+ Array fonts;
int font_size = 0;
Variant embedded_key;
@@ -262,6 +329,38 @@ class TextServerAdvanced : public TextServer {
};
Vector<Span> spans;
+ struct EmbeddedObject {
+ int pos = 0;
+ InlineAlignment inline_align = INLINE_ALIGNMENT_CENTER;
+ Rect2 rect;
+ };
+ Map<Variant, EmbeddedObject> objects;
+
+ /* Shaped data */
+ TextServer::Direction para_direction = DIRECTION_LTR; // Detected text direction.
+ bool valid = false; // String is shaped.
+ bool line_breaks_valid = false; // Line and word break flags are populated (and virtual zero width spaces inserted).
+ bool justification_ops_valid = false; // Virtual elongation glyphs are added to the string.
+ bool sort_valid = false;
+ bool text_trimmed = false;
+
+ bool preserve_invalid = true; // Draw hex code box instead of missing characters.
+ bool preserve_control = false; // Draw control characters.
+
+ double ascent = 0.0; // Ascent for horizontal layout, 1/2 of width for vertical.
+ double descent = 0.0; // Descent for horizontal layout, 1/2 of width for vertical.
+ double width = 0.0; // Width for horizontal layout, height for vertical.
+ double width_trimmed = 0.0;
+
+ double upos = 0.0;
+ double uthk = 0.0;
+
+ TrimData overrun_trim_data;
+ bool fit_width_minimum_reached = false;
+
+ Vector<Glyph> glyphs;
+ Vector<Glyph> glyphs_logical;
+
/* Intermediate data */
Char16String utf16;
Vector<UBiDi *> bidi_iter;
@@ -289,16 +388,18 @@ class TextServerAdvanced : public TextServer {
// Common data.
- float oversampling = 1.f;
+ double oversampling = 1.0;
mutable RID_PtrOwner<FontDataAdvanced> font_owner;
mutable RID_PtrOwner<ShapedTextDataAdvanced> shaped_owner;
void _realign(ShapedTextDataAdvanced *p_sd) const;
- int _convert_pos(const ShapedTextDataAdvanced *p_sd, int p_pos) const;
- int _convert_pos_inv(const ShapedTextDataAdvanced *p_sd, int p_pos) const;
- bool _shape_substr(ShapedTextDataAdvanced *p_new_sd, const ShapedTextDataAdvanced *p_sd, int p_start, int p_length) const;
- void _shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_start, int32_t p_end, hb_script_t p_script, hb_direction_t p_direction, Vector<RID> p_fonts, int p_span, int p_fb_index);
- Glyph _shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, RID p_font, int p_font_size);
+ int64_t _convert_pos(const String &p_utf32, const Char16String &p_utf16, int64_t p_pos) const;
+ int64_t _convert_pos(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const;
+ int64_t _convert_pos_inv(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const;
+ bool _shape_substr(ShapedTextDataAdvanced *p_new_sd, const ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_length) const;
+ void _shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_end, hb_script_t p_script, hb_direction_t p_direction, Array p_fonts, int64_t p_span, int64_t p_fb_index);
+ Glyph _shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, const RID &p_font, int64_t p_font_size);
+
_FORCE_INLINE_ void _add_featuers(const Dictionary &p_source, Vector<hb_feature_t> &r_ftrs);
// HarfBuzz bitmap font interface.
@@ -324,6 +425,25 @@ class TextServerAdvanced : public TextServer {
static void _bmp_font_set_funcs(hb_font_t *p_font, TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref);
static hb_font_t *_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, hb_destroy_func_t p_destroy);
+ hb_font_t *_font_get_hb_handle(const RID &p_font, int64_t p_font_size) const;
+
+ struct GlyphCompare { // For line breaking reordering.
+ _FORCE_INLINE_ bool operator()(const Glyph &l, const Glyph &r) const {
+ if (l.start == r.start) {
+ if (l.count == r.count) {
+ if ((l.flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ return l.count > r.count; // Sort first glyph with count & flags, order of the rest are irrelevant.
+ } else {
+ return l.start < r.start;
+ }
+ }
+ };
+
protected:
static void _bind_methods(){};
@@ -333,10 +453,10 @@ protected:
public:
virtual bool has_feature(Feature p_feature) const override;
virtual String get_name() const override;
- virtual uint32_t get_features() const override;
+ virtual int64_t get_features() const override;
- virtual void free(RID p_rid) override;
- virtual bool has(RID p_rid) override;
+ virtual void free_rid(const RID &p_rid) override;
+ virtual bool has(const RID &p_rid) override;
virtual bool load_support_data(const String &p_filename) override;
virtual String get_support_data_filename() const override;
@@ -345,225 +465,231 @@ public:
virtual bool is_locale_right_to_left(const String &p_locale) const override;
- virtual int32_t name_to_tag(const String &p_name) const override;
- virtual String tag_to_name(int32_t p_tag) const override;
+ virtual int64_t name_to_tag(const String &p_name) const override;
+ virtual String tag_to_name(int64_t p_tag) const override;
/* Font interface */
virtual RID create_font() override;
- virtual void font_set_data(RID p_font_rid, const PackedByteArray &p_data) override;
- virtual void font_set_data_ptr(RID p_font_rid, const uint8_t *p_data_ptr, size_t p_data_size) override;
+ virtual void font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) override;
+ virtual void font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) override;
- virtual void font_set_style(RID p_font_rid, uint32_t /*FontStyle*/ p_style) override;
- virtual uint32_t /*FontStyle*/ font_get_style(RID p_font_rid) const override;
+ virtual void font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) override;
+ virtual int64_t /*FontStyle*/ font_get_style(const RID &p_font_rid) const override;
- virtual void font_set_style_name(RID p_font_rid, const String &p_name) override;
- virtual String font_get_style_name(RID p_font_rid) const override;
+ virtual void font_set_style_name(const RID &p_font_rid, const String &p_name) override;
+ virtual String font_get_style_name(const RID &p_font_rid) const override;
- virtual void font_set_name(RID p_font_rid, const String &p_name) override;
- virtual String font_get_name(RID p_font_rid) const override;
+ virtual void font_set_name(const RID &p_font_rid, const String &p_name) override;
+ virtual String font_get_name(const RID &p_font_rid) const override;
- virtual void font_set_antialiased(RID p_font_rid, bool p_antialiased) override;
- virtual bool font_is_antialiased(RID p_font_rid) const override;
+ virtual void font_set_antialiased(const RID &p_font_rid, bool p_antialiased) override;
+ virtual bool font_is_antialiased(const RID &p_font_rid) const override;
- virtual void font_set_multichannel_signed_distance_field(RID p_font_rid, bool p_msdf) override;
- virtual bool font_is_multichannel_signed_distance_field(RID p_font_rid) const override;
+ virtual void font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) override;
+ virtual bool font_get_generate_mipmaps(const RID &p_font_rid) const override;
- virtual void font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pixel_range) override;
- virtual int font_get_msdf_pixel_range(RID p_font_rid) const override;
+ virtual void font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) override;
+ virtual bool font_is_multichannel_signed_distance_field(const RID &p_font_rid) const override;
- virtual void font_set_msdf_size(RID p_font_rid, int p_msdf_size) override;
- virtual int font_get_msdf_size(RID p_font_rid) const override;
+ virtual void font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) override;
+ virtual int64_t font_get_msdf_pixel_range(const RID &p_font_rid) const override;
- virtual void font_set_fixed_size(RID p_font_rid, int p_fixed_size) override;
- virtual int font_get_fixed_size(RID p_font_rid) const override;
+ virtual void font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) override;
+ virtual int64_t font_get_msdf_size(const RID &p_font_rid) const override;
- virtual void font_set_force_autohinter(RID p_font_rid, bool p_force_autohinter) override;
- virtual bool font_is_force_autohinter(RID p_font_rid) const override;
+ virtual void font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) override;
+ virtual int64_t font_get_fixed_size(const RID &p_font_rid) const override;
- virtual void font_set_hinting(RID p_font_rid, TextServer::Hinting p_hinting) override;
- virtual TextServer::Hinting font_get_hinting(RID p_font_rid) const override;
+ virtual void font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) override;
+ virtual bool font_is_force_autohinter(const RID &p_font_rid) const override;
- virtual void font_set_subpixel_positioning(RID p_font_rid, SubpixelPositioning p_subpixel) override;
- virtual SubpixelPositioning font_get_subpixel_positioning(RID p_font_rid) const override;
+ virtual void font_set_subpixel_positioning(const RID &p_font_rid, SubpixelPositioning p_subpixel) override;
+ virtual SubpixelPositioning font_get_subpixel_positioning(const RID &p_font_rid) const override;
- virtual void font_set_embolden(RID p_font_rid, float p_strength) override;
- virtual float font_get_embolden(RID p_font_rid) const override;
+ virtual void font_set_embolden(const RID &p_font_rid, double p_strength) override;
+ virtual double font_get_embolden(const RID &p_font_rid) const override;
- virtual void font_set_transform(RID p_font_rid, Transform2D p_transform) override;
- virtual Transform2D font_get_transform(RID p_font_rid) const override;
+ virtual void font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) override;
+ virtual Transform2D font_get_transform(const RID &p_font_rid) const override;
- virtual void font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) override;
- virtual Dictionary font_get_variation_coordinates(RID p_font_rid) const override;
+ virtual void font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) override;
+ virtual Dictionary font_get_variation_coordinates(const RID &p_font_rid) const override;
- virtual void font_set_oversampling(RID p_font_rid, float p_oversampling) override;
- virtual float font_get_oversampling(RID p_font_rid) const override;
+ virtual void font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) override;
+ virtual TextServer::Hinting font_get_hinting(const RID &p_font_rid) const override;
- virtual Array font_get_size_cache_list(RID p_font_rid) const override;
- virtual void font_clear_size_cache(RID p_font_rid) override;
- virtual void font_remove_size_cache(RID p_font_rid, const Vector2i &p_size) override;
+ virtual void font_set_oversampling(const RID &p_font_rid, double p_oversampling) override;
+ virtual double font_get_oversampling(const RID &p_font_rid) const override;
- hb_font_t *_font_get_hb_handle(RID p_font, int p_font_size) const;
+ virtual Array font_get_size_cache_list(const RID &p_font_rid) const override;
+ virtual void font_clear_size_cache(const RID &p_font_rid) override;
+ virtual void font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) override;
- virtual void font_set_ascent(RID p_font_rid, int p_size, float p_ascent) override;
- virtual float font_get_ascent(RID p_font_rid, int p_size) const override;
+ virtual void font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) override;
+ virtual double font_get_ascent(const RID &p_font_rid, int64_t p_size) const override;
- virtual void font_set_descent(RID p_font_rid, int p_size, float p_descent) override;
- virtual float font_get_descent(RID p_font_rid, int p_size) const override;
+ virtual void font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) override;
+ virtual double font_get_descent(const RID &p_font_rid, int64_t p_size) const override;
- virtual void font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) override;
- virtual float font_get_underline_position(RID p_font_rid, int p_size) const override;
+ virtual void font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) override;
+ virtual double font_get_underline_position(const RID &p_font_rid, int64_t p_size) const override;
- virtual void font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) override;
- virtual float font_get_underline_thickness(RID p_font_rid, int p_size) const override;
+ virtual void font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) override;
+ virtual double font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const override;
- virtual void font_set_scale(RID p_font_rid, int p_size, float p_scale) override;
- virtual float font_get_scale(RID p_font_rid, int p_size) const override;
+ virtual void font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) override;
+ virtual double font_get_scale(const RID &p_font_rid, int64_t p_size) const override;
- virtual void font_set_spacing(RID p_font_rid, int p_size, SpacingType p_spacing, int p_value) override;
- virtual int font_get_spacing(RID p_font_rid, int p_size, SpacingType p_spacing) const override;
+ virtual void font_set_spacing(const RID &p_font_rid, int64_t p_size, SpacingType p_spacing, int64_t p_value) override;
+ virtual int64_t font_get_spacing(const RID &p_font_rid, int64_t p_size, SpacingType p_spacing) const override;
- virtual int font_get_texture_count(RID p_font_rid, const Vector2i &p_size) const override;
- virtual void font_clear_textures(RID p_font_rid, const Vector2i &p_size) override;
- virtual void font_remove_texture(RID p_font_rid, const Vector2i &p_size, int p_texture_index) override;
+ virtual int64_t font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const override;
+ virtual void font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) override;
+ virtual void font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) override;
- virtual void font_set_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) override;
- virtual Ref<Image> font_get_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const override;
+ virtual void font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) override;
+ virtual Ref<Image> font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const override;
- virtual void font_set_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) override;
- virtual PackedInt32Array font_get_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const override;
+ virtual void font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) override;
+ virtual PackedInt32Array font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const override;
- virtual Array font_get_glyph_list(RID p_font_rid, const Vector2i &p_size) const override;
- virtual void font_clear_glyphs(RID p_font_rid, const Vector2i &p_size) override;
- virtual void font_remove_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) override;
+ virtual Array font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const override;
+ virtual void font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) override;
+ virtual void font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) override;
- virtual Vector2 font_get_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph) const override;
- virtual void font_set_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph, const Vector2 &p_advance) override;
+ virtual Vector2 font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const override;
+ virtual void font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) override;
- virtual Vector2 font_get_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
- virtual void font_set_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) override;
+ virtual Vector2 font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override;
+ virtual void font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) override;
- virtual Vector2 font_get_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
- virtual void font_set_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) override;
+ virtual Vector2 font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override;
+ virtual void font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) override;
- virtual Rect2 font_get_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
- virtual void font_set_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) override;
+ virtual Rect2 font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override;
+ virtual void font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) override;
- virtual int font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
- virtual void font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) override;
+ virtual int64_t font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override;
+ virtual void font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) override;
- virtual Dictionary font_get_glyph_contours(RID p_font, int p_size, int32_t p_index) const override;
+ virtual RID font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override;
+ virtual Size2 font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override;
- virtual Array font_get_kerning_list(RID p_font_rid, int p_size) const override;
- virtual void font_clear_kerning_map(RID p_font_rid, int p_size) override;
- virtual void font_remove_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) override;
+ virtual Dictionary font_get_glyph_contours(const RID &p_font, int64_t p_size, int64_t p_index) const override;
- virtual void font_set_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) override;
- virtual Vector2 font_get_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) const override;
+ virtual Array font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const override;
+ virtual void font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) override;
+ virtual void font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) override;
- virtual int32_t font_get_glyph_index(RID p_font_rid, int p_size, char32_t p_char, char32_t p_variation_selector = 0) const override;
+ virtual void font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) override;
+ virtual Vector2 font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const override;
- virtual bool font_has_char(RID p_font_rid, char32_t p_char) const override;
- virtual String font_get_supported_chars(RID p_font_rid) const override;
+ virtual int64_t font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector = 0) const override;
- virtual void font_render_range(RID p_font, const Vector2i &p_size, char32_t p_start, char32_t p_end) override;
- virtual void font_render_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_index) override;
+ virtual bool font_has_char(const RID &p_font_rid, int64_t p_char) const override;
+ virtual String font_get_supported_chars(const RID &p_font_rid) const override;
- virtual void font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
- virtual void font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
+ virtual void font_render_range(const RID &p_font, const Vector2i &p_size, int64_t p_start, int64_t p_end) override;
+ virtual void font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) override;
- virtual bool font_is_language_supported(RID p_font_rid, const String &p_language) const override;
- virtual void font_set_language_support_override(RID p_font_rid, const String &p_language, bool p_supported) override;
- virtual bool font_get_language_support_override(RID p_font_rid, const String &p_language) override;
- virtual void font_remove_language_support_override(RID p_font_rid, const String &p_language) override;
- virtual Vector<String> font_get_language_support_overrides(RID p_font_rid) override;
+ virtual void font_draw_glyph(const RID &p_font, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
+ virtual void font_draw_glyph_outline(const RID &p_font, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
- virtual bool font_is_script_supported(RID p_font_rid, const String &p_script) const override;
- virtual void font_set_script_support_override(RID p_font_rid, const String &p_script, bool p_supported) override;
- virtual bool font_get_script_support_override(RID p_font_rid, const String &p_script) override;
- virtual void font_remove_script_support_override(RID p_font_rid, const String &p_script) override;
- virtual Vector<String> font_get_script_support_overrides(RID p_font_rid) override;
+ virtual bool font_is_language_supported(const RID &p_font_rid, const String &p_language) const override;
+ virtual void font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) override;
+ virtual bool font_get_language_support_override(const RID &p_font_rid, const String &p_language) override;
+ virtual void font_remove_language_support_override(const RID &p_font_rid, const String &p_language) override;
+ virtual PackedStringArray font_get_language_support_overrides(const RID &p_font_rid) override;
- virtual void font_set_opentype_feature_overrides(RID p_font_rid, const Dictionary &p_overrides) override;
- virtual Dictionary font_get_opentype_feature_overrides(RID p_font_rid) const override;
+ virtual bool font_is_script_supported(const RID &p_font_rid, const String &p_script) const override;
+ virtual void font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) override;
+ virtual bool font_get_script_support_override(const RID &p_font_rid, const String &p_script) override;
+ virtual void font_remove_script_support_override(const RID &p_font_rid, const String &p_script) override;
+ virtual PackedStringArray font_get_script_support_overrides(const RID &p_font_rid) override;
- virtual Dictionary font_supported_feature_list(RID p_font_rid) const override;
- virtual Dictionary font_supported_variation_list(RID p_font_rid) const override;
+ virtual void font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) override;
+ virtual Dictionary font_get_opentype_feature_overrides(const RID &p_font_rid) const override;
- virtual float font_get_global_oversampling() const override;
- virtual void font_set_global_oversampling(float p_oversampling) override;
+ virtual Dictionary font_supported_feature_list(const RID &p_font_rid) const override;
+ virtual Dictionary font_supported_variation_list(const RID &p_font_rid) const override;
+
+ virtual double font_get_global_oversampling() const override;
+ virtual void font_set_global_oversampling(double p_oversampling) override;
/* Shaped text buffer interface */
virtual RID create_shaped_text(Direction p_direction = DIRECTION_AUTO, Orientation p_orientation = ORIENTATION_HORIZONTAL) override;
- virtual void shaped_text_clear(RID p_shaped) override;
+ virtual void shaped_text_clear(const RID &p_shaped) override;
- virtual void shaped_text_set_direction(RID p_shaped, Direction p_direction = DIRECTION_AUTO) override;
- virtual Direction shaped_text_get_direction(RID p_shaped) const override;
- virtual Direction shaped_text_get_inferred_direction(RID p_shaped) const override;
+ virtual void shaped_text_set_direction(const RID &p_shaped, Direction p_direction = DIRECTION_AUTO) override;
+ virtual Direction shaped_text_get_direction(const RID &p_shaped) const override;
+ virtual Direction shaped_text_get_inferred_direction(const RID &p_shaped) const override;
- virtual void shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) override;
+ virtual void shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) override;
- virtual void shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) override;
- virtual String shaped_text_get_custom_punctuation(RID p_shaped) const override;
+ virtual void shaped_text_set_custom_punctuation(const RID &p_shaped, const String &p_punct) override;
+ virtual String shaped_text_get_custom_punctuation(const RID &p_shaped) const override;
- virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override;
- virtual Orientation shaped_text_get_orientation(RID p_shaped) const override;
+ virtual void shaped_text_set_orientation(const RID &p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override;
+ virtual Orientation shaped_text_get_orientation(const RID &p_shaped) const override;
- virtual void shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) override;
- virtual bool shaped_text_get_preserve_invalid(RID p_shaped) const override;
+ virtual void shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) override;
+ virtual bool shaped_text_get_preserve_invalid(const RID &p_shaped) const override;
- virtual void shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) override;
- virtual bool shaped_text_get_preserve_control(RID p_shaped) const override;
+ virtual void shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) override;
+ virtual bool shaped_text_get_preserve_control(const RID &p_shaped) const override;
- virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant()) override;
- virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int p_length = 1) override;
- virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER) override;
+ virtual bool shaped_text_add_string(const RID &p_shaped, const String &p_text, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant()) override;
+ virtual bool shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int64_t p_length = 1) override;
+ virtual bool shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER) override;
- virtual int shaped_get_span_count(RID p_shaped) const override;
- virtual Variant shaped_get_span_meta(RID p_shaped, int p_index) const override;
- virtual void shaped_set_span_update_font(RID p_shaped, int p_index, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary()) override;
+ virtual int64_t shaped_get_span_count(const RID &p_shaped) const override;
+ virtual Variant shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const override;
+ virtual void shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary()) override;
- virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override;
- virtual RID shaped_text_get_parent(RID p_shaped) const override;
+ virtual RID shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const override;
+ virtual RID shaped_text_get_parent(const RID &p_shaped) const override;
- virtual float shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override;
- virtual float shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) override;
+ virtual double shaped_text_fit_to_width(const RID &p_shaped, double p_width, int64_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override;
+ virtual double shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) override;
- virtual bool shaped_text_shape(RID p_shaped) override;
- virtual bool shaped_text_update_breaks(RID p_shaped) override;
- virtual bool shaped_text_update_justification_ops(RID p_shaped) override;
+ virtual bool shaped_text_shape(const RID &p_shaped) override;
+ virtual bool shaped_text_update_breaks(const RID &p_shaped) override;
+ virtual bool shaped_text_update_justification_ops(const RID &p_shaped) override;
- virtual int shaped_text_get_trim_pos(RID p_shaped) const override;
- virtual int shaped_text_get_ellipsis_pos(RID p_shaped) const override;
- virtual const Glyph *shaped_text_get_ellipsis_glyphs(RID p_shaped) const override;
- virtual int shaped_text_get_ellipsis_glyph_count(RID p_shaped) const override;
+ virtual int64_t shaped_text_get_trim_pos(const RID &p_shaped) const override;
+ virtual int64_t shaped_text_get_ellipsis_pos(const RID &p_shaped) const override;
+ virtual const Glyph *shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const override;
+ virtual int64_t shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const override;
- virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint16_t p_trim_flags) override;
+ virtual void shaped_text_overrun_trim_to_width(const RID &p_shaped, double p_width, int64_t p_trim_flags) override;
- virtual bool shaped_text_is_ready(RID p_shaped) const override;
+ virtual bool shaped_text_is_ready(const RID &p_shaped) const override;
- virtual const Glyph *shaped_text_get_glyphs(RID p_shaped) const override;
- virtual const Glyph *shaped_text_sort_logical(RID p_shaped) override;
- virtual int shaped_text_get_glyph_count(RID p_shaped) const override;
+ virtual const Glyph *shaped_text_get_glyphs(const RID &p_shaped) const override;
+ virtual const Glyph *shaped_text_sort_logical(const RID &p_shaped) override;
+ virtual int64_t shaped_text_get_glyph_count(const RID &p_shaped) const override;
- virtual Vector2i shaped_text_get_range(RID p_shaped) const override;
+ virtual Vector2i shaped_text_get_range(const RID &p_shaped) const override;
- virtual Array shaped_text_get_objects(RID p_shaped) const override;
- virtual Rect2 shaped_text_get_object_rect(RID p_shaped, Variant p_key) const override;
+ virtual Array shaped_text_get_objects(const RID &p_shaped) const override;
+ virtual Rect2 shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const override;
- virtual Size2 shaped_text_get_size(RID p_shaped) const override;
- virtual float shaped_text_get_ascent(RID p_shaped) const override;
- virtual float shaped_text_get_descent(RID p_shaped) const override;
- virtual float shaped_text_get_width(RID p_shaped) const override;
- virtual float shaped_text_get_underline_position(RID p_shaped) const override;
- virtual float shaped_text_get_underline_thickness(RID p_shaped) const override;
+ virtual Size2 shaped_text_get_size(const RID &p_shaped) const override;
+ virtual double shaped_text_get_ascent(const RID &p_shaped) const override;
+ virtual double shaped_text_get_descent(const RID &p_shaped) const override;
+ virtual double shaped_text_get_width(const RID &p_shaped) const override;
+ virtual double shaped_text_get_underline_position(const RID &p_shaped) const override;
+ virtual double shaped_text_get_underline_thickness(const RID &p_shaped) const override;
virtual String format_number(const String &p_string, const String &p_language = "") const override;
virtual String parse_number(const String &p_string, const String &p_language = "") const override;
virtual String percent_sign(const String &p_language = "") const override;
+ virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "") const override;
+
virtual String strip_diacritics(const String &p_string) const override;
virtual String string_to_upper(const String &p_string, const String &p_language = "") const override;
diff --git a/modules/text_server_fb/.gitignore b/modules/text_server_fb/.gitignore
new file mode 100644
index 0000000000..15cc38b59c
--- /dev/null
+++ b/modules/text_server_fb/.gitignore
@@ -0,0 +1,2 @@
+# Godot-cpp headers
+gdextension_build/godot-cpp
diff --git a/modules/text_server_fb/SCsub b/modules/text_server_fb/SCsub
index 31d1db6167..121f38fcd5 100644
--- a/modules/text_server_fb/SCsub
+++ b/modules/text_server_fb/SCsub
@@ -4,22 +4,14 @@ Import("env")
Import("env_modules")
freetype_enabled = env.module_check_dependencies("text_server_fb", ["freetype"], True)
-msdngen_enabled = env.module_check_dependencies("text_server_fb", ["msdfgen"], True)
+msdfgen_enabled = env.module_check_dependencies("text_server_fb", ["msdfgen"], True)
env_text_server_fb = env_modules.Clone()
-if msdngen_enabled:
- env_text_server_fb.Append(
- CPPPATH=[
- "#thirdparty/msdfgen",
- ]
- )
+if env["builtin_msdfgen"] and msdfgen_enabled:
+ env_text_server_fb.Append(CPPPATH=["#thirdparty/msdfgen"])
-if freetype_enabled:
- env_text_server_fb.Append(
- CPPPATH=[
- "#thirdparty/freetype/include",
- ]
- )
+if env["builtin_freetype"] and freetype_enabled:
+ env_text_server_fb.Append(CPPPATH=["#thirdparty/freetype/include"])
env_text_server_fb.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/text_server_fb/doc_classes/TextServerFallback.xml b/modules/text_server_fb/doc_classes/TextServerFallback.xml
index 76194a7bda..950b64e49f 100644
--- a/modules/text_server_fb/doc_classes/TextServerFallback.xml
+++ b/modules/text_server_fb/doc_classes/TextServerFallback.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TextServerFallback" inherits="TextServer" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="TextServerFallback" inherits="TextServerExtension" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Fallback implementation of the Text Server, without BiDi and complex text layout support.
</brief_description>
diff --git a/modules/text_server_fb/gdextension_build/SConstruct b/modules/text_server_fb/gdextension_build/SConstruct
new file mode 100644
index 0000000000..1753bc8b86
--- /dev/null
+++ b/modules/text_server_fb/gdextension_build/SConstruct
@@ -0,0 +1,205 @@
+#!/usr/bin/env python
+import atexit
+import os
+import sys
+import methods
+import time
+
+# For the reference:
+# - CCFLAGS are compilation flags shared between C and C++
+# - CFLAGS are for C-specific compilation flags
+# - CXXFLAGS are for C++-specific compilation flags
+# - CPPFLAGS are for pre-processor flags
+# - CPPDEFINES are for pre-processor defines
+# - LINKFLAGS are for linking flags
+
+time_at_start = time.time()
+
+env = SConscript("./godot-cpp/SConstruct")
+env.__class__.disable_warnings = methods.disable_warnings
+
+opts = Variables([], ARGUMENTS)
+opts.Add(BoolVariable("freetype_enabled", "Use FreeType library", True))
+opts.Add(BoolVariable("msdfgen_enabled", "Use MSDFgen library (require FreeType)", True))
+opts.Add(BoolVariable("verbose", "Enable verbose output for the compilation", False))
+
+opts.Update(env)
+
+if not env["verbose"]:
+ methods.no_verbose(sys, env)
+
+# MSDFGEN
+if env["msdfgen_enabled"] and env["freetype_enabled"]:
+ env_msdfgen = env.Clone()
+ env_msdfgen.disable_warnings()
+
+ thirdparty_msdfgen_dir = "../../../thirdparty/msdfgen/"
+ thirdparty_msdfgen_sources = [
+ "core/Contour.cpp",
+ "core/EdgeHolder.cpp",
+ "core/MSDFErrorCorrection.cpp",
+ "core/Projection.cpp",
+ "core/Scanline.cpp",
+ "core/Shape.cpp",
+ "core/SignedDistance.cpp",
+ "core/Vector2.cpp",
+ "core/contour-combiners.cpp",
+ "core/edge-coloring.cpp",
+ "core/edge-segments.cpp",
+ "core/edge-selectors.cpp",
+ "core/equation-solver.cpp",
+ "core/msdf-error-correction.cpp",
+ "core/msdfgen.cpp",
+ "core/rasterization.cpp",
+ "core/render-sdf.cpp",
+ "core/sdf-error-estimation.cpp",
+ "core/shape-description.cpp",
+ ]
+ thirdparty_msdfgen_sources = [thirdparty_msdfgen_dir + file for file in thirdparty_msdfgen_sources]
+
+ env_msdfgen.Append(CPPPATH=["../../../thirdparty/freetype/include", "../../../thirdparty/msdfgen"])
+ env.Append(CPPPATH=["../../../thirdparty/msdfgen"])
+ env.Append(CPPDEFINES=["MODULE_MSDFGEN_ENABLED"])
+
+ lib = env_msdfgen.Library(
+ f'msdfgen_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}',
+ thirdparty_msdfgen_sources,
+ )
+ env.Append(LIBS=[lib])
+
+# FreeType
+if env["freetype_enabled"]:
+ env_freetype = env.Clone()
+ env_freetype.disable_warnings()
+
+ thirdparty_freetype_dir = "../../../thirdparty/freetype/"
+ thirdparty_freetype_sources = [
+ "src/autofit/autofit.c",
+ "src/base/ftbase.c",
+ "src/base/ftbbox.c",
+ "src/base/ftbdf.c",
+ "src/base/ftbitmap.c",
+ "src/base/ftcid.c",
+ "src/base/ftdebug.c",
+ "src/base/ftfstype.c",
+ "src/base/ftgasp.c",
+ "src/base/ftglyph.c",
+ "src/base/ftgxval.c",
+ "src/base/ftinit.c",
+ "src/base/ftmm.c",
+ "src/base/ftotval.c",
+ "src/base/ftpatent.c",
+ "src/base/ftpfr.c",
+ "src/base/ftstroke.c",
+ "src/base/ftsynth.c",
+ "src/base/ftsystem.c",
+ "src/base/fttype1.c",
+ "src/base/ftwinfnt.c",
+ "src/bdf/bdf.c",
+ "src/bzip2/ftbzip2.c",
+ "src/cache/ftcache.c",
+ "src/cff/cff.c",
+ "src/cid/type1cid.c",
+ "src/gxvalid/gxvalid.c",
+ "src/gzip/ftgzip.c",
+ "src/lzw/ftlzw.c",
+ "src/otvalid/otvalid.c",
+ "src/pcf/pcf.c",
+ "src/pfr/pfr.c",
+ "src/psaux/psaux.c",
+ "src/pshinter/pshinter.c",
+ "src/psnames/psnames.c",
+ "src/raster/raster.c",
+ "src/sdf/sdf.c",
+ "src/smooth/smooth.c",
+ "src/truetype/truetype.c",
+ "src/type1/type1.c",
+ "src/type42/type42.c",
+ "src/winfonts/winfnt.c",
+ "src/sfnt/sfnt.c",
+ ]
+ thirdparty_freetype_sources = [thirdparty_freetype_dir + file for file in thirdparty_freetype_sources]
+
+ thirdparty_png_dir = "../../../thirdparty/libpng/"
+ thirdparty_png_sources = [
+ "png.c",
+ "pngerror.c",
+ "pngget.c",
+ "pngmem.c",
+ "pngpread.c",
+ "pngread.c",
+ "pngrio.c",
+ "pngrtran.c",
+ "pngrutil.c",
+ "pngset.c",
+ "pngtrans.c",
+ "pngwio.c",
+ "pngwrite.c",
+ "pngwtran.c",
+ "pngwutil.c",
+ ]
+ thirdparty_freetype_sources += [thirdparty_png_dir + file for file in thirdparty_png_sources]
+
+ thirdparty_zlib_dir = "../../../thirdparty/zlib/"
+ thirdparty_zlib_sources = [
+ "adler32.c",
+ "compress.c",
+ "crc32.c",
+ "deflate.c",
+ "infback.c",
+ "inffast.c",
+ "inflate.c",
+ "inftrees.c",
+ "trees.c",
+ "uncompr.c",
+ "zutil.c",
+ ]
+ thirdparty_freetype_sources += [thirdparty_zlib_dir + file for file in thirdparty_zlib_sources]
+
+ env_freetype.Append(CPPPATH=[thirdparty_freetype_dir + "/include", thirdparty_zlib_dir, thirdparty_png_dir])
+ env.Append(CPPPATH=[thirdparty_freetype_dir + "/include"])
+
+ env_freetype.Append(CPPDEFINES=["FT2_BUILD_LIBRARY", "FT_CONFIG_OPTION_USE_PNG", ("PNG_ARM_NEON_OPT", 0)])
+ if env["target"] == "debug":
+ env_freetype.Append(CPPDEFINES=["ZLIB_DEBUG"])
+
+ env.Append(CPPDEFINES=["MODULE_FREETYPE_ENABLED"])
+
+ lib = env_freetype.Library(
+ f'freetype_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}',
+ thirdparty_freetype_sources,
+ )
+ env.Append(LIBS=[lib])
+
+
+env.Append(CPPDEFINES=["GDEXTENSION"])
+env.Append(CPPPATH=["../"])
+sources = Glob("../*.cpp")
+
+if env["platform"] == "osx":
+ methods.write_osx_plist(
+ f'./bin/libtextserver_fallback.osx.{env["target"]}.framework',
+ f'libtextserver_fallback.osx.{env["target"]}',
+ "org.godotengine.textserver_fallback",
+ "Fallback Text Server",
+ )
+ library = env.SharedLibrary(
+ f'./bin/libtextserver_fallback.osx.{env["target"]}.framework/libtextserver_fallback.osx.{env["target"]}',
+ source=sources,
+ )
+else:
+ library = env.SharedLibrary(
+ f'./bin/libtextserver_fallback.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["SHLIBSUFFIX"]}',
+ source=sources,
+ )
+
+Default(library)
+
+
+def print_elapsed_time():
+ elapsed_time_sec = round(time.time() - time_at_start, 3)
+ time_ms = round((elapsed_time_sec % 1) * 1000)
+ print("[Time elapsed: {}.{:03}]".format(time.strftime("%H:%M:%S", time.gmtime(elapsed_time_sec)), time_ms))
+
+
+atexit.register(print_elapsed_time)
diff --git a/modules/text_server_fb/gdextension_build/methods.py b/modules/text_server_fb/gdextension_build/methods.py
new file mode 100644
index 0000000000..d404f2851e
--- /dev/null
+++ b/modules/text_server_fb/gdextension_build/methods.py
@@ -0,0 +1,130 @@
+import os
+import sys
+
+
+def no_verbose(sys, env):
+ colors = {}
+
+ # Colors are disabled in non-TTY environments such as pipes. This means
+ # that if output is redirected to a file, it will not contain color codes
+ if sys.stdout.isatty():
+ colors["blue"] = "\033[0;94m"
+ colors["bold_blue"] = "\033[1;94m"
+ colors["reset"] = "\033[0m"
+ else:
+ colors["blue"] = ""
+ colors["bold_blue"] = ""
+ colors["reset"] = ""
+
+ # There is a space before "..." to ensure that source file names can be
+ # Ctrl + clicked in the VS Code terminal.
+ compile_source_message = "{}Compiling {}$SOURCE{} ...{}".format(
+ colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
+ )
+ java_compile_source_message = "{}Compiling {}$SOURCE{} ...{}".format(
+ colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
+ )
+ compile_shared_source_message = "{}Compiling shared {}$SOURCE{} ...{}".format(
+ colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
+ )
+ link_program_message = "{}Linking Program {}$TARGET{} ...{}".format(
+ colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
+ )
+ link_library_message = "{}Linking Static Library {}$TARGET{} ...{}".format(
+ colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
+ )
+ ranlib_library_message = "{}Ranlib Library {}$TARGET{} ...{}".format(
+ colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
+ )
+ link_shared_library_message = "{}Linking Shared Library {}$TARGET{} ...{}".format(
+ colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
+ )
+ java_library_message = "{}Creating Java Archive {}$TARGET{} ...{}".format(
+ colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
+ )
+
+ env.Append(CXXCOMSTR=[compile_source_message])
+ env.Append(CCCOMSTR=[compile_source_message])
+ env.Append(SHCCCOMSTR=[compile_shared_source_message])
+ env.Append(SHCXXCOMSTR=[compile_shared_source_message])
+ env.Append(ARCOMSTR=[link_library_message])
+ env.Append(RANLIBCOMSTR=[ranlib_library_message])
+ env.Append(SHLINKCOMSTR=[link_shared_library_message])
+ env.Append(LINKCOMSTR=[link_program_message])
+ env.Append(JARCOMSTR=[java_library_message])
+ env.Append(JAVACCOMSTR=[java_compile_source_message])
+
+
+def disable_warnings(self):
+ # 'self' is the environment
+ if self["platform"] == "windows" and not self["use_mingw"]:
+ # We have to remove existing warning level defines before appending /w,
+ # otherwise we get: "warning D9025 : overriding '/W3' with '/w'"
+ warn_flags = ["/Wall", "/W4", "/W3", "/W2", "/W1", "/WX"]
+ self.Append(CCFLAGS=["/w"])
+ self.Append(CFLAGS=["/w"])
+ self.Append(CXXFLAGS=["/w"])
+ self["CCFLAGS"] = [x for x in self["CCFLAGS"] if not x in warn_flags]
+ self["CFLAGS"] = [x for x in self["CFLAGS"] if not x in warn_flags]
+ self["CXXFLAGS"] = [x for x in self["CXXFLAGS"] if not x in warn_flags]
+ else:
+ self.Append(CCFLAGS=["-w"])
+ self.Append(CFLAGS=["-w"])
+ self.Append(CXXFLAGS=["-w"])
+
+
+def make_icu_data(target, source, env):
+ dst = target[0].srcnode().abspath
+ g = open(dst, "w", encoding="utf-8")
+
+ g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
+ g.write("/* (C) 2016 and later: Unicode, Inc. and others. */\n")
+ g.write("/* License & terms of use: https://www.unicode.org/copyright.html */\n")
+ g.write("#ifndef _ICU_DATA_H\n")
+ g.write("#define _ICU_DATA_H\n")
+ g.write('#include "unicode/utypes.h"\n')
+ g.write('#include "unicode/udata.h"\n')
+ g.write('#include "unicode/uversion.h"\n')
+
+ f = open(source[0].srcnode().abspath, "rb")
+ buf = f.read()
+
+ g.write('extern "C" U_EXPORT const size_t U_ICUDATA_SIZE = ' + str(len(buf)) + ";\n")
+ g.write('extern "C" U_EXPORT const unsigned char U_ICUDATA_ENTRY_POINT[] = {\n')
+ for i in range(len(buf)):
+ g.write("\t" + str(buf[i]) + ",\n")
+
+ g.write("};\n")
+ g.write("#endif")
+
+
+def write_osx_plist(target, binary_name, identifier, name):
+ os.makedirs(f"{target}/Resourece/", exist_ok=True)
+ f = open(f"{target}/Resourece/Info.plist", "w")
+
+ f.write(f'<?xml version="1.0" encoding="UTF-8"?>\n')
+ f.write(f'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n')
+ f.write(f'<plist version="1.0">\n')
+ f.write(f"<dict>\n")
+ f.write(f"\t<key>CFBundleExecutable</key>\n")
+ f.write(f"\t<string>{binary_name}</string>\n")
+ f.write(f"\t<key>CFBundleIdentifier</key>\n")
+ f.write(f"\t<string>{identifier}</string>\n")
+ f.write(f"\t<key>CFBundleInfoDictionaryVersion</key>\n")
+ f.write(f"\t<string>6.0</string>\n")
+ f.write(f"\t<key>CFBundleName</key>\n")
+ f.write(f"\t<string>{name}</string>\n")
+ f.write(f"\t<key>CFBundlePackageType</key>\n")
+ f.write(f"\t<string>FMWK</string>\n")
+ f.write(f"\t<key>CFBundleShortVersionString</key>\n")
+ f.write(f"\t<string>1.0.0</string>\n")
+ f.write(f"\t<key>CFBundleSupportedPlatforms</key>\n")
+ f.write(f"\t<array>\n")
+ f.write(f"\t\t<string>MacOSX</string>\n")
+ f.write(f"\t</array>\n")
+ f.write(f"\t<key>CFBundleVersion</key>\n")
+ f.write(f"\t<string>1.0.0</string>\n")
+ f.write(f"\t<key>LSMinimumSystemVersion</key>\n")
+ f.write(f"\t<string>10.14</string>\n")
+ f.write(f"</dict>\n")
+ f.write(f"</plist>\n")
diff --git a/modules/text_server_fb/gdextension_build/text_server_fb.gdextension b/modules/text_server_fb/gdextension_build/text_server_fb.gdextension
new file mode 100644
index 0000000000..1026c6cb85
--- /dev/null
+++ b/modules/text_server_fb/gdextension_build/text_server_fb.gdextension
@@ -0,0 +1,12 @@
+[configuration]
+
+entry_symbol = "textserver_fallback_init"
+
+[libraries]
+
+linux.64.debug = "bin/libtextserver_fallback.linux.debug.64.so"
+linux.64.release = "bin/libtextserver_fallback.linux.release.64.so"
+windows.64.debug = "bin/libtextserver_fallback.windows.debug.64.dll"
+windows.64.release = "bin/libtextserver_fallback.windows.release.64.dll"
+macos.debug = "bin/libtextserver_fallback.osx.debug.framework"
+macos.release = "bin/libtextserver_fallback.osx.release.framework"
diff --git a/modules/text_server_fb/register_types.cpp b/modules/text_server_fb/register_types.cpp
index a545f84939..fa7b87fc17 100644
--- a/modules/text_server_fb/register_types.cpp
+++ b/modules/text_server_fb/register_types.cpp
@@ -32,17 +32,46 @@
#include "text_server_fb.h"
-void preregister_text_server_fb_types() {
+void initialize_text_server_fb_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SERVERS) {
+ return;
+ }
+
GDREGISTER_CLASS(TextServerFallback);
- if (TextServerManager::get_singleton()) {
+ TextServerManager *tsman = TextServerManager::get_singleton();
+ if (tsman) {
Ref<TextServerFallback> ts;
ts.instantiate();
- TextServerManager::get_singleton()->add_interface(ts);
+ tsman->add_interface(ts);
}
}
-void register_text_server_fb_types() {
+void uninitialize_text_server_fb_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SERVERS) {
+ return;
+ }
}
-void unregister_text_server_fb_types() {
+#ifdef GDEXTENSION
+
+#include <godot_cpp/core/class_db.hpp>
+#include <godot_cpp/core/defs.hpp>
+#include <godot_cpp/core/memory.hpp>
+
+using namespace godot;
+
+extern "C" {
+
+GDNativeBool GDN_EXPORT textserver_fallback_init(const GDNativeInterface *p_interface, const GDNativeExtensionClassLibraryPtr p_library, GDNativeInitialization *r_initialization) {
+ GDExtensionBinding::InitObject init_obj(p_interface, p_library, r_initialization);
+
+ init_obj.register_initializer(&initialize_text_server_fb_module);
+ init_obj.register_terminator(&uninitialize_text_server_fb_module);
+ init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SERVERS);
+
+ return init_obj.init();
}
+
+} // ! extern "C"
+
+#endif // ! GDEXTENSION
diff --git a/modules/text_server_fb/register_types.h b/modules/text_server_fb/register_types.h
index 8652a8e9db..229aec2266 100644
--- a/modules/text_server_fb/register_types.h
+++ b/modules/text_server_fb/register_types.h
@@ -31,10 +31,14 @@
#ifndef TEXT_SERVER_FB_REGISTER_TYPES_H
#define TEXT_SERVER_FB_REGISTER_TYPES_H
-#define MODULE_TEXT_SERVER_FB_HAS_PREREGISTER
+#ifdef GDEXTENSION
+#include <godot_cpp/core/class_db.hpp>
+using namespace godot;
+#else
+#include "modules/register_module_types.h"
+#endif
-void preregister_text_server_fb_types();
-void register_text_server_fb_types();
-void unregister_text_server_fb_types();
+void initialize_text_server_fb_module(ModuleInitializationLevel p_level);
+void uninitialize_text_server_fb_module(ModuleInitializationLevel p_level);
#endif // TEXT_SERVER_FB_REGISTER_TYPES_H
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 0d7a9d0db8..8ae56aa64d 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -30,12 +30,29 @@
#include "text_server_fb.h"
+#ifdef GDEXTENSION
+// Headers for building as GDExtension plug-in.
+
+#include <godot_cpp/classes/file.hpp>
+#include <godot_cpp/classes/rendering_server.hpp>
+#include <godot_cpp/classes/translation_server.hpp>
+#include <godot_cpp/core/error_macros.hpp>
+
+using namespace godot;
+
+#else
+// Headers for building as built-in module.
+
#include "core/error/error_macros.h"
#include "core/string/print_string.h"
#include "core/string/ucaps.h"
#include "modules/modules_enabled.gen.h" // For freetype, msdfgen.
+#endif
+
+// Thirdparty headers.
+
#ifdef MODULE_MSDFGEN_ENABLED
#include "core/ShapeDistanceFinder.h"
#include "core/contour-combiners.h"
@@ -45,22 +62,46 @@
/*************************************************************************/
-String TextServerFallback::interface_name = "Fallback";
-uint32_t TextServerFallback::interface_features = 0; // Nothing is supported.
+#define OT_TAG(c1, c2, c3, c4) ((int32_t)((((uint32_t)(c1)&0xff) << 24) | (((uint32_t)(c2)&0xff) << 16) | (((uint32_t)(c3)&0xff) << 8) | ((uint32_t)(c4)&0xff)))
bool TextServerFallback::has_feature(Feature p_feature) const {
- return (interface_features & p_feature) == p_feature;
+ switch (p_feature) {
+ case FEATURE_SIMPLE_LAYOUT:
+ case FEATURE_FONT_BITMAP:
+#ifdef MODULE_FREETYPE_ENABLED
+ case FEATURE_FONT_DYNAMIC:
+#endif
+#ifdef MODULE_MSDFGEN_ENABLED
+ case FEATURE_FONT_MSDF:
+#endif
+ return true;
+ default: {
+ }
+ }
+ return false;
}
String TextServerFallback::get_name() const {
- return interface_name;
+#ifdef GDEXTENSION
+ return "Fallback (GDExtension)";
+#else
+ return "Fallback (Built-in)";
+#endif
}
-uint32_t TextServerFallback::get_features() const {
+int64_t TextServerFallback::get_features() const {
+ int64_t interface_features = FEATURE_SIMPLE_LAYOUT | FEATURE_FONT_BITMAP;
+#ifdef MODULE_FREETYPE_ENABLED
+ interface_features |= FEATURE_FONT_DYNAMIC;
+#endif
+#ifdef MODULE_MSDFGEN_ENABLED
+ interface_features |= FEATURE_FONT_MSDF;
+#endif
+
return interface_features;
}
-void TextServerFallback::free(RID p_rid) {
+void TextServerFallback::free_rid(const RID &p_rid) {
_THREAD_SAFE_METHOD_
if (font_owner.owns(p_rid)) {
FontDataFallback *fd = font_owner.get_or_null(p_rid);
@@ -73,7 +114,7 @@ void TextServerFallback::free(RID p_rid) {
}
}
-bool TextServerFallback::has(RID p_rid) {
+bool TextServerFallback::has(const RID &p_rid) {
_THREAD_SAFE_METHOD_
return font_owner.owns(p_rid) || shaped_owner.owns(p_rid);
}
@@ -90,13 +131,18 @@ bool TextServerFallback::is_locale_right_to_left(const String &p_locale) const {
return false; // No RTL support.
}
+_FORCE_INLINE_ void TextServerFallback::_insert_feature(const StringName &p_name, int32_t p_tag) {
+ feature_sets.insert(p_name, p_tag);
+ feature_sets_inv.insert(p_tag, p_name);
+}
+
void TextServerFallback::_insert_feature_sets() {
// Registered OpenType variation tag.
- feature_sets.insert("italic", OT_TAG('i', 't', 'a', 'l'));
- feature_sets.insert("optical_size", OT_TAG('o', 'p', 's', 'z'));
- feature_sets.insert("slant", OT_TAG('s', 'l', 'n', 't'));
- feature_sets.insert("width", OT_TAG('w', 'd', 't', 'h'));
- feature_sets.insert("weight", OT_TAG('w', 'g', 'h', 't'));
+ _insert_feature("italic", OT_TAG('i', 't', 'a', 'l'));
+ _insert_feature("optical_size", OT_TAG('o', 'p', 's', 'z'));
+ _insert_feature("slant", OT_TAG('s', 'l', 'n', 't'));
+ _insert_feature("width", OT_TAG('w', 'd', 't', 'h'));
+ _insert_feature("weight", OT_TAG('w', 'g', 'h', 't'));
}
_FORCE_INLINE_ int32_t ot_tag_from_string(const char *p_str, int p_len) {
@@ -121,7 +167,7 @@ _FORCE_INLINE_ int32_t ot_tag_from_string(const char *p_str, int p_len) {
return OT_TAG(tag[0], tag[1], tag[2], tag[3]);
}
-int32_t TextServerFallback::name_to_tag(const String &p_name) const {
+int64_t TextServerFallback::name_to_tag(const String &p_name) const {
if (feature_sets.has(p_name)) {
return feature_sets[p_name];
}
@@ -137,11 +183,9 @@ _FORCE_INLINE_ void ot_tag_to_string(int32_t p_tag, char *p_buf) {
p_buf[3] = (char)(uint8_t)(p_tag >> 0);
}
-String TextServerFallback::tag_to_name(int32_t p_tag) const {
- for (const KeyValue<StringName, int32_t> &E : feature_sets) {
- if (E.value == p_tag) {
- return E.key;
- }
+String TextServerFallback::tag_to_name(int64_t p_tag) const {
+ if (feature_sets_inv.has(p_tag)) {
+ return feature_sets_inv[p_tag];
}
// No readable name, use tag string.
@@ -165,12 +209,6 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_
for (int i = 0; i < p_data->textures.size(); i++) {
const FontTexture &ct = p_data->textures[i];
- if (RenderingServer::get_singleton() != nullptr) {
- if (ct.texture->get_format() != p_image_format) {
- continue;
- }
- }
-
if (mw > ct.texture_w || mh > ct.texture_h) { // Too big for this texture.
continue;
}
@@ -179,7 +217,7 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_
continue;
}
- ret.y = 0x7FFFFFFF;
+ ret.y = 0x7fffffff;
ret.x = 0;
for (int j = 0; j < ct.texture_w - mw; j++) {
@@ -198,7 +236,7 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_
}
}
- if (ret.y == 0x7FFFFFFF || ret.y + mh > ct.texture_h) {
+ if (ret.y == 0x7fffffff || ret.y + mh > ct.texture_h) {
continue; // Fail, could not fit it here.
}
@@ -212,20 +250,32 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_
ret.y = 0;
int texsize = MAX(p_data->size.x * p_data->oversampling * 8, 256);
- if (mw > texsize) {
- texsize = mw; // Special case, adapt to it?
- }
- if (mh > texsize) {
- texsize = mh; // Special case, adapt to it?
- }
+#ifdef GDEXTENSION
+ texsize = Math::next_power_of_2(texsize);
+#else
texsize = next_power_of_2(texsize);
+#endif
if (p_msdf) {
texsize = MIN(texsize, 2048);
} else {
texsize = MIN(texsize, 1024);
}
+ if (mw > texsize) { // Special case, adapt to it?
+#ifdef GDEXTENSION
+ texsize = Math::next_power_of_2(mw);
+#else
+ texsize = next_power_of_2(mw);
+#endif
+ }
+ if (mh > texsize) { // Special case, adapt to it?
+#ifdef GDEXTENSION
+ texsize = Math::next_power_of_2(mh);
+#else
+ texsize = next_power_of_2(mh);
+#endif
+ }
FontTexture tex;
tex.texture_w = texsize;
@@ -256,8 +306,9 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_
}
}
tex.offsets.resize(texsize);
+ int32_t *offw = tex.offsets.ptrw();
for (int i = 0; i < texsize; i++) { // Zero offsets.
- tex.offsets.write[i] = 0;
+ offw[i] = 0;
}
p_data->textures.push_back(tex);
@@ -271,8 +322,8 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_
struct MSContext {
msdfgen::Point2 position;
- msdfgen::Shape *shape;
- msdfgen::Contour *contour;
+ msdfgen::Shape *shape = nullptr;
+ msdfgen::Contour *contour = nullptr;
};
class DistancePixelConversion {
@@ -301,7 +352,7 @@ static msdfgen::Point2 ft_point2(const FT_Vector &vector) {
}
static int ft_move_to(const FT_Vector *to, void *user) {
- MSContext *context = reinterpret_cast<MSContext *>(user);
+ MSContext *context = static_cast<MSContext *>(user);
if (!(context->contour && context->contour->edges.empty())) {
context->contour = &context->shape->addContour();
}
@@ -310,7 +361,7 @@ static int ft_move_to(const FT_Vector *to, void *user) {
}
static int ft_line_to(const FT_Vector *to, void *user) {
- MSContext *context = reinterpret_cast<MSContext *>(user);
+ MSContext *context = static_cast<MSContext *>(user);
msdfgen::Point2 endpoint = ft_point2(*to);
if (endpoint != context->position) {
context->contour->addEdge(new msdfgen::LinearSegment(context->position, endpoint));
@@ -320,21 +371,21 @@ static int ft_line_to(const FT_Vector *to, void *user) {
}
static int ft_conic_to(const FT_Vector *control, const FT_Vector *to, void *user) {
- MSContext *context = reinterpret_cast<MSContext *>(user);
+ MSContext *context = static_cast<MSContext *>(user);
context->contour->addEdge(new msdfgen::QuadraticSegment(context->position, ft_point2(*control), ft_point2(*to)));
context->position = ft_point2(*to);
return 0;
}
static int ft_cubic_to(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) {
- MSContext *context = reinterpret_cast<MSContext *>(user);
+ MSContext *context = static_cast<MSContext *>(user);
context->contour->addEdge(new msdfgen::CubicSegment(context->position, ft_point2(*control1), ft_point2(*control2), ft_point2(*to)));
context->position = ft_point2(*to);
return 0;
}
void TextServerFallback::_generateMTSDF_threaded(uint32_t y, void *p_td) const {
- MSDFThreadData *td = (MSDFThreadData *)p_td;
+ MSDFThreadData *td = static_cast<MSDFThreadData *>(p_td);
msdfgen::ShapeDistanceFinder<msdfgen::OverlappingContourCombiner<msdfgen::MultiAndTrueDistanceSelector>> distanceFinder(*td->shape);
int row = td->shape->inverseYAxis ? td->output->height() - y - 1 : y;
@@ -387,11 +438,11 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf(
int w = (bounds.r - bounds.l);
int h = (bounds.t - bounds.b);
- int mw = w + p_rect_margin * 2;
- int mh = h + p_rect_margin * 2;
+ int mw = w + p_rect_margin * 4;
+ int mh = h + p_rect_margin * 4;
- ERR_FAIL_COND_V(mw > 1024, FontGlyph());
- ERR_FAIL_COND_V(mh > 1024, FontGlyph());
+ ERR_FAIL_COND_V(mw > 4096, FontGlyph());
+ ERR_FAIL_COND_V(mh > 4096, FontGlyph());
FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, 4, Image::FORMAT_RGBA8, mw, mh, true);
ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());
@@ -422,7 +473,7 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf(
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
- int ofs = ((i + tex_pos.y + p_rect_margin) * tex.texture_w + j + tex_pos.x + p_rect_margin) * 4;
+ int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * 4;
ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), FontGlyph());
wr[ofs + 0] = (uint8_t)(CLAMP(image(j, i)[0] * 256.f, 0.f, 255.f));
wr[ofs + 1] = (uint8_t)(CLAMP(image(j, i)[1] * 256.f, 0.f, 255.f));
@@ -432,28 +483,18 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf(
}
}
- // Blit to image and texture.
- {
- if (RenderingServer::get_singleton() != nullptr) {
- Ref<Image> img = memnew(Image(tex.texture_w, tex.texture_h, 0, Image::FORMAT_RGBA8, tex.imgdata));
- if (tex.texture.is_null()) {
- tex.texture.instantiate();
- tex.texture->create_from_image(img);
- } else {
- tex.texture->update(img);
- }
- }
- }
+ tex.dirty = true;
// Update height array.
+ int32_t *offw = tex.offsets.ptrw();
for (int k = tex_pos.x; k < tex_pos.x + mw; k++) {
- tex.offsets.write[k] = tex_pos.y + mh;
+ offw[k] = tex_pos.y + mh;
}
chr.texture_idx = tex_pos.index;
- chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w, h);
- chr.rect.position = Vector2(bounds.l, -bounds.t);
+ chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w + p_rect_margin * 2, h + p_rect_margin * 2);
+ chr.rect.position = Vector2(bounds.l - p_rect_margin, -bounds.t - p_rect_margin);
chr.rect.size = chr.uv_rect.size;
}
return chr;
@@ -465,11 +506,11 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma
int w = bitmap.width;
int h = bitmap.rows;
- int mw = w + p_rect_margin * 2;
- int mh = h + p_rect_margin * 2;
+ int mw = w + p_rect_margin * 4;
+ int mh = h + p_rect_margin * 4;
- ERR_FAIL_COND_V(mw > 1024, FontGlyph());
- ERR_FAIL_COND_V(mh > 1024, FontGlyph());
+ ERR_FAIL_COND_V(mw > 4096, FontGlyph());
+ ERR_FAIL_COND_V(mh > 4096, FontGlyph());
int color_size = bitmap.pixel_mode == FT_PIXEL_MODE_BGRA ? 4 : 2;
Image::Format require_format = color_size == 4 ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8;
@@ -486,7 +527,7 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
- int ofs = ((i + tex_pos.y + p_rect_margin) * tex.texture_w + j + tex_pos.x + p_rect_margin) * color_size;
+ int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * color_size;
ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), FontGlyph());
switch (bitmap.pixel_mode) {
case FT_PIXEL_MODE_MONO: {
@@ -507,30 +548,19 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma
wr[ofs + 3] = bitmap.buffer[ofs_color + 3];
} break;
default:
- ERR_FAIL_V_MSG(FontGlyph(), "Font uses unsupported pixel format: " + itos(bitmap.pixel_mode) + ".");
+ ERR_FAIL_V_MSG(FontGlyph(), "Font uses unsupported pixel format: " + String::num_int64(bitmap.pixel_mode) + ".");
break;
}
}
}
}
- // Blit to image and texture.
- {
- if (RenderingServer::get_singleton() != nullptr) {
- Ref<Image> img = memnew(Image(tex.texture_w, tex.texture_h, 0, require_format, tex.imgdata));
-
- if (tex.texture.is_null()) {
- tex.texture.instantiate();
- tex.texture->create_from_image(img);
- } else {
- tex.texture->update(img);
- }
- }
- }
+ tex.dirty = true;
// Update height array.
+ int32_t *offw = tex.offsets.ptrw();
for (int k = tex_pos.x; k < tex_pos.x + mw; k++) {
- tex.offsets.write[k] = tex_pos.y + mh;
+ offw[k] = tex_pos.y + mh;
}
FontGlyph chr;
@@ -538,8 +568,8 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma
chr.texture_idx = tex_pos.index;
chr.found = true;
- chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w, h);
- chr.rect.position = Vector2(xofs, -yofs) * p_data->scale / p_data->oversampling;
+ chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w + p_rect_margin * 2, h + p_rect_margin * 2);
+ chr.rect.position = Vector2(xofs - p_rect_margin, -yofs - p_rect_margin) * p_data->scale / p_data->oversampling;
chr.rect.size = chr.uv_rect.size * p_data->scale / p_data->oversampling;
return chr;
}
@@ -552,7 +582,7 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma
_FORCE_INLINE_ bool TextServerFallback::_ensure_glyph(FontDataFallback *p_font_data, const Vector2i &p_size, int32_t p_glyph) const {
ERR_FAIL_COND_V(!_ensure_cache_for_size(p_font_data, p_size), false);
- int32_t glyph_index = p_glyph & 0xFFFFFF; // Remove subpixel shifts.
+ int32_t glyph_index = p_glyph & 0xffffff; // Remove subpixel shifts.
FontDataForSizeFallback *fd = p_font_data->cache[p_size];
if (fd->glyph_map.has(p_glyph)) {
@@ -641,7 +671,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_glyph(FontDataFallback *p_font_d
}
} else {
FT_Stroker stroker;
- if (FT_Stroker_New(library, &stroker) != 0) {
+ if (FT_Stroker_New(ft_library, &stroker) != 0) {
fd->glyph_map[p_glyph] = FontGlyph();
ERR_FAIL_V_MSG(false, "FreeType: Failed to load glyph stroker.");
}
@@ -687,8 +717,8 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback
// Init dynamic font.
#ifdef MODULE_FREETYPE_ENABLED
int error = 0;
- if (!library) {
- error = FT_Init_FreeType(&library);
+ if (!ft_library) {
+ error = FT_Init_FreeType(&ft_library);
ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
}
@@ -703,7 +733,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback
fargs.memory_size = p_font_data->data_size;
fargs.flags = FT_OPEN_MEMORY;
fargs.stream = &fd->stream;
- error = FT_Open_Face(library, &fargs, 0, &fd->face);
+ error = FT_Open_Face(ft_library, &fargs, 0, &fd->face);
if (error) {
FT_Done_Face(fd->face);
fd->face = nullptr;
@@ -711,9 +741,9 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback
}
if (p_font_data->msdf) {
- fd->oversampling = 1.0f;
+ fd->oversampling = 1.0;
fd->size.x = p_font_data->msdf_source_size;
- } else if (p_font_data->oversampling <= 0.0f) {
+ } else if (p_font_data->oversampling <= 0.0) {
fd->oversampling = font_get_global_oversampling();
} else {
fd->oversampling = p_font_data->oversampling;
@@ -722,19 +752,19 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback
if (FT_HAS_COLOR(fd->face) && fd->face->num_fixed_sizes > 0) {
int best_match = 0;
int diff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[0].width));
- fd->scale = float(fd->size.x * fd->oversampling) / fd->face->available_sizes[0].width;
+ fd->scale = double(fd->size.x * fd->oversampling) / fd->face->available_sizes[0].width;
for (int i = 1; i < fd->face->num_fixed_sizes; i++) {
int ndiff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[i].width));
if (ndiff < diff) {
best_match = i;
diff = ndiff;
- fd->scale = float(fd->size.x * fd->oversampling) / fd->face->available_sizes[i].width;
+ fd->scale = double(fd->size.x * fd->oversampling) / fd->face->available_sizes[i].width;
}
}
FT_Select_Size(fd->face, best_match);
} else {
FT_Set_Pixel_Sizes(fd->face, 0, Math::round(fd->size.x * fd->oversampling));
- fd->scale = ((float)fd->size.x * fd->oversampling) / (float)fd->face->size->metrics.y_ppem;
+ fd->scale = ((double)fd->size.x * fd->oversampling) / (double)fd->face->size->metrics.y_ppem;
}
fd->ascent = (fd->face->size->metrics.ascender / 64.0) / fd->oversampling * fd->scale;
@@ -768,7 +798,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback
for (FT_UInt i = 0; i < amaster->num_axis; i++) {
p_font_data->supported_varaitions[(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);
+ FT_Done_MM_Var(ft_library, amaster);
}
p_font_data->face_init = true;
}
@@ -787,22 +817,22 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback
for (FT_UInt i = 0; i < amaster->num_axis; i++) {
// Reset to default.
int32_t var_tag = amaster->axis[i].tag;
- float var_value = (double)amaster->axis[i].def / 65536.f;
+ double var_value = (double)amaster->axis[i].def / 65536.0;
coords.write[i] = amaster->axis[i].def;
if (p_font_data->variation_coordinates.has(var_tag)) {
var_value = p_font_data->variation_coordinates[var_tag];
- coords.write[i] = CLAMP(var_value * 65536.f, amaster->axis[i].minimum, amaster->axis[i].maximum);
+ coords.write[i] = CLAMP(var_value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum);
}
if (p_font_data->variation_coordinates.has(tag_to_name(var_tag))) {
var_value = p_font_data->variation_coordinates[tag_to_name(var_tag)];
- coords.write[i] = CLAMP(var_value * 65536.f, amaster->axis[i].minimum, amaster->axis[i].maximum);
+ coords.write[i] = CLAMP(var_value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum);
}
}
FT_Set_Var_Design_Coordinates(fd->face, coords.size(), coords.ptrw());
- FT_Done_MM_Var(library, amaster);
+ FT_Done_MM_Var(ft_library, amaster);
}
#else
ERR_FAIL_V_MSG(false, "FreeType: Can't load dynamic font, engine is compiled without FreeType support!");
@@ -828,7 +858,7 @@ RID TextServerFallback::create_font() {
return font_owner.make_rid(fd);
}
-void TextServerFallback::font_set_data(RID p_font_rid, const PackedByteArray &p_data) {
+void TextServerFallback::font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -839,18 +869,18 @@ void TextServerFallback::font_set_data(RID p_font_rid, const PackedByteArray &p_
fd->data_size = fd->data.size();
}
-void TextServerFallback::font_set_data_ptr(RID p_font_rid, const uint8_t *p_data_ptr, size_t p_data_size) {
+void TextServerFallback::font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
_font_clear_cache(fd);
- fd->data.clear();
+ fd->data.resize(0);
fd->data_ptr = p_data_ptr;
fd->data_size = p_data_size;
}
-void TextServerFallback::font_set_style(RID p_font_rid, uint32_t /*FontStyle*/ p_style) {
+void TextServerFallback::font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -860,7 +890,7 @@ void TextServerFallback::font_set_style(RID p_font_rid, uint32_t /*FontStyle*/ p
fd->style_flags = p_style;
}
-uint32_t /*FontStyle*/ TextServerFallback::font_get_style(RID p_font_rid) const {
+int64_t /*FontStyle*/ TextServerFallback::font_get_style(const RID &p_font_rid) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0);
@@ -870,7 +900,7 @@ uint32_t /*FontStyle*/ TextServerFallback::font_get_style(RID p_font_rid) const
return fd->style_flags;
}
-void TextServerFallback::font_set_style_name(RID p_font_rid, const String &p_name) {
+void TextServerFallback::font_set_style_name(const RID &p_font_rid, const String &p_name) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -880,7 +910,7 @@ void TextServerFallback::font_set_style_name(RID p_font_rid, const String &p_nam
fd->style_name = p_name;
}
-String TextServerFallback::font_get_style_name(RID p_font_rid) const {
+String TextServerFallback::font_get_style_name(const RID &p_font_rid) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, String());
@@ -890,7 +920,7 @@ String TextServerFallback::font_get_style_name(RID p_font_rid) const {
return fd->style_name;
}
-void TextServerFallback::font_set_name(RID p_font_rid, const String &p_name) {
+void TextServerFallback::font_set_name(const RID &p_font_rid, const String &p_name) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -900,7 +930,7 @@ void TextServerFallback::font_set_name(RID p_font_rid, const String &p_name) {
fd->font_name = p_name;
}
-String TextServerFallback::font_get_name(RID p_font_rid) const {
+String TextServerFallback::font_get_name(const RID &p_font_rid) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, String());
@@ -910,7 +940,7 @@ String TextServerFallback::font_get_name(RID p_font_rid) const {
return fd->font_name;
}
-void TextServerFallback::font_set_antialiased(RID p_font_rid, bool p_antialiased) {
+void TextServerFallback::font_set_antialiased(const RID &p_font_rid, bool p_antialiased) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -921,7 +951,7 @@ void TextServerFallback::font_set_antialiased(RID p_font_rid, bool p_antialiased
}
}
-bool TextServerFallback::font_is_antialiased(RID p_font_rid) const {
+bool TextServerFallback::font_is_antialiased(const RID &p_font_rid) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -929,7 +959,30 @@ bool TextServerFallback::font_is_antialiased(RID p_font_rid) const {
return fd->antialiased;
}
-void TextServerFallback::font_set_multichannel_signed_distance_field(RID p_font_rid, bool p_msdf) {
+void TextServerFallback::font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) {
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ if (fd->mipmaps != p_generate_mipmaps) {
+ for (KeyValue<Vector2i, FontDataForSizeFallback *> &E : fd->cache) {
+ for (int i = 0; i < E.value->textures.size(); i++) {
+ E.value->textures.write[i].dirty = true;
+ }
+ }
+ fd->mipmaps = p_generate_mipmaps;
+ }
+}
+
+bool TextServerFallback::font_get_generate_mipmaps(const RID &p_font_rid) const {
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, false);
+
+ MutexLock lock(fd->mutex);
+ return fd->mipmaps;
+}
+
+void TextServerFallback::font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -940,7 +993,7 @@ void TextServerFallback::font_set_multichannel_signed_distance_field(RID p_font_
}
}
-bool TextServerFallback::font_is_multichannel_signed_distance_field(RID p_font_rid) const {
+bool TextServerFallback::font_is_multichannel_signed_distance_field(const RID &p_font_rid) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -948,7 +1001,7 @@ bool TextServerFallback::font_is_multichannel_signed_distance_field(RID p_font_r
return fd->msdf;
}
-void TextServerFallback::font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pixel_range) {
+void TextServerFallback::font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -959,7 +1012,7 @@ void TextServerFallback::font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pi
}
}
-int TextServerFallback::font_get_msdf_pixel_range(RID p_font_rid) const {
+int64_t TextServerFallback::font_get_msdf_pixel_range(const RID &p_font_rid) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -967,7 +1020,7 @@ int TextServerFallback::font_get_msdf_pixel_range(RID p_font_rid) const {
return fd->msdf_range;
}
-void TextServerFallback::font_set_msdf_size(RID p_font_rid, int p_msdf_size) {
+void TextServerFallback::font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -978,7 +1031,7 @@ void TextServerFallback::font_set_msdf_size(RID p_font_rid, int p_msdf_size) {
}
}
-int TextServerFallback::font_get_msdf_size(RID p_font_rid) const {
+int64_t TextServerFallback::font_get_msdf_size(const RID &p_font_rid) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -986,17 +1039,15 @@ int TextServerFallback::font_get_msdf_size(RID p_font_rid) const {
return fd->msdf_source_size;
}
-void TextServerFallback::font_set_fixed_size(RID p_font_rid, int p_fixed_size) {
+void TextServerFallback::font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
- if (fd->fixed_size != p_fixed_size) {
- fd->fixed_size = p_fixed_size;
- }
+ fd->fixed_size = p_fixed_size;
}
-int TextServerFallback::font_get_fixed_size(RID p_font_rid) const {
+int64_t TextServerFallback::font_get_fixed_size(const RID &p_font_rid) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -1004,7 +1055,7 @@ int TextServerFallback::font_get_fixed_size(RID p_font_rid) const {
return fd->fixed_size;
}
-void TextServerFallback::font_set_force_autohinter(RID p_font_rid, bool p_force_autohinter) {
+void TextServerFallback::font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1015,7 +1066,7 @@ void TextServerFallback::font_set_force_autohinter(RID p_font_rid, bool p_force_
}
}
-bool TextServerFallback::font_is_force_autohinter(RID p_font_rid) const {
+bool TextServerFallback::font_is_force_autohinter(const RID &p_font_rid) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -1023,7 +1074,7 @@ bool TextServerFallback::font_is_force_autohinter(RID p_font_rid) const {
return fd->force_autohinter;
}
-void TextServerFallback::font_set_hinting(RID p_font_rid, TextServer::Hinting p_hinting) {
+void TextServerFallback::font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1034,7 +1085,7 @@ void TextServerFallback::font_set_hinting(RID p_font_rid, TextServer::Hinting p_
}
}
-TextServer::Hinting TextServerFallback::font_get_hinting(RID p_font_rid) const {
+TextServer::Hinting TextServerFallback::font_get_hinting(const RID &p_font_rid) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, HINTING_NONE);
@@ -1042,17 +1093,15 @@ TextServer::Hinting TextServerFallback::font_get_hinting(RID p_font_rid) const {
return fd->hinting;
}
-void TextServerFallback::font_set_subpixel_positioning(RID p_font_rid, TextServer::SubpixelPositioning p_subpixel) {
+void TextServerFallback::font_set_subpixel_positioning(const RID &p_font_rid, TextServer::SubpixelPositioning p_subpixel) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
- if (fd->subpixel_positioning != p_subpixel) {
- fd->subpixel_positioning = p_subpixel;
- }
+ fd->subpixel_positioning = p_subpixel;
}
-TextServer::SubpixelPositioning TextServerFallback::font_get_subpixel_positioning(RID p_font_rid) const {
+TextServer::SubpixelPositioning TextServerFallback::font_get_subpixel_positioning(const RID &p_font_rid) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, SUBPIXEL_POSITIONING_DISABLED);
@@ -1060,7 +1109,7 @@ TextServer::SubpixelPositioning TextServerFallback::font_get_subpixel_positionin
return fd->subpixel_positioning;
}
-void TextServerFallback::font_set_embolden(RID p_font_rid, float p_strength) {
+void TextServerFallback::font_set_embolden(const RID &p_font_rid, double p_strength) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1071,15 +1120,15 @@ void TextServerFallback::font_set_embolden(RID p_font_rid, float p_strength) {
}
}
-float TextServerFallback::font_get_embolden(RID p_font_rid) const {
+double TextServerFallback::font_get_embolden(const RID &p_font_rid) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, 0.f);
+ ERR_FAIL_COND_V(!fd, 0.0);
MutexLock lock(fd->mutex);
return fd->embolden;
}
-void TextServerFallback::font_set_transform(RID p_font_rid, Transform2D p_transform) {
+void TextServerFallback::font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1090,7 +1139,7 @@ void TextServerFallback::font_set_transform(RID p_font_rid, Transform2D p_transf
}
}
-Transform2D TextServerFallback::font_get_transform(RID p_font_rid) const {
+Transform2D TextServerFallback::font_get_transform(const RID &p_font_rid) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Transform2D());
@@ -1098,7 +1147,7 @@ Transform2D TextServerFallback::font_get_transform(RID p_font_rid) const {
return fd->transform;
}
-void TextServerFallback::font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) {
+void TextServerFallback::font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1109,7 +1158,7 @@ void TextServerFallback::font_set_variation_coordinates(RID p_font_rid, const Di
}
}
-Dictionary TextServerFallback::font_get_variation_coordinates(RID p_font_rid) const {
+Dictionary TextServerFallback::font_get_variation_coordinates(const RID &p_font_rid) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Dictionary());
@@ -1117,7 +1166,7 @@ Dictionary TextServerFallback::font_get_variation_coordinates(RID p_font_rid) co
return fd->variation_coordinates;
}
-void TextServerFallback::font_set_oversampling(RID p_font_rid, float p_oversampling) {
+void TextServerFallback::font_set_oversampling(const RID &p_font_rid, double p_oversampling) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1128,15 +1177,15 @@ void TextServerFallback::font_set_oversampling(RID p_font_rid, float p_oversampl
}
}
-float TextServerFallback::font_get_oversampling(RID p_font_rid) const {
+double TextServerFallback::font_get_oversampling(const RID &p_font_rid) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, 0.f);
+ ERR_FAIL_COND_V(!fd, 0.0);
MutexLock lock(fd->mutex);
return fd->oversampling;
}
-Array TextServerFallback::font_get_size_cache_list(RID p_font_rid) const {
+Array TextServerFallback::font_get_size_cache_list(const RID &p_font_rid) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Array());
@@ -1148,7 +1197,7 @@ Array TextServerFallback::font_get_size_cache_list(RID p_font_rid) const {
return ret;
}
-void TextServerFallback::font_clear_size_cache(RID p_font_rid) {
+void TextServerFallback::font_clear_size_cache(const RID &p_font_rid) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1159,7 +1208,7 @@ void TextServerFallback::font_clear_size_cache(RID p_font_rid) {
fd->cache.clear();
}
-void TextServerFallback::font_remove_size_cache(RID p_font_rid, const Vector2i &p_size) {
+void TextServerFallback::font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1170,7 +1219,7 @@ void TextServerFallback::font_remove_size_cache(RID p_font_rid, const Vector2i &
}
}
-void TextServerFallback::font_set_ascent(RID p_font_rid, int p_size, float p_ascent) {
+void TextServerFallback::font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1181,23 +1230,23 @@ void TextServerFallback::font_set_ascent(RID p_font_rid, int p_size, float p_asc
fd->cache[size]->ascent = p_ascent;
}
-float TextServerFallback::font_get_ascent(RID p_font_rid, int p_size) const {
+double TextServerFallback::font_get_ascent(const RID &p_font_rid, int64_t p_size) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, 0.f);
+ ERR_FAIL_COND_V(!fd, 0.0);
MutexLock lock(fd->mutex);
Vector2i size = _get_size(fd, p_size);
- ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0);
if (fd->msdf) {
- return fd->cache[size]->ascent * (float)p_size / (float)fd->msdf_source_size;
+ return fd->cache[size]->ascent * (double)p_size / (double)fd->msdf_source_size;
} else {
return fd->cache[size]->ascent;
}
}
-void TextServerFallback::font_set_descent(RID p_font_rid, int p_size, float p_descent) {
+void TextServerFallback::font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1207,23 +1256,23 @@ void TextServerFallback::font_set_descent(RID p_font_rid, int p_size, float p_de
fd->cache[size]->descent = p_descent;
}
-float TextServerFallback::font_get_descent(RID p_font_rid, int p_size) const {
+double TextServerFallback::font_get_descent(const RID &p_font_rid, int64_t p_size) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, 0.f);
+ ERR_FAIL_COND_V(!fd, 0.0);
MutexLock lock(fd->mutex);
Vector2i size = _get_size(fd, p_size);
- ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0);
if (fd->msdf) {
- return fd->cache[size]->descent * (float)p_size / (float)fd->msdf_source_size;
+ return fd->cache[size]->descent * (double)p_size / (double)fd->msdf_source_size;
} else {
return fd->cache[size]->descent;
}
}
-void TextServerFallback::font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) {
+void TextServerFallback::font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1234,23 +1283,23 @@ void TextServerFallback::font_set_underline_position(RID p_font_rid, int p_size,
fd->cache[size]->underline_position = p_underline_position;
}
-float TextServerFallback::font_get_underline_position(RID p_font_rid, int p_size) const {
+double TextServerFallback::font_get_underline_position(const RID &p_font_rid, int64_t p_size) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, 0.f);
+ ERR_FAIL_COND_V(!fd, 0.0);
MutexLock lock(fd->mutex);
Vector2i size = _get_size(fd, p_size);
- ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0);
if (fd->msdf) {
- return fd->cache[size]->underline_position * (float)p_size / (float)fd->msdf_source_size;
+ return fd->cache[size]->underline_position * (double)p_size / (double)fd->msdf_source_size;
} else {
return fd->cache[size]->underline_position;
}
}
-void TextServerFallback::font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) {
+void TextServerFallback::font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1261,23 +1310,23 @@ void TextServerFallback::font_set_underline_thickness(RID p_font_rid, int p_size
fd->cache[size]->underline_thickness = p_underline_thickness;
}
-float TextServerFallback::font_get_underline_thickness(RID p_font_rid, int p_size) const {
+double TextServerFallback::font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, 0.f);
+ ERR_FAIL_COND_V(!fd, 0.0);
MutexLock lock(fd->mutex);
Vector2i size = _get_size(fd, p_size);
- ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0);
if (fd->msdf) {
- return fd->cache[size]->underline_thickness * (float)p_size / (float)fd->msdf_source_size;
+ return fd->cache[size]->underline_thickness * (double)p_size / (double)fd->msdf_source_size;
} else {
return fd->cache[size]->underline_thickness;
}
}
-void TextServerFallback::font_set_scale(RID p_font_rid, int p_size, float p_scale) {
+void TextServerFallback::font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1288,23 +1337,23 @@ void TextServerFallback::font_set_scale(RID p_font_rid, int p_size, float p_scal
fd->cache[size]->scale = p_scale;
}
-float TextServerFallback::font_get_scale(RID p_font_rid, int p_size) const {
+double TextServerFallback::font_get_scale(const RID &p_font_rid, int64_t p_size) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, 0.f);
+ ERR_FAIL_COND_V(!fd, 0.0);
MutexLock lock(fd->mutex);
Vector2i size = _get_size(fd, p_size);
- ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0);
if (fd->msdf) {
- return fd->cache[size]->scale * (float)p_size / (float)fd->msdf_source_size;
+ return fd->cache[size]->scale * (double)p_size / (double)fd->msdf_source_size;
} else {
return fd->cache[size]->scale / fd->cache[size]->oversampling;
}
}
-void TextServerFallback::font_set_spacing(RID p_font_rid, int p_size, TextServer::SpacingType p_spacing, int p_value) {
+void TextServerFallback::font_set_spacing(const RID &p_font_rid, int64_t p_size, TextServer::SpacingType p_spacing, int64_t p_value) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1320,12 +1369,12 @@ void TextServerFallback::font_set_spacing(RID p_font_rid, int p_size, TextServer
fd->cache[size]->spacing_space = p_value;
} break;
default: {
- ERR_FAIL_MSG("Invalid spacing type: " + itos(p_spacing));
+ ERR_FAIL_MSG("Invalid spacing type: " + String::num_int64(p_spacing));
} break;
}
}
-int TextServerFallback::font_get_spacing(RID p_font_rid, int p_size, TextServer::SpacingType p_spacing) const {
+int64_t TextServerFallback::font_get_spacing(const RID &p_font_rid, int64_t p_size, TextServer::SpacingType p_spacing) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0);
@@ -1337,26 +1386,26 @@ int TextServerFallback::font_get_spacing(RID p_font_rid, int p_size, TextServer:
switch (p_spacing) {
case TextServer::SPACING_GLYPH: {
if (fd->msdf) {
- return fd->cache[size]->spacing_glyph * (float)p_size / (float)fd->msdf_source_size;
+ return fd->cache[size]->spacing_glyph * (double)p_size / (double)fd->msdf_source_size;
} else {
return fd->cache[size]->spacing_glyph;
}
} break;
case TextServer::SPACING_SPACE: {
if (fd->msdf) {
- return fd->cache[size]->spacing_space * (float)p_size / (float)fd->msdf_source_size;
+ return fd->cache[size]->spacing_space * (double)p_size / (double)fd->msdf_source_size;
} else {
return fd->cache[size]->spacing_space;
}
} break;
default: {
- ERR_FAIL_V_MSG(0, "Invalid spacing type: " + itos(p_spacing));
+ ERR_FAIL_V_MSG(0, "Invalid spacing type: " + String::num_int64(p_spacing));
} break;
}
return 0;
}
-int TextServerFallback::font_get_texture_count(RID p_font_rid, const Vector2i &p_size) const {
+int64_t TextServerFallback::font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0);
@@ -1368,7 +1417,7 @@ int TextServerFallback::font_get_texture_count(RID p_font_rid, const Vector2i &p
return fd->cache[size]->textures.size();
}
-void TextServerFallback::font_clear_textures(RID p_font_rid, const Vector2i &p_size) {
+void TextServerFallback::font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1378,7 +1427,7 @@ void TextServerFallback::font_clear_textures(RID p_font_rid, const Vector2i &p_s
fd->cache[size]->textures.clear();
}
-void TextServerFallback::font_remove_texture(RID p_font_rid, const Vector2i &p_size, int p_texture_index) {
+void TextServerFallback::font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1390,7 +1439,7 @@ void TextServerFallback::font_remove_texture(RID p_font_rid, const Vector2i &p_s
fd->cache[size]->textures.remove_at(p_texture_index);
}
-void TextServerFallback::font_set_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) {
+void TextServerFallback::font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
ERR_FAIL_COND(p_image.is_null());
@@ -1410,13 +1459,20 @@ void TextServerFallback::font_set_texture_image(RID p_font_rid, const Vector2i &
tex.texture_h = p_image->get_height();
tex.format = p_image->get_format();
- Ref<Image> img = memnew(Image(tex.texture_w, tex.texture_h, 0, tex.format, tex.imgdata));
+ Ref<Image> img;
+ img.instantiate();
+ img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ if (fd->mipmaps) {
+ img->generate_mipmaps();
+ }
+
tex.texture = Ref<ImageTexture>();
tex.texture.instantiate();
tex.texture->create_from_image(img);
+ tex.dirty = false;
}
-Ref<Image> TextServerFallback::font_get_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const {
+Ref<Image> TextServerFallback::font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Ref<Image>());
@@ -1425,13 +1481,15 @@ Ref<Image> TextServerFallback::font_get_texture_image(RID p_font_rid, const Vect
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Ref<Image>());
ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), Ref<Image>());
- const FontTexture &tex = fd->cache[size]->textures.write[p_texture_index];
- Ref<Image> img = memnew(Image(tex.texture_w, tex.texture_h, 0, tex.format, tex.imgdata));
+ const FontTexture &tex = fd->cache[size]->textures[p_texture_index];
+ Ref<Image> img;
+ img.instantiate();
+ img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
return img;
}
-void TextServerFallback::font_set_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) {
+void TextServerFallback::font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1447,7 +1505,7 @@ void TextServerFallback::font_set_texture_offsets(RID p_font_rid, const Vector2i
tex.offsets = p_offset;
}
-PackedInt32Array TextServerFallback::font_get_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const {
+PackedInt32Array TextServerFallback::font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, PackedInt32Array());
@@ -1456,11 +1514,11 @@ PackedInt32Array TextServerFallback::font_get_texture_offsets(RID p_font_rid, co
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), PackedInt32Array());
ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), PackedInt32Array());
- const FontTexture &tex = fd->cache[size]->textures.write[p_texture_index];
+ const FontTexture &tex = fd->cache[size]->textures[p_texture_index];
return tex.offsets;
}
-Array TextServerFallback::font_get_glyph_list(RID p_font_rid, const Vector2i &p_size) const {
+Array TextServerFallback::font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Array());
@@ -1477,7 +1535,7 @@ Array TextServerFallback::font_get_glyph_list(RID p_font_rid, const Vector2i &p_
return ret;
}
-void TextServerFallback::font_clear_glyphs(RID p_font_rid, const Vector2i &p_size) {
+void TextServerFallback::font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1488,7 +1546,7 @@ void TextServerFallback::font_clear_glyphs(RID p_font_rid, const Vector2i &p_siz
fd->cache[size]->glyph_map.clear();
}
-void TextServerFallback::font_remove_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) {
+void TextServerFallback::font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1499,7 +1557,7 @@ void TextServerFallback::font_remove_glyph(RID p_font_rid, const Vector2i &p_siz
fd->cache[size]->glyph_map.erase(p_glyph);
}
-Vector2 TextServerFallback::font_get_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph) const {
+Vector2 TextServerFallback::font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector2());
@@ -1515,11 +1573,11 @@ Vector2 TextServerFallback::font_get_glyph_advance(RID p_font_rid, int p_size, i
Vector2 ea;
if (fd->embolden != 0.0) {
- ea.x = fd->embolden * float(size.x) / 64.0;
+ ea.x = fd->embolden * double(size.x) / 64.0;
}
if (fd->msdf) {
- return (gl[p_glyph].advance + ea) * (float)p_size / (float)fd->msdf_source_size;
+ return (gl[p_glyph].advance + ea) * (double)p_size / (double)fd->msdf_source_size;
} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_DISABLED) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x > SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
return (gl[p_glyph].advance + ea).round();
} else {
@@ -1527,7 +1585,7 @@ Vector2 TextServerFallback::font_get_glyph_advance(RID p_font_rid, int p_size, i
}
}
-void TextServerFallback::font_set_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph, const Vector2 &p_advance) {
+void TextServerFallback::font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1542,7 +1600,7 @@ void TextServerFallback::font_set_glyph_advance(RID p_font_rid, int p_size, int3
gl[p_glyph].found = true;
}
-Vector2 TextServerFallback::font_get_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
+Vector2 TextServerFallback::font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector2());
@@ -1557,13 +1615,13 @@ Vector2 TextServerFallback::font_get_glyph_offset(RID p_font_rid, const Vector2i
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
if (fd->msdf) {
- return gl[p_glyph].rect.position * (float)p_size.x / (float)fd->msdf_source_size;
+ return gl[p_glyph].rect.position * (double)p_size.x / (double)fd->msdf_source_size;
} else {
return gl[p_glyph].rect.position;
}
}
-void TextServerFallback::font_set_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) {
+void TextServerFallback::font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1578,7 +1636,7 @@ void TextServerFallback::font_set_glyph_offset(RID p_font_rid, const Vector2i &p
gl[p_glyph].found = true;
}
-Vector2 TextServerFallback::font_get_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
+Vector2 TextServerFallback::font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector2());
@@ -1593,13 +1651,13 @@ Vector2 TextServerFallback::font_get_glyph_size(RID p_font_rid, const Vector2i &
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
if (fd->msdf) {
- return gl[p_glyph].rect.size * (float)p_size.x / (float)fd->msdf_source_size;
+ return gl[p_glyph].rect.size * (double)p_size.x / (double)fd->msdf_source_size;
} else {
return gl[p_glyph].rect.size;
}
}
-void TextServerFallback::font_set_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) {
+void TextServerFallback::font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1614,7 +1672,7 @@ void TextServerFallback::font_set_glyph_size(RID p_font_rid, const Vector2i &p_s
gl[p_glyph].found = true;
}
-Rect2 TextServerFallback::font_get_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
+Rect2 TextServerFallback::font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Rect2());
@@ -1630,7 +1688,7 @@ Rect2 TextServerFallback::font_get_glyph_uv_rect(RID p_font_rid, const Vector2i
return gl[p_glyph].uv_rect;
}
-void TextServerFallback::font_set_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) {
+void TextServerFallback::font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1645,7 +1703,7 @@ void TextServerFallback::font_set_glyph_uv_rect(RID p_font_rid, const Vector2i &
gl[p_glyph].found = true;
}
-int TextServerFallback::font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
+int64_t TextServerFallback::font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, -1);
@@ -1661,7 +1719,7 @@ int TextServerFallback::font_get_glyph_texture_idx(RID p_font_rid, const Vector2
return gl[p_glyph].texture_idx;
}
-void TextServerFallback::font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) {
+void TextServerFallback::font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1676,7 +1734,87 @@ void TextServerFallback::font_set_glyph_texture_idx(RID p_font_rid, const Vector
gl[p_glyph].found = true;
}
-Dictionary TextServerFallback::font_get_glyph_contours(RID p_font_rid, int p_size, int32_t p_index) const {
+RID TextServerFallback::font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, RID());
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), RID());
+ if (!_ensure_glyph(fd, size, p_glyph)) {
+ return RID(); // Invalid or non graphicl glyph, do not display errors.
+ }
+
+ const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
+ ERR_FAIL_COND_V(gl[p_glyph].texture_idx < -1 || gl[p_glyph].texture_idx >= fd->cache[size]->textures.size(), RID());
+
+ if (RenderingServer::get_singleton() != nullptr) {
+ if (gl[p_glyph].texture_idx != -1) {
+ if (fd->cache[size]->textures[gl[p_glyph].texture_idx].dirty) {
+ FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph].texture_idx];
+ Ref<Image> img;
+ img.instantiate();
+ img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ if (fd->mipmaps) {
+ img->generate_mipmaps();
+ }
+ if (tex.texture.is_null()) {
+ tex.texture.instantiate();
+ tex.texture->create_from_image(img);
+ } else {
+ tex.texture->update(img);
+ }
+ tex.dirty = false;
+ }
+ return fd->cache[size]->textures[gl[p_glyph].texture_idx].texture->get_rid();
+ }
+ }
+
+ return RID();
+}
+
+Size2 TextServerFallback::font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, Size2());
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Size2());
+ if (!_ensure_glyph(fd, size, p_glyph)) {
+ return Size2(); // Invalid or non graphicl glyph, do not display errors.
+ }
+
+ const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
+ ERR_FAIL_COND_V(gl[p_glyph].texture_idx < -1 || gl[p_glyph].texture_idx >= fd->cache[size]->textures.size(), Size2());
+
+ if (RenderingServer::get_singleton() != nullptr) {
+ if (gl[p_glyph].texture_idx != -1) {
+ if (fd->cache[size]->textures[gl[p_glyph].texture_idx].dirty) {
+ FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph].texture_idx];
+ Ref<Image> img;
+ img.instantiate();
+ img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ if (fd->mipmaps) {
+ img->generate_mipmaps();
+ }
+ if (tex.texture.is_null()) {
+ tex.texture.instantiate();
+ tex.texture->create_from_image(img);
+ } else {
+ tex.texture->update(img);
+ }
+ tex.dirty = false;
+ }
+ return fd->cache[size]->textures[gl[p_glyph].texture_idx].texture->get_size();
+ }
+ }
+
+ return Size2();
+}
+
+Dictionary TextServerFallback::font_get_glyph_contours(const RID &p_font_rid, int64_t p_size, int64_t p_index) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Dictionary());
@@ -1685,20 +1823,19 @@ Dictionary TextServerFallback::font_get_glyph_contours(RID p_font_rid, int p_siz
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary());
- Vector<Vector3> points;
- Vector<int32_t> contours;
- bool orientation;
#ifdef MODULE_FREETYPE_ENABLED
- int error = FT_Load_Glyph(fd->cache[size]->face, FT_Get_Char_Index(fd->cache[size]->face, p_index), FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
- ERR_FAIL_COND_V(error, Dictionary());
+ PackedVector3Array points;
+ PackedInt32Array contours;
+
+ int32_t index = p_index & 0xffffff; // Remove subpixel shifts.
- points.clear();
- contours.clear();
+ int error = FT_Load_Glyph(fd->cache[size]->face, FT_Get_Char_Index(fd->cache[size]->face, index), FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
+ ERR_FAIL_COND_V(error, Dictionary());
- float h = fd->cache[size]->ascent;
- float scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale;
+ double h = fd->cache[size]->ascent;
+ double scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale;
if (fd->msdf) {
- scale = scale * (float)p_size / (float)fd->msdf_source_size;
+ scale = scale * (double)p_size / (double)fd->msdf_source_size;
}
for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_points; i++) {
points.push_back(Vector3(fd->cache[size]->face->glyph->outline.points[i].x * scale, h - fd->cache[size]->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fd->cache[size]->face->glyph->outline.tags[i])));
@@ -1706,19 +1843,19 @@ Dictionary TextServerFallback::font_get_glyph_contours(RID p_font_rid, int p_siz
for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_contours; i++) {
contours.push_back(fd->cache[size]->face->glyph->outline.contours[i]);
}
- orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);
-#else
- return Dictionary();
-#endif
+ bool orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);
Dictionary out;
out["points"] = points;
out["contours"] = contours;
out["orientation"] = orientation;
return out;
+#else
+ return Dictionary();
+#endif
}
-Array TextServerFallback::font_get_kerning_list(RID p_font_rid, int p_size) const {
+Array TextServerFallback::font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Array());
@@ -1734,7 +1871,7 @@ Array TextServerFallback::font_get_kerning_list(RID p_font_rid, int p_size) cons
return ret;
}
-void TextServerFallback::font_clear_kerning_map(RID p_font_rid, int p_size) {
+void TextServerFallback::font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1745,7 +1882,7 @@ void TextServerFallback::font_clear_kerning_map(RID p_font_rid, int p_size) {
fd->cache[size]->kerning_map.clear();
}
-void TextServerFallback::font_remove_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) {
+void TextServerFallback::font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1756,7 +1893,7 @@ void TextServerFallback::font_remove_kerning(RID p_font_rid, int p_size, const V
fd->cache[size]->kerning_map.erase(p_glyph_pair);
}
-void TextServerFallback::font_set_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) {
+void TextServerFallback::font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1767,7 +1904,7 @@ void TextServerFallback::font_set_kerning(RID p_font_rid, int p_size, const Vect
fd->cache[size]->kerning_map[p_glyph_pair] = p_kerning;
}
-Vector2 TextServerFallback::font_get_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) const {
+Vector2 TextServerFallback::font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector2());
@@ -1780,7 +1917,7 @@ Vector2 TextServerFallback::font_get_kerning(RID p_font_rid, int p_size, const V
if (kern.has(p_glyph_pair)) {
if (fd->msdf) {
- return kern[p_glyph_pair] * (float)p_size / (float)fd->msdf_source_size;
+ return kern[p_glyph_pair] * (double)p_size / (double)fd->msdf_source_size;
} else {
return kern[p_glyph_pair];
}
@@ -1792,7 +1929,7 @@ Vector2 TextServerFallback::font_get_kerning(RID p_font_rid, int p_size, const V
int32_t glyph_b = FT_Get_Char_Index(fd->cache[size]->face, p_glyph_pair.y);
FT_Get_Kerning(fd->cache[size]->face, glyph_a, glyph_b, FT_KERNING_DEFAULT, &delta);
if (fd->msdf) {
- return Vector2(delta.x, delta.y) * (float)p_size / (float)fd->msdf_source_size;
+ return Vector2(delta.x, delta.y) * (double)p_size / (double)fd->msdf_source_size;
} else {
return Vector2(delta.x, delta.y);
}
@@ -1802,12 +1939,12 @@ Vector2 TextServerFallback::font_get_kerning(RID p_font_rid, int p_size, const V
return Vector2();
}
-int32_t TextServerFallback::font_get_glyph_index(RID p_font_rid, int p_size, char32_t p_char, char32_t p_variation_selector) const {
+int64_t TextServerFallback::font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector) const {
ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), 0, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + ".");
- return (int32_t)p_char;
+ return (int64_t)p_char;
}
-bool TextServerFallback::font_has_char(RID p_font_rid, char32_t p_char) const {
+bool TextServerFallback::font_has_char(const RID &p_font_rid, int64_t p_char) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), false, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + ".");
@@ -1826,7 +1963,7 @@ bool TextServerFallback::font_has_char(RID p_font_rid, char32_t p_char) const {
return (at_size) ? at_size->glyph_map.has((int32_t)p_char) : false;
}
-String TextServerFallback::font_get_supported_chars(RID p_font_rid) const {
+String TextServerFallback::font_get_supported_chars(const RID &p_font_rid) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, String());
@@ -1843,7 +1980,7 @@ String TextServerFallback::font_get_supported_chars(RID p_font_rid) const {
FT_ULong charcode = FT_Get_First_Char(at_size->face, &gindex);
while (gindex != 0) {
if (charcode != 0) {
- chars += char32_t(charcode);
+ chars = chars + String::chr(charcode);
}
charcode = FT_Get_Next_Char(at_size->face, charcode, &gindex);
}
@@ -1854,13 +1991,13 @@ String TextServerFallback::font_get_supported_chars(RID p_font_rid) const {
const HashMap<int32_t, FontGlyph> &gl = at_size->glyph_map;
const int32_t *E = nullptr;
while ((E = gl.next(E))) {
- chars += char32_t(*E);
+ chars = chars + String::chr(*E);
}
}
return chars;
}
-void TextServerFallback::font_render_range(RID p_font_rid, const Vector2i &p_size, char32_t p_start, char32_t p_end) {
+void TextServerFallback::font_render_range(const RID &p_font_rid, const Vector2i &p_size, int64_t p_start, int64_t p_end) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
ERR_FAIL_COND_MSG((p_start >= 0xd800 && p_start <= 0xdfff) || (p_start > 0x10ffff), "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_start, 16) + ".");
@@ -1869,7 +2006,7 @@ void TextServerFallback::font_render_range(RID p_font_rid, const Vector2i &p_siz
MutexLock lock(fd->mutex);
Vector2i size = _get_size_outline(fd, p_size);
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
- for (char32_t i = p_start; i <= p_end; i++) {
+ for (int64_t i = p_start; i <= p_end; i++) {
#ifdef MODULE_FREETYPE_ENABLED
int32_t idx = i;
if (fd->cache[size]->face) {
@@ -1893,7 +2030,7 @@ void TextServerFallback::font_render_range(RID p_font_rid, const Vector2i &p_siz
}
}
-void TextServerFallback::font_render_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_index) {
+void TextServerFallback::font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1901,7 +2038,7 @@ void TextServerFallback::font_render_glyph(RID p_font_rid, const Vector2i &p_siz
Vector2i size = _get_size_outline(fd, p_size);
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
#ifdef MODULE_FREETYPE_ENABLED
- int32_t idx = p_index;
+ int32_t idx = p_index & 0xffffff; // Remove subpixel shifts.
if (fd->cache[size]->face) {
if (fd->msdf) {
_ensure_glyph(fd, size, (int32_t)idx);
@@ -1922,7 +2059,7 @@ void TextServerFallback::font_render_glyph(RID p_font_rid, const Vector2i &p_siz
#endif
}
-void TextServerFallback::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color) const {
+void TextServerFallback::font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1930,7 +2067,7 @@ void TextServerFallback::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_siz
Vector2i size = _get_size(fd, p_size);
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
- int32_t index = p_index;
+ int32_t index = p_index & 0xffffff; // Remove subpixel shifts.
#ifdef MODULE_FREETYPE_ENABLED
if (!fd->msdf && fd->cache[size]->face) {
@@ -1960,11 +2097,27 @@ void TextServerFallback::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_siz
}
#endif
if (RenderingServer::get_singleton() != nullptr) {
+ if (fd->cache[size]->textures[gl.texture_idx].dirty) {
+ FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
+ Ref<Image> img;
+ img.instantiate();
+ img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ if (fd->mipmaps) {
+ img->generate_mipmaps();
+ }
+ if (tex.texture.is_null()) {
+ tex.texture.instantiate();
+ tex.texture->create_from_image(img);
+ } else {
+ tex.texture->update(img);
+ }
+ tex.dirty = false;
+ }
RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid();
if (fd->msdf) {
Point2 cpos = p_pos;
- cpos += gl.rect.position * (float)p_size / (float)fd->msdf_source_size;
- Size2 csize = gl.rect.size * (float)p_size / (float)fd->msdf_source_size;
+ cpos += gl.rect.position * (double)p_size / (double)fd->msdf_source_size;
+ Size2 csize = gl.rect.size * (double)p_size / (double)fd->msdf_source_size;
RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range);
} else {
Point2 cpos = p_pos;
@@ -1985,7 +2138,7 @@ void TextServerFallback::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_siz
}
}
-void TextServerFallback::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color) const {
+void TextServerFallback::font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1993,7 +2146,7 @@ void TextServerFallback::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, i
Vector2i size = _get_size_outline(fd, Vector2i(p_size, p_outline_size));
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
- int32_t index = p_index;
+ int32_t index = p_index & 0xffffff; // Remove subpixel shifts.
#ifdef MODULE_FREETYPE_ENABLED
if (!fd->msdf && fd->cache[size]->face) {
@@ -2023,11 +2176,27 @@ void TextServerFallback::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, i
}
#endif
if (RenderingServer::get_singleton() != nullptr) {
+ if (fd->cache[size]->textures[gl.texture_idx].dirty) {
+ FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
+ Ref<Image> img;
+ img.instantiate();
+ img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ if (fd->mipmaps) {
+ img->generate_mipmaps();
+ }
+ if (tex.texture.is_null()) {
+ tex.texture.instantiate();
+ tex.texture->create_from_image(img);
+ } else {
+ tex.texture->update(img);
+ }
+ tex.dirty = false;
+ }
RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid();
if (fd->msdf) {
Point2 cpos = p_pos;
- cpos += gl.rect.position * (float)p_size / (float)fd->msdf_source_size;
- Size2 csize = gl.rect.size * (float)p_size / (float)fd->msdf_source_size;
+ cpos += gl.rect.position * (double)p_size / (double)fd->msdf_source_size;
+ Size2 csize = gl.rect.size * (double)p_size / (double)fd->msdf_source_size;
RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, p_outline_size * 2, fd->msdf_range);
} else {
Point2 cpos = p_pos;
@@ -2048,7 +2217,7 @@ void TextServerFallback::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, i
}
}
-bool TextServerFallback::font_is_language_supported(RID p_font_rid, const String &p_language) const {
+bool TextServerFallback::font_is_language_supported(const RID &p_font_rid, const String &p_language) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -2060,7 +2229,7 @@ bool TextServerFallback::font_is_language_supported(RID p_font_rid, const String
}
}
-void TextServerFallback::font_set_language_support_override(RID p_font_rid, const String &p_language, bool p_supported) {
+void TextServerFallback::font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2068,7 +2237,7 @@ void TextServerFallback::font_set_language_support_override(RID p_font_rid, cons
fd->language_support_overrides[p_language] = p_supported;
}
-bool TextServerFallback::font_get_language_support_override(RID p_font_rid, const String &p_language) {
+bool TextServerFallback::font_get_language_support_override(const RID &p_font_rid, const String &p_language) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -2076,7 +2245,7 @@ bool TextServerFallback::font_get_language_support_override(RID p_font_rid, cons
return fd->language_support_overrides[p_language];
}
-void TextServerFallback::font_remove_language_support_override(RID p_font_rid, const String &p_language) {
+void TextServerFallback::font_remove_language_support_override(const RID &p_font_rid, const String &p_language) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2084,19 +2253,19 @@ void TextServerFallback::font_remove_language_support_override(RID p_font_rid, c
fd->language_support_overrides.erase(p_language);
}
-Vector<String> TextServerFallback::font_get_language_support_overrides(RID p_font_rid) {
+PackedStringArray TextServerFallback::font_get_language_support_overrides(const RID &p_font_rid) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, Vector<String>());
+ ERR_FAIL_COND_V(!fd, PackedStringArray());
MutexLock lock(fd->mutex);
- Vector<String> out;
+ PackedStringArray out;
for (const KeyValue<String, bool> &E : fd->language_support_overrides) {
out.push_back(E.key);
}
return out;
}
-bool TextServerFallback::font_is_script_supported(RID p_font_rid, const String &p_script) const {
+bool TextServerFallback::font_is_script_supported(const RID &p_font_rid, const String &p_script) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -2108,7 +2277,7 @@ bool TextServerFallback::font_is_script_supported(RID p_font_rid, const String &
}
}
-void TextServerFallback::font_set_script_support_override(RID p_font_rid, const String &p_script, bool p_supported) {
+void TextServerFallback::font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2116,7 +2285,7 @@ void TextServerFallback::font_set_script_support_override(RID p_font_rid, const
fd->script_support_overrides[p_script] = p_supported;
}
-bool TextServerFallback::font_get_script_support_override(RID p_font_rid, const String &p_script) {
+bool TextServerFallback::font_get_script_support_override(const RID &p_font_rid, const String &p_script) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -2124,7 +2293,7 @@ bool TextServerFallback::font_get_script_support_override(RID p_font_rid, const
return fd->script_support_overrides[p_script];
}
-void TextServerFallback::font_remove_script_support_override(RID p_font_rid, const String &p_script) {
+void TextServerFallback::font_remove_script_support_override(const RID &p_font_rid, const String &p_script) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2134,19 +2303,19 @@ void TextServerFallback::font_remove_script_support_override(RID p_font_rid, con
fd->script_support_overrides.erase(p_script);
}
-Vector<String> TextServerFallback::font_get_script_support_overrides(RID p_font_rid) {
+PackedStringArray TextServerFallback::font_get_script_support_overrides(const RID &p_font_rid) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, Vector<String>());
+ ERR_FAIL_COND_V(!fd, PackedStringArray());
MutexLock lock(fd->mutex);
- Vector<String> out;
+ PackedStringArray out;
for (const KeyValue<String, bool> &E : fd->script_support_overrides) {
out.push_back(E.key);
}
return out;
}
-void TextServerFallback::font_set_opentype_feature_overrides(RID p_font_rid, const Dictionary &p_overrides) {
+void TextServerFallback::font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2156,7 +2325,7 @@ void TextServerFallback::font_set_opentype_feature_overrides(RID p_font_rid, con
fd->feature_overrides = p_overrides;
}
-Dictionary TextServerFallback::font_get_opentype_feature_overrides(RID p_font_rid) const {
+Dictionary TextServerFallback::font_get_opentype_feature_overrides(const RID &p_font_rid) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Dictionary());
@@ -2164,11 +2333,11 @@ Dictionary TextServerFallback::font_get_opentype_feature_overrides(RID p_font_ri
return fd->feature_overrides;
}
-Dictionary TextServerFallback::font_supported_feature_list(RID p_font_rid) const {
+Dictionary TextServerFallback::font_supported_feature_list(const RID &p_font_rid) const {
return Dictionary();
}
-Dictionary TextServerFallback::font_supported_variation_list(RID p_font_rid) const {
+Dictionary TextServerFallback::font_supported_variation_list(const RID &p_font_rid) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Dictionary());
@@ -2178,11 +2347,11 @@ Dictionary TextServerFallback::font_supported_variation_list(RID p_font_rid) con
return fd->supported_varaitions;
}
-float TextServerFallback::font_get_global_oversampling() const {
+double TextServerFallback::font_get_global_oversampling() const {
return oversampling;
}
-void TextServerFallback::font_set_global_oversampling(float p_oversampling) {
+void TextServerFallback::font_set_global_oversampling(double p_oversampling) {
_THREAD_SAFE_METHOD_
if (oversampling != p_oversampling) {
oversampling = p_oversampling;
@@ -2215,11 +2384,11 @@ void TextServerFallback::invalidate(ShapedTextDataFallback *p_shaped) {
p_shaped->sort_valid = false;
p_shaped->line_breaks_valid = false;
p_shaped->justification_ops_valid = false;
- p_shaped->ascent = 0.f;
- p_shaped->descent = 0.f;
- p_shaped->width = 0.f;
- p_shaped->upos = 0.f;
- p_shaped->uthk = 0.f;
+ p_shaped->ascent = 0.0;
+ p_shaped->descent = 0.0;
+ p_shaped->width = 0.0;
+ p_shaped->upos = 0.0;
+ p_shaped->uthk = 0.0;
p_shaped->glyphs.clear();
p_shaped->glyphs_logical.clear();
}
@@ -2255,7 +2424,7 @@ RID TextServerFallback::create_shaped_text(TextServer::Direction p_direction, Te
return shaped_owner.make_rid(sd);
}
-void TextServerFallback::shaped_text_clear(RID p_shaped) {
+void TextServerFallback::shaped_text_clear(const RID &p_shaped) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
@@ -2269,21 +2438,21 @@ void TextServerFallback::shaped_text_clear(RID p_shaped) {
invalidate(sd);
}
-void TextServerFallback::shaped_text_set_direction(RID p_shaped, TextServer::Direction p_direction) {
+void TextServerFallback::shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) {
if (p_direction == DIRECTION_RTL) {
ERR_PRINT_ONCE("Right-to-left layout is not supported by this text server.");
}
}
-TextServer::Direction TextServerFallback::shaped_text_get_direction(RID p_shaped) const {
+TextServer::Direction TextServerFallback::shaped_text_get_direction(const RID &p_shaped) const {
return TextServer::DIRECTION_LTR;
}
-TextServer::Direction TextServerFallback::shaped_text_get_inferred_direction(RID p_shaped) const {
+TextServer::Direction TextServerFallback::shaped_text_get_inferred_direction(const RID &p_shaped) const {
return TextServer::DIRECTION_LTR;
}
-void TextServerFallback::shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) {
+void TextServerFallback::shaped_text_set_custom_punctuation(const RID &p_shaped, const String &p_punct) {
_THREAD_SAFE_METHOD_
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
@@ -2297,14 +2466,14 @@ void TextServerFallback::shaped_text_set_custom_punctuation(RID p_shaped, const
}
}
-String TextServerFallback::shaped_text_get_custom_punctuation(RID p_shaped) const {
+String TextServerFallback::shaped_text_get_custom_punctuation(const RID &p_shaped) const {
_THREAD_SAFE_METHOD_
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, String());
return sd->custom_punct;
}
-void TextServerFallback::shaped_text_set_orientation(RID p_shaped, TextServer::Orientation p_orientation) {
+void TextServerFallback::shaped_text_set_orientation(const RID &p_shaped, TextServer::Orientation p_orientation) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
@@ -2318,11 +2487,11 @@ void TextServerFallback::shaped_text_set_orientation(RID p_shaped, TextServer::O
}
}
-void TextServerFallback::shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) {
+void TextServerFallback::shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) {
// No BiDi support, ignore.
}
-TextServer::Orientation TextServerFallback::shaped_text_get_orientation(RID p_shaped) const {
+TextServer::Orientation TextServerFallback::shaped_text_get_orientation(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, TextServer::ORIENTATION_HORIZONTAL);
@@ -2330,7 +2499,7 @@ TextServer::Orientation TextServerFallback::shaped_text_get_orientation(RID p_sh
return sd->orientation;
}
-void TextServerFallback::shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) {
+void TextServerFallback::shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
MutexLock lock(sd->mutex);
@@ -2344,7 +2513,7 @@ void TextServerFallback::shaped_text_set_preserve_invalid(RID p_shaped, bool p_e
}
}
-bool TextServerFallback::shaped_text_get_preserve_invalid(RID p_shaped) const {
+bool TextServerFallback::shaped_text_get_preserve_invalid(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -2352,7 +2521,7 @@ bool TextServerFallback::shaped_text_get_preserve_invalid(RID p_shaped) const {
return sd->preserve_invalid;
}
-void TextServerFallback::shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) {
+void TextServerFallback::shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
@@ -2366,7 +2535,7 @@ void TextServerFallback::shaped_text_set_preserve_control(RID p_shaped, bool p_e
}
}
-bool TextServerFallback::shaped_text_get_preserve_control(RID p_shaped) const {
+bool TextServerFallback::shaped_text_get_preserve_control(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -2374,28 +2543,28 @@ bool TextServerFallback::shaped_text_get_preserve_control(RID p_shaped) const {
return sd->preserve_control;
}
-int TextServerFallback::shaped_get_span_count(RID p_shaped) const {
+int64_t TextServerFallback::shaped_get_span_count(const RID &p_shaped) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0);
return sd->spans.size();
}
-Variant TextServerFallback::shaped_get_span_meta(RID p_shaped, int p_index) const {
+Variant TextServerFallback::shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, Variant());
ERR_FAIL_INDEX_V(p_index, sd->spans.size(), Variant());
return sd->spans[p_index].meta;
}
-void TextServerFallback::shaped_set_span_update_font(RID p_shaped, int p_index, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features) {
+void TextServerFallback::shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
ERR_FAIL_INDEX(p_index, sd->spans.size());
- ShapedTextDataFallback::Span &span = sd->spans.write[p_index];
+ ShapedTextDataFallback::Span &span = sd->spans.ptrw()[p_index];
span.fonts.clear();
// Pre-sort fonts, push fonts with the language support first.
- Vector<RID> fonts_no_match;
+ Array fonts_no_match;
int font_count = p_fonts.size();
for (int i = 0; i < font_count; i++) {
if (font_is_language_supported(p_fonts[i], span.language)) {
@@ -2411,7 +2580,7 @@ void TextServerFallback::shaped_set_span_update_font(RID p_shaped, int p_index,
sd->valid = false;
}
-bool TextServerFallback::shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) {
+bool TextServerFallback::shaped_text_add_string(const RID &p_shaped, const String &p_text, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -2435,7 +2604,7 @@ bool TextServerFallback::shaped_text_add_string(RID p_shaped, const String &p_te
span.end = span.start + p_text.length();
// Pre-sort fonts, push fonts with the language support first.
- Vector<RID> fonts_no_match;
+ Array fonts_no_match;
int font_count = p_fonts.size();
for (int i = 0; i < font_count; i++) {
if (font_is_language_supported(p_fonts[i], p_language)) {
@@ -2452,14 +2621,14 @@ bool TextServerFallback::shaped_text_add_string(RID p_shaped, const String &p_te
span.meta = p_meta;
sd->spans.push_back(span);
- sd->text += p_text;
+ sd->text = sd->text + p_text;
sd->end += p_text.length();
invalidate(sd);
return true;
}
-bool TextServerFallback::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align, int p_length) {
+bool TextServerFallback::shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, int64_t p_length) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -2482,7 +2651,7 @@ bool TextServerFallback::shaped_text_add_object(RID p_shaped, Variant p_key, con
obj.pos = span.start;
sd->spans.push_back(span);
- sd->text += String::chr(0xfffc).repeat(p_length);
+ sd->text = sd->text + String::chr(0xfffc).repeat(p_length);
sd->end += p_length;
sd->objects[p_key] = obj;
invalidate(sd);
@@ -2490,7 +2659,7 @@ bool TextServerFallback::shaped_text_add_object(RID p_shaped, Variant p_key, con
return true;
}
-bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align) {
+bool TextServerFallback::shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -2544,8 +2713,8 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
if (sd->orientation == ORIENTATION_HORIZONTAL) {
sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y);
} else {
- sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
- sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
+ sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));
+ sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));
}
}
sd->width += gl.advance * gl.repeat;
@@ -2558,8 +2727,8 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
void TextServerFallback::_realign(ShapedTextDataFallback *p_sd) const {
// Align embedded objects to baseline.
- float full_ascent = p_sd->ascent;
- float full_descent = p_sd->descent;
+ double full_ascent = p_sd->ascent;
+ double full_descent = p_sd->descent;
for (KeyValue<Variant, ShapedTextDataFallback::EmbeddedObject> &E : p_sd->objects) {
if ((E.value.pos >= p_sd->start) && (E.value.pos < p_sd->end)) {
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
@@ -2625,7 +2794,7 @@ void TextServerFallback::_realign(ShapedTextDataFallback *p_sd) const {
p_sd->descent = full_descent;
}
-RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_length) const {
+RID TextServerFallback::shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, RID());
@@ -2697,8 +2866,8 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y);
} else {
- new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
- new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));
+ new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));
}
}
new_sd->width += gl.advance * gl.repeat;
@@ -2707,79 +2876,14 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
}
}
- // Align embedded objects to baseline.
- float full_ascent = new_sd->ascent;
- float full_descent = new_sd->descent;
- for (KeyValue<Variant, ShapedTextDataFallback::EmbeddedObject> &E : new_sd->objects) {
- if ((E.value.pos >= new_sd->start) && (E.value.pos < new_sd->end)) {
- if (sd->orientation == ORIENTATION_HORIZONTAL) {
- switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) {
- case INLINE_ALIGNMENT_TO_TOP: {
- E.value.rect.position.y = -new_sd->ascent;
- } break;
- case INLINE_ALIGNMENT_TO_CENTER: {
- E.value.rect.position.y = (-new_sd->ascent + new_sd->descent) / 2;
- } break;
- case INLINE_ALIGNMENT_TO_BASELINE: {
- E.value.rect.position.y = 0;
- } break;
- case INLINE_ALIGNMENT_TO_BOTTOM: {
- E.value.rect.position.y = new_sd->descent;
- } break;
- }
- switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) {
- case INLINE_ALIGNMENT_BOTTOM_TO: {
- E.value.rect.position.y -= E.value.rect.size.y;
- } break;
- case INLINE_ALIGNMENT_CENTER_TO: {
- E.value.rect.position.y -= E.value.rect.size.y / 2;
- } break;
- case INLINE_ALIGNMENT_TOP_TO: {
- // NOP
- } break;
- }
- full_ascent = MAX(full_ascent, -E.value.rect.position.y);
- full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y);
- } else {
- switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) {
- case INLINE_ALIGNMENT_TO_TOP: {
- E.value.rect.position.x = -new_sd->ascent;
- } break;
- case INLINE_ALIGNMENT_TO_CENTER: {
- E.value.rect.position.x = (-new_sd->ascent + new_sd->descent) / 2;
- } break;
- case INLINE_ALIGNMENT_TO_BASELINE: {
- E.value.rect.position.x = 0;
- } break;
- case INLINE_ALIGNMENT_TO_BOTTOM: {
- E.value.rect.position.x = new_sd->descent;
- } break;
- }
- switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) {
- case INLINE_ALIGNMENT_BOTTOM_TO: {
- E.value.rect.position.x -= E.value.rect.size.x;
- } break;
- case INLINE_ALIGNMENT_CENTER_TO: {
- E.value.rect.position.x -= E.value.rect.size.x / 2;
- } break;
- case INLINE_ALIGNMENT_TOP_TO: {
- // NOP
- } break;
- }
- full_ascent = MAX(full_ascent, -E.value.rect.position.x);
- full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x);
- }
- }
- }
- new_sd->ascent = full_ascent;
- new_sd->descent = full_descent;
+ _realign(new_sd);
}
new_sd->valid = true;
return shaped_owner.make_rid(new_sd);
}
-RID TextServerFallback::shaped_text_get_parent(RID p_shaped) const {
+RID TextServerFallback::shaped_text_get_parent(const RID &p_shaped) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, RID());
@@ -2787,9 +2891,9 @@ RID TextServerFallback::shaped_text_get_parent(RID p_shaped) const {
return sd->parent;
}
-float TextServerFallback::shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t /*JustificationFlag*/ p_jst_flags) {
+double TextServerFallback::shaped_text_fit_to_width(const RID &p_shaped, double p_width, int64_t /*JustificationFlag*/ p_jst_flags) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
- ERR_FAIL_COND_V(!sd, 0.f);
+ ERR_FAIL_COND_V(!sd, 0.0);
MutexLock lock(sd->mutex);
if (!sd->valid) {
@@ -2827,7 +2931,7 @@ float TextServerFallback::shaped_text_fit_to_width(RID p_shaped, float p_width,
}
}
- float justification_width;
+ double justification_width;
if ((p_jst_flags & JUSTIFICATION_CONSTRAIN_ELLIPSIS) == JUSTIFICATION_CONSTRAIN_ELLIPSIS) {
if (sd->overrun_trim_data.trim_pos >= 0) {
end_pos = sd->overrun_trim_data.trim_pos;
@@ -2872,12 +2976,12 @@ float TextServerFallback::shaped_text_fit_to_width(RID p_shaped, float p_width,
}
if ((space_count > 0) && ((p_jst_flags & JUSTIFICATION_WORD_BOUND) == JUSTIFICATION_WORD_BOUND)) {
- float delta_width_per_space = (p_width - justification_width) / space_count;
+ double delta_width_per_space = (p_width - justification_width) / space_count;
for (int i = start_pos; i <= end_pos; i++) {
Glyph &gl = sd->glyphs.write[i];
if (gl.count > 0) {
if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) {
- float old_adv = gl.advance;
+ double old_adv = gl.advance;
gl.advance = MAX(gl.advance + delta_width_per_space, Math::round(0.1 * gl.font_size));
justification_width += (gl.advance - old_adv);
}
@@ -2896,9 +3000,9 @@ float TextServerFallback::shaped_text_fit_to_width(RID p_shaped, float p_width,
return Math::ceil(justification_width);
}
-float TextServerFallback::shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) {
+double TextServerFallback::shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
- ERR_FAIL_COND_V(!sd, 0.f);
+ ERR_FAIL_COND_V(!sd, 0.0);
MutexLock lock(sd->mutex);
if (!sd->valid) {
@@ -2910,12 +3014,12 @@ float TextServerFallback::shaped_text_tab_align(RID p_shaped, const PackedFloat3
for (int i = 0; i < p_tab_stops.size(); i++) {
if (p_tab_stops[i] <= 0) {
- return 0.f;
+ return 0.0;
}
}
int tab_index = 0;
- float off = 0.f;
+ double off = 0.0;
int start, end, delta;
if (sd->para_direction == DIRECTION_LTR) {
@@ -2932,7 +3036,7 @@ float TextServerFallback::shaped_text_tab_align(RID p_shaped, const PackedFloat3
for (int i = start; i != end; i += delta) {
if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
- float tab_off = 0.f;
+ double tab_off = 0.0;
while (tab_off <= off) {
tab_off += p_tab_stops[tab_index];
tab_index++;
@@ -2940,7 +3044,7 @@ float TextServerFallback::shaped_text_tab_align(RID p_shaped, const PackedFloat3
tab_index = 0;
}
}
- float old_adv = gl[i].advance;
+ double old_adv = gl[i].advance;
gl[i].advance = tab_off - off;
sd->width += gl[i].advance - old_adv;
off = 0;
@@ -2949,10 +3053,10 @@ float TextServerFallback::shaped_text_tab_align(RID p_shaped, const PackedFloat3
off += gl[i].advance * gl[i].repeat;
}
- return 0.f;
+ return 0.0;
}
-bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) {
+bool TextServerFallback::shaped_text_update_breaks(const RID &p_shaped) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -2975,7 +3079,7 @@ bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) {
if (sd_glyphs[i].count > 0) {
char32_t c = sd->text[sd_glyphs[i].start - sd->start];
if (c_punct_size == 0) {
- if (is_punct(c)) {
+ if (is_punct(c) && c != 0x005F) {
sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION;
}
} else {
@@ -3008,7 +3112,7 @@ bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) {
return sd->line_breaks_valid;
}
-bool TextServerFallback::shaped_text_update_justification_ops(RID p_shaped) {
+bool TextServerFallback::shaped_text_update_justification_ops(const RID &p_shaped) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -3024,7 +3128,7 @@ bool TextServerFallback::shaped_text_update_justification_ops(RID p_shaped) {
return true;
}
-void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint16_t p_trim_flags) {
+void TextServerFallback::shaped_text_overrun_trim_to_width(const RID &p_shaped_line, double p_width, int64_t p_trim_flags) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped_line);
ERR_FAIL_COND_MSG(!sd, "ShapedTextDataFallback invalid.");
@@ -3070,20 +3174,20 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
// Find usable fonts, if fonts from the last glyph do not have required chars.
RID dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;
if (!font_has_char(dot_gl_font_rid, '.')) {
- const Vector<RID> &fonts = spans[spans.size() - 1].fonts;
- for (const RID &font : fonts) {
- if (font_has_char(font, '.')) {
- dot_gl_font_rid = font;
+ const Array &fonts = spans[spans.size() - 1].fonts;
+ for (int i = 0; i < fonts.size(); i++) {
+ if (font_has_char(fonts[i], '.')) {
+ dot_gl_font_rid = fonts[i];
break;
}
}
}
RID whitespace_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;
if (!font_has_char(whitespace_gl_font_rid, '.')) {
- const Vector<RID> &fonts = spans[spans.size() - 1].fonts;
- for (const RID &font : fonts) {
- if (font_has_char(font, ' ')) {
- whitespace_gl_font_rid = font;
+ const Array &fonts = spans[spans.size() - 1].fonts;
+ for (int i = 0; i < fonts.size(); i++) {
+ if (font_has_char(fonts[i], ' ')) {
+ whitespace_gl_font_rid = fonts[i];
break;
}
}
@@ -3100,7 +3204,7 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
}
int ell_min_characters = 6;
- float width = sd->width;
+ double width = sd->width;
int trim_pos = 0;
int ellipsis_pos = (enforce_ellipsis) ? 0 : -1;
@@ -3176,7 +3280,7 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
}
}
-int TextServerFallback::shaped_text_get_trim_pos(RID p_shaped) const {
+int64_t TextServerFallback::shaped_text_get_trim_pos(const RID &p_shaped) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataFallback invalid.");
@@ -3184,7 +3288,7 @@ int TextServerFallback::shaped_text_get_trim_pos(RID p_shaped) const {
return sd->overrun_trim_data.trim_pos;
}
-int TextServerFallback::shaped_text_get_ellipsis_pos(RID p_shaped) const {
+int64_t TextServerFallback::shaped_text_get_ellipsis_pos(const RID &p_shaped) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataFallback invalid.");
@@ -3192,7 +3296,7 @@ int TextServerFallback::shaped_text_get_ellipsis_pos(RID p_shaped) const {
return sd->overrun_trim_data.ellipsis_pos;
}
-const Glyph *TextServerFallback::shaped_text_get_ellipsis_glyphs(RID p_shaped) const {
+const Glyph *TextServerFallback::shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V_MSG(!sd, nullptr, "ShapedTextDataFallback invalid.");
@@ -3200,7 +3304,7 @@ const Glyph *TextServerFallback::shaped_text_get_ellipsis_glyphs(RID p_shaped) c
return sd->overrun_trim_data.ellipsis_glyph_buf.ptr();
}
-int TextServerFallback::shaped_text_get_ellipsis_glyph_count(RID p_shaped) const {
+int64_t TextServerFallback::shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V_MSG(!sd, 0, "ShapedTextDataFallback invalid.");
@@ -3208,7 +3312,7 @@ int TextServerFallback::shaped_text_get_ellipsis_glyph_count(RID p_shaped) const
return sd->overrun_trim_data.ellipsis_glyph_buf.size();
}
-bool TextServerFallback::shaped_text_shape(RID p_shaped) {
+bool TextServerFallback::shaped_text_shape(const RID &p_shaped) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -3224,9 +3328,9 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
// Cleanup.
sd->justification_ops_valid = false;
sd->line_breaks_valid = false;
- sd->ascent = 0.f;
- sd->descent = 0.f;
- sd->width = 0.f;
+ sd->ascent = 0.0;
+ sd->descent = 0.0;
+ sd->width = 0.0;
sd->glyphs.clear();
if (sd->text.length() == 0) {
@@ -3327,8 +3431,8 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y);
} else {
gl.advance = get_hex_code_box_size(gl.font_size, gl.index).y;
- sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
- sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
+ sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));
+ sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));
}
}
sd->width += gl.advance;
@@ -3338,74 +3442,13 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
}
// Align embedded objects to baseline.
- float full_ascent = sd->ascent;
- float full_descent = sd->descent;
- for (KeyValue<Variant, ShapedTextDataFallback::EmbeddedObject> &E : sd->objects) {
- if (sd->orientation == ORIENTATION_HORIZONTAL) {
- switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) {
- case INLINE_ALIGNMENT_TO_TOP: {
- E.value.rect.position.y = -sd->ascent;
- } break;
- case INLINE_ALIGNMENT_TO_CENTER: {
- E.value.rect.position.y = (-sd->ascent + sd->descent) / 2;
- } break;
- case INLINE_ALIGNMENT_TO_BASELINE: {
- E.value.rect.position.y = 0;
- } break;
- case INLINE_ALIGNMENT_TO_BOTTOM: {
- E.value.rect.position.y = sd->descent;
- } break;
- }
- switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) {
- case INLINE_ALIGNMENT_BOTTOM_TO: {
- E.value.rect.position.y -= E.value.rect.size.y;
- } break;
- case INLINE_ALIGNMENT_CENTER_TO: {
- E.value.rect.position.y -= E.value.rect.size.y / 2;
- } break;
- case INLINE_ALIGNMENT_TOP_TO: {
- // NOP
- } break;
- }
- full_ascent = MAX(full_ascent, -E.value.rect.position.y);
- full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y);
- } else {
- switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) {
- case INLINE_ALIGNMENT_TO_TOP: {
- E.value.rect.position.x = -sd->ascent;
- } break;
- case INLINE_ALIGNMENT_TO_CENTER: {
- E.value.rect.position.x = (-sd->ascent + sd->descent) / 2;
- } break;
- case INLINE_ALIGNMENT_TO_BASELINE: {
- E.value.rect.position.x = 0;
- } break;
- case INLINE_ALIGNMENT_TO_BOTTOM: {
- E.value.rect.position.x = sd->descent;
- } break;
- }
- switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) {
- case INLINE_ALIGNMENT_BOTTOM_TO: {
- E.value.rect.position.x -= E.value.rect.size.x;
- } break;
- case INLINE_ALIGNMENT_CENTER_TO: {
- E.value.rect.position.x -= E.value.rect.size.x / 2;
- } break;
- case INLINE_ALIGNMENT_TOP_TO: {
- // NOP
- } break;
- }
- full_ascent = MAX(full_ascent, -E.value.rect.position.x);
- full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x);
- }
- }
- sd->ascent = full_ascent;
- sd->descent = full_descent;
+ _realign(sd);
+
sd->valid = true;
return sd->valid;
}
-bool TextServerFallback::shaped_text_is_ready(RID p_shaped) const {
+bool TextServerFallback::shaped_text_is_ready(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -3413,7 +3456,7 @@ bool TextServerFallback::shaped_text_is_ready(RID p_shaped) const {
return sd->valid;
}
-const Glyph *TextServerFallback::shaped_text_get_glyphs(RID p_shaped) const {
+const Glyph *TextServerFallback::shaped_text_get_glyphs(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, nullptr);
@@ -3424,7 +3467,7 @@ const Glyph *TextServerFallback::shaped_text_get_glyphs(RID p_shaped) const {
return sd->glyphs.ptr();
}
-int TextServerFallback::shaped_text_get_glyph_count(RID p_shaped) const {
+int64_t TextServerFallback::shaped_text_get_glyph_count(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0);
@@ -3435,7 +3478,7 @@ int TextServerFallback::shaped_text_get_glyph_count(RID p_shaped) const {
return sd->glyphs.size();
}
-const Glyph *TextServerFallback::shaped_text_sort_logical(RID p_shaped) {
+const Glyph *TextServerFallback::shaped_text_sort_logical(const RID &p_shaped) {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, nullptr);
@@ -3447,7 +3490,7 @@ const Glyph *TextServerFallback::shaped_text_sort_logical(RID p_shaped) {
return sd->glyphs.ptr(); // Already in the logical order, return as is.
}
-Vector2i TextServerFallback::shaped_text_get_range(RID p_shaped) const {
+Vector2i TextServerFallback::shaped_text_get_range(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, Vector2i());
@@ -3455,7 +3498,7 @@ Vector2i TextServerFallback::shaped_text_get_range(RID p_shaped) const {
return Vector2(sd->start, sd->end);
}
-Array TextServerFallback::shaped_text_get_objects(RID p_shaped) const {
+Array TextServerFallback::shaped_text_get_objects(const RID &p_shaped) const {
Array ret;
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, ret);
@@ -3468,7 +3511,7 @@ Array TextServerFallback::shaped_text_get_objects(RID p_shaped) const {
return ret;
}
-Rect2 TextServerFallback::shaped_text_get_object_rect(RID p_shaped, Variant p_key) const {
+Rect2 TextServerFallback::shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, Rect2());
@@ -3480,7 +3523,7 @@ Rect2 TextServerFallback::shaped_text_get_object_rect(RID p_shaped, Variant p_ke
return sd->objects[p_key].rect;
}
-Size2 TextServerFallback::shaped_text_get_size(RID p_shaped) const {
+Size2 TextServerFallback::shaped_text_get_size(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, Size2());
@@ -3495,9 +3538,9 @@ Size2 TextServerFallback::shaped_text_get_size(RID p_shaped) const {
}
}
-float TextServerFallback::shaped_text_get_ascent(RID p_shaped) const {
+double TextServerFallback::shaped_text_get_ascent(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
- ERR_FAIL_COND_V(!sd, 0.f);
+ ERR_FAIL_COND_V(!sd, 0.0);
MutexLock lock(sd->mutex);
if (!sd->valid) {
@@ -3506,9 +3549,9 @@ float TextServerFallback::shaped_text_get_ascent(RID p_shaped) const {
return sd->ascent;
}
-float TextServerFallback::shaped_text_get_descent(RID p_shaped) const {
+double TextServerFallback::shaped_text_get_descent(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
- ERR_FAIL_COND_V(!sd, 0.f);
+ ERR_FAIL_COND_V(!sd, 0.0);
MutexLock lock(sd->mutex);
if (!sd->valid) {
@@ -3517,9 +3560,9 @@ float TextServerFallback::shaped_text_get_descent(RID p_shaped) const {
return sd->descent;
}
-float TextServerFallback::shaped_text_get_width(RID p_shaped) const {
+double TextServerFallback::shaped_text_get_width(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
- ERR_FAIL_COND_V(!sd, 0.f);
+ ERR_FAIL_COND_V(!sd, 0.0);
MutexLock lock(sd->mutex);
if (!sd->valid) {
@@ -3528,9 +3571,9 @@ float TextServerFallback::shaped_text_get_width(RID p_shaped) const {
return Math::ceil(sd->width);
}
-float TextServerFallback::shaped_text_get_underline_position(RID p_shaped) const {
+double TextServerFallback::shaped_text_get_underline_position(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
- ERR_FAIL_COND_V(!sd, 0.f);
+ ERR_FAIL_COND_V(!sd, 0.0);
MutexLock lock(sd->mutex);
if (!sd->valid) {
@@ -3540,9 +3583,9 @@ float TextServerFallback::shaped_text_get_underline_position(RID p_shaped) const
return sd->upos;
}
-float TextServerFallback::shaped_text_get_underline_thickness(RID p_shaped) const {
+double TextServerFallback::shaped_text_get_underline_thickness(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
- ERR_FAIL_COND_V(!sd, 0.f);
+ ERR_FAIL_COND_V(!sd, 0.0);
MutexLock lock(sd->mutex);
if (!sd->valid) {
@@ -3555,7 +3598,7 @@ float TextServerFallback::shaped_text_get_underline_thickness(RID p_shaped) cons
String TextServerFallback::string_to_upper(const String &p_string, const String &p_language) const {
String upper = p_string;
- for (int i = 0; i < upper.size(); i++) {
+ for (int i = 0; i <= upper.length(); i++) {
const char32_t s = upper[i];
const char32_t t = _find_upper(s);
if (s != t) { // avoid copy on write
@@ -3569,7 +3612,7 @@ String TextServerFallback::string_to_upper(const String &p_string, const String
String TextServerFallback::string_to_lower(const String &p_string, const String &p_language) const {
String lower = p_string;
- for (int i = 0; i < lower.size(); i++) {
+ for (int i = 0; i <= lower.length(); i++) {
const char32_t s = lower[i];
const char32_t t = _find_lower(s);
if (s != t) { // avoid copy on write
@@ -3580,14 +3623,37 @@ String TextServerFallback::string_to_lower(const String &p_string, const String
return lower;
}
+PackedInt32Array TextServerFallback::string_get_word_breaks(const String &p_string, const String &p_language) const {
+ PackedInt32Array ret;
+ for (int i = 0; i < p_string.length(); i++) {
+ char32_t c = p_string[i];
+ if (c == 0xfffc) {
+ continue;
+ }
+ if (is_punct(c) && c != 0x005F) {
+ ret.push_back(i);
+ continue;
+ }
+ if (is_underscore(c)) {
+ ret.push_back(i);
+ continue;
+ }
+ if (is_whitespace(c) || is_linebreak(c)) {
+ ret.push_back(i);
+ continue;
+ }
+ }
+ return ret;
+}
+
TextServerFallback::TextServerFallback() {
_insert_feature_sets();
};
TextServerFallback::~TextServerFallback() {
#ifdef MODULE_FREETYPE_ENABLED
- if (library != nullptr) {
- FT_Done_FreeType(library);
+ if (ft_library != nullptr) {
+ FT_Done_FreeType(ft_library);
}
#endif
};
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index d4c7b5666e..c837029623 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -36,7 +36,49 @@
/* BiDi, shaping and advanced font features support. */
/*************************************************************************/
-#include "servers/text_server.h"
+#ifdef GDEXTENSION
+// Headers for building as GDExtension plug-in.
+
+#include <godot_cpp/godot.hpp>
+
+#include <godot_cpp/core/class_db.hpp>
+#include <godot_cpp/core/mutex_lock.hpp>
+
+#include <godot_cpp/variant/array.hpp>
+#include <godot_cpp/variant/dictionary.hpp>
+#include <godot_cpp/variant/packed_int32_array.hpp>
+#include <godot_cpp/variant/packed_string_array.hpp>
+#include <godot_cpp/variant/packed_vector2_array.hpp>
+#include <godot_cpp/variant/rect2.hpp>
+#include <godot_cpp/variant/rid.hpp>
+#include <godot_cpp/variant/string.hpp>
+#include <godot_cpp/variant/vector2.hpp>
+#include <godot_cpp/variant/vector2i.hpp>
+
+#include <godot_cpp/classes/text_server.hpp>
+#include <godot_cpp/classes/text_server_extension.hpp>
+#include <godot_cpp/classes/text_server_manager.hpp>
+
+#include <godot_cpp/classes/caret_info.hpp>
+#include <godot_cpp/classes/global_constants_binds.hpp>
+#include <godot_cpp/classes/glyph.hpp>
+#include <godot_cpp/classes/image.hpp>
+#include <godot_cpp/classes/image_texture.hpp>
+#include <godot_cpp/classes/ref.hpp>
+
+#include <godot_cpp/templates/hash_map.hpp>
+#include <godot_cpp/templates/map.hpp>
+#include <godot_cpp/templates/rid_owner.hpp>
+#include <godot_cpp/templates/set.hpp>
+#include <godot_cpp/templates/thread_work_pool.hpp>
+#include <godot_cpp/templates/vector.hpp>
+
+using namespace godot;
+
+#else
+// Headers for building as built-in module.
+
+#include "servers/text/text_server_extension.h"
#include "core/templates/rid_owner.h"
#include "core/templates/thread_work_pool.h"
@@ -44,6 +86,10 @@
#include "modules/modules_enabled.gen.h" // For freetype, msdfgen.
+#endif
+
+// Thirdparty headers.
+
#ifdef MODULE_FREETYPE_ENABLED
#include <ft2build.h>
#include FT_FREETYPE_H
@@ -54,26 +100,25 @@
#include FT_BBOX_H
#endif
-#define OT_TAG(c1, c2, c3, c4) ((int32_t)((((uint32_t)(c1)&0xFF) << 24) | (((uint32_t)(c2)&0xFF) << 16) | (((uint32_t)(c3)&0xFF) << 8) | ((uint32_t)(c4)&0xFF)))
+/*************************************************************************/
-class TextServerFallback : public TextServer {
- GDCLASS(TextServerFallback, TextServer);
+class TextServerFallback : public TextServerExtension {
+ GDCLASS(TextServerFallback, TextServerExtension);
_THREAD_SAFE_CLASS_
- static String interface_name;
- static uint32_t interface_features;
-
Map<StringName, int32_t> feature_sets;
+ Map<int32_t, StringName> feature_sets_inv;
void _insert_feature_sets();
+ _FORCE_INLINE_ void _insert_feature(const StringName &p_name, int32_t p_tag);
// Font cache data.
#ifdef MODULE_FREETYPE_ENABLED
- mutable FT_Library library = nullptr;
+ mutable FT_Library ft_library = nullptr;
#endif
- const int rect_range = 2;
+ const int rect_range = 1;
struct FontTexture {
Image::Format format;
@@ -82,6 +127,7 @@ class TextServerFallback : public TextServer {
int texture_h = 0;
PackedInt32Array offsets;
Ref<ImageTexture> texture;
+ bool dirty = true;
};
struct FontTexturePosition {
@@ -99,12 +145,12 @@ class TextServerFallback : public TextServer {
};
struct FontDataForSizeFallback {
- float ascent = 0.f;
- float descent = 0.f;
- float underline_position = 0.f;
- float underline_thickness = 0.f;
- float scale = 1.f;
- float oversampling = 1.f;
+ double ascent = 0.0;
+ double descent = 0.0;
+ double underline_position = 0.0;
+ double underline_thickness = 0.0;
+ double scale = 1.0;
+ double oversampling = 1.0;
int spacing_glyph = 0;
int spacing_space = 0;
@@ -133,6 +179,7 @@ class TextServerFallback : public TextServer {
Mutex mutex;
bool antialiased = true;
+ bool mipmaps = false;
bool msdf = false;
int msdf_range = 14;
int msdf_source_size = 48;
@@ -141,8 +188,8 @@ class TextServerFallback : public TextServer {
TextServer::Hinting hinting = TextServer::HINTING_LIGHT;
TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO;
Dictionary variation_coordinates;
- float oversampling = 0.f;
- float embolden = 0.f;
+ double oversampling = 0.0;
+ double embolden = 0.0;
Transform2D transform;
uint32_t style_flags = 0;
@@ -167,8 +214,8 @@ class TextServerFallback : public TextServer {
~FontDataFallback() {
work_pool.finish();
- for (const Map<Vector2i, FontDataForSizeFallback *>::Element *E = cache.front(); E; E = E->next()) {
- memdelete(E->get());
+ for (const KeyValue<Vector2i, FontDataForSizeFallback *> &E : cache) {
+ memdelete(E.value);
}
cache.clear();
}
@@ -207,13 +254,31 @@ class TextServerFallback : public TextServer {
}
// Shaped text cache data.
+ struct TrimData {
+ int trim_pos = -1;
+ int ellipsis_pos = -1;
+ Vector<Glyph> ellipsis_glyph_buf;
+ };
+
+ struct ShapedTextDataFallback {
+ Mutex mutex;
+
+ /* Source data */
+ RID parent; // Substring parent ShapedTextData.
+
+ int start = 0; // Substring start offset in the parent string.
+ int end = 0; // Substring end offset in the parent string.
+
+ String text;
+ String custom_punct;
+ TextServer::Direction direction = DIRECTION_LTR; // Desired text direction.
+ TextServer::Orientation orientation = ORIENTATION_HORIZONTAL;
- struct ShapedTextDataFallback : public ShapedTextData {
struct Span {
int start = -1;
int end = -1;
- Vector<RID> fonts;
+ Array fonts;
int font_size = 0;
Variant embedded_key;
@@ -223,11 +288,43 @@ class TextServerFallback : public TextServer {
Variant meta;
};
Vector<Span> spans;
+
+ struct EmbeddedObject {
+ int pos = 0;
+ InlineAlignment inline_align = INLINE_ALIGNMENT_CENTER;
+ Rect2 rect;
+ };
+ Map<Variant, EmbeddedObject> objects;
+
+ /* Shaped data */
+ TextServer::Direction para_direction = DIRECTION_LTR; // Detected text direction.
+ bool valid = false; // String is shaped.
+ bool line_breaks_valid = false; // Line and word break flags are populated (and virtual zero width spaces inserted).
+ bool justification_ops_valid = false; // Virtual elongation glyphs are added to the string.
+ bool sort_valid = false;
+ bool text_trimmed = false;
+
+ bool preserve_invalid = true; // Draw hex code box instead of missing characters.
+ bool preserve_control = false; // Draw control characters.
+
+ double ascent = 0.0; // Ascent for horizontal layout, 1/2 of width for vertical.
+ double descent = 0.0; // Descent for horizontal layout, 1/2 of width for vertical.
+ double width = 0.0; // Width for horizontal layout, height for vertical.
+ double width_trimmed = 0.0;
+
+ double upos = 0.0;
+ double uthk = 0.0;
+
+ TrimData overrun_trim_data;
+ bool fit_width_minimum_reached = false;
+
+ Vector<Glyph> glyphs;
+ Vector<Glyph> glyphs_logical;
};
// Common data.
- float oversampling = 1.f;
+ double oversampling = 1.0;
mutable RID_PtrOwner<FontDataFallback> font_owner;
mutable RID_PtrOwner<ShapedTextDataFallback> shaped_owner;
@@ -242,230 +339,241 @@ protected:
public:
virtual bool has_feature(Feature p_feature) const override;
virtual String get_name() const override;
- virtual uint32_t get_features() const override;
+ virtual int64_t get_features() const override;
- virtual void free(RID p_rid) override;
- virtual bool has(RID p_rid) override;
+ virtual void free_rid(const RID &p_rid) override;
+ virtual bool has(const RID &p_rid) override;
virtual bool load_support_data(const String &p_filename) override;
- virtual String get_support_data_filename() const override { return ""; };
- virtual String get_support_data_info() const override { return "Not supported"; };
+ virtual String get_support_data_filename() const override {
+ return "";
+ };
+ virtual String get_support_data_info() const override {
+ return "Not supported";
+ };
virtual bool save_support_data(const String &p_filename) const override;
virtual bool is_locale_right_to_left(const String &p_locale) const override;
- virtual int32_t name_to_tag(const String &p_name) const override;
- virtual String tag_to_name(int32_t p_tag) const override;
+ virtual int64_t name_to_tag(const String &p_name) const override;
+ virtual String tag_to_name(int64_t p_tag) const override;
/* Font interface */
virtual RID create_font() override;
- virtual void font_set_data(RID p_font_rid, const PackedByteArray &p_data) override;
- virtual void font_set_data_ptr(RID p_font_rid, const uint8_t *p_data_ptr, size_t p_data_size) override;
+ virtual void font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) override;
+ virtual void font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) override;
- virtual void font_set_style(RID p_font_rid, uint32_t /*FontStyle*/ p_style) override;
- virtual uint32_t /*FontStyle*/ font_get_style(RID p_font_rid) const override;
+ virtual void font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) override;
+ virtual int64_t /*FontStyle*/ font_get_style(const RID &p_font_rid) const override;
- virtual void font_set_style_name(RID p_font_rid, const String &p_name) override;
- virtual String font_get_style_name(RID p_font_rid) const override;
+ virtual void font_set_style_name(const RID &p_font_rid, const String &p_name) override;
+ virtual String font_get_style_name(const RID &p_font_rid) const override;
- virtual void font_set_name(RID p_font_rid, const String &p_name) override;
- virtual String font_get_name(RID p_font_rid) const override;
+ virtual void font_set_name(const RID &p_font_rid, const String &p_name) override;
+ virtual String font_get_name(const RID &p_font_rid) const override;
- virtual void font_set_antialiased(RID p_font_rid, bool p_antialiased) override;
- virtual bool font_is_antialiased(RID p_font_rid) const override;
+ virtual void font_set_antialiased(const RID &p_font_rid, bool p_antialiased) override;
+ virtual bool font_is_antialiased(const RID &p_font_rid) const override;
- virtual void font_set_multichannel_signed_distance_field(RID p_font_rid, bool p_msdf) override;
- virtual bool font_is_multichannel_signed_distance_field(RID p_font_rid) const override;
+ virtual void font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) override;
+ virtual bool font_get_generate_mipmaps(const RID &p_font_rid) const override;
- virtual void font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pixel_range) override;
- virtual int font_get_msdf_pixel_range(RID p_font_rid) const override;
+ virtual void font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) override;
+ virtual bool font_is_multichannel_signed_distance_field(const RID &p_font_rid) const override;
- virtual void font_set_msdf_size(RID p_font_rid, int p_msdf_size) override;
- virtual int font_get_msdf_size(RID p_font_rid) const override;
+ virtual void font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) override;
+ virtual int64_t font_get_msdf_pixel_range(const RID &p_font_rid) const override;
- virtual void font_set_fixed_size(RID p_font_rid, int p_fixed_size) override;
- virtual int font_get_fixed_size(RID p_font_rid) const override;
+ virtual void font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) override;
+ virtual int64_t font_get_msdf_size(const RID &p_font_rid) const override;
- virtual void font_set_force_autohinter(RID p_font_rid, bool p_force_autohinter) override;
- virtual bool font_is_force_autohinter(RID p_font_rid) const override;
+ virtual void font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) override;
+ virtual int64_t font_get_fixed_size(const RID &p_font_rid) const override;
- virtual void font_set_hinting(RID p_font_rid, TextServer::Hinting p_hinting) override;
- virtual TextServer::Hinting font_get_hinting(RID p_font_rid) const override;
+ virtual void font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) override;
+ virtual bool font_is_force_autohinter(const RID &p_font_rid) const override;
- virtual void font_set_subpixel_positioning(RID p_font_rid, SubpixelPositioning p_subpixel) override;
- virtual SubpixelPositioning font_get_subpixel_positioning(RID p_font_rid) const override;
+ virtual void font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) override;
+ virtual TextServer::Hinting font_get_hinting(const RID &p_font_rid) const override;
- virtual void font_set_embolden(RID p_font_rid, float p_strength) override;
- virtual float font_get_embolden(RID p_font_rid) const override;
+ virtual void font_set_subpixel_positioning(const RID &p_font_rid, SubpixelPositioning p_subpixel) override;
+ virtual SubpixelPositioning font_get_subpixel_positioning(const RID &p_font_rid) const override;
- virtual void font_set_transform(RID p_font_rid, Transform2D p_transform) override;
- virtual Transform2D font_get_transform(RID p_font_rid) const override;
+ virtual void font_set_embolden(const RID &p_font_rid, double p_strength) override;
+ virtual double font_get_embolden(const RID &p_font_rid) const override;
- virtual void font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) override;
- virtual Dictionary font_get_variation_coordinates(RID p_font_rid) const override;
+ virtual void font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) override;
+ virtual Transform2D font_get_transform(const RID &p_font_rid) const override;
- virtual void font_set_oversampling(RID p_font_rid, float p_oversampling) override;
- virtual float font_get_oversampling(RID p_font_rid) const override;
+ virtual void font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) override;
+ virtual Dictionary font_get_variation_coordinates(const RID &p_font_rid) const override;
- virtual Array font_get_size_cache_list(RID p_font_rid) const override;
- virtual void font_clear_size_cache(RID p_font_rid) override;
- virtual void font_remove_size_cache(RID p_font_rid, const Vector2i &p_size) override;
+ virtual void font_set_oversampling(const RID &p_font_rid, double p_oversampling) override;
+ virtual double font_get_oversampling(const RID &p_font_rid) const override;
- virtual void font_set_ascent(RID p_font_rid, int p_size, float p_ascent) override;
- virtual float font_get_ascent(RID p_font_rid, int p_size) const override;
+ virtual Array font_get_size_cache_list(const RID &p_font_rid) const override;
+ virtual void font_clear_size_cache(const RID &p_font_rid) override;
+ virtual void font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) override;
- virtual void font_set_descent(RID p_font_rid, int p_size, float p_descent) override;
- virtual float font_get_descent(RID p_font_rid, int p_size) const override;
+ virtual void font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) override;
+ virtual double font_get_ascent(const RID &p_font_rid, int64_t p_size) const override;
- virtual void font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) override;
- virtual float font_get_underline_position(RID p_font_rid, int p_size) const override;
+ virtual void font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) override;
+ virtual double font_get_descent(const RID &p_font_rid, int64_t p_size) const override;
- virtual void font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) override;
- virtual float font_get_underline_thickness(RID p_font_rid, int p_size) const override;
+ virtual void font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) override;
+ virtual double font_get_underline_position(const RID &p_font_rid, int64_t p_size) const override;
- virtual void font_set_scale(RID p_font_rid, int p_size, float p_scale) override;
- virtual float font_get_scale(RID p_font_rid, int p_size) const override;
+ virtual void font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) override;
+ virtual double font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const override;
- virtual void font_set_spacing(RID p_font_rid, int p_size, SpacingType p_spacing, int p_value) override;
- virtual int font_get_spacing(RID p_font_rid, int p_size, SpacingType p_spacing) const override;
+ virtual void font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) override;
+ virtual double font_get_scale(const RID &p_font_rid, int64_t p_size) const override;
- virtual int font_get_texture_count(RID p_font_rid, const Vector2i &p_size) const override;
- virtual void font_clear_textures(RID p_font_rid, const Vector2i &p_size) override;
- virtual void font_remove_texture(RID p_font_rid, const Vector2i &p_size, int p_texture_index) override;
+ virtual void font_set_spacing(const RID &p_font_rid, int64_t p_size, SpacingType p_spacing, int64_t p_value) override;
+ virtual int64_t font_get_spacing(const RID &p_font_rid, int64_t p_size, SpacingType p_spacing) const override;
- virtual void font_set_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) override;
- virtual Ref<Image> font_get_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const override;
+ virtual int64_t font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const override;
+ virtual void font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) override;
+ virtual void font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) override;
- virtual void font_set_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) override;
- virtual PackedInt32Array font_get_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const override;
+ virtual void font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) override;
+ virtual Ref<Image> font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const override;
- virtual Array font_get_glyph_list(RID p_font_rid, const Vector2i &p_size) const override;
- virtual void font_clear_glyphs(RID p_font_rid, const Vector2i &p_size) override;
- virtual void font_remove_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) override;
+ virtual void font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) override;
+ virtual PackedInt32Array font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const override;
- virtual Vector2 font_get_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph) const override;
- virtual void font_set_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph, const Vector2 &p_advance) override;
+ virtual Array font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const override;
+ virtual void font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) override;
+ virtual void font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) override;
- virtual Vector2 font_get_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
- virtual void font_set_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) override;
+ virtual Vector2 font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const override;
+ virtual void font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) override;
- virtual Vector2 font_get_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
- virtual void font_set_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) override;
+ virtual Vector2 font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override;
+ virtual void font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) override;
- virtual Rect2 font_get_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
- virtual void font_set_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) override;
+ virtual Vector2 font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override;
+ virtual void font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) override;
- virtual int font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
- virtual void font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) override;
+ virtual Rect2 font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override;
+ virtual void font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) override;
- virtual Dictionary font_get_glyph_contours(RID p_font, int p_size, int32_t p_index) const override;
+ virtual int64_t font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override;
+ virtual void font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) override;
+ virtual RID font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override;
+ virtual Size2 font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override;
- virtual Array font_get_kerning_list(RID p_font_rid, int p_size) const override;
- virtual void font_clear_kerning_map(RID p_font_rid, int p_size) override;
- virtual void font_remove_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) override;
+ virtual Dictionary font_get_glyph_contours(const RID &p_font, int64_t p_size, int64_t p_index) const override;
- virtual void font_set_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) override;
- virtual Vector2 font_get_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) const override;
+ virtual Array font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const override;
+ virtual void font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) override;
+ virtual void font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) override;
- virtual int32_t font_get_glyph_index(RID p_font_rid, int p_size, char32_t p_char, char32_t p_variation_selector = 0) const override;
+ virtual void font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) override;
+ virtual Vector2 font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const override;
- virtual bool font_has_char(RID p_font_rid, char32_t p_char) const override;
- virtual String font_get_supported_chars(RID p_font_rid) const override;
+ virtual int64_t font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector = 0) const override;
- virtual void font_render_range(RID p_font, const Vector2i &p_size, char32_t p_start, char32_t p_end) override;
- virtual void font_render_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_index) override;
+ virtual bool font_has_char(const RID &p_font_rid, int64_t p_char) const override;
+ virtual String font_get_supported_chars(const RID &p_font_rid) const override;
- virtual void font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
- virtual void font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
+ virtual void font_render_range(const RID &p_font, const Vector2i &p_size, int64_t p_start, int64_t p_end) override;
+ virtual void font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) override;
- virtual bool font_is_language_supported(RID p_font_rid, const String &p_language) const override;
- virtual void font_set_language_support_override(RID p_font_rid, const String &p_language, bool p_supported) override;
- virtual bool font_get_language_support_override(RID p_font_rid, const String &p_language) override;
- virtual void font_remove_language_support_override(RID p_font_rid, const String &p_language) override;
- virtual Vector<String> font_get_language_support_overrides(RID p_font_rid) override;
+ virtual void font_draw_glyph(const RID &p_font, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
+ virtual void font_draw_glyph_outline(const RID &p_font, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
- virtual bool font_is_script_supported(RID p_font_rid, const String &p_script) const override;
- virtual void font_set_script_support_override(RID p_font_rid, const String &p_script, bool p_supported) override;
- virtual bool font_get_script_support_override(RID p_font_rid, const String &p_script) override;
- virtual void font_remove_script_support_override(RID p_font_rid, const String &p_script) override;
- virtual Vector<String> font_get_script_support_overrides(RID p_font_rid) override;
+ virtual bool font_is_language_supported(const RID &p_font_rid, const String &p_language) const override;
+ virtual void font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) override;
+ virtual bool font_get_language_support_override(const RID &p_font_rid, const String &p_language) override;
+ virtual void font_remove_language_support_override(const RID &p_font_rid, const String &p_language) override;
+ virtual PackedStringArray font_get_language_support_overrides(const RID &p_font_rid) override;
- virtual void font_set_opentype_feature_overrides(RID p_font_rid, const Dictionary &p_overrides) override;
- virtual Dictionary font_get_opentype_feature_overrides(RID p_font_rid) const override;
+ virtual bool font_is_script_supported(const RID &p_font_rid, const String &p_script) const override;
+ virtual void font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) override;
+ virtual bool font_get_script_support_override(const RID &p_font_rid, const String &p_script) override;
+ virtual void font_remove_script_support_override(const RID &p_font_rid, const String &p_script) override;
+ virtual PackedStringArray font_get_script_support_overrides(const RID &p_font_rid) override;
- virtual Dictionary font_supported_feature_list(RID p_font_rid) const override;
- virtual Dictionary font_supported_variation_list(RID p_font_rid) const override;
+ virtual void font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) override;
+ virtual Dictionary font_get_opentype_feature_overrides(const RID &p_font_rid) const override;
- virtual float font_get_global_oversampling() const override;
- virtual void font_set_global_oversampling(float p_oversampling) override;
+ virtual Dictionary font_supported_feature_list(const RID &p_font_rid) const override;
+ virtual Dictionary font_supported_variation_list(const RID &p_font_rid) const override;
+
+ virtual double font_get_global_oversampling() const override;
+ virtual void font_set_global_oversampling(double p_oversampling) override;
/* Shaped text buffer interface */
virtual RID create_shaped_text(Direction p_direction = DIRECTION_AUTO, Orientation p_orientation = ORIENTATION_HORIZONTAL) override;
- virtual void shaped_text_clear(RID p_shaped) override;
+ virtual void shaped_text_clear(const RID &p_shaped) override;
+
+ virtual void shaped_text_set_direction(const RID &p_shaped, Direction p_direction = DIRECTION_AUTO) override;
+ virtual Direction shaped_text_get_direction(const RID &p_shaped) const override;
+ virtual Direction shaped_text_get_inferred_direction(const RID &p_shaped) const override;
- virtual void shaped_text_set_direction(RID p_shaped, Direction p_direction = DIRECTION_AUTO) override;
- virtual Direction shaped_text_get_direction(RID p_shaped) const override;
- virtual Direction shaped_text_get_inferred_direction(RID p_shaped) const override;
+ virtual void shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) override;
- virtual void shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) override;
+ virtual void shaped_text_set_custom_punctuation(const RID &p_shaped, const String &p_punct) override;
+ virtual String shaped_text_get_custom_punctuation(const RID &p_shaped) const override;
- virtual void shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) override;
- virtual String shaped_text_get_custom_punctuation(RID p_shaped) const override;
+ virtual void shaped_text_set_orientation(const RID &p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override;
+ virtual Orientation shaped_text_get_orientation(const RID &p_shaped) const override;
- virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override;
- virtual Orientation shaped_text_get_orientation(RID p_shaped) const override;
+ virtual void shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) override;
+ virtual bool shaped_text_get_preserve_invalid(const RID &p_shaped) const override;
- virtual void shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) override;
- virtual bool shaped_text_get_preserve_invalid(RID p_shaped) const override;
+ virtual void shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) override;
+ virtual bool shaped_text_get_preserve_control(const RID &p_shaped) const override;
- virtual void shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) override;
- virtual bool shaped_text_get_preserve_control(RID p_shaped) const override;
+ virtual bool shaped_text_add_string(const RID &p_shaped, const String &p_text, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant()) override;
+ virtual bool shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int64_t p_length = 1) override;
+ virtual bool shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER) override;
- virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant()) override;
- virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int p_length = 1) override;
- virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER) override;
+ virtual int64_t shaped_get_span_count(const RID &p_shaped) const override;
+ virtual Variant shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const override;
+ virtual void shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary()) override;
- virtual int shaped_get_span_count(RID p_shaped) const override;
- virtual Variant shaped_get_span_meta(RID p_shaped, int p_index) const override;
- virtual void shaped_set_span_update_font(RID p_shaped, int p_index, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary()) override;
+ virtual RID shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const override;
+ virtual RID shaped_text_get_parent(const RID &p_shaped) const override;
- virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override;
- virtual RID shaped_text_get_parent(RID p_shaped) const override;
+ virtual double shaped_text_fit_to_width(const RID &p_shaped, double p_width, int64_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override;
+ virtual double shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) override;
- virtual float shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override;
- virtual float shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) override;
+ virtual bool shaped_text_shape(const RID &p_shaped) override;
+ virtual bool shaped_text_update_breaks(const RID &p_shaped) override;
+ virtual bool shaped_text_update_justification_ops(const RID &p_shaped) override;
- virtual bool shaped_text_shape(RID p_shaped) override;
- virtual bool shaped_text_update_breaks(RID p_shaped) override;
- virtual bool shaped_text_update_justification_ops(RID p_shaped) override;
+ virtual int64_t shaped_text_get_trim_pos(const RID &p_shaped) const override;
+ virtual int64_t shaped_text_get_ellipsis_pos(const RID &p_shaped) const override;
+ virtual const Glyph *shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const override;
+ virtual int64_t shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const override;
- virtual int shaped_text_get_trim_pos(RID p_shaped) const override;
- virtual int shaped_text_get_ellipsis_pos(RID p_shaped) const override;
- virtual const Glyph *shaped_text_get_ellipsis_glyphs(RID p_shaped) const override;
- virtual int shaped_text_get_ellipsis_glyph_count(RID p_shaped) const override;
+ virtual void shaped_text_overrun_trim_to_width(const RID &p_shaped, double p_width, int64_t p_trim_flags) override;
- virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint16_t p_trim_flags) override;
+ virtual bool shaped_text_is_ready(const RID &p_shaped) const override;
- virtual bool shaped_text_is_ready(RID p_shaped) const override;
+ virtual const Glyph *shaped_text_get_glyphs(const RID &p_shaped) const override;
+ virtual const Glyph *shaped_text_sort_logical(const RID &p_shaped) override;
+ virtual int64_t shaped_text_get_glyph_count(const RID &p_shaped) const override;
- virtual const Glyph *shaped_text_get_glyphs(RID p_shaped) const override;
- virtual const Glyph *shaped_text_sort_logical(RID p_shaped) override;
- virtual int shaped_text_get_glyph_count(RID p_shaped) const override;
+ virtual Vector2i shaped_text_get_range(const RID &p_shaped) const override;
- virtual Vector2i shaped_text_get_range(RID p_shaped) const override;
+ virtual Array shaped_text_get_objects(const RID &p_shaped) const override;
+ virtual Rect2 shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const override;
- virtual Array shaped_text_get_objects(RID p_shaped) const override;
- virtual Rect2 shaped_text_get_object_rect(RID p_shaped, Variant p_key) const override;
+ virtual Size2 shaped_text_get_size(const RID &p_shaped) const override;
+ virtual double shaped_text_get_ascent(const RID &p_shaped) const override;
+ virtual double shaped_text_get_descent(const RID &p_shaped) const override;
+ virtual double shaped_text_get_width(const RID &p_shaped) const override;
+ virtual double shaped_text_get_underline_position(const RID &p_shaped) const override;
+ virtual double shaped_text_get_underline_thickness(const RID &p_shaped) const override;
- virtual Size2 shaped_text_get_size(RID p_shaped) const override;
- virtual float shaped_text_get_ascent(RID p_shaped) const override;
- virtual float shaped_text_get_descent(RID p_shaped) const override;
- virtual float shaped_text_get_width(RID p_shaped) const override;
- virtual float shaped_text_get_underline_position(RID p_shaped) const override;
- virtual float shaped_text_get_underline_thickness(RID p_shaped) const override;
+ virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "") const override;
virtual String string_to_upper(const String &p_string, const String &p_language = "") const override;
virtual String string_to_lower(const String &p_string, const String &p_language = "") const override;
diff --git a/modules/tga/image_loader_tga.cpp b/modules/tga/image_loader_tga.cpp
index 5060c1ab35..08ad1ef9f8 100644
--- a/modules/tga/image_loader_tga.cpp
+++ b/modules/tga/image_loader_tga.cpp
@@ -230,7 +230,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff
return OK;
}
-Error ImageLoaderTGA::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) {
+Error ImageLoaderTGA::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) {
Vector<uint8_t> src_image;
uint64_t src_image_len = f->get_length();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
@@ -330,7 +330,6 @@ Error ImageLoaderTGA::load_image(Ref<Image> p_image, FileAccess *f, bool p_force
}
}
- f->close();
return err;
}
@@ -339,12 +338,14 @@ void ImageLoaderTGA::get_recognized_extensions(List<String> *p_extensions) const
}
static Ref<Image> _tga_mem_loader_func(const uint8_t *p_tga, int p_size) {
- FileAccessMemory memfile;
- Error open_memfile_error = memfile.open_custom(p_tga, p_size);
+ Ref<FileAccessMemory> memfile;
+ memfile.instantiate();
+ Error open_memfile_error = memfile->open_custom(p_tga, p_size);
ERR_FAIL_COND_V_MSG(open_memfile_error, Ref<Image>(), "Could not create memfile for TGA image buffer.");
+
Ref<Image> img;
img.instantiate();
- Error load_error = ImageLoaderTGA().load_image(img, &memfile, false, 1.0f);
+ Error load_error = ImageLoaderTGA().load_image(img, memfile, false, 1.0f);
ERR_FAIL_COND_V_MSG(load_error, Ref<Image>(), "Failed to load TGA image.");
return img;
}
diff --git a/modules/tga/image_loader_tga.h b/modules/tga/image_loader_tga.h
index 282a2a1662..9b7cbbac77 100644
--- a/modules/tga/image_loader_tga.h
+++ b/modules/tga/image_loader_tga.h
@@ -73,7 +73,7 @@ class ImageLoaderTGA : public ImageFormatLoader {
static Error convert_to_image(Ref<Image> p_image, const uint8_t *p_buffer, const tga_header_s &p_header, const uint8_t *p_palette, const bool p_is_monochrome, size_t p_input_size);
public:
- virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderTGA();
};
diff --git a/modules/tga/register_types.cpp b/modules/tga/register_types.cpp
index 35f9d10956..520ed5f799 100644
--- a/modules/tga/register_types.cpp
+++ b/modules/tga/register_types.cpp
@@ -34,11 +34,19 @@
static ImageLoaderTGA *image_loader_tga = nullptr;
-void register_tga_types() {
+void initialize_tga_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
image_loader_tga = memnew(ImageLoaderTGA);
ImageLoader::add_image_format_loader(image_loader_tga);
}
-void unregister_tga_types() {
+void uninitialize_tga_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
memdelete(image_loader_tga);
}
diff --git a/modules/tga/register_types.h b/modules/tga/register_types.h
index ae91aa560f..37cdab70dd 100644
--- a/modules/tga/register_types.h
+++ b/modules/tga/register_types.h
@@ -31,7 +31,9 @@
#ifndef TGA_REGISTER_TYPES_H
#define TGA_REGISTER_TYPES_H
-void register_tga_types();
-void unregister_tga_types();
+#include "modules/register_module_types.h"
+
+void initialize_tga_module(ModuleInitializationLevel p_level);
+void uninitialize_tga_module(ModuleInitializationLevel p_level);
#endif // TGA_REGISTER_TYPES_H
diff --git a/modules/theora/register_types.cpp b/modules/theora/register_types.cpp
index f658627574..9ed8a86415 100644
--- a/modules/theora/register_types.cpp
+++ b/modules/theora/register_types.cpp
@@ -34,14 +34,22 @@
static Ref<ResourceFormatLoaderTheora> resource_loader_theora;
-void register_theora_types() {
+void initialize_theora_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
resource_loader_theora.instantiate();
ResourceLoader::add_resource_format_loader(resource_loader_theora, true);
GDREGISTER_CLASS(VideoStreamTheora);
}
-void unregister_theora_types() {
+void uninitialize_theora_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
ResourceLoader::remove_resource_format_loader(resource_loader_theora);
resource_loader_theora.unref();
}
diff --git a/modules/theora/register_types.h b/modules/theora/register_types.h
index d0c089ef49..2529b09306 100644
--- a/modules/theora/register_types.h
+++ b/modules/theora/register_types.h
@@ -31,7 +31,9 @@
#ifndef THEORA_REGISTER_TYPES_H
#define THEORA_REGISTER_TYPES_H
-void register_theora_types();
-void unregister_theora_types();
+#include "modules/register_module_types.h"
+
+void initialize_theora_module(ModuleInitializationLevel p_level);
+void uninitialize_theora_module(ModuleInitializationLevel p_level);
#endif // THEORA_REGISTER_TYPES_H
diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp
index 0a4ad96d97..77e370849f 100644
--- a/modules/theora/video_stream_theora.cpp
+++ b/modules/theora/video_stream_theora.cpp
@@ -114,7 +114,7 @@ void VideoStreamPlaybackTheora::video_write() {
}
void VideoStreamPlaybackTheora::clear() {
- if (!file) {
+ if (file.is_null()) {
return;
}
@@ -152,10 +152,7 @@ void VideoStreamPlaybackTheora::clear() {
theora_eos = false;
vorbis_eos = false;
- if (file) {
- memdelete(file);
- }
- file = nullptr;
+ file.unref();
playing = false;
};
@@ -165,11 +162,8 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) {
th_setup_info *ts = nullptr;
file_name = p_file;
- if (file) {
- memdelete(file);
- }
file = FileAccess::open(p_file, FileAccess::READ);
- ERR_FAIL_COND_MSG(!file, "Cannot open file '" + p_file + "'.");
+ ERR_FAIL_COND_MSG(file.is_null(), "Cannot open file '" + p_file + "'.");
#ifdef THEORA_USE_THREAD_STREAMING
thread_exit = false;
@@ -375,7 +369,7 @@ Ref<Texture2D> VideoStreamPlaybackTheora::get_texture() const {
}
void VideoStreamPlaybackTheora::update(float p_delta) {
- if (!file) {
+ if (file.is_null()) {
return;
}
@@ -506,9 +500,9 @@ void VideoStreamPlaybackTheora::update(float p_delta) {
}
#ifdef THEORA_USE_THREAD_STREAMING
- if (file && thread_eof && no_theora && theora_eos && ring_buffer.data_left() == 0) {
+ if (file.is_valid() && thread_eof && no_theora && theora_eos && ring_buffer.data_left() == 0) {
#else
- if (file && /*!videobuf_ready && */ no_theora && theora_eos) {
+ if (file.is_valid() && /*!videobuf_ready && */ no_theora && theora_eos) {
#endif
//printf("video done, stopping\n");
stop();
@@ -627,7 +621,7 @@ int VideoStreamPlaybackTheora::get_mix_rate() const {
#ifdef THEORA_USE_THREAD_STREAMING
void VideoStreamPlaybackTheora::_streaming_thread(void *ud) {
- VideoStreamPlaybackTheora *vs = (VideoStreamPlaybackTheora *)ud;
+ VideoStreamPlaybackTheora *vs = static_cast<VideoStreamPlaybackTheora *>(ud);
while (!vs->thread_exit) {
//just fill back the buffer
@@ -664,10 +658,6 @@ VideoStreamPlaybackTheora::~VideoStreamPlaybackTheora() {
memdelete(thread_sem);
#endif
clear();
-
- if (file) {
- memdelete(file);
- }
};
void VideoStreamTheora::_bind_methods() {
@@ -679,13 +669,13 @@ void VideoStreamTheora::_bind_methods() {
////////////
-RES ResourceFormatLoaderTheora::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
- if (!f) {
+Ref<Resource> ResourceFormatLoaderTheora::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
+ if (f.is_null()) {
if (r_error) {
*r_error = ERR_CANT_OPEN;
}
- return RES();
+ return Ref<Resource>();
}
VideoStreamTheora *stream = memnew(VideoStreamTheora);
@@ -697,8 +687,6 @@ RES ResourceFormatLoaderTheora::load(const String &p_path, const String &p_origi
*r_error = OK;
}
- f->close();
- memdelete(f);
return ogv_stream;
}
diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h
index 3bc96908a2..8940ed6aff 100644
--- a/modules/theora/video_stream_theora.h
+++ b/modules/theora/video_stream_theora.h
@@ -56,7 +56,7 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback {
Image::Format format = Image::Format::FORMAT_L8;
Vector<uint8_t> frame_data;
int frames_pending = 0;
- FileAccess *file = nullptr;
+ Ref<FileAccess> file;
String file_name;
int audio_frames_wrote = 0;
Point2i size;
@@ -99,7 +99,7 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback {
Ref<ImageTexture> texture;
- AudioMixCallback mix_callback;
+ AudioMixCallback mix_callback = nullptr;
void *mix_udata = nullptr;
bool paused = false;
@@ -112,7 +112,7 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback {
RingBuffer<uint8_t> ring_buffer;
Vector<uint8_t> read_buffer;
bool thread_eof = false;
- Semaphore *thread_sem;
+ Semaphore *thread_sem = nullptr;
Thread thread;
SafeFlag thread_exit;
@@ -186,7 +186,7 @@ public:
class ResourceFormatLoaderTheora : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/modules/tinyexr/image_loader_tinyexr.cpp b/modules/tinyexr/image_loader_tinyexr.cpp
index 688707a42d..864df765ee 100644
--- a/modules/tinyexr/image_loader_tinyexr.cpp
+++ b/modules/tinyexr/image_loader_tinyexr.cpp
@@ -37,7 +37,7 @@
#include "thirdparty/tinyexr/tinyexr.h"
-Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) {
+Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) {
Vector<uint8_t> src_image;
uint64_t src_image_len = f->get_length();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
@@ -47,8 +47,6 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_f
f->get_buffer(&w[0], src_image_len);
- f->close();
-
// Re-implementation of tinyexr's LoadEXRFromMemory using Godot types to store the Image data
// and Godot's error codes.
// When debugging after updating the thirdparty library, check that we're still in sync with
@@ -232,7 +230,7 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_f
}
if (p_force_linear) {
- color = color.to_linear();
+ color = color.srgb_to_linear();
}
*row_w++ = Math::make_half_float(color.r);
@@ -263,7 +261,7 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_f
}
if (p_force_linear) {
- color = color.to_linear();
+ color = color.srgb_to_linear();
}
*row_w++ = color.r;
diff --git a/modules/tinyexr/image_loader_tinyexr.h b/modules/tinyexr/image_loader_tinyexr.h
index aba5fdb959..c147861c26 100644
--- a/modules/tinyexr/image_loader_tinyexr.h
+++ b/modules/tinyexr/image_loader_tinyexr.h
@@ -35,7 +35,7 @@
class ImageLoaderTinyEXR : public ImageFormatLoader {
public:
- virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderTinyEXR();
};
diff --git a/modules/tinyexr/image_saver_tinyexr.cpp b/modules/tinyexr/image_saver_tinyexr.cpp
index 3750994663..5fa6ace827 100644
--- a/modules/tinyexr/image_saver_tinyexr.cpp
+++ b/modules/tinyexr/image_saver_tinyexr.cpp
@@ -275,8 +275,8 @@ Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale)
print_error(String("Saving EXR failed. Error: {0}").format(varray(err)));
return ERR_FILE_CANT_WRITE;
} else {
- FileAccessRef ref = FileAccess::open(p_path, FileAccess::WRITE);
- ERR_FAIL_COND_V(!ref, ERR_FILE_CANT_WRITE);
+ Ref<FileAccess> ref = FileAccess::open(p_path, FileAccess::WRITE);
+ ERR_FAIL_COND_V(ref.is_null(), ERR_FILE_CANT_WRITE);
ref->store_buffer(mem, bytes);
free(mem);
}
diff --git a/modules/tinyexr/register_types.cpp b/modules/tinyexr/register_types.cpp
index 0879a55b6e..d49ac23fea 100644
--- a/modules/tinyexr/register_types.cpp
+++ b/modules/tinyexr/register_types.cpp
@@ -35,14 +35,22 @@
static ImageLoaderTinyEXR *image_loader_tinyexr = nullptr;
-void register_tinyexr_types() {
+void initialize_tinyexr_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
image_loader_tinyexr = memnew(ImageLoaderTinyEXR);
ImageLoader::add_image_format_loader(image_loader_tinyexr);
Image::save_exr_func = save_exr;
}
-void unregister_tinyexr_types() {
+void uninitialize_tinyexr_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
memdelete(image_loader_tinyexr);
Image::save_exr_func = nullptr;
diff --git a/modules/tinyexr/register_types.h b/modules/tinyexr/register_types.h
index 4c34757d8b..bb50e024cb 100644
--- a/modules/tinyexr/register_types.h
+++ b/modules/tinyexr/register_types.h
@@ -31,7 +31,9 @@
#ifndef TINYEXR_REGISTER_TYPES_H
#define TINYEXR_REGISTER_TYPES_H
-void register_tinyexr_types();
-void unregister_tinyexr_types();
+#include "modules/register_module_types.h"
+
+void initialize_tinyexr_module(ModuleInitializationLevel p_level);
+void uninitialize_tinyexr_module(ModuleInitializationLevel p_level);
#endif // TINYEXR_REGISTER_TYPES_H
diff --git a/modules/upnp/register_types.cpp b/modules/upnp/register_types.cpp
index 7345901829..9e041a0c6e 100644
--- a/modules/upnp/register_types.cpp
+++ b/modules/upnp/register_types.cpp
@@ -35,10 +35,17 @@
#include "upnp.h"
#include "upnp_device.h"
-void register_upnp_types() {
+void initialize_upnp_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
GDREGISTER_CLASS(UPNP);
GDREGISTER_CLASS(UPNPDevice);
}
-void unregister_upnp_types() {
+void uninitialize_upnp_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
diff --git a/modules/upnp/register_types.h b/modules/upnp/register_types.h
index e4482314f8..ef559cc4e8 100644
--- a/modules/upnp/register_types.h
+++ b/modules/upnp/register_types.h
@@ -31,7 +31,9 @@
#ifndef UPNP_REGISTER_TYPES_H
#define UPNP_REGISTER_TYPES_H
-void register_upnp_types();
-void unregister_upnp_types();
+#include "modules/register_module_types.h"
+
+void initialize_upnp_module(ModuleInitializationLevel p_level);
+void uninitialize_upnp_module(ModuleInitializationLevel p_level);
#endif // UPNP_REGISTER_TYPES_H
diff --git a/modules/vhacd/register_types.cpp b/modules/vhacd/register_types.cpp
index 6242c8faa3..8bb7e780de 100644
--- a/modules/vhacd/register_types.cpp
+++ b/modules/vhacd/register_types.cpp
@@ -89,10 +89,18 @@ static Vector<Vector<Vector3>> convex_decompose(const real_t *p_vertices, int p_
return ret;
}
-void register_vhacd_types() {
+void initialize_vhacd_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
Mesh::convex_decomposition_function = convex_decompose;
}
-void unregister_vhacd_types() {
+void uninitialize_vhacd_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
Mesh::convex_decomposition_function = nullptr;
}
diff --git a/modules/vhacd/register_types.h b/modules/vhacd/register_types.h
index e0e34d494d..04ec180cd6 100644
--- a/modules/vhacd/register_types.h
+++ b/modules/vhacd/register_types.h
@@ -31,7 +31,9 @@
#ifndef VHACD_REGISTER_TYPES_H
#define VHACD_REGISTER_TYPES_H
-void register_vhacd_types();
-void unregister_vhacd_types();
+#include "modules/register_module_types.h"
+
+void initialize_vhacd_module(ModuleInitializationLevel p_level);
+void uninitialize_vhacd_module(ModuleInitializationLevel p_level);
#endif // VHACD_REGISTER_TYPES_H
diff --git a/modules/visual_script/doc_classes/VisualScript.xml b/modules/visual_script/doc_classes/VisualScript.xml
index 96310538bf..5807c98d32 100644
--- a/modules/visual_script/doc_classes/VisualScript.xml
+++ b/modules/visual_script/doc_classes/VisualScript.xml
@@ -316,7 +316,7 @@
</method>
<method name="set_scroll">
<return type="void" />
- <argument index="0" name="ofs" type="Vector2" />
+ <argument index="0" name="offset" type="Vector2" />
<description>
Set the screen center to the given position.
</description>
diff --git a/modules/visual_script/editor/visual_script_editor.cpp b/modules/visual_script/editor/visual_script_editor.cpp
index a2e59c9cdf..3e6680d8d8 100644
--- a/modules/visual_script/editor/visual_script_editor.cpp
+++ b/modules/visual_script/editor/visual_script_editor.cpp
@@ -2611,11 +2611,11 @@ void VisualScriptEditor::_button_resource_previewed(const String &p_path, const
void VisualScriptEditor::apply_code() {
}
-RES VisualScriptEditor::get_edited_resource() const {
+Ref<Resource> VisualScriptEditor::get_edited_resource() const {
return script;
}
-void VisualScriptEditor::set_edited_resource(const RES &p_res) {
+void VisualScriptEditor::set_edited_resource(const Ref<Resource> &p_res) {
ERR_FAIL_COND(script.is_valid());
ERR_FAIL_COND(p_res.is_null());
script = p_res;
@@ -2727,7 +2727,7 @@ void VisualScriptEditor::_center_on_node(int p_id) {
if (gn) {
gn->set_selected(true);
- Vector2 new_scroll = gn->get_position_offset() - graph->get_size() * 0.5 + gn->get_size() * 0.5;
+ Vector2 new_scroll = gn->get_position_offset() * graph->get_zoom() - graph->get_size() * 0.5 + gn->get_size() * 0.5;
graph->set_scroll_ofs(new_scroll);
script->set_scroll(new_scroll / EDSCALE);
script->set_edited(true);
@@ -3390,6 +3390,8 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri
n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_NODE_PATH);
n->set_base_path(drop_path);
}
+ } else {
+ n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE);
}
if (drop_node) {
n->set_base_type(drop_node->get_class());
@@ -3702,8 +3704,13 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri
Object::cast_to<VisualScriptTypeCast>(vnode.ptr())->set_base_type(base_type);
Object::cast_to<VisualScriptTypeCast>(vnode.ptr())->set_base_script(base_script);
} else if (Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())) {
- Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_base_type(base_type);
- Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_base_script(base_script);
+ if (base_type_map.has(base_type)) {
+ Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_basic_type(base_type_map[base_type]);
+ Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_call_mode(VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE);
+ } else {
+ Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_base_type(base_type);
+ Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_base_script(base_script);
+ }
} else if (Object::cast_to<VisualScriptPropertySet>(vnode.ptr())) {
Object::cast_to<VisualScriptPropertySet>(vnode.ptr())->set_base_type(base_type);
Object::cast_to<VisualScriptPropertySet>(vnode.ptr())->set_base_script(base_script);
@@ -4751,6 +4758,35 @@ VisualScriptEditor::VisualScriptEditor() {
popup_menu->add_item(TTR("Duplicate"), EDIT_DUPLICATE_NODES);
popup_menu->add_item(TTR("Clear Copy Buffer"), EDIT_CLEAR_COPY_BUFFER);
popup_menu->connect("id_pressed", callable_mp(this, &VisualScriptEditor::_menu_option));
+
+ base_type_map.insert("String", Variant::STRING);
+ base_type_map.insert("Vector2", Variant::VECTOR2);
+ base_type_map.insert("Vector2i", Variant::VECTOR2I);
+ base_type_map.insert("Rect2", Variant::RECT2);
+ base_type_map.insert("Rect2i", Variant::RECT2I);
+ base_type_map.insert("Vector3", Variant::VECTOR3);
+ base_type_map.insert("Vector3i", Variant::VECTOR3I);
+ base_type_map.insert("Transform2D", Variant::TRANSFORM2D);
+ base_type_map.insert("Plane", Variant::PLANE);
+ base_type_map.insert("Quaternion", Variant::QUATERNION);
+ base_type_map.insert("AABB", Variant::AABB);
+ base_type_map.insert("Basis", Variant::BASIS);
+ base_type_map.insert("Transform3D", Variant::TRANSFORM3D);
+ base_type_map.insert("Color", Variant::COLOR);
+ base_type_map.insert("NodePath", Variant::NODE_PATH);
+ base_type_map.insert("RID", Variant::RID);
+ base_type_map.insert("Callable", Variant::CALLABLE);
+ base_type_map.insert("Dictionary", Variant::DICTIONARY);
+ base_type_map.insert("Array", Variant::ARRAY);
+ base_type_map.insert("PackedByteArray", Variant::PACKED_BYTE_ARRAY);
+ base_type_map.insert("PackedInt32Array", Variant::PACKED_INT32_ARRAY);
+ base_type_map.insert("PackedFloat32Array", Variant::PACKED_FLOAT32_ARRAY);
+ base_type_map.insert("PackedInt64Array", Variant::PACKED_INT64_ARRAY);
+ base_type_map.insert("PackedFloat64Array", Variant::PACKED_FLOAT64_ARRAY);
+ base_type_map.insert("PackedStringArray", Variant::PACKED_STRING_ARRAY);
+ base_type_map.insert("PackedVector2Array", Variant::PACKED_VECTOR2_ARRAY);
+ base_type_map.insert("PackedVector3Array", Variant::PACKED_VECTOR3_ARRAY);
+ base_type_map.insert("PackedColorArray", Variant::PACKED_COLOR_ARRAY);
}
VisualScriptEditor::~VisualScriptEditor() {
@@ -4759,7 +4795,7 @@ VisualScriptEditor::~VisualScriptEditor() {
memdelete(variable_editor);
}
-static ScriptEditorBase *create_editor(const RES &p_resource) {
+static ScriptEditorBase *create_editor(const Ref<Resource> &p_resource) {
if (Object::cast_to<VisualScript>(*p_resource)) {
return memnew(VisualScriptEditor);
}
@@ -4803,7 +4839,7 @@ Ref<VisualScriptNode> VisualScriptCustomNodes::create_node_custom(const String &
}
VisualScriptCustomNodes *VisualScriptCustomNodes::singleton = nullptr;
-Map<String, REF> VisualScriptCustomNodes::custom_nodes;
+Map<String, Ref<RefCounted>> VisualScriptCustomNodes::custom_nodes;
VisualScriptCustomNodes::VisualScriptCustomNodes() {
singleton = this;
diff --git a/modules/visual_script/editor/visual_script_editor.h b/modules/visual_script/editor/visual_script_editor.h
index 5b355a71df..e63539ac5b 100644
--- a/modules/visual_script/editor/visual_script_editor.h
+++ b/modules/visual_script/editor/visual_script_editor.h
@@ -144,6 +144,7 @@ class VisualScriptEditor : public ScriptEditorBase {
Map<StringName, Color> node_colors;
HashMap<StringName, Ref<StyleBox>> node_styles;
+ Map<StringName, Variant::Type> base_type_map;
void _update_graph_connections();
void _update_graph(int p_only_id = -1);
@@ -302,8 +303,8 @@ public:
virtual void set_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) override;
virtual void apply_code() override;
- virtual RES get_edited_resource() const override;
- virtual void set_edited_resource(const RES &p_res) override;
+ virtual Ref<Resource> get_edited_resource() const override;
+ virtual void set_edited_resource(const Ref<Resource> &p_res) override;
virtual void enable_editor() override;
virtual Vector<String> get_functions() override;
virtual void reload_text() override;
@@ -358,7 +359,7 @@ protected:
static void _bind_methods();
static VisualScriptCustomNodes *singleton;
- static Map<String, REF> custom_nodes;
+ static Map<String, Ref<RefCounted>> custom_nodes;
static Ref<VisualScriptNode> create_node_custom(const String &p_name);
public:
diff --git a/modules/visual_script/editor/visual_script_property_selector.cpp b/modules/visual_script/editor/visual_script_property_selector.cpp
index 31406a2a6f..07929e5c0e 100644
--- a/modules/visual_script/editor/visual_script_property_selector.cpp
+++ b/modules/visual_script/editor/visual_script_property_selector.cpp
@@ -86,6 +86,13 @@ void VisualScriptPropertySelector::_update_results_s(String p_string) {
_update_results();
}
+void VisualScriptPropertySelector::_update_results_search_all() {
+ if (search_classes->is_pressed()) {
+ scope_combo->select(COMBO_ALL);
+ }
+ _update_results();
+}
+
void VisualScriptPropertySelector::_update_results() {
_update_icons();
search_runner = Ref<SearchRunner>(memnew(SearchRunner(this, results_tree)));
@@ -167,7 +174,7 @@ void VisualScriptPropertySelector::select_method_from_base_type(const String &p_
search_properties->set_pressed(false);
search_theme_items->set_pressed(false);
- scope_combo->select(2); //id0 = "Search Related" //id2 = "Search Base" //id3 = "Search Inheriters" //id4 = "Search Unrelated"
+ scope_combo->select(COMBO_BASE);
results_tree->clear();
show_window(.5f);
@@ -201,8 +208,7 @@ void VisualScriptPropertySelector::select_from_base_type(const String &p_base, c
search_properties->set_pressed(true);
search_theme_items->set_pressed(false);
- // When class is Input only show inheritors
- scope_combo->select(0); //id0 = "Search Related" //id2 = "Search Base" //id3 = "Search Inheriters" //id4 = "Search Unrelated"
+ scope_combo->select(COMBO_RELATED);
results_tree->clear();
show_window(.5f);
@@ -234,7 +240,7 @@ void VisualScriptPropertySelector::select_from_script(const Ref<Script> &p_scrip
search_properties->set_pressed(true);
search_theme_items->set_pressed(false);
- scope_combo->select(2); //id0 = "Search Related" //id2 = "Search Base" //id3 = "Search Inheriters" //id4 = "Search Unrelated"
+ scope_combo->select(COMBO_BASE);
results_tree->clear();
show_window(.5f);
@@ -264,7 +270,7 @@ void VisualScriptPropertySelector::select_from_basic_type(Variant::Type p_type,
search_properties->set_pressed(true);
search_theme_items->set_pressed(false);
- scope_combo->select(2); //id0 = "Search Related" //id2 = "Search Base" //id3 = "Search Inheriters" //id4 = "Search Unrelated" //id5 "Search All"
+ scope_combo->select(COMBO_BASE);
results_tree->clear();
show_window(.5f);
@@ -294,7 +300,7 @@ void VisualScriptPropertySelector::select_from_action(const String &p_type, cons
search_properties->set_pressed(false);
search_theme_items->set_pressed(false);
- scope_combo->select(0); //id0 = "Search Related" //id2 = "Search Base" //id3 = "Search Inheriters" //id4 = "Search Unrelated" //id5 "Search All"
+ scope_combo->select(COMBO_RELATED);
results_tree->clear();
show_window(.5f);
@@ -330,7 +336,7 @@ void VisualScriptPropertySelector::select_from_instance(Object *p_instance, cons
search_properties->set_pressed(true);
search_theme_items->set_pressed(false);
- scope_combo->select(2); //id0 = "Search Related" //id2 = "Search Base" //id3 = "Search Inheriters" //id4 = "Search Unrelated" //id5 "Search All"
+ scope_combo->select(COMBO_BASE);
results_tree->clear();
show_window(.5f);
@@ -363,7 +369,7 @@ void VisualScriptPropertySelector::select_from_visual_script(const Ref<Script> &
search_properties->set_pressed(true);
search_theme_items->set_pressed(false);
- scope_combo->select(2); //id0 = "Search Related" //id2 = "Search Base" //id3 = "Search Inheriters" //id4 = "Search Unrelated" //id5 "Search All"
+ scope_combo->select(COMBO_BASE);
results_tree->clear();
show_window(.5f);
@@ -418,7 +424,7 @@ VisualScriptPropertySelector::VisualScriptPropertySelector() {
search_classes = memnew(Button);
search_classes->set_flat(true);
search_classes->set_tooltip(TTR("Search Classes"));
- search_classes->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results));
+ search_classes->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results_search_all));
search_classes->set_toggle_mode(true);
search_classes->set_pressed(true);
search_classes->set_focus_mode(Control::FOCUS_NONE);
@@ -739,49 +745,46 @@ bool VisualScriptPropertySelector::SearchRunner::_phase_node_classes_build() {
if (vs_nodes.is_empty()) {
return true;
}
- String registerd_node_name = vs_nodes[0];
+ String registered_node_name = vs_nodes[0];
vs_nodes.pop_front();
- Vector<String> path = registerd_node_name.split("/");
+ Vector<String> path = registered_node_name.split("/");
if (path[0] == "constants") {
- _add_class_doc(registerd_node_name, "", "constants");
+ _add_class_doc(registered_node_name, "", "constants");
} else if (path[0] == "custom") {
- _add_class_doc(registerd_node_name, "", "custom");
+ _add_class_doc(registered_node_name, "", "custom");
} else if (path[0] == "data") {
- _add_class_doc(registerd_node_name, "", "data");
+ _add_class_doc(registered_node_name, "", "data");
} else if (path[0] == "flow_control") {
- _add_class_doc(registerd_node_name, "", "flow_control");
+ _add_class_doc(registered_node_name, "", "flow_control");
} else if (path[0] == "functions") {
if (path[1] == "built_in") {
- _add_class_doc(registerd_node_name, "functions", "built_in");
+ _add_class_doc(registered_node_name, "functions", "built_in");
} else if (path[1] == "by_type") {
- if (search_flags & SEARCH_CLASSES) {
- _add_class_doc(registerd_node_name, path[2], "by_type_class");
- }
+ // No action is required.
+ // Using function references from ClassDB to remove confusion for users.
} else if (path[1] == "constructors") {
- if (search_flags & SEARCH_CLASSES) {
- _add_class_doc(registerd_node_name, path[2].substr(0, path[2].find_char('(')), "constructors_class");
- }
+ _add_class_doc(registered_node_name, "", "constructors");
} else if (path[1] == "deconstruct") {
- _add_class_doc(registerd_node_name, "", "deconstruct");
+ _add_class_doc(registered_node_name, "", "deconstruct");
} else if (path[1] == "wait") {
- _add_class_doc(registerd_node_name, "functions", "yield");
+ _add_class_doc(registered_node_name, "functions", "yield");
} else {
- _add_class_doc(registerd_node_name, "functions", "");
+ _add_class_doc(registered_node_name, "functions", "");
}
} else if (path[0] == "index") {
- _add_class_doc(registerd_node_name, "", "index");
+ _add_class_doc(registered_node_name, "", "index");
} else if (path[0] == "operators") {
if (path[1] == "bitwise") {
- _add_class_doc(registerd_node_name, "operators", "bitwise");
+ _add_class_doc(registered_node_name, "operators", "bitwise");
} else if (path[1] == "compare") {
- _add_class_doc(registerd_node_name, "operators", "compare");
+ _add_class_doc(registered_node_name, "operators", "compare");
} else if (path[1] == "logic") {
- _add_class_doc(registerd_node_name, "operators", "logic");
+ _add_class_doc(registered_node_name, "operators", "logic");
} else if (path[1] == "math") {
- _add_class_doc(registerd_node_name, "operators", "math");
+ _add_class_doc(registered_node_name, "operators", "math");
} else {
- _add_class_doc(registerd_node_name, "operators", "");
+ _add_class_doc(registered_node_name, "operators", "");
}
}
return false;
diff --git a/modules/visual_script/editor/visual_script_property_selector.h b/modules/visual_script/editor/visual_script_property_selector.h
index 6b5112f1af..90a6265ab7 100644
--- a/modules/visual_script/editor/visual_script_property_selector.h
+++ b/modules/visual_script/editor/visual_script_property_selector.h
@@ -62,23 +62,32 @@ class VisualScriptPropertySelector : public ConfirmationDialog {
SCOPE_ALL = SCOPE_BASE | SCOPE_INHERITERS | SCOPE_UNRELATED
};
- LineEdit *search_box;
+ enum ScopeCombo {
+ COMBO_RELATED,
+ COMBO_SEPARATOR,
+ COMBO_BASE,
+ COMBO_INHERITERS,
+ COMBO_UNRELATED,
+ COMBO_ALL,
+ };
+
+ LineEdit *search_box = nullptr;
- Button *case_sensitive_button;
- Button *hierarchy_button;
+ Button *case_sensitive_button = nullptr;
+ Button *hierarchy_button = nullptr;
- Button *search_visual_script_nodes;
- Button *search_classes;
- Button *search_operators;
+ Button *search_visual_script_nodes = nullptr;
+ Button *search_classes = nullptr;
+ Button *search_operators = nullptr;
- Button *search_methods;
- Button *search_signals;
- Button *search_constants;
- Button *search_properties;
- Button *search_theme_items;
+ Button *search_methods = nullptr;
+ Button *search_signals = nullptr;
+ Button *search_constants = nullptr;
+ Button *search_properties = nullptr;
+ Button *search_theme_items = nullptr;
- OptionButton *scope_combo;
- Tree *results_tree;
+ OptionButton *scope_combo = nullptr;
+ Tree *results_tree = nullptr;
class SearchRunner;
Ref<SearchRunner> search_runner;
@@ -88,13 +97,14 @@ class VisualScriptPropertySelector : public ConfirmationDialog {
void _sbox_input(const Ref<InputEvent> &p_ie);
void _update_results_i(int p_int);
void _update_results_s(String p_string);
+ void _update_results_search_all();
void _update_results();
void _confirmed();
void _item_selected();
void _hide_requested();
- EditorHelpBit *help_bit;
+ EditorHelpBit *help_bit = nullptr;
bool properties = false;
bool visual_script_generic = false;
@@ -104,9 +114,9 @@ class VisualScriptPropertySelector : public ConfirmationDialog {
String base_type;
String base_script;
ObjectID script;
- Object *instance;
+ Object *instance = nullptr;
bool virtuals_only = false;
- VBoxContainer *vbox;
+ VBoxContainer *vbox = nullptr;
protected:
void _notification(int p_what);
@@ -159,12 +169,12 @@ class VisualScriptPropertySelector::SearchRunner : public RefCounted {
}
};
- VisualScriptPropertySelector *selector_ui;
- Control *ui_service;
- Tree *results_tree;
+ VisualScriptPropertySelector *selector_ui = nullptr;
+ Control *ui_service = nullptr;
+ Tree *results_tree = nullptr;
String term;
- int search_flags;
- int scope_flags;
+ int search_flags = 0;
+ int scope_flags = 0;
Ref<Texture2D> empty_icon;
Color disabled_color;
diff --git a/modules/visual_script/register_types.cpp b/modules/visual_script/register_types.cpp
index d19870921d..04a7442d0a 100644
--- a/modules/visual_script/register_types.cpp
+++ b/modules/visual_script/register_types.cpp
@@ -47,95 +47,104 @@ VisualScriptLanguage *visual_script_language = nullptr;
static VisualScriptCustomNodes *vs_custom_nodes_singleton = nullptr;
#endif
-void register_visual_script_types() {
- visual_script_language = memnew(VisualScriptLanguage);
- //script_language_gd->init();
- ScriptServer::register_language(visual_script_language);
-
- GDREGISTER_CLASS(VisualScript);
- GDREGISTER_ABSTRACT_CLASS(VisualScriptNode);
- GDREGISTER_CLASS(VisualScriptFunctionState);
- GDREGISTER_CLASS(VisualScriptFunction);
- GDREGISTER_ABSTRACT_CLASS(VisualScriptLists);
- GDREGISTER_CLASS(VisualScriptComposeArray);
- GDREGISTER_CLASS(VisualScriptOperator);
- GDREGISTER_CLASS(VisualScriptVariableSet);
- GDREGISTER_CLASS(VisualScriptVariableGet);
- GDREGISTER_CLASS(VisualScriptConstant);
- GDREGISTER_CLASS(VisualScriptIndexGet);
- GDREGISTER_CLASS(VisualScriptIndexSet);
- GDREGISTER_CLASS(VisualScriptGlobalConstant);
- GDREGISTER_CLASS(VisualScriptClassConstant);
- GDREGISTER_CLASS(VisualScriptMathConstant);
- GDREGISTER_CLASS(VisualScriptBasicTypeConstant);
- GDREGISTER_CLASS(VisualScriptEngineSingleton);
- GDREGISTER_CLASS(VisualScriptSceneNode);
- GDREGISTER_CLASS(VisualScriptSceneTree);
- GDREGISTER_CLASS(VisualScriptResourcePath);
- GDREGISTER_CLASS(VisualScriptSelf);
- GDREGISTER_CLASS(VisualScriptCustomNode);
- GDREGISTER_CLASS(VisualScriptSubCall);
- GDREGISTER_CLASS(VisualScriptComment);
- GDREGISTER_CLASS(VisualScriptConstructor);
- GDREGISTER_CLASS(VisualScriptLocalVar);
- GDREGISTER_CLASS(VisualScriptLocalVarSet);
- GDREGISTER_CLASS(VisualScriptInputAction);
- GDREGISTER_CLASS(VisualScriptDeconstruct);
- GDREGISTER_CLASS(VisualScriptPreload);
- GDREGISTER_CLASS(VisualScriptTypeCast);
-
- GDREGISTER_CLASS(VisualScriptFunctionCall);
- GDREGISTER_CLASS(VisualScriptPropertySet);
- GDREGISTER_CLASS(VisualScriptPropertyGet);
- //ClassDB::register_type<VisualScriptScriptCall>();
- GDREGISTER_CLASS(VisualScriptEmitSignal);
-
- GDREGISTER_CLASS(VisualScriptReturn);
- GDREGISTER_CLASS(VisualScriptCondition);
- GDREGISTER_CLASS(VisualScriptWhile);
- GDREGISTER_CLASS(VisualScriptIterator);
- GDREGISTER_CLASS(VisualScriptSequence);
- //GDREGISTER_CLASS(VisualScriptInputFilter);
- GDREGISTER_CLASS(VisualScriptSwitch);
- GDREGISTER_CLASS(VisualScriptSelect);
-
- GDREGISTER_CLASS(VisualScriptYield);
- GDREGISTER_CLASS(VisualScriptYieldSignal);
-
- GDREGISTER_CLASS(VisualScriptBuiltinFunc);
-
- GDREGISTER_CLASS(VisualScriptExpression);
-
- register_visual_script_nodes();
- register_visual_script_func_nodes();
- register_visual_script_builtin_func_node();
- register_visual_script_flow_control_nodes();
- register_visual_script_yield_nodes();
- register_visual_script_expression_node();
+void initialize_visual_script_module(ModuleInitializationLevel p_level) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) {
+ visual_script_language = memnew(VisualScriptLanguage);
+ //script_language_gd->init();
+ ScriptServer::register_language(visual_script_language);
+
+ GDREGISTER_CLASS(VisualScript);
+ GDREGISTER_ABSTRACT_CLASS(VisualScriptNode);
+ GDREGISTER_CLASS(VisualScriptFunctionState);
+ GDREGISTER_CLASS(VisualScriptFunction);
+ GDREGISTER_ABSTRACT_CLASS(VisualScriptLists);
+ GDREGISTER_CLASS(VisualScriptComposeArray);
+ GDREGISTER_CLASS(VisualScriptOperator);
+ GDREGISTER_CLASS(VisualScriptVariableSet);
+ GDREGISTER_CLASS(VisualScriptVariableGet);
+ GDREGISTER_CLASS(VisualScriptConstant);
+ GDREGISTER_CLASS(VisualScriptIndexGet);
+ GDREGISTER_CLASS(VisualScriptIndexSet);
+ GDREGISTER_CLASS(VisualScriptGlobalConstant);
+ GDREGISTER_CLASS(VisualScriptClassConstant);
+ GDREGISTER_CLASS(VisualScriptMathConstant);
+ GDREGISTER_CLASS(VisualScriptBasicTypeConstant);
+ GDREGISTER_CLASS(VisualScriptEngineSingleton);
+ GDREGISTER_CLASS(VisualScriptSceneNode);
+ GDREGISTER_CLASS(VisualScriptSceneTree);
+ GDREGISTER_CLASS(VisualScriptResourcePath);
+ GDREGISTER_CLASS(VisualScriptSelf);
+ GDREGISTER_CLASS(VisualScriptCustomNode);
+ GDREGISTER_CLASS(VisualScriptSubCall);
+ GDREGISTER_CLASS(VisualScriptComment);
+ GDREGISTER_CLASS(VisualScriptConstructor);
+ GDREGISTER_CLASS(VisualScriptLocalVar);
+ GDREGISTER_CLASS(VisualScriptLocalVarSet);
+ GDREGISTER_CLASS(VisualScriptInputAction);
+ GDREGISTER_CLASS(VisualScriptDeconstruct);
+ GDREGISTER_CLASS(VisualScriptPreload);
+ GDREGISTER_CLASS(VisualScriptTypeCast);
+
+ GDREGISTER_CLASS(VisualScriptFunctionCall);
+ GDREGISTER_CLASS(VisualScriptPropertySet);
+ GDREGISTER_CLASS(VisualScriptPropertyGet);
+ //ClassDB::register_type<VisualScriptScriptCall>();
+ GDREGISTER_CLASS(VisualScriptEmitSignal);
+
+ GDREGISTER_CLASS(VisualScriptReturn);
+ GDREGISTER_CLASS(VisualScriptCondition);
+ GDREGISTER_CLASS(VisualScriptWhile);
+ GDREGISTER_CLASS(VisualScriptIterator);
+ GDREGISTER_CLASS(VisualScriptSequence);
+ //GDREGISTER_CLASS(VisualScriptInputFilter);
+ GDREGISTER_CLASS(VisualScriptSwitch);
+ GDREGISTER_CLASS(VisualScriptSelect);
+
+ GDREGISTER_CLASS(VisualScriptYield);
+ GDREGISTER_CLASS(VisualScriptYieldSignal);
+
+ GDREGISTER_CLASS(VisualScriptBuiltinFunc);
+
+ GDREGISTER_CLASS(VisualScriptExpression);
+
+ register_visual_script_nodes();
+ register_visual_script_func_nodes();
+ register_visual_script_builtin_func_node();
+ register_visual_script_flow_control_nodes();
+ register_visual_script_yield_nodes();
+ register_visual_script_expression_node();
+ }
#ifdef TOOLS_ENABLED
- ClassDB::set_current_api(ClassDB::API_EDITOR);
- GDREGISTER_CLASS(VisualScriptCustomNodes);
- ClassDB::set_current_api(ClassDB::API_CORE);
- vs_custom_nodes_singleton = memnew(VisualScriptCustomNodes);
- Engine::get_singleton()->add_singleton(Engine::Singleton("VisualScriptCustomNodes", VisualScriptCustomNodes::get_singleton()));
-
- VisualScriptEditor::register_editor();
+ if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
+ ClassDB::set_current_api(ClassDB::API_EDITOR);
+ GDREGISTER_CLASS(VisualScriptCustomNodes);
+ ClassDB::set_current_api(ClassDB::API_CORE);
+ vs_custom_nodes_singleton = memnew(VisualScriptCustomNodes);
+ Engine::get_singleton()->add_singleton(Engine::Singleton("VisualScriptCustomNodes", VisualScriptCustomNodes::get_singleton()));
+
+ VisualScriptEditor::register_editor();
+ }
#endif
}
-void unregister_visual_script_types() {
- unregister_visual_script_nodes();
+void uninitialize_visual_script_module(ModuleInitializationLevel p_level) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) {
+ unregister_visual_script_nodes();
- ScriptServer::unregister_language(visual_script_language);
+ ScriptServer::unregister_language(visual_script_language);
+
+ if (visual_script_language) {
+ memdelete(visual_script_language);
+ }
+ }
#ifdef TOOLS_ENABLED
- VisualScriptEditor::free_clipboard();
- if (vs_custom_nodes_singleton) {
- memdelete(vs_custom_nodes_singleton);
+ if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
+ VisualScriptEditor::free_clipboard();
+ if (vs_custom_nodes_singleton) {
+ memdelete(vs_custom_nodes_singleton);
+ }
}
#endif
- if (visual_script_language) {
- memdelete(visual_script_language);
- }
}
diff --git a/modules/visual_script/register_types.h b/modules/visual_script/register_types.h
index 29768da67f..90f84de11c 100644
--- a/modules/visual_script/register_types.h
+++ b/modules/visual_script/register_types.h
@@ -31,7 +31,9 @@
#ifndef VISUAL_SCRIPT_REGISTER_TYPES_H
#define VISUAL_SCRIPT_REGISTER_TYPES_H
-void register_visual_script_types();
-void unregister_visual_script_types();
+#include "modules/register_module_types.h"
+
+void initialize_visual_script_module(ModuleInitializationLevel p_level);
+void uninitialize_visual_script_module(ModuleInitializationLevel p_level);
#endif // VISUAL_SCRIPT_REGISTER_TYPES_H
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index e8c44e2556..e31550b203 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -1118,7 +1118,7 @@ void VisualScript::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_function", "name"), &VisualScript::has_function);
ClassDB::bind_method(D_METHOD("remove_function", "name"), &VisualScript::remove_function);
ClassDB::bind_method(D_METHOD("rename_function", "name", "new_name"), &VisualScript::rename_function);
- ClassDB::bind_method(D_METHOD("set_scroll", "ofs"), &VisualScript::set_scroll);
+ ClassDB::bind_method(D_METHOD("set_scroll", "offset"), &VisualScript::set_scroll);
ClassDB::bind_method(D_METHOD("get_scroll"), &VisualScript::get_scroll);
ClassDB::bind_method(D_METHOD("add_node", "id", "node", "position"), &VisualScript::add_node, DEFVAL(Point2()));
diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h
index d4dffdfc7a..6b27af15f6 100644
--- a/modules/visual_script/visual_script.h
+++ b/modules/visual_script/visual_script.h
@@ -338,8 +338,8 @@ public:
virtual Error reload(bool p_keep_state = false) override;
#ifdef TOOLS_ENABLED
- virtual const Vector<DocData::ClassDoc> &get_documentation() const override {
- static Vector<DocData::ClassDoc> docs;
+ virtual Vector<DocData::ClassDoc> get_documentation() const override {
+ Vector<DocData::ClassDoc> docs;
return docs;
}
#endif // TOOLS_ENABLED
@@ -495,7 +495,7 @@ class VisualScriptLanguage : public ScriptLanguage {
String _debug_error;
int _debug_call_stack_pos = 0;
int _debug_max_call_stack;
- CallLevel *_call_stack;
+ CallLevel *_call_stack = nullptr;
public:
StringName notification = "_notification";
diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp
index f6bc855a50..44e792869d 100644
--- a/modules/visual_script/visual_script_builtin_funcs.cpp
+++ b/modules/visual_script/visual_script_builtin_funcs.cpp
@@ -989,7 +989,7 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
}
if (p_inputs[0]->is_ref_counted()) {
- REF r = *p_inputs[0];
+ Ref<RefCounted> r = *p_inputs[0];
if (!r.is_valid()) {
return;
}
@@ -1180,16 +1180,16 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
class VisualScriptNodeInstanceBuiltinFunc : public VisualScriptNodeInstance {
public:
- VisualScriptBuiltinFunc *node;
- VisualScriptInstance *instance;
+ VisualScriptBuiltinFunc *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
VisualScriptBuiltinFunc::BuiltinFunc func;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
VisualScriptBuiltinFunc::exec_func(func, p_inputs, p_outputs[0], r_error, r_error_str);
return 0;
}
diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp
index fef159bf87..e0f6436094 100644
--- a/modules/visual_script/visual_script_expression.cpp
+++ b/modules/visual_script/visual_script_expression.cpp
@@ -1299,10 +1299,10 @@ bool VisualScriptExpression::_compile_expression() {
class VisualScriptNodeInstanceExpression : public VisualScriptNodeInstance {
public:
- VisualScriptInstance *instance;
- VisualScriptExpression *expression;
+ VisualScriptInstance *instance = nullptr;
+ VisualScriptExpression *expression = nullptr;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
//execute by parsing the tree directly
virtual bool _execute(const Variant **p_inputs, VisualScriptExpression::ENode *p_node, Variant &r_ret, String &r_error_str, Callable::CallError &ce) {
switch (p_node->type) {
@@ -1512,7 +1512,7 @@ public:
return false;
}
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (!expression->root || expression->error_set) {
r_error_str = expression->error_str;
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp
index d28744a09f..0e63753720 100644
--- a/modules/visual_script/visual_script_flow_control.cpp
+++ b/modules/visual_script/visual_script_flow_control.cpp
@@ -119,15 +119,15 @@ void VisualScriptReturn::_bind_methods() {
class VisualScriptNodeInstanceReturn : public VisualScriptNodeInstance {
public:
- VisualScriptReturn *node;
- VisualScriptInstance *instance;
- bool with_value;
+ VisualScriptReturn *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
+ bool with_value = false;
- virtual int get_working_memory_size() const { return 1; }
+ virtual int get_working_memory_size() const override { return 1; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (with_value) {
*p_working_mem = *p_inputs[0];
return STEP_EXIT_FUNCTION_BIT;
@@ -213,14 +213,14 @@ void VisualScriptCondition::_bind_methods() {
class VisualScriptNodeInstanceCondition : public VisualScriptNodeInstance {
public:
- VisualScriptCondition *node;
- VisualScriptInstance *instance;
+ VisualScriptCondition *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
- //virtual int get_working_memory_size() const { return 1; }
+ //virtual int get_working_memory_size() const override { return 1; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (p_start_mode == START_MODE_CONTINUE_SEQUENCE) {
return 2;
} else if (p_inputs[0]->operator bool()) {
@@ -293,14 +293,14 @@ void VisualScriptWhile::_bind_methods() {
class VisualScriptNodeInstanceWhile : public VisualScriptNodeInstance {
public:
- VisualScriptWhile *node;
- VisualScriptInstance *instance;
+ VisualScriptWhile *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
- //virtual int get_working_memory_size() const { return 1; }
+ //virtual int get_working_memory_size() const override { return 1; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
bool keep_going = p_inputs[0]->operator bool();
if (keep_going) {
@@ -376,14 +376,14 @@ void VisualScriptIterator::_bind_methods() {
class VisualScriptNodeInstanceIterator : public VisualScriptNodeInstance {
public:
- VisualScriptIterator *node;
- VisualScriptInstance *instance;
+ VisualScriptIterator *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
- virtual int get_working_memory_size() const { return 2; }
+ virtual int get_working_memory_size() const override { return 2; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (p_start_mode == START_MODE_BEGIN_SEQUENCE) {
p_working_mem[0] = *p_inputs[0];
bool valid;
@@ -508,15 +508,15 @@ void VisualScriptSequence::_bind_methods() {
class VisualScriptNodeInstanceSequence : public VisualScriptNodeInstance {
public:
- VisualScriptSequence *node;
- VisualScriptInstance *instance;
- int steps;
+ VisualScriptSequence *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
+ int steps = 0;
- virtual int get_working_memory_size() const { return 1; }
+ virtual int get_working_memory_size() const override { return 1; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (p_start_mode == START_MODE_BEGIN_SEQUENCE) {
p_working_mem[0] = 0;
}
@@ -596,14 +596,14 @@ String VisualScriptSwitch::get_text() const {
class VisualScriptNodeInstanceSwitch : public VisualScriptNodeInstance {
public:
- VisualScriptInstance *instance;
- int case_count;
+ VisualScriptInstance *instance = nullptr;
+ int case_count = 0;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (p_start_mode == START_MODE_CONTINUE_SEQUENCE) {
return case_count; //exit
}
@@ -774,15 +774,15 @@ VisualScriptTypeCast::TypeGuess VisualScriptTypeCast::guess_output_type(TypeGues
class VisualScriptNodeInstanceTypeCast : public VisualScriptNodeInstance {
public:
- VisualScriptInstance *instance;
+ VisualScriptInstance *instance = nullptr;
StringName base_type;
String script;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
Object *obj = *p_inputs[0];
*p_outputs[0] = Variant();
diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp
index 2c9d23e457..483fc8b6c3 100644
--- a/modules/visual_script/visual_script_func_nodes.cpp
+++ b/modules/visual_script/visual_script_func_nodes.cpp
@@ -720,17 +720,17 @@ class VisualScriptNodeInstanceFunctionCall : public VisualScriptNodeInstance {
public:
VisualScriptFunctionCall::CallMode call_mode;
NodePath node_path;
- int input_args;
- bool validate;
- int returns;
+ int input_args = 0;
+ bool validate = false;
+ int returns = 0;
VisualScriptFunctionCall::RPCCallMode rpc_mode;
StringName function;
StringName singleton;
- VisualScriptFunctionCall *node;
- VisualScriptInstance *instance;
+ VisualScriptFunctionCall *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
@@ -765,7 +765,7 @@ public:
return true;
}
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
switch (call_mode) {
case VisualScriptFunctionCall::CALL_MODE_SELF: {
Object *object = instance->get_owner_ptr();
@@ -1462,13 +1462,13 @@ public:
NodePath node_path;
StringName property;
- VisualScriptPropertySet *node;
- VisualScriptInstance *instance;
+ VisualScriptPropertySet *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
VisualScriptPropertySet::AssignOp assign_op;
StringName index;
- bool needs_get;
+ bool needs_get = false;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
@@ -1529,7 +1529,7 @@ public:
}
}
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
switch (call_mode) {
case VisualScriptPropertySet::CALL_MODE_SELF: {
Object *object = instance->get_owner_ptr();
@@ -2152,10 +2152,10 @@ public:
StringName property;
StringName index;
- VisualScriptPropertyGet *node;
- VisualScriptInstance *instance;
+ VisualScriptPropertyGet *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
switch (call_mode) {
case VisualScriptPropertyGet::CALL_MODE_SELF: {
Object *object = instance->get_owner_ptr();
@@ -2362,16 +2362,16 @@ void VisualScriptEmitSignal::_bind_methods() {
class VisualScriptNodeInstanceEmitSignal : public VisualScriptNodeInstance {
public:
- VisualScriptEmitSignal *node;
- VisualScriptInstance *instance;
- int argcount;
+ VisualScriptEmitSignal *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
+ int argcount = 0;
StringName name;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
Object *obj = instance->get_owner_ptr();
obj->emit_signalp(name, p_inputs, argcount);
diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp
index b65b9f090a..dbbe74f3d5 100644
--- a/modules/visual_script/visual_script_nodes.cpp
+++ b/modules/visual_script/visual_script_nodes.cpp
@@ -271,12 +271,12 @@ Multiplayer::RPCMode VisualScriptFunction::get_rpc_mode() const {
class VisualScriptNodeInstanceFunction : public VisualScriptNodeInstance {
public:
- VisualScriptFunction *node;
- VisualScriptInstance *instance;
+ VisualScriptFunction *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
int ac = node->get_argument_count();
for (int i = 0; i < ac; i++) {
@@ -777,9 +777,9 @@ String VisualScriptComposeArray::get_text() const {
class VisualScriptComposeArrayNode : public VisualScriptNodeInstance {
public:
int input_count = 0;
- virtual int get_working_memory_size() const { return 0; }
+ virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (input_count > 0) {
Array arr;
for (int i = 0; i < input_count; i++) {
@@ -1097,12 +1097,12 @@ void VisualScriptOperator::_bind_methods() {
class VisualScriptNodeInstanceOperator : public VisualScriptNodeInstance {
public:
- bool unary;
+ bool unary = false;
Variant::Operator op;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
bool valid;
if (unary) {
Variant::evaluate(op, *p_inputs[0], Variant(), *p_outputs[0], valid);
@@ -1220,9 +1220,9 @@ void VisualScriptSelect::_bind_methods() {
class VisualScriptNodeInstanceSelect : public VisualScriptNodeInstance {
public:
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
bool cond = *p_inputs[0];
if (cond) {
*p_outputs[0] = *p_inputs[1];
@@ -1328,11 +1328,11 @@ void VisualScriptVariableGet::_bind_methods() {
class VisualScriptNodeInstanceVariableGet : public VisualScriptNodeInstance {
public:
- VisualScriptVariableGet *node;
- VisualScriptInstance *instance;
+ VisualScriptVariableGet *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
StringName variable;
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (!instance->get_variable(variable, p_outputs[0])) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
r_error_str = RTR("VariableGet not found in script: ") + "'" + String(variable) + "'";
@@ -1438,13 +1438,13 @@ void VisualScriptVariableSet::_bind_methods() {
class VisualScriptNodeInstanceVariableSet : public VisualScriptNodeInstance {
public:
- VisualScriptVariableSet *node;
- VisualScriptInstance *instance;
+ VisualScriptVariableSet *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
StringName variable;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (!instance->set_variable(variable, *p_inputs[0])) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
r_error_str = RTR("VariableSet not found in script: ") + "'" + String(variable) + "'";
@@ -1561,9 +1561,9 @@ void VisualScriptConstant::_bind_methods() {
class VisualScriptNodeInstanceConstant : public VisualScriptNodeInstance {
public:
Variant constant;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
*p_outputs[0] = constant;
return 0;
}
@@ -1654,9 +1654,9 @@ void VisualScriptPreload::_bind_methods() {
class VisualScriptNodeInstancePreload : public VisualScriptNodeInstance {
public:
Ref<Resource> preload;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
*p_outputs[0] = preload;
return 0;
}
@@ -1713,9 +1713,9 @@ String VisualScriptIndexGet::get_caption() const {
class VisualScriptNodeInstanceIndexGet : public VisualScriptNodeInstance {
public:
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
bool valid;
*p_outputs[0] = p_inputs[0]->get(*p_inputs[1], &valid);
@@ -1780,9 +1780,9 @@ String VisualScriptIndexSet::get_caption() const {
class VisualScriptNodeInstanceIndexSet : public VisualScriptNodeInstance {
public:
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
bool valid;
((Variant *)p_inputs[0])->set(*p_inputs[1], *p_inputs[2], &valid);
@@ -1851,10 +1851,9 @@ int VisualScriptGlobalConstant::get_global_constant() {
class VisualScriptNodeInstanceGlobalConstant : public VisualScriptNodeInstance {
public:
- int index;
- //virtual int get_working_memory_size() const { return 0; }
+ int index = 0;
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
*p_outputs[0] = CoreConstants::get_global_constant_value(index);
return 0;
}
@@ -1963,11 +1962,10 @@ StringName VisualScriptClassConstant::get_base_type() {
class VisualScriptNodeInstanceClassConstant : public VisualScriptNodeInstance {
public:
- int value;
- bool valid;
- //virtual int get_working_memory_size() const { return 0; }
+ int value = 0;
+ bool valid = false;
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (!valid) {
r_error_str = "Invalid constant name, pick a valid class constant.";
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
@@ -2098,10 +2096,9 @@ Variant::Type VisualScriptBasicTypeConstant::get_basic_type() const {
class VisualScriptNodeInstanceBasicTypeConstant : public VisualScriptNodeInstance {
public:
Variant value;
- bool valid;
- //virtual int get_working_memory_size() const { return 0; }
+ bool valid = false;
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (!valid) {
r_error_str = "Invalid constant name, pick a valid basic type constant.";
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
@@ -2227,10 +2224,9 @@ VisualScriptMathConstant::MathConstant VisualScriptMathConstant::get_math_consta
class VisualScriptNodeInstanceMathConstant : public VisualScriptNodeInstance {
public:
- float value;
- //virtual int get_working_memory_size() const { return 0; }
+ float value = 0.0f;
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
*p_outputs[0] = value;
return 0;
}
@@ -2320,11 +2316,11 @@ String VisualScriptEngineSingleton::get_singleton() {
class VisualScriptNodeInstanceEngineSingleton : public VisualScriptNodeInstance {
public:
- Object *singleton;
+ Object *singleton = nullptr;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
*p_outputs[0] = singleton;
return 0;
}
@@ -2429,13 +2425,13 @@ NodePath VisualScriptSceneNode::get_node_path() {
class VisualScriptNodeInstanceSceneNode : public VisualScriptNodeInstance {
public:
- VisualScriptSceneNode *node;
- VisualScriptInstance *instance;
+ VisualScriptSceneNode *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
NodePath path;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
Node *node = Object::cast_to<Node>(instance->get_owner_ptr());
if (!node) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
@@ -2610,12 +2606,12 @@ String VisualScriptSceneTree::get_caption() const {
class VisualScriptNodeInstanceSceneTree : public VisualScriptNodeInstance {
public:
- VisualScriptSceneTree *node;
- VisualScriptInstance *instance;
+ VisualScriptSceneTree *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
Node *node = Object::cast_to<Node>(instance->get_owner_ptr());
if (!node) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
@@ -2709,9 +2705,9 @@ class VisualScriptNodeInstanceResourcePath : public VisualScriptNodeInstance {
public:
String path;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
*p_outputs[0] = path;
return 0;
}
@@ -2779,11 +2775,11 @@ String VisualScriptSelf::get_caption() const {
class VisualScriptNodeInstanceSelf : public VisualScriptNodeInstance {
public:
- VisualScriptInstance *instance;
+ VisualScriptInstance *instance = nullptr;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
*p_outputs[0] = instance->get_owner_ptr();
return 0;
}
@@ -2965,14 +2961,14 @@ String VisualScriptCustomNode::get_category() const {
class VisualScriptNodeInstanceCustomNode : public VisualScriptNodeInstance {
public:
- VisualScriptInstance *instance;
- VisualScriptCustomNode *node;
- int in_count;
- int out_count;
- int work_mem_size;
-
- virtual int get_working_memory_size() const { return work_mem_size; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ VisualScriptInstance *instance = nullptr;
+ VisualScriptCustomNode *node = nullptr;
+ int in_count = 0;
+ int out_count = 0;
+ int work_mem_size = 0;
+
+ virtual int get_working_memory_size() const override { return work_mem_size; }
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (GDVIRTUAL_IS_OVERRIDDEN_PTR(node, _step)) {
Array in_values;
Array out_values;
@@ -3161,14 +3157,14 @@ String VisualScriptSubCall::get_category() const {
class VisualScriptNodeInstanceSubCall : public VisualScriptNodeInstance {
public:
- VisualScriptInstance *instance;
- VisualScriptSubCall *subcall;
- int input_args;
- bool valid;
+ VisualScriptInstance *instance = nullptr;
+ VisualScriptSubCall *subcall = nullptr;
+ int input_args = 0;
+ bool valid = false;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (!valid) {
r_error_str = "Node requires a script with a _subcall(<args>) method to work.";
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
@@ -3281,11 +3277,11 @@ String VisualScriptComment::get_category() const {
class VisualScriptNodeInstanceComment : public VisualScriptNodeInstance {
public:
- VisualScriptInstance *instance;
+ VisualScriptInstance *instance = nullptr;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
return 0;
}
};
@@ -3380,13 +3376,13 @@ Dictionary VisualScriptConstructor::get_constructor() const {
class VisualScriptNodeInstanceConstructor : public VisualScriptNodeInstance {
public:
- VisualScriptInstance *instance;
+ VisualScriptInstance *instance = nullptr;
Variant::Type type;
- int argcount;
+ int argcount = 0;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
Callable::CallError ce;
Variant::construct(type, *p_outputs[0], p_inputs, argcount, ce);
if (ce.error != Callable::CallError::CALL_OK) {
@@ -3497,11 +3493,11 @@ Variant::Type VisualScriptLocalVar::get_var_type() const {
class VisualScriptNodeInstanceLocalVar : public VisualScriptNodeInstance {
public:
- VisualScriptInstance *instance;
+ VisualScriptInstance *instance = nullptr;
StringName name;
- virtual int get_working_memory_size() const { return 1; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int get_working_memory_size() const override { return 1; }
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
*p_outputs[0] = *p_working_mem;
return 0;
}
@@ -3604,11 +3600,11 @@ Variant::Type VisualScriptLocalVarSet::get_var_type() const {
class VisualScriptNodeInstanceLocalVarSet : public VisualScriptNodeInstance {
public:
- VisualScriptInstance *instance;
+ VisualScriptInstance *instance = nullptr;
StringName name;
- virtual int get_working_memory_size() const { return 1; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int get_working_memory_size() const override { return 1; }
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
*p_working_mem = *p_inputs[0];
*p_outputs[0] = *p_working_mem;
return 0;
@@ -3728,11 +3724,11 @@ VisualScriptInputAction::Mode VisualScriptInputAction::get_action_mode() const {
class VisualScriptNodeInstanceInputAction : public VisualScriptNodeInstance {
public:
- VisualScriptInstance *instance;
+ VisualScriptInstance *instance = nullptr;
StringName action;
VisualScriptInputAction::Mode mode;
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
switch (mode) {
case VisualScriptInputAction::MODE_PRESSED: {
*p_outputs[0] = Input::get_singleton()->is_action_pressed(action);
@@ -3906,12 +3902,12 @@ Array VisualScriptDeconstruct::_get_elem_cache() const {
class VisualScriptNodeInstanceDeconstruct : public VisualScriptNodeInstance {
public:
- VisualScriptInstance *instance;
+ VisualScriptInstance *instance = nullptr;
Vector<StringName> outputs;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
Variant in = *p_inputs[0];
for (int i = 0; i < outputs.size(); i++) {
diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp
index dcd8815394..96e91a0baf 100644
--- a/modules/visual_script/visual_script_yield_nodes.cpp
+++ b/modules/visual_script/visual_script_yield_nodes.cpp
@@ -93,13 +93,13 @@ String VisualScriptYield::get_text() const {
class VisualScriptNodeInstanceYield : public VisualScriptNodeInstance {
public:
VisualScriptYield::YieldMode mode;
- double wait_time;
+ double wait_time = 0.0;
- virtual int get_working_memory_size() const { return 1; } //yield needs at least 1
+ virtual int get_working_memory_size() const override { return 1; } //yield needs at least 1
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (p_start_mode == START_MODE_RESUME_YIELD) {
return 0; //resuming yield
} else {
@@ -500,17 +500,17 @@ class VisualScriptNodeInstanceYieldSignal : public VisualScriptNodeInstance {
public:
VisualScriptYieldSignal::CallMode call_mode;
NodePath node_path;
- int output_args;
+ int output_args = 0;
StringName signal;
- VisualScriptYieldSignal *node;
- VisualScriptInstance *instance;
+ VisualScriptYieldSignal *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
- virtual int get_working_memory_size() const { return 1; }
+ virtual int get_working_memory_size() const override { return 1; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (p_start_mode == START_MODE_RESUME_YIELD) {
return 0; //resuming yield
} else {
diff --git a/modules/vorbis/register_types.cpp b/modules/vorbis/register_types.cpp
index 1baf7b2edc..7f81f88cdb 100644
--- a/modules/vorbis/register_types.cpp
+++ b/modules/vorbis/register_types.cpp
@@ -33,7 +33,11 @@
#include "audio_stream_ogg_vorbis.h"
#include "resource_importer_ogg_vorbis.h"
-void register_vorbis_types() {
+void initialize_vorbis_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
Ref<ResourceImporterOGGVorbis> ogg_vorbis_importer;
@@ -45,4 +49,8 @@ void register_vorbis_types() {
GDREGISTER_CLASS(AudioStreamPlaybackOGGVorbis);
}
-void unregister_vorbis_types() {}
+void uninitialize_vorbis_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+}
diff --git a/modules/vorbis/register_types.h b/modules/vorbis/register_types.h
index 666c7e5b9f..74c18b9c04 100644
--- a/modules/vorbis/register_types.h
+++ b/modules/vorbis/register_types.h
@@ -31,7 +31,9 @@
#ifndef VORBIS_REGISTER_TYPES_H
#define VORBIS_REGISTER_TYPES_H
-void register_vorbis_types();
-void unregister_vorbis_types();
+#include "modules/register_module_types.h"
+
+void initialize_vorbis_module(ModuleInitializationLevel p_level);
+void uninitialize_vorbis_module(ModuleInitializationLevel p_level);
#endif // VORBIS_REGISTER_TYPES_H
diff --git a/modules/vorbis/resource_importer_ogg_vorbis.cpp b/modules/vorbis/resource_importer_ogg_vorbis.cpp
index d12e65a96a..03e145216a 100644
--- a/modules/vorbis/resource_importer_ogg_vorbis.cpp
+++ b/modules/vorbis/resource_importer_ogg_vorbis.cpp
@@ -78,9 +78,8 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin
bool loop = p_options["loop"];
float loop_offset = p_options["loop_offset"];
- FileAccess *f = FileAccess::open(p_source_file, FileAccess::READ);
-
- ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot open file '" + p_source_file + "'.");
+ Ref<FileAccess> f = FileAccess::open(p_source_file, FileAccess::READ);
+ ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, "Cannot open file '" + p_source_file + "'.");
uint64_t len = f->get_length();
@@ -90,8 +89,6 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin
f->get_buffer(w, len);
- memdelete(f);
-
Ref<AudioStreamOGGVorbis> ogg_vorbis_stream;
ogg_vorbis_stream.instantiate();
diff --git a/modules/webp/image_loader_webp.cpp b/modules/webp/image_loader_webp.cpp
index 902e182d83..0e41f6c973 100644
--- a/modules/webp/image_loader_webp.cpp
+++ b/modules/webp/image_loader_webp.cpp
@@ -211,7 +211,7 @@ static Ref<Image> _webp_mem_loader_func(const uint8_t *p_png, int p_size) {
return img;
}
-Error ImageLoaderWEBP::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) {
+Error ImageLoaderWEBP::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) {
Vector<uint8_t> src_image;
uint64_t src_image_len = f->get_length();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
@@ -221,8 +221,6 @@ Error ImageLoaderWEBP::load_image(Ref<Image> p_image, FileAccess *f, bool p_forc
f->get_buffer(&w[0], src_image_len);
- f->close();
-
Error err = webp_load_image_from_buffer(p_image.ptr(), w, src_image_len);
return err;
diff --git a/modules/webp/image_loader_webp.h b/modules/webp/image_loader_webp.h
index 327582ca55..1acd1459a0 100644
--- a/modules/webp/image_loader_webp.h
+++ b/modules/webp/image_loader_webp.h
@@ -35,7 +35,7 @@
class ImageLoaderWEBP : public ImageFormatLoader {
public:
- virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderWEBP();
};
diff --git a/modules/webp/register_types.cpp b/modules/webp/register_types.cpp
index 462c0a0b3d..148e325498 100644
--- a/modules/webp/register_types.cpp
+++ b/modules/webp/register_types.cpp
@@ -34,11 +34,19 @@
static ImageLoaderWEBP *image_loader_webp = nullptr;
-void register_webp_types() {
+void initialize_webp_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
image_loader_webp = memnew(ImageLoaderWEBP);
ImageLoader::add_image_format_loader(image_loader_webp);
}
-void unregister_webp_types() {
+void uninitialize_webp_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
memdelete(image_loader_webp);
}
diff --git a/modules/webp/register_types.h b/modules/webp/register_types.h
index 828ef07f9a..6e37dcfb61 100644
--- a/modules/webp/register_types.h
+++ b/modules/webp/register_types.h
@@ -31,7 +31,9 @@
#ifndef WEBP_REGISTER_TYPES_H
#define WEBP_REGISTER_TYPES_H
-void register_webp_types();
-void unregister_webp_types();
+#include "modules/register_module_types.h"
+
+void initialize_webp_module(ModuleInitializationLevel p_level);
+void uninitialize_webp_module(ModuleInitializationLevel p_level);
#endif // WEBP_REGISTER_TYPES_H
diff --git a/modules/webrtc/register_types.cpp b/modules/webrtc/register_types.cpp
index 283e421e11..09cd538b96 100644
--- a/modules/webrtc/register_types.cpp
+++ b/modules/webrtc/register_types.cpp
@@ -37,7 +37,11 @@
#include "webrtc_data_channel_extension.h"
#include "webrtc_peer_connection_extension.h"
-void register_webrtc_types() {
+void initialize_webrtc_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
#define SET_HINT(NAME, _VAL_, _MAX_) \
GLOBAL_DEF(NAME, _VAL_); \
ProjectSettings::get_singleton()->set_custom_property_info(NAME, PropertyInfo(Variant::INT, NAME, PROPERTY_HINT_RANGE, "2," #_MAX_ ",1,or_greater"));
@@ -55,4 +59,8 @@ void register_webrtc_types() {
#undef SET_HINT
}
-void unregister_webrtc_types() {}
+void uninitialize_webrtc_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+}
diff --git a/modules/webrtc/register_types.h b/modules/webrtc/register_types.h
index 2e4457beaf..17171d0e0b 100644
--- a/modules/webrtc/register_types.h
+++ b/modules/webrtc/register_types.h
@@ -31,7 +31,9 @@
#ifndef WEBRTC_REGISTER_TYPES_H
#define WEBRTC_REGISTER_TYPES_H
-void register_webrtc_types();
-void unregister_webrtc_types();
+#include "modules/register_module_types.h"
+
+void initialize_webrtc_module(ModuleInitializationLevel p_level);
+void uninitialize_webrtc_module(ModuleInitializationLevel p_level);
#endif // WEBRTC_REGISTER_TYPES_H
diff --git a/modules/webrtc/webrtc_peer_connection_js.h b/modules/webrtc/webrtc_peer_connection_js.h
index 3d0b365355..8fa5ea7779 100644
--- a/modules/webrtc/webrtc_peer_connection_js.h
+++ b/modules/webrtc/webrtc_peer_connection_js.h
@@ -63,16 +63,16 @@ private:
static void _on_error(void *p_obj);
public:
- virtual ConnectionState get_connection_state() const;
+ virtual ConnectionState get_connection_state() const override;
- virtual Error initialize(Dictionary configuration = Dictionary());
- virtual Ref<WebRTCDataChannel> create_data_channel(String p_channel_name, Dictionary p_channel_config = Dictionary());
- virtual Error create_offer();
- virtual Error set_remote_description(String type, String sdp);
- virtual Error set_local_description(String type, String sdp);
- virtual Error add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName);
- virtual Error poll();
- virtual void close();
+ virtual Error initialize(Dictionary configuration = Dictionary()) override;
+ virtual Ref<WebRTCDataChannel> create_data_channel(String p_channel_name, Dictionary p_channel_config = Dictionary()) override;
+ virtual Error create_offer() override;
+ virtual Error set_remote_description(String type, String sdp) override;
+ virtual Error set_local_description(String type, String sdp) override;
+ virtual Error add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName) override;
+ virtual Error poll() override;
+ virtual void close() override;
WebRTCPeerConnectionJS();
~WebRTCPeerConnectionJS();
diff --git a/modules/websocket/SCsub b/modules/websocket/SCsub
index 63c941c4a8..dc0661995f 100644
--- a/modules/websocket/SCsub
+++ b/modules/websocket/SCsub
@@ -41,6 +41,8 @@ elif env["builtin_wslay"]:
module_obj = []
env_ws.add_source_files(module_obj, "*.cpp")
+if env["tools"]:
+ env_ws.add_source_files(module_obj, "editor/*.cpp")
env.modules_sources += module_obj
# Needed to force rebuilding the module files when the thirdparty library is updated.
diff --git a/modules/websocket/doc_classes/WebSocketServer.xml b/modules/websocket/doc_classes/WebSocketServer.xml
index ef3279aac4..46b0274de3 100644
--- a/modules/websocket/doc_classes/WebSocketServer.xml
+++ b/modules/websocket/doc_classes/WebSocketServer.xml
@@ -60,6 +60,13 @@
If [code]false[/code] is passed instead (default), you must call [PacketPeer] functions ([code]put_packet[/code], [code]get_packet[/code], etc.), on the [WebSocketPeer] returned via [code]get_peer(id)[/code] to communicate with the peer with given [code]id[/code] (e.g. [code]get_peer(id).get_available_packet_count[/code]).
</description>
</method>
+ <method name="set_extra_headers">
+ <return type="void" />
+ <argument index="0" name="headers" type="PackedStringArray" default="PackedStringArray()" />
+ <description>
+ Sets additional headers to be sent to clients during the HTTP handshake.
+ </description>
+ </method>
<method name="stop">
<return type="void" />
<description>
diff --git a/modules/websocket/editor_debugger_server_websocket.cpp b/modules/websocket/editor/editor_debugger_server_websocket.cpp
index 4f1a56f00b..0443147d98 100644
--- a/modules/websocket/editor_debugger_server_websocket.cpp
+++ b/modules/websocket/editor/editor_debugger_server_websocket.cpp
@@ -30,11 +30,13 @@
#include "editor_debugger_server_websocket.h"
+#ifdef TOOLS_ENABLED
+
+#include "../remote_debugger_peer_websocket.h"
#include "core/config/project_settings.h"
#include "editor/editor_log.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
-#include "modules/websocket/remote_debugger_peer_websocket.h"
void EditorDebuggerServerWebSocket::_peer_connected(int p_id, String _protocol) {
pending_peers.push_back(p_id);
@@ -129,3 +131,5 @@ EditorDebuggerServer *EditorDebuggerServerWebSocket::create(const String &p_prot
ERR_FAIL_COND_V(p_protocol != "ws://", nullptr);
return memnew(EditorDebuggerServerWebSocket);
}
+
+#endif // TOOLS_ENABLED
diff --git a/modules/websocket/editor_debugger_server_websocket.h b/modules/websocket/editor/editor_debugger_server_websocket.h
index cc14bf62ba..7c0705302d 100644
--- a/modules/websocket/editor_debugger_server_websocket.h
+++ b/modules/websocket/editor/editor_debugger_server_websocket.h
@@ -31,8 +31,10 @@
#ifndef EDITOR_DEBUGGER_SERVER_WEBSOCKET_H
#define EDITOR_DEBUGGER_SERVER_WEBSOCKET_H
+#ifdef TOOLS_ENABLED
+
+#include "../websocket_server.h"
#include "editor/debugger/editor_debugger_server.h"
-#include "modules/websocket/websocket_server.h"
class EditorDebuggerServerWebSocket : public EditorDebuggerServer {
GDCLASS(EditorDebuggerServerWebSocket, EditorDebuggerServer);
@@ -60,4 +62,6 @@ public:
~EditorDebuggerServerWebSocket();
};
+#endif // TOOLS_ENABLED
+
#endif // EDITOR_DEBUGGER_SERVER_WEBSOCKET_H
diff --git a/modules/websocket/emws_client.h b/modules/websocket/emws_client.h
index 61ea0002ea..ca327a56fa 100644
--- a/modules/websocket/emws_client.h
+++ b/modules/websocket/emws_client.h
@@ -53,15 +53,15 @@ private:
static void _esws_on_close(void *obj, int code, const char *reason, int was_clean);
public:
- Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets);
- Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const Vector<String> p_protocol = Vector<String>(), const Vector<String> p_custom_headers = Vector<String>());
- Ref<WebSocketPeer> get_peer(int p_peer_id) const;
- void disconnect_from_host(int p_code = 1000, String p_reason = "");
- IPAddress get_connected_host() const;
- uint16_t get_connected_port() const;
- virtual ConnectionStatus get_connection_status() const;
- int get_max_packet_size() const;
- virtual void poll();
+ Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) override;
+ Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const Vector<String> p_protocol = Vector<String>(), const Vector<String> p_custom_headers = Vector<String>()) override;
+ Ref<WebSocketPeer> get_peer(int p_peer_id) const override;
+ void disconnect_from_host(int p_code = 1000, String p_reason = "") override;
+ IPAddress get_connected_host() const override;
+ uint16_t get_connected_port() const override;
+ virtual ConnectionStatus get_connection_status() const override;
+ int get_max_packet_size() const override;
+ virtual void poll() override;
EMWSClient();
~EMWSClient();
};
diff --git a/modules/websocket/emws_peer.h b/modules/websocket/emws_peer.h
index df63d2d801..6bb4552c37 100644
--- a/modules/websocket/emws_peer.h
+++ b/modules/websocket/emws_peer.h
@@ -68,21 +68,21 @@ private:
public:
Error read_msg(const uint8_t *p_data, uint32_t p_size, bool p_is_string);
void set_sock(int p_sock, unsigned int p_in_buf_size, unsigned int p_in_pkt_size, unsigned int p_out_buf_size);
- virtual int get_available_packet_count() const;
- virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size);
- virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size);
- virtual int get_max_packet_size() const { return _packet_buffer.size(); };
- virtual int get_current_outbound_buffered_amount() const;
+ virtual int get_available_packet_count() const override;
+ virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override;
+ virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override;
+ virtual int get_max_packet_size() const override { return _packet_buffer.size(); };
+ virtual int get_current_outbound_buffered_amount() const override;
- virtual void close(int p_code = 1000, String p_reason = "");
- virtual bool is_connected_to_host() const;
- virtual IPAddress get_connected_host() const;
- virtual uint16_t get_connected_port() const;
+ virtual void close(int p_code = 1000, String p_reason = "") override;
+ virtual bool is_connected_to_host() const override;
+ virtual IPAddress get_connected_host() const override;
+ virtual uint16_t get_connected_port() const override;
- virtual WriteMode get_write_mode() const;
- virtual void set_write_mode(WriteMode p_mode);
- virtual bool was_string_packet() const;
- virtual void set_no_delay(bool p_enabled);
+ virtual WriteMode get_write_mode() const override;
+ virtual void set_write_mode(WriteMode p_mode) override;
+ virtual bool was_string_packet() const override;
+ virtual void set_no_delay(bool p_enabled) override;
EMWSPeer();
~EMWSPeer();
diff --git a/modules/websocket/emws_server.cpp b/modules/websocket/emws_server.cpp
index 53b4a0207d..2033098cad 100644
--- a/modules/websocket/emws_server.cpp
+++ b/modules/websocket/emws_server.cpp
@@ -33,6 +33,9 @@
#include "emws_server.h"
#include "core/os/os.h"
+void EMWSServer::set_extra_headers(const Vector<String> &p_headers) {
+}
+
Error EMWSServer::listen(int p_port, Vector<String> p_protocols, bool gd_mp_api) {
return FAILED;
}
diff --git a/modules/websocket/emws_server.h b/modules/websocket/emws_server.h
index f310c17c9d..ae31d9dbb0 100644
--- a/modules/websocket/emws_server.h
+++ b/modules/websocket/emws_server.h
@@ -41,17 +41,18 @@ class EMWSServer : public WebSocketServer {
GDCIIMPL(EMWSServer, WebSocketServer);
public:
- Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets);
- Error listen(int p_port, Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false);
- void stop();
- bool is_listening() const;
- bool has_peer(int p_id) const;
- Ref<WebSocketPeer> get_peer(int p_id) const;
- IPAddress get_peer_address(int p_peer_id) const;
- int get_peer_port(int p_peer_id) const;
- void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "");
- int get_max_packet_size() const;
- virtual void poll();
+ Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) override;
+ void set_extra_headers(const Vector<String> &p_headers) override;
+ Error listen(int p_port, Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false) override;
+ void stop() override;
+ bool is_listening() const override;
+ bool has_peer(int p_id) const override;
+ Ref<WebSocketPeer> get_peer(int p_id) const override;
+ IPAddress get_peer_address(int p_peer_id) const override;
+ int get_peer_port(int p_peer_id) const override;
+ void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "") override;
+ int get_max_packet_size() const override;
+ virtual void poll() override;
virtual Vector<String> get_protocols() const;
EMWSServer();
diff --git a/modules/websocket/library_godot_websocket.js b/modules/websocket/library_godot_websocket.js
index c88986fbe3..57f1f10b02 100644
--- a/modules/websocket/library_godot_websocket.js
+++ b/modules/websocket/library_godot_websocket.js
@@ -135,7 +135,7 @@ const GodotWebSocket = {
if (!ref) {
return;
}
- GodotWebSocket.close(p_id, 1001, '');
+ GodotWebSocket.close(p_id, 3001, 'destroyed');
IDHandler.remove(p_id);
ref.onopen = null;
ref.onmessage = null;
diff --git a/modules/websocket/register_types.cpp b/modules/websocket/register_types.cpp
index ff900f496f..f562de111f 100644
--- a/modules/websocket/register_types.cpp
+++ b/modules/websocket/register_types.cpp
@@ -29,8 +29,10 @@
/*************************************************************************/
#include "register_types.h"
+
#include "core/config/project_settings.h"
#include "core/error/error_macros.h"
+
#ifdef JAVASCRIPT_ENABLED
#include "emscripten.h"
#include "emws_client.h"
@@ -40,10 +42,11 @@
#include "wsl_client.h"
#include "wsl_server.h"
#endif
+
#ifdef TOOLS_ENABLED
#include "editor/debugger/editor_debugger_server.h"
+#include "editor/editor_debugger_server_websocket.h"
#include "editor/editor_node.h"
-#include "editor_debugger_server_websocket.h"
#endif
#ifdef TOOLS_ENABLED
@@ -52,25 +55,33 @@ static void _editor_init_callback() {
}
#endif
-void register_websocket_types() {
+void initialize_websocket_module(ModuleInitializationLevel p_level) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
#ifdef JAVASCRIPT_ENABLED
- EMWSPeer::make_default();
- EMWSClient::make_default();
- EMWSServer::make_default();
+ EMWSPeer::make_default();
+ EMWSClient::make_default();
+ EMWSServer::make_default();
#else
- WSLPeer::make_default();
- WSLClient::make_default();
- WSLServer::make_default();
+ WSLPeer::make_default();
+ WSLClient::make_default();
+ WSLServer::make_default();
#endif
- GDREGISTER_ABSTRACT_CLASS(WebSocketMultiplayerPeer);
- ClassDB::register_custom_instance_class<WebSocketServer>();
- ClassDB::register_custom_instance_class<WebSocketClient>();
- ClassDB::register_custom_instance_class<WebSocketPeer>();
+ GDREGISTER_ABSTRACT_CLASS(WebSocketMultiplayerPeer);
+ ClassDB::register_custom_instance_class<WebSocketServer>();
+ ClassDB::register_custom_instance_class<WebSocketClient>();
+ ClassDB::register_custom_instance_class<WebSocketPeer>();
+ }
#ifdef TOOLS_ENABLED
- EditorNode::add_init_callback(&_editor_init_callback);
+ if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
+ EditorNode::add_init_callback(&_editor_init_callback);
+ }
#endif
}
-void unregister_websocket_types() {}
+void uninitialize_websocket_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+}
diff --git a/modules/websocket/register_types.h b/modules/websocket/register_types.h
index 4ab6c0cfd3..dab42d6ed9 100644
--- a/modules/websocket/register_types.h
+++ b/modules/websocket/register_types.h
@@ -31,7 +31,9 @@
#ifndef WEBSOCKET_REGISTER_TYPES_H
#define WEBSOCKET_REGISTER_TYPES_H
-void register_websocket_types();
-void unregister_websocket_types();
+#include "modules/register_module_types.h"
+
+void initialize_websocket_module(ModuleInitializationLevel p_level);
+void uninitialize_websocket_module(ModuleInitializationLevel p_level);
#endif // WEBSOCKET_REGISTER_TYPES_H
diff --git a/modules/websocket/remote_debugger_peer_websocket.h b/modules/websocket/remote_debugger_peer_websocket.h
index ddf5425d81..3227065ded 100644
--- a/modules/websocket/remote_debugger_peer_websocket.h
+++ b/modules/websocket/remote_debugger_peer_websocket.h
@@ -31,12 +31,13 @@
#ifndef REMOTE_DEBUGGER_PEER_WEBSOCKET_H
#define REMOTE_DEBUGGER_PEER_WEBSOCKET_H
+#include "core/debugger/remote_debugger_peer.h"
+
#ifdef JAVASCRIPT_ENABLED
-#include "modules/websocket/emws_client.h"
+#include "emws_client.h"
#else
-#include "modules/websocket/wsl_client.h"
+#include "wsl_client.h"
#endif
-#include "core/debugger/remote_debugger_peer.h"
class RemoteDebuggerPeerWebSocket : public RemoteDebuggerPeer {
Ref<WebSocketClient> ws_client;
@@ -50,14 +51,14 @@ public:
static RemoteDebuggerPeer *create(const String &p_uri);
Error connect_to_host(const String &p_uri);
- bool is_peer_connected();
- int get_max_message_size() const;
- bool has_message();
- Error put_message(const Array &p_arr);
- Array get_message();
- void close();
- void poll();
- bool can_block() const;
+ bool is_peer_connected() override;
+ int get_max_message_size() const override;
+ bool has_message() override;
+ Error put_message(const Array &p_arr) override;
+ Array get_message() override;
+ void close() override;
+ void poll() override;
+ bool can_block() const override;
RemoteDebuggerPeerWebSocket(Ref<WebSocketPeer> p_peer = Ref<WebSocketPeer>());
};
diff --git a/modules/websocket/websocket_server.cpp b/modules/websocket/websocket_server.cpp
index b3f0140b80..b7851b02c4 100644
--- a/modules/websocket/websocket_server.cpp
+++ b/modules/websocket/websocket_server.cpp
@@ -42,6 +42,7 @@ WebSocketServer::~WebSocketServer() {
void WebSocketServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_listening"), &WebSocketServer::is_listening);
+ ClassDB::bind_method(D_METHOD("set_extra_headers", "headers"), &WebSocketServer::set_extra_headers, DEFVAL(Vector<String>()));
ClassDB::bind_method(D_METHOD("listen", "port", "protocols", "gd_mp_api"), &WebSocketServer::listen, DEFVAL(Vector<String>()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("stop"), &WebSocketServer::stop);
ClassDB::bind_method(D_METHOD("has_peer", "id"), &WebSocketServer::has_peer);
diff --git a/modules/websocket/websocket_server.h b/modules/websocket/websocket_server.h
index f6f3b80045..7bd80851f5 100644
--- a/modules/websocket/websocket_server.h
+++ b/modules/websocket/websocket_server.h
@@ -51,6 +51,7 @@ protected:
uint32_t handshake_timeout = 3000;
public:
+ virtual void set_extra_headers(const Vector<String> &p_headers) = 0;
virtual Error listen(int p_port, const Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false) = 0;
virtual void stop() = 0;
virtual bool is_listening() const = 0;
diff --git a/modules/websocket/wsl_client.cpp b/modules/websocket/wsl_client.cpp
index 1ef571b6ee..894ba7766f 100644
--- a/modules/websocket/wsl_client.cpp
+++ b/modules/websocket/wsl_client.cpp
@@ -91,6 +91,7 @@ void WSLClient::_do_handshake() {
data->id = 1;
_peer->make_context(data, _in_buf_size, _in_pkt_size, _out_buf_size, _out_pkt_size);
_peer->set_no_delay(true);
+ _status = CONNECTION_CONNECTED;
_on_connect(protocol);
break;
}
@@ -103,13 +104,14 @@ bool WSLClient::_verify_headers(String &r_protocol) {
String s = (char *)_resp_buf;
Vector<String> psa = s.split("\r\n");
int len = psa.size();
- ERR_FAIL_COND_V_MSG(len < 4, false, "Not enough response headers, got: " + itos(len) + ", expected >= 4.");
+ ERR_FAIL_COND_V_MSG(len < 4, false, "Not enough response headers. Got: " + itos(len) + ", expected >= 4.");
Vector<String> req = psa[0].split(" ", false);
- ERR_FAIL_COND_V_MSG(req.size() < 2, false, "Invalid protocol or status code.");
+ ERR_FAIL_COND_V_MSG(req.size() < 2, false, "Invalid protocol or status code. Got '" + psa[0] + "', expected 'HTTP/1.1 101'.");
// Wrong protocol
- ERR_FAIL_COND_V_MSG(req[0] != "HTTP/1.1" || req[1] != "101", false, "Invalid protocol or status code.");
+ ERR_FAIL_COND_V_MSG(req[0] != "HTTP/1.1", false, "Invalid protocol. Got: '" + req[0] + "', expected 'HTTP/1.1'.");
+ ERR_FAIL_COND_V_MSG(req[1] != "101", false, "Invalid status code. Got: '" + req[1] + "', expected '101'.");
Map<String, String> headers;
for (int i = 1; i < len; i++) {
@@ -137,9 +139,11 @@ bool WSLClient::_verify_headers(String &r_protocol) {
#undef WSL_CHECK
if (_protocols.size() == 0) {
// We didn't request a custom protocol
- ERR_FAIL_COND_V(headers.has("sec-websocket-protocol"), false);
+ ERR_FAIL_COND_V_MSG(headers.has("sec-websocket-protocol"), false, "Received unrequested sub-protocol -> " + headers["sec-websocket-protocol"]);
} else {
- ERR_FAIL_COND_V(!headers.has("sec-websocket-protocol"), false);
+ // We requested at least one custom protocol but didn't receive one
+ ERR_FAIL_COND_V_MSG(!headers.has("sec-websocket-protocol"), false, "Requested sub-protocol(s) but received none.");
+ // Check received sub-protocol was one of those requested.
r_protocol = headers["sec-websocket-protocol"];
bool valid = false;
for (int i = 0; i < _protocols.size(); i++) {
@@ -150,6 +154,7 @@ bool WSLClient::_verify_headers(String &r_protocol) {
break;
}
if (!valid) {
+ ERR_FAIL_V_MSG(false, "Received unrequested sub-protocol -> " + r_protocol);
return false;
}
}
@@ -227,6 +232,7 @@ Error WSLClient::connect_to_host(String p_host, String p_path, uint16_t p_port,
}
request += "\r\n";
_request = request.utf8();
+ _status = CONNECTION_CONNECTING;
return OK;
}
@@ -273,6 +279,7 @@ void WSLClient::poll() {
return; // Not connected.
}
+ _tcp->poll();
switch (_tcp->get_status()) {
case StreamPeerTCP::STATUS_NONE:
// Clean close
@@ -332,21 +339,19 @@ Ref<WebSocketPeer> WSLClient::get_peer(int p_peer_id) const {
}
MultiplayerPeer::ConnectionStatus WSLClient::get_connection_status() const {
+ // This is surprising, but keeps the current behaviour to allow clean close requests.
+ // TODO Refactor WebSocket and split Client/Server/Multiplayer like done in other peers.
if (_peer->is_connected_to_host()) {
return CONNECTION_CONNECTED;
}
-
- if (_tcp->is_connected_to_host() || _resolver_id != IP::RESOLVER_INVALID_ID) {
- return CONNECTION_CONNECTING;
- }
-
- return CONNECTION_DISCONNECTED;
+ return _status;
}
void WSLClient::disconnect_from_host(int p_code, String p_reason) {
_peer->close(p_code, p_reason);
_connection = Ref<StreamPeer>(nullptr);
_tcp = Ref<StreamPeerTCP>(memnew(StreamPeerTCP));
+ _status = CONNECTION_DISCONNECTED;
_key = "";
_host = "";
diff --git a/modules/websocket/wsl_client.h b/modules/websocket/wsl_client.h
index d846e6be00..22d7ffa839 100644
--- a/modules/websocket/wsl_client.h
+++ b/modules/websocket/wsl_client.h
@@ -52,6 +52,7 @@ private:
Ref<WSLPeer> _peer;
Ref<StreamPeerTCP> _tcp;
Ref<StreamPeer> _connection;
+ ConnectionStatus _status = CONNECTION_DISCONNECTED;
CharString _request;
int _requested = 0;
@@ -59,11 +60,9 @@ private:
uint8_t _resp_buf[WSL_MAX_HEADER_SIZE];
int _resp_pos = 0;
- String _response;
-
String _key;
String _host;
- uint16_t _port;
+ uint16_t _port = 0;
Array _ip_candidates;
Vector<String> _protocols;
bool _use_ssl = false;
@@ -73,15 +72,15 @@ private:
bool _verify_headers(String &r_protocol);
public:
- Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets);
- Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const Vector<String> p_protocol = Vector<String>(), const Vector<String> p_custom_headers = Vector<String>());
- int get_max_packet_size() const;
- Ref<WebSocketPeer> get_peer(int p_peer_id) const;
- void disconnect_from_host(int p_code = 1000, String p_reason = "");
- IPAddress get_connected_host() const;
- uint16_t get_connected_port() const;
- virtual ConnectionStatus get_connection_status() const;
- virtual void poll();
+ Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) override;
+ Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const Vector<String> p_protocol = Vector<String>(), const Vector<String> p_custom_headers = Vector<String>()) override;
+ int get_max_packet_size() const override;
+ Ref<WebSocketPeer> get_peer(int p_peer_id) const override;
+ void disconnect_from_host(int p_code = 1000, String p_reason = "") override;
+ IPAddress get_connected_host() const override;
+ uint16_t get_connected_port() const override;
+ virtual ConnectionStatus get_connection_status() const override;
+ virtual void poll() override;
WSLClient();
~WSLClient();
diff --git a/modules/websocket/wsl_peer.cpp b/modules/websocket/wsl_peer.cpp
index d277eedace..15df4d039c 100644
--- a/modules/websocket/wsl_peer.cpp
+++ b/modules/websocket/wsl_peer.cpp
@@ -146,17 +146,17 @@ void wsl_msg_recv_callback(wslay_event_context_ptr ctx, const struct wslay_event
if (!peer_data->valid || peer_data->closing) {
return;
}
- WSLPeer *peer = (WSLPeer *)peer_data->peer;
+ WSLPeer *peer = static_cast<WSLPeer *>(peer_data->peer);
if (peer->parse_message(arg) != OK) {
return;
}
if (peer_data->is_server) {
- WSLServer *helper = (WSLServer *)peer_data->obj;
+ WSLServer *helper = static_cast<WSLServer *>(peer_data->obj);
helper->_on_peer_packet(peer_data->id);
} else {
- WSLClient *helper = (WSLClient *)peer_data->obj;
+ WSLClient *helper = static_cast<WSLClient *>(peer_data->obj);
helper->_on_peer_packet();
}
}
@@ -184,10 +184,10 @@ Error WSLPeer::parse_message(const wslay_event_on_msg_recv_arg *arg) {
}
if (!wslay_event_get_close_sent(_data->ctx)) {
if (_data->is_server) {
- WSLServer *helper = (WSLServer *)_data->obj;
+ WSLServer *helper = static_cast<WSLServer *>(_data->obj);
helper->_on_close_request(_data->id, close_code, close_reason);
} else {
- WSLClient *helper = (WSLClient *)_data->obj;
+ WSLClient *helper = static_cast<WSLClient *>(_data->obj);
helper->_on_close_request(close_code, close_reason);
}
}
diff --git a/modules/websocket/wsl_peer.h b/modules/websocket/wsl_peer.h
index 555559c6e1..abeecdd537 100644
--- a/modules/websocket/wsl_peer.h
+++ b/modules/websocket/wsl_peer.h
@@ -85,22 +85,22 @@ public:
String close_reason;
void poll(); // Used by client and server.
- virtual int get_available_packet_count() const;
- virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size);
- virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size);
- virtual int get_max_packet_size() const { return _packet_buffer.size(); };
- virtual int get_current_outbound_buffered_amount() const;
+ virtual int get_available_packet_count() const override;
+ virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override;
+ virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override;
+ virtual int get_max_packet_size() const override { return _packet_buffer.size(); };
+ virtual int get_current_outbound_buffered_amount() const override;
virtual void close_now();
- virtual void close(int p_code = 1000, String p_reason = "");
- virtual bool is_connected_to_host() const;
- virtual IPAddress get_connected_host() const;
- virtual uint16_t get_connected_port() const;
-
- virtual WriteMode get_write_mode() const;
- virtual void set_write_mode(WriteMode p_mode);
- virtual bool was_string_packet() const;
- virtual void set_no_delay(bool p_enabled);
+ virtual void close(int p_code = 1000, String p_reason = "") override;
+ virtual bool is_connected_to_host() const override;
+ virtual IPAddress get_connected_host() const override;
+ virtual uint16_t get_connected_port() const override;
+
+ virtual WriteMode get_write_mode() const override;
+ virtual void set_write_mode(WriteMode p_mode) override;
+ virtual bool was_string_packet() const override;
+ virtual void set_no_delay(bool p_enabled) override;
void make_context(PeerData *p_data, unsigned int p_in_buf_size, unsigned int p_in_pkt_size, unsigned int p_out_buf_size, unsigned int p_out_pkt_size);
Error parse_message(const wslay_event_on_msg_recv_arg *arg);
diff --git a/modules/websocket/wsl_server.cpp b/modules/websocket/wsl_server.cpp
index eadd7ef7ac..b58b2e4724 100644
--- a/modules/websocket/wsl_server.cpp
+++ b/modules/websocket/wsl_server.cpp
@@ -96,7 +96,7 @@ bool WSLServer::PendingPeer::_parse_request(const Vector<String> p_protocols, St
return true;
}
-Error WSLServer::PendingPeer::do_handshake(const Vector<String> p_protocols, uint64_t p_timeout, String &r_resource_name) {
+Error WSLServer::PendingPeer::do_handshake(const Vector<String> p_protocols, uint64_t p_timeout, String &r_resource_name, const Vector<String> &p_extra_headers) {
if (OS::get_singleton()->get_ticks_msec() - time > p_timeout) {
print_verbose(vformat("WebSocket handshake timed out after %.3f seconds.", p_timeout * 0.001));
return ERR_TIMEOUT;
@@ -141,6 +141,9 @@ Error WSLServer::PendingPeer::do_handshake(const Vector<String> p_protocols, uin
if (!protocol.is_empty()) {
s += "Sec-WebSocket-Protocol: " + protocol + "\r\n";
}
+ for (int i = 0; i < p_extra_headers.size(); i++) {
+ s += p_extra_headers[i] + "\r\n";
+ }
s += "\r\n";
response = s.utf8();
has_request = true;
@@ -167,6 +170,10 @@ Error WSLServer::PendingPeer::do_handshake(const Vector<String> p_protocols, uin
return OK;
}
+void WSLServer::set_extra_headers(const Vector<String> &p_headers) {
+ _extra_headers = p_headers;
+}
+
Error WSLServer::listen(int p_port, const Vector<String> p_protocols, bool gd_mp_api) {
ERR_FAIL_COND_V(is_listening(), ERR_ALREADY_IN_USE);
@@ -183,7 +190,7 @@ Error WSLServer::listen(int p_port, const Vector<String> p_protocols, bool gd_mp
void WSLServer::poll() {
List<int> remove_ids;
for (const KeyValue<int, Ref<WebSocketPeer>> &E : _peer_map) {
- Ref<WSLPeer> peer = (WSLPeer *)E.value.ptr();
+ Ref<WSLPeer> peer = const_cast<WSLPeer *>(static_cast<const WSLPeer *>(E.value.ptr()));
peer->poll();
if (!peer->is_connected_to_host()) {
_on_disconnect(E.key, peer->close_code != -1);
@@ -199,7 +206,7 @@ void WSLServer::poll() {
for (const Ref<PendingPeer> &E : _pending) {
String resource_name;
Ref<PendingPeer> ppeer = E;
- Error err = ppeer->do_handshake(_protocols, handshake_timeout, resource_name);
+ Error err = ppeer->do_handshake(_protocols, handshake_timeout, resource_name, _extra_headers);
if (err == ERR_BUSY) {
continue;
} else if (err != OK) {
@@ -266,7 +273,7 @@ int WSLServer::get_max_packet_size() const {
void WSLServer::stop() {
_server->stop();
for (const KeyValue<int, Ref<WebSocketPeer>> &E : _peer_map) {
- Ref<WSLPeer> peer = (WSLPeer *)E.value.ptr();
+ Ref<WSLPeer> peer = const_cast<WSLPeer *>(static_cast<const WSLPeer *>(E.value.ptr()));
peer->close_now();
}
_pending.clear();
diff --git a/modules/websocket/wsl_server.h b/modules/websocket/wsl_server.h
index 221cae4793..a920e9c665 100644
--- a/modules/websocket/wsl_server.h
+++ b/modules/websocket/wsl_server.h
@@ -62,7 +62,7 @@ private:
CharString response;
int response_sent = 0;
- Error do_handshake(const Vector<String> p_protocols, uint64_t p_timeout, String &r_resource_name);
+ Error do_handshake(const Vector<String> p_protocols, uint64_t p_timeout, String &r_resource_name, const Vector<String> &p_extra_headers);
};
int _in_buf_size = DEF_BUF_SHIFT;
@@ -73,19 +73,21 @@ private:
List<Ref<PendingPeer>> _pending;
Ref<TCPServer> _server;
Vector<String> _protocols;
+ Vector<String> _extra_headers;
public:
- Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets);
- Error listen(int p_port, const Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false);
- void stop();
- bool is_listening() const;
- int get_max_packet_size() const;
- bool has_peer(int p_id) const;
- Ref<WebSocketPeer> get_peer(int p_id) const;
- IPAddress get_peer_address(int p_peer_id) const;
- int get_peer_port(int p_peer_id) const;
- void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "");
- virtual void poll();
+ Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) override;
+ void set_extra_headers(const Vector<String> &p_headers) override;
+ Error listen(int p_port, const Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false) override;
+ void stop() override;
+ bool is_listening() const override;
+ int get_max_packet_size() const override;
+ bool has_peer(int p_id) const override;
+ Ref<WebSocketPeer> get_peer(int p_id) const override;
+ IPAddress get_peer_address(int p_peer_id) const override;
+ int get_peer_port(int p_peer_id) const override;
+ void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "") override;
+ virtual void poll() override;
WSLServer();
~WSLServer();
diff --git a/modules/webxr/register_types.cpp b/modules/webxr/register_types.cpp
index a15dc93248..cd403a4996 100644
--- a/modules/webxr/register_types.cpp
+++ b/modules/webxr/register_types.cpp
@@ -37,7 +37,11 @@
Ref<WebXRInterfaceJS> webxr;
#endif
-void register_webxr_types() {
+void initialize_webxr_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
GDREGISTER_ABSTRACT_CLASS(WebXRInterface);
#ifdef JAVASCRIPT_ENABLED
@@ -46,7 +50,11 @@ void register_webxr_types() {
#endif
}
-void unregister_webxr_types() {
+void uninitialize_webxr_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
#ifdef JAVASCRIPT_ENABLED
if (webxr.is_valid()) {
// uninitialise our interface if it is initialised
diff --git a/modules/webxr/register_types.h b/modules/webxr/register_types.h
index 5dda728099..2ea9bc1169 100644
--- a/modules/webxr/register_types.h
+++ b/modules/webxr/register_types.h
@@ -31,7 +31,9 @@
#ifndef WEBXR_REGISTER_TYPES_H
#define WEBXR_REGISTER_TYPES_H
-void register_webxr_types();
-void unregister_webxr_types();
+#include "modules/register_module_types.h"
+
+void initialize_webxr_module(ModuleInitializationLevel p_level);
+void uninitialize_webxr_module(ModuleInitializationLevel p_level);
#endif // WEBXR_REGISTER_TYPES_H
diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp
index 06b0e31801..74e744402b 100644
--- a/modules/webxr/webxr_interface_js.cpp
+++ b/modules/webxr/webxr_interface_js.cpp
@@ -59,7 +59,7 @@ void _emwebxr_on_session_started(char *p_reference_space_type) {
ERR_FAIL_COND(interface.is_null());
String reference_space_type = String(p_reference_space_type);
- ((WebXRInterfaceJS *)interface.ptr())->_set_reference_space_type(reference_space_type);
+ static_cast<WebXRInterfaceJS *>(interface.ptr())->_set_reference_space_type(reference_space_type);
interface->emit_signal(SNAME("session_started"));
}
@@ -94,7 +94,7 @@ void _emwebxr_on_controller_changed() {
Ref<XRInterface> interface = xr_server->find_interface("WebXR");
ERR_FAIL_COND(interface.is_null());
- ((WebXRInterfaceJS *)interface.ptr())->_on_controller_changed();
+ static_cast<WebXRInterfaceJS *>(interface.ptr())->_on_controller_changed();
}
extern "C" EMSCRIPTEN_KEEPALIVE void _emwebxr_on_input_event(char *p_signal_name, int p_input_source) {
@@ -291,15 +291,15 @@ void WebXRInterfaceJS::uninitialize() {
Transform3D WebXRInterfaceJS::_js_matrix_to_transform(float *p_js_matrix) {
Transform3D transform;
- transform.basis.elements[0].x = p_js_matrix[0];
- transform.basis.elements[1].x = p_js_matrix[1];
- transform.basis.elements[2].x = p_js_matrix[2];
- transform.basis.elements[0].y = p_js_matrix[4];
- transform.basis.elements[1].y = p_js_matrix[5];
- transform.basis.elements[2].y = p_js_matrix[6];
- transform.basis.elements[0].z = p_js_matrix[8];
- transform.basis.elements[1].z = p_js_matrix[9];
- transform.basis.elements[2].z = p_js_matrix[10];
+ transform.basis.rows[0].x = p_js_matrix[0];
+ transform.basis.rows[1].x = p_js_matrix[1];
+ transform.basis.rows[2].x = p_js_matrix[2];
+ transform.basis.rows[0].y = p_js_matrix[4];
+ transform.basis.rows[1].y = p_js_matrix[5];
+ transform.basis.rows[2].y = p_js_matrix[6];
+ transform.basis.rows[0].z = p_js_matrix[8];
+ transform.basis.rows[1].z = p_js_matrix[9];
+ transform.basis.rows[2].z = p_js_matrix[10];
transform.origin.x = p_js_matrix[12];
transform.origin.y = p_js_matrix[13];
transform.origin.z = p_js_matrix[14];
diff --git a/modules/xatlas_unwrap/register_types.cpp b/modules/xatlas_unwrap/register_types.cpp
index 139df9c735..e9985984a6 100644
--- a/modules/xatlas_unwrap/register_types.cpp
+++ b/modules/xatlas_unwrap/register_types.cpp
@@ -222,9 +222,16 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
return true;
}
-void register_xatlas_unwrap_types() {
+void initialize_xatlas_unwrap_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
array_mesh_lightmap_unwrap_callback = xatlas_mesh_lightmap_unwrap_callback;
}
-void unregister_xatlas_unwrap_types() {
+void uninitialize_xatlas_unwrap_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
diff --git a/modules/xatlas_unwrap/register_types.h b/modules/xatlas_unwrap/register_types.h
index 63a985f8c5..f82b5912f4 100644
--- a/modules/xatlas_unwrap/register_types.h
+++ b/modules/xatlas_unwrap/register_types.h
@@ -31,7 +31,9 @@
#ifndef XATLAS_UNWRAP_REGISTER_TYPES_H
#define XATLAS_UNWRAP_REGISTER_TYPES_H
-void register_xatlas_unwrap_types();
-void unregister_xatlas_unwrap_types();
+#include "modules/register_module_types.h"
+
+void initialize_xatlas_unwrap_module(ModuleInitializationLevel p_level);
+void uninitialize_xatlas_unwrap_module(ModuleInitializationLevel p_level);
#endif // XATLAS_UNWRAP_REGISTER_TYPES_H