summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/SCsub5
-rw-r--r--modules/arkit/SCsub15
-rw-r--r--modules/arkit/arkit_interface.mm791
-rw-r--r--modules/assimp/SCsub94
-rw-r--r--modules/assimp/config.py6
-rw-r--r--modules/assimp/editor_scene_importer_assimp.cpp1486
-rw-r--r--modules/assimp/editor_scene_importer_assimp.h149
-rwxr-xr-xmodules/assimp/godot_update_assimp.sh262
-rw-r--r--modules/assimp/import_state.h132
-rw-r--r--modules/assimp/import_utils.h463
-rw-r--r--modules/basis_universal/SCsub17
-rw-r--r--modules/basis_universal/register_types.cpp6
-rw-r--r--modules/basis_universal/register_types.h4
-rw-r--r--modules/basis_universal/texture_basisu.cpp18
-rw-r--r--modules/basis_universal/texture_basisu.h6
-rw-r--r--modules/bmp/image_loader_bmp.cpp24
-rw-r--r--modules/bmp/image_loader_bmp.h4
-rw-r--r--modules/bmp/register_types.cpp4
-rw-r--r--modules/bmp/register_types.h4
-rw-r--r--modules/bullet/SCsub14
-rw-r--r--modules/bullet/area_bullet.cpp4
-rw-r--r--modules/bullet/area_bullet.h6
-rw-r--r--modules/bullet/btRayShape.cpp4
-rw-r--r--modules/bullet/btRayShape.h4
-rw-r--r--modules/bullet/bullet_physics_server.cpp61
-rw-r--r--modules/bullet/bullet_physics_server.h44
-rw-r--r--modules/bullet/bullet_types_converter.cpp4
-rw-r--r--modules/bullet/bullet_types_converter.h4
-rw-r--r--modules/bullet/bullet_utilities.h4
-rw-r--r--modules/bullet/collision_object_bullet.cpp4
-rw-r--r--modules/bullet/collision_object_bullet.h8
-rw-r--r--modules/bullet/cone_twist_joint_bullet.cpp4
-rw-r--r--modules/bullet/cone_twist_joint_bullet.h4
-rw-r--r--modules/bullet/constraint_bullet.cpp4
-rw-r--r--modules/bullet/constraint_bullet.h4
-rw-r--r--modules/bullet/generic_6dof_joint_bullet.cpp12
-rw-r--r--modules/bullet/generic_6dof_joint_bullet.h7
-rw-r--r--modules/bullet/godot_collision_configuration.cpp4
-rw-r--r--modules/bullet/godot_collision_configuration.h4
-rw-r--r--modules/bullet/godot_collision_dispatcher.cpp4
-rw-r--r--modules/bullet/godot_collision_dispatcher.h6
-rw-r--r--modules/bullet/godot_motion_state.h4
-rw-r--r--modules/bullet/godot_ray_world_algorithm.cpp4
-rw-r--r--modules/bullet/godot_ray_world_algorithm.h4
-rw-r--r--modules/bullet/godot_result_callbacks.cpp4
-rw-r--r--modules/bullet/godot_result_callbacks.h4
-rw-r--r--modules/bullet/hinge_joint_bullet.cpp4
-rw-r--r--modules/bullet/hinge_joint_bullet.h4
-rw-r--r--modules/bullet/joint_bullet.cpp4
-rw-r--r--modules/bullet/joint_bullet.h4
-rw-r--r--modules/bullet/pin_joint_bullet.cpp4
-rw-r--r--modules/bullet/pin_joint_bullet.h4
-rw-r--r--modules/bullet/register_types.cpp8
-rw-r--r--modules/bullet/register_types.h4
-rw-r--r--modules/bullet/rid_bullet.h6
-rw-r--r--modules/bullet/rigid_body_bullet.cpp35
-rw-r--r--modules/bullet/rigid_body_bullet.h18
-rw-r--r--modules/bullet/shape_bullet.cpp18
-rw-r--r--modules/bullet/shape_bullet.h6
-rw-r--r--modules/bullet/shape_owner_bullet.cpp4
-rw-r--r--modules/bullet/shape_owner_bullet.h4
-rw-r--r--modules/bullet/slider_joint_bullet.cpp4
-rw-r--r--modules/bullet/slider_joint_bullet.h4
-rw-r--r--modules/bullet/soft_body_bullet.cpp4
-rw-r--r--modules/bullet/soft_body_bullet.h4
-rw-r--r--modules/bullet/space_bullet.cpp58
-rw-r--r--modules/bullet/space_bullet.h21
-rw-r--r--modules/camera/SCsub12
-rw-r--r--modules/camera/camera_ios.mm445
-rw-r--r--modules/camera/camera_osx.h4
-rw-r--r--modules/camera/camera_osx.mm4
-rw-r--r--modules/camera/camera_win.cpp4
-rw-r--r--modules/camera/camera_win.h4
-rw-r--r--modules/camera/config.py2
-rw-r--r--modules/camera/register_types.cpp10
-rw-r--r--modules/camera/register_types.h4
-rw-r--r--modules/csg/csg.cpp6
-rw-r--r--modules/csg/csg.h14
-rw-r--r--modules/csg/csg_gizmos.cpp82
-rw-r--r--modules/csg/csg_gizmos.h6
-rw-r--r--modules/csg/csg_shape.cpp107
-rw-r--r--modules/csg/csg_shape.h20
-rw-r--r--modules/csg/doc_classes/CSGBox3D.xml10
-rw-r--r--modules/csg/icons/CSGBox3D.svg7
-rw-r--r--modules/csg/icons/CSGCapsule3D.svg7
-rw-r--r--modules/csg/icons/CSGCombiner3D.svg9
-rw-r--r--modules/csg/icons/CSGCylinder3D.svg7
-rw-r--r--modules/csg/icons/CSGMesh3D.svg7
-rw-r--r--modules/csg/icons/CSGPolygon3D.svg7
-rw-r--r--modules/csg/icons/CSGSphere3D.svg7
-rw-r--r--modules/csg/icons/CSGTorus3D.svg7
-rw-r--r--modules/csg/register_types.cpp4
-rw-r--r--modules/csg/register_types.h4
-rw-r--r--modules/cvtt/SCsub15
-rw-r--r--modules/cvtt/image_compress_cvtt.cpp14
-rw-r--r--modules/cvtt/image_compress_cvtt.h6
-rw-r--r--modules/cvtt/register_types.cpp4
-rw-r--r--modules/cvtt/register_types.h4
-rw-r--r--modules/dds/register_types.cpp4
-rw-r--r--modules/dds/register_types.h4
-rw-r--r--modules/dds/texture_loader_dds.cpp6
-rw-r--r--modules/dds/texture_loader_dds.h4
-rw-r--r--modules/denoise/SCsub17
-rw-r--r--modules/denoise/denoise_wrapper.cpp4
-rw-r--r--modules/denoise/denoise_wrapper.h4
-rw-r--r--modules/denoise/lightmap_denoiser.cpp4
-rw-r--r--modules/denoise/lightmap_denoiser.h6
-rw-r--r--modules/denoise/register_types.cpp6
-rw-r--r--modules/denoise/register_types.h4
-rw-r--r--modules/enet/SCsub16
-rw-r--r--modules/enet/doc_classes/NetworkedMultiplayerENet.xml2
-rw-r--r--modules/enet/networked_multiplayer_enet.cpp4
-rw-r--r--modules/enet/networked_multiplayer_enet.h4
-rw-r--r--modules/enet/register_types.cpp6
-rw-r--r--modules/enet/register_types.h4
-rw-r--r--modules/etc/SCsub15
-rw-r--r--modules/etc/image_compress_etc.cpp (renamed from modules/etc/image_etc.cpp)30
-rw-r--r--modules/etc/image_compress_etc.h (renamed from modules/etc/image_etc.h)12
-rw-r--r--modules/etc/register_types.cpp6
-rw-r--r--modules/etc/register_types.h4
-rw-r--r--modules/etc/texture_loader_pkm.cpp4
-rw-r--r--modules/etc/texture_loader_pkm.h4
-rw-r--r--modules/fbx/README.md196
-rw-r--r--modules/fbx/SCsub15
-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.cpp (renamed from modules/arkit/arkit_session_delegate.h)40
-rw-r--r--modules/fbx/data/fbx_bone.h90
-rw-r--r--modules/fbx/data/fbx_material.cpp464
-rw-r--r--modules/fbx/data/fbx_material.h285
-rw-r--r--modules/fbx/data/fbx_mesh_data.cpp1447
-rw-r--r--modules/fbx/data/fbx_mesh_data.h184
-rw-r--r--modules/fbx/data/fbx_node.h63
-rw-r--r--modules/fbx/data/fbx_skeleton.cpp123
-rw-r--r--modules/fbx/data/fbx_skeleton.h53
-rw-r--r--modules/fbx/data/import_state.h113
-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/doc_classes/EditorSceneImporterFBX.xml36
-rw-r--r--modules/fbx/editor_scene_importer_fbx.cpp1427
-rw-r--r--modules/fbx/editor_scene_importer_fbx.h135
-rw-r--r--modules/fbx/fbx_parser/ByteSwapper.h282
-rw-r--r--modules/fbx/fbx_parser/CREDITS183
-rw-r--r--modules/fbx/fbx_parser/FBXAnimation.cpp290
-rw-r--r--modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp467
-rw-r--r--modules/fbx/fbx_parser/FBXCommon.h110
-rw-r--r--modules/fbx/fbx_parser/FBXDeformer.cpp279
-rw-r--r--modules/fbx/fbx_parser/FBXDocument.cpp713
-rw-r--r--modules/fbx/fbx_parser/FBXDocument.h1319
-rw-r--r--modules/fbx/fbx_parser/FBXDocumentUtil.cpp172
-rw-r--r--modules/fbx/fbx_parser/FBXDocumentUtil.h141
-rw-r--r--modules/fbx/fbx_parser/FBXImportSettings.h173
-rw-r--r--modules/fbx/fbx_parser/FBXMaterial.cpp407
-rw-r--r--modules/fbx/fbx_parser/FBXMeshGeometry.cpp485
-rw-r--r--modules/fbx/fbx_parser/FBXMeshGeometry.h263
-rw-r--r--modules/fbx/fbx_parser/FBXModel.cpp176
-rw-r--r--modules/fbx/fbx_parser/FBXNodeAttribute.cpp183
-rw-r--r--modules/fbx/fbx_parser/FBXParseTools.h111
-rw-r--r--modules/fbx/fbx_parser/FBXParser.cpp1295
-rw-r--r--modules/fbx/fbx_parser/FBXParser.h263
-rw-r--r--modules/fbx/fbx_parser/FBXPose.cpp104
-rw-r--r--modules/fbx/fbx_parser/FBXProperties.cpp237
-rw-r--r--modules/fbx/fbx_parser/FBXProperties.h221
-rw-r--r--modules/fbx/fbx_parser/FBXTokenizer.cpp251
-rw-r--r--modules/fbx/fbx_parser/FBXTokenizer.h203
-rw-r--r--modules/fbx/fbx_parser/FBXUtil.cpp220
-rw-r--r--modules/fbx/fbx_parser/FBXUtil.h122
-rw-r--r--modules/fbx/fbx_parser/LICENSE39
-rw-r--r--modules/fbx/register_types.cpp (renamed from modules/assimp/register_types.cpp)18
-rw-r--r--modules/fbx/register_types.h (renamed from modules/arkit/register_types.h)14
-rw-r--r--modules/fbx/tools/import_utils.cpp151
-rw-r--r--modules/fbx/tools/import_utils.h400
-rw-r--r--modules/fbx/tools/validation_tools.cpp48
-rw-r--r--modules/fbx/tools/validation_tools.h92
-rw-r--r--modules/freetype/SCsub14
-rw-r--r--modules/freetype/register_types.cpp4
-rw-r--r--modules/freetype/register_types.h4
-rw-r--r--modules/freetype/uwpdef.h4
-rw-r--r--modules/gdnative/SCsub3
-rw-r--r--modules/gdnative/android/android_gdn.cpp6
-rw-r--r--modules/gdnative/config.py2
-rw-r--r--modules/gdnative/gdnative.cpp10
-rw-r--r--modules/gdnative/gdnative.h6
-rw-r--r--modules/gdnative/gdnative/aabb.cpp192
-rw-r--r--modules/gdnative/gdnative/array.cpp349
-rw-r--r--modules/gdnative/gdnative/basis.cpp263
-rw-r--r--modules/gdnative/gdnative/callable.cpp215
-rw-r--r--modules/gdnative/gdnative/color.cpp184
-rw-r--r--modules/gdnative/gdnative/dictionary.cpp153
-rw-r--r--modules/gdnative/gdnative/gdnative.cpp34
-rw-r--r--modules/gdnative/gdnative/node_path.cpp88
-rw-r--r--modules/gdnative/gdnative/packed_arrays.cpp970
-rw-r--r--modules/gdnative/gdnative/plane.cpp136
-rw-r--r--modules/gdnative/gdnative/quat.cpp202
-rw-r--r--modules/gdnative/gdnative/rect2.cpp299
-rw-r--r--modules/gdnative/gdnative/rid.cpp44
-rw-r--r--modules/gdnative/gdnative/signal.cpp53
-rw-r--r--modules/gdnative/gdnative/string.cpp1247
-rw-r--r--modules/gdnative/gdnative/string_name.cpp51
-rw-r--r--modules/gdnative/gdnative/transform.cpp195
-rw-r--r--modules/gdnative/gdnative/transform2d.cpp176
-rw-r--r--modules/gdnative/gdnative/variant.cpp715
-rw-r--r--modules/gdnative/gdnative/vector2.cpp428
-rw-r--r--modules/gdnative/gdnative/vector3.cpp432
-rw-r--r--modules/gdnative/gdnative_api.json12158
-rw-r--r--modules/gdnative/gdnative_builders.py1
-rw-r--r--modules/gdnative/gdnative_library_editor_plugin.cpp28
-rw-r--r--modules/gdnative/gdnative_library_editor_plugin.h4
-rw-r--r--modules/gdnative/gdnative_library_singleton_editor.cpp4
-rw-r--r--modules/gdnative/gdnative_library_singleton_editor.h4
-rw-r--r--modules/gdnative/icons/GDNativeLibrary.svg6
-rw-r--r--modules/gdnative/icons/NativeScript.svg6
-rw-r--r--modules/gdnative/include/android/godot_android.h4
-rw-r--r--modules/gdnative/include/gdnative/aabb.h73
-rw-r--r--modules/gdnative/include/gdnative/array.h97
-rw-r--r--modules/gdnative/include/gdnative/basis.h89
-rw-r--r--modules/gdnative/include/gdnative/callable.h74
-rw-r--r--modules/gdnative/include/gdnative/color.h72
-rw-r--r--modules/gdnative/include/gdnative/dictionary.h57
-rw-r--r--modules/gdnative/include/gdnative/gdnative.h30
-rw-r--r--modules/gdnative/include/gdnative/math_defs.h66
-rw-r--r--modules/gdnative/include/gdnative/node_path.h37
-rw-r--r--modules/gdnative/include/gdnative/packed_arrays.h356
-rw-r--r--modules/gdnative/include/gdnative/plane.h54
-rw-r--r--modules/gdnative/include/gdnative/quat.h71
-rw-r--r--modules/gdnative/include/gdnative/rect2.h111
-rw-r--r--modules/gdnative/include/gdnative/rid.h23
-rw-r--r--modules/gdnative/include/gdnative/signal.h58
-rw-r--r--modules/gdnative/include/gdnative/string.h240
-rw-r--r--modules/gdnative/include/gdnative/string_name.h28
-rw-r--r--modules/gdnative/include/gdnative/transform.h64
-rw-r--r--modules/gdnative/include/gdnative/transform2d.h62
-rw-r--r--modules/gdnative/include/gdnative/variant.h224
-rw-r--r--modules/gdnative/include/gdnative/vector2.h144
-rw-r--r--modules/gdnative/include/gdnative/vector3.h149
-rw-r--r--modules/gdnative/include/nativescript/godot_nativescript.h5
-rw-r--r--modules/gdnative/include/net/godot_net.h4
-rw-r--r--modules/gdnative/include/net/godot_webrtc.h4
-rw-r--r--modules/gdnative/include/pluginscript/godot_pluginscript.h6
-rw-r--r--modules/gdnative/include/text/godot_text.h231
-rw-r--r--modules/gdnative/include/videodecoder/godot_videodecoder.h12
-rw-r--r--modules/gdnative/include/xr/godot_xr.h12
-rw-r--r--modules/gdnative/nativescript/api_generator.cpp438
-rw-r--r--modules/gdnative/nativescript/api_generator.h7
-rw-r--r--modules/gdnative/nativescript/godot_nativescript.cpp14
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp27
-rw-r--r--modules/gdnative/nativescript/nativescript.h22
-rw-r--r--modules/gdnative/nativescript/register_types.cpp4
-rw-r--r--modules/gdnative/nativescript/register_types.h4
-rw-r--r--modules/gdnative/net/multiplayer_peer_gdnative.cpp4
-rw-r--r--modules/gdnative/net/multiplayer_peer_gdnative.h4
-rw-r--r--modules/gdnative/net/packet_peer_gdnative.cpp4
-rw-r--r--modules/gdnative/net/packet_peer_gdnative.h4
-rw-r--r--modules/gdnative/net/register_types.cpp4
-rw-r--r--modules/gdnative/net/register_types.h4
-rw-r--r--modules/gdnative/net/stream_peer_gdnative.cpp4
-rw-r--r--modules/gdnative/net/stream_peer_gdnative.h4
-rw-r--r--modules/gdnative/net/webrtc_gdnative.cpp6
-rw-r--r--modules/gdnative/pluginscript/pluginscript_instance.cpp6
-rw-r--r--modules/gdnative/pluginscript/pluginscript_instance.h6
-rw-r--r--modules/gdnative/pluginscript/pluginscript_language.cpp36
-rw-r--r--modules/gdnative/pluginscript/pluginscript_language.h17
-rw-r--r--modules/gdnative/pluginscript/pluginscript_loader.cpp4
-rw-r--r--modules/gdnative/pluginscript/pluginscript_loader.h6
-rw-r--r--modules/gdnative/pluginscript/pluginscript_script.cpp5
-rw-r--r--modules/gdnative/pluginscript/pluginscript_script.h24
-rw-r--r--modules/gdnative/pluginscript/register_types.cpp6
-rw-r--r--modules/gdnative/pluginscript/register_types.h4
-rw-r--r--modules/gdnative/register_types.cpp8
-rw-r--r--modules/gdnative/register_types.h4
-rw-r--r--modules/gdnative/tests/test_string.h1980
-rw-r--r--modules/gdnative/tests/test_variant.h204
-rw-r--r--modules/gdnative/text/SCsub6
-rw-r--r--modules/gdnative/text/config.py (renamed from modules/gdnative/xr/config.py)0
-rw-r--r--modules/gdnative/text/register_types.cpp (renamed from modules/camera/camera_ios.h)23
-rw-r--r--modules/gdnative/text/register_types.h37
-rw-r--r--modules/gdnative/text/text_server_gdnative.cpp853
-rw-r--r--modules/gdnative/text/text_server_gdnative.h187
-rw-r--r--modules/gdnative/videodecoder/register_types.cpp6
-rw-r--r--modules/gdnative/videodecoder/register_types.h4
-rw-r--r--modules/gdnative/videodecoder/video_stream_gdnative.cpp6
-rw-r--r--modules/gdnative/videodecoder/video_stream_gdnative.h4
-rw-r--r--modules/gdnative/xr/register_types.cpp4
-rw-r--r--modules/gdnative/xr/register_types.h4
-rw-r--r--modules/gdnative/xr/xr_interface_gdnative.cpp22
-rw-r--r--modules/gdnative/xr/xr_interface_gdnative.h4
-rw-r--r--modules/gdnavigation/SCsub31
-rw-r--r--modules/gdnavigation/gd_navigation_server.cpp4
-rw-r--r--modules/gdnavigation/gd_navigation_server.h8
-rw-r--r--modules/gdnavigation/nav_map.cpp6
-rw-r--r--modules/gdnavigation/nav_map.h4
-rw-r--r--modules/gdnavigation/nav_region.cpp4
-rw-r--r--modules/gdnavigation/nav_region.h4
-rw-r--r--modules/gdnavigation/nav_rid.h6
-rw-r--r--modules/gdnavigation/nav_utils.h4
-rw-r--r--modules/gdnavigation/navigation_mesh_editor_plugin.cpp6
-rw-r--r--modules/gdnavigation/navigation_mesh_editor_plugin.h4
-rw-r--r--modules/gdnavigation/navigation_mesh_generator.cpp14
-rw-r--r--modules/gdnavigation/navigation_mesh_generator.h4
-rw-r--r--modules/gdnavigation/register_types.cpp6
-rw-r--r--modules/gdnavigation/register_types.h4
-rw-r--r--modules/gdnavigation/rvo_agent.cpp4
-rw-r--r--modules/gdnavigation/rvo_agent.h7
-rw-r--r--modules/gdscript/config.py1
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml1142
-rw-r--r--modules/gdscript/doc_classes/GDScriptFunctionState.xml45
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp18
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.h6
-rw-r--r--modules/gdscript/editor/gdscript_translation_parser_plugin.cpp4
-rw-r--r--modules/gdscript/editor/gdscript_translation_parser_plugin.h6
-rw-r--r--modules/gdscript/gdscript.cpp295
-rw-r--r--modules/gdscript/gdscript.h43
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp406
-rw-r--r--modules/gdscript/gdscript_analyzer.h16
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp815
-rw-r--r--modules/gdscript/gdscript_byte_codegen.h239
-rw-r--r--modules/gdscript/gdscript_cache.cpp6
-rw-r--r--modules/gdscript/gdscript_cache.h10
-rw-r--r--modules/gdscript/gdscript_codegen.h27
-rw-r--r--modules/gdscript/gdscript_compiler.cpp280
-rw-r--r--modules/gdscript/gdscript_compiler.h20
-rw-r--r--modules/gdscript/gdscript_disassembler.cpp842
-rw-r--r--modules/gdscript/gdscript_editor.cpp144
-rw-r--r--modules/gdscript/gdscript_function.cpp2087
-rw-r--r--modules/gdscript/gdscript_function.h216
-rw-r--r--modules/gdscript/gdscript_functions.cpp1964
-rw-r--r--modules/gdscript/gdscript_parser.cpp401
-rw-r--r--modules/gdscript/gdscript_parser.h71
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp32
-rw-r--r--modules/gdscript/gdscript_tokenizer.h34
-rw-r--r--modules/gdscript/gdscript_utility_functions.cpp718
-rw-r--r--modules/gdscript/gdscript_utility_functions.h58
-rw-r--r--modules/gdscript/gdscript_vm.cpp2918
-rw-r--r--modules/gdscript/gdscript_warning.cpp6
-rw-r--r--modules/gdscript/gdscript_warning.h8
-rw-r--r--modules/gdscript/icons/GDScript.svg6
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.cpp22
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.h6
-rw-r--r--modules/gdscript/language_server/gdscript_language_protocol.cpp15
-rw-r--r--modules/gdscript/language_server/gdscript_language_protocol.h4
-rw-r--r--modules/gdscript/language_server/gdscript_language_server.cpp14
-rw-r--r--modules/gdscript/language_server/gdscript_language_server.h6
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp12
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.h6
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.cpp33
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.h6
-rw-r--r--modules/gdscript/language_server/lsp.hpp15
-rw-r--r--modules/gdscript/register_types.cpp11
-rw-r--r--modules/gdscript/register_types.h4
-rw-r--r--modules/gdscript/tests/test_gdscript.cpp85
-rw-r--r--modules/gdscript/tests/test_gdscript.h5
-rw-r--r--modules/glslang/SCsub24
-rw-r--r--modules/glslang/register_types.cpp117
-rw-r--r--modules/glslang/register_types.h4
-rw-r--r--modules/gltf/SCsub10
-rw-r--r--modules/gltf/config.py (renamed from modules/arkit/config.py)2
-rw-r--r--modules/gltf/editor_scene_exporter_gltf_plugin.cpp90
-rw-r--r--modules/gltf/editor_scene_exporter_gltf_plugin.h52
-rw-r--r--modules/gltf/editor_scene_importer_gltf.cpp180
-rw-r--r--modules/gltf/editor_scene_importer_gltf.h96
-rw-r--r--modules/gltf/gltf_accessor.cpp189
-rw-r--r--modules/gltf/gltf_accessor.h104
-rw-r--r--modules/gltf/gltf_animation.cpp53
-rw-r--r--modules/gltf/gltf_animation.h74
-rw-r--r--modules/gltf/gltf_buffer_view.cpp90
-rw-r--r--modules/gltf/gltf_buffer_view.h68
-rw-r--r--modules/gltf/gltf_camera.cpp47
-rw-r--r--modules/gltf/gltf_camera.h (renamed from modules/arkit/arkit_session_delegate.mm)50
-rw-r--r--modules/gltf/gltf_document.cpp6554
-rw-r--r--modules/gltf/gltf_document.h433
-rw-r--r--modules/gltf/gltf_light.cpp101
-rw-r--r--modules/gltf/gltf_light.h72
-rw-r--r--modules/gltf/gltf_mesh.cpp58
-rw-r--r--modules/gltf/gltf_mesh.h55
-rw-r--r--modules/gltf/gltf_node.cpp189
-rw-r--r--modules/gltf/gltf_node.h105
-rw-r--r--modules/gltf/gltf_skeleton.cpp95
-rw-r--r--modules/gltf/gltf_skeleton.h101
-rw-r--r--modules/gltf/gltf_skin.cpp155
-rw-r--r--modules/gltf/gltf_skin.h109
-rw-r--r--modules/gltf/gltf_spec_gloss.cpp90
-rw-r--r--modules/gltf/gltf_spec_gloss.h67
-rw-r--r--modules/gltf/gltf_state.cpp296
-rw-r--r--modules/gltf/gltf_state.h180
-rw-r--r--modules/gltf/gltf_texture.cpp46
-rw-r--r--modules/gltf/gltf_texture.h51
-rw-r--r--modules/gltf/register_types.cpp88
-rw-r--r--modules/gltf/register_types.h32
-rw-r--r--modules/gridmap/grid_map.cpp8
-rw-r--r--modules/gridmap/grid_map.h4
-rw-r--r--modules/gridmap/grid_map_editor_plugin.cpp12
-rw-r--r--modules/gridmap/grid_map_editor_plugin.h10
-rw-r--r--modules/gridmap/icons/GridMap.svg6
-rw-r--r--modules/gridmap/register_types.cpp6
-rw-r--r--modules/gridmap/register_types.h4
-rw-r--r--modules/hdr/image_loader_hdr.cpp6
-rw-r--r--modules/hdr/image_loader_hdr.h4
-rw-r--r--modules/hdr/register_types.cpp4
-rw-r--r--modules/hdr/register_types.h4
-rw-r--r--modules/jpg/SCsub17
-rw-r--r--modules/jpg/image_loader_jpegd.cpp6
-rw-r--r--modules/jpg/image_loader_jpegd.h4
-rw-r--r--modules/jpg/register_types.cpp4
-rw-r--r--modules/jpg/register_types.h4
-rw-r--r--modules/jsonrpc/jsonrpc.cpp6
-rw-r--r--modules/jsonrpc/jsonrpc.h8
-rw-r--r--modules/jsonrpc/register_types.cpp6
-rw-r--r--modules/jsonrpc/register_types.h4
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.cpp89
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.h6
-rw-r--r--modules/lightmapper_rd/lm_compute.glsl11
-rw-r--r--modules/lightmapper_rd/register_types.cpp6
-rw-r--r--modules/lightmapper_rd/register_types.h4
-rw-r--r--[-rwxr-xr-x]modules/mbedtls/SCsub25
-rw-r--r--[-rwxr-xr-x]modules/mbedtls/config.py0
-rw-r--r--modules/mbedtls/crypto_mbedtls.cpp79
-rw-r--r--modules/mbedtls/crypto_mbedtls.h28
-rw-r--r--modules/mbedtls/dtls_server_mbedtls.cpp4
-rw-r--r--modules/mbedtls/dtls_server_mbedtls.h4
-rw-r--r--modules/mbedtls/packet_peer_mbed_dtls.cpp4
-rw-r--r--[-rwxr-xr-x]modules/mbedtls/packet_peer_mbed_dtls.h4
-rw-r--r--modules/mbedtls/register_types.cpp8
-rw-r--r--[-rwxr-xr-x]modules/mbedtls/register_types.h4
-rw-r--r--modules/mbedtls/ssl_context_mbedtls.cpp4
-rw-r--r--modules/mbedtls/ssl_context_mbedtls.h6
-rw-r--r--modules/mbedtls/stream_peer_mbedtls.cpp4
-rw-r--r--[-rwxr-xr-x]modules/mbedtls/stream_peer_mbedtls.h4
-rw-r--r--modules/mbedtls/tests/test_crypto_mbedtls.cpp62
-rw-r--r--modules/mbedtls/tests/test_crypto_mbedtls.h61
-rw-r--r--modules/meshoptimizer/SCsub45
-rw-r--r--modules/meshoptimizer/config.py7
-rw-r--r--modules/meshoptimizer/register_types.cpp47
-rw-r--r--modules/meshoptimizer/register_types.h37
-rw-r--r--modules/minimp3/SCsub17
-rw-r--r--modules/minimp3/audio_stream_mp3.cpp231
-rw-r--r--modules/minimp3/audio_stream_mp3.h110
-rw-r--r--modules/minimp3/config.py16
-rw-r--r--modules/minimp3/doc_classes/AudioStreamMP3.xml26
-rw-r--r--modules/minimp3/register_types.cpp52
-rw-r--r--modules/minimp3/register_types.h37
-rw-r--r--modules/minimp3/resource_importer_mp3.cpp104
-rw-r--r--modules/minimp3/resource_importer_mp3.h58
-rw-r--r--modules/mobile_vr/mobile_vr_interface.cpp4
-rw-r--r--modules/mobile_vr/mobile_vr_interface.h4
-rw-r--r--modules/mobile_vr/register_types.cpp4
-rw-r--r--modules/mobile_vr/register_types.h4
-rw-r--r--modules/mono/SCsub5
-rw-r--r--modules/mono/build_scripts/godot_net_sdk_build.py45
-rw-r--r--modules/mono/build_scripts/make_android_mono_config.py5
-rw-r--r--modules/mono/build_scripts/mono_configure.py10
-rw-r--r--modules/mono/class_db_api_json.cpp18
-rw-r--r--modules/mono/class_db_api_json.h12
-rw-r--r--modules/mono/config.py9
-rw-r--r--modules/mono/csharp_script.cpp252
-rw-r--r--modules/mono/csharp_script.h20
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj19
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk_PackageVersion.txt1
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs65
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj1
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs5
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets36
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj6
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.sln6
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/BottomPanel.cs339
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs (renamed from modules/mono/editor/GodotTools/GodotTools/BuildInfo.cs)10
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs (renamed from modules/mono/editor/GodotTools/GodotTools/BuildManager.cs)132
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs417
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildResult.cs8
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs42
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs185
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs8
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs296
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/BuildTab.cs267
-rw-r--r--[-rwxr-xr-x]modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs0
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs54
-rw-r--r--[-rwxr-xr-x]modules/mono/editor/GodotTools/GodotTools/Export/XcodeHelper.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs73
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs2
-rw-r--r--modules/mono/editor/bindings_generator.cpp123
-rw-r--r--modules/mono/editor/bindings_generator.h19
-rw-r--r--modules/mono/editor/code_completion.cpp21
-rw-r--r--modules/mono/editor/code_completion.h10
-rw-r--r--modules/mono/editor/editor_internal_calls.cpp145
-rw-r--r--modules/mono/editor/editor_internal_calls.h4
-rw-r--r--modules/mono/editor/godotsharp_export.cpp15
-rw-r--r--modules/mono/editor/godotsharp_export.h11
-rw-r--r--modules/mono/editor/script_class_parser.cpp10
-rw-r--r--modules/mono/editor/script_class_parser.h20
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs13
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs176
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs19
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs13
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs10
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs65
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs65
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs251
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs3
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs7
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs11
-rw-r--r--modules/mono/glue/arguments_vector.h4
-rw-r--r--modules/mono/glue/base_object_glue.cpp39
-rw-r--r--modules/mono/glue/collections_glue.cpp115
-rw-r--r--modules/mono/glue/gd_glue.cpp70
-rw-r--r--modules/mono/glue/glue_header.h21
-rw-r--r--modules/mono/glue/nodepath_glue.cpp30
-rw-r--r--modules/mono/glue/rid_glue.cpp16
-rw-r--r--modules/mono/glue/scene_tree_glue.cpp14
-rw-r--r--modules/mono/glue/string_glue.cpp22
-rw-r--r--modules/mono/glue/string_name_glue.cpp16
-rw-r--r--modules/mono/godotsharp_defs.h4
-rw-r--r--modules/mono/godotsharp_dirs.cpp9
-rw-r--r--modules/mono/godotsharp_dirs.h7
-rw-r--r--modules/mono/icons/CSharpScript.svg6
-rw-r--r--modules/mono/managed_callable.cpp4
-rw-r--r--modules/mono/managed_callable.h8
-rw-r--r--modules/mono/mono_gc_handle.cpp4
-rw-r--r--modules/mono/mono_gc_handle.h7
-rw-r--r--modules/mono/mono_gd/android_mono_config.h6
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp37
-rw-r--r--modules/mono/mono_gd/gd_mono.h5
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.cpp24
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.h10
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.cpp5
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.h5
-rw-r--r--modules/mono/mono_gd/gd_mono_class.cpp22
-rw-r--r--modules/mono/mono_gd/gd_mono_class.h19
-rw-r--r--modules/mono/mono_gd/gd_mono_field.cpp329
-rw-r--r--modules/mono/mono_gd/gd_mono_field.h4
-rw-r--r--modules/mono/mono_gd/gd_mono_header.h6
-rw-r--r--modules/mono/mono_gd/gd_mono_internals.cpp7
-rw-r--r--modules/mono/mono_gd/gd_mono_internals.h7
-rw-r--r--modules/mono/mono_gd/gd_mono_log.cpp10
-rw-r--r--modules/mono/mono_gd/gd_mono_log.h4
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp982
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.h51
-rw-r--r--modules/mono/mono_gd/gd_mono_method.cpp29
-rw-r--r--modules/mono/mono_gd/gd_mono_method.h15
-rw-r--r--modules/mono/mono_gd/gd_mono_method_thunk.h4
-rw-r--r--modules/mono/mono_gd/gd_mono_property.cpp11
-rw-r--r--modules/mono/mono_gd/gd_mono_property.h4
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp16
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h28
-rw-r--r--modules/mono/mono_gd/gd_mono_wasm_m2n.cpp79
-rw-r--r--modules/mono/mono_gd/gd_mono_wasm_m2n.h263
-rw-r--r--modules/mono/mono_gd/i_mono_class_member.h4
-rw-r--r--modules/mono/mono_gd/managed_type.cpp4
-rw-r--r--modules/mono/mono_gd/managed_type.h4
-rw-r--r--modules/mono/mono_gd/support/android_support.cpp31
-rw-r--r--[-rwxr-xr-x]modules/mono/mono_gd/support/android_support.h7
-rw-r--r--[-rwxr-xr-x]modules/mono/mono_gd/support/ios_support.h7
-rw-r--r--modules/mono/mono_gd/support/ios_support.mm5
-rw-r--r--modules/mono/register_types.cpp6
-rw-r--r--modules/mono/register_types.h4
-rw-r--r--modules/mono/signal_awaiter_utils.cpp28
-rw-r--r--modules/mono/signal_awaiter_utils.h6
-rw-r--r--modules/mono/utils/macros.h5
-rw-r--r--modules/mono/utils/mono_reg_utils.cpp9
-rw-r--r--modules/mono/utils/mono_reg_utils.h6
-rw-r--r--modules/mono/utils/osx_utils.cpp6
-rw-r--r--modules/mono/utils/osx_utils.h6
-rw-r--r--modules/mono/utils/path_utils.cpp11
-rw-r--r--modules/mono/utils/path_utils.h9
-rw-r--r--modules/mono/utils/string_utils.cpp5
-rw-r--r--modules/mono/utils/string_utils.h8
-rw-r--r--modules/ogg/SCsub16
-rw-r--r--modules/ogg/register_types.cpp4
-rw-r--r--modules/ogg/register_types.h4
-rw-r--r--modules/opensimplex/SCsub17
-rw-r--r--modules/opensimplex/doc_classes/NoiseTexture.xml4
-rw-r--r--modules/opensimplex/doc_classes/OpenSimplexNoise.xml20
-rw-r--r--modules/opensimplex/icons/NoiseTexture.svg4
-rw-r--r--modules/opensimplex/noise_texture.cpp46
-rw-r--r--modules/opensimplex/noise_texture.h16
-rw-r--r--modules/opensimplex/open_simplex_noise.cpp44
-rw-r--r--modules/opensimplex/open_simplex_noise.h42
-rw-r--r--modules/opensimplex/register_types.cpp4
-rw-r--r--modules/opensimplex/register_types.h4
-rw-r--r--modules/opus/SCsub19
-rw-r--r--modules/opus/register_types.cpp4
-rw-r--r--modules/opus/register_types.h4
-rw-r--r--modules/pvr/SCsub15
-rw-r--r--modules/pvr/image_compress_pvrtc.cpp84
-rw-r--r--modules/pvr/image_compress_pvrtc.h36
-rw-r--r--modules/pvr/register_types.cpp7
-rw-r--r--modules/pvr/register_types.h4
-rw-r--r--modules/pvr/texture_loader_pvr.cpp66
-rw-r--r--modules/pvr/texture_loader_pvr.h4
-rw-r--r--modules/regex/SCsub18
-rw-r--r--modules/regex/doc_classes/RegEx.xml4
-rw-r--r--modules/regex/regex.cpp4
-rw-r--r--modules/regex/regex.h17
-rw-r--r--modules/regex/register_types.cpp6
-rw-r--r--modules/regex/register_types.h4
-rw-r--r--modules/regex/tests/test_regex.h164
-rw-r--r--modules/register_module_types.h4
-rw-r--r--modules/squish/SCsub16
-rw-r--r--modules/squish/image_compress_squish.cpp4
-rw-r--r--modules/squish/image_compress_squish.h6
-rw-r--r--modules/squish/register_types.cpp4
-rw-r--r--modules/squish/register_types.h4
-rw-r--r--modules/stb_vorbis/SCsub17
-rw-r--r--modules/stb_vorbis/audio_stream_ogg_vorbis.cpp9
-rw-r--r--modules/stb_vorbis/audio_stream_ogg_vorbis.h4
-rw-r--r--modules/stb_vorbis/register_types.cpp6
-rw-r--r--modules/stb_vorbis/register_types.h4
-rw-r--r--modules/stb_vorbis/resource_importer_ogg_vorbis.cpp4
-rw-r--r--modules/stb_vorbis/resource_importer_ogg_vorbis.h4
-rw-r--r--modules/svg/SCsub17
-rw-r--r--modules/svg/image_loader_svg.cpp4
-rw-r--r--modules/svg/image_loader_svg.h6
-rw-r--r--modules/svg/register_types.cpp4
-rw-r--r--modules/svg/register_types.h4
-rw-r--r--modules/text_server_adv/SCsub501
-rw-r--r--modules/text_server_adv/bitmap_font_adv.cpp580
-rw-r--r--modules/text_server_adv/bitmap_font_adv.h118
-rw-r--r--modules/text_server_adv/config.py6
-rw-r--r--modules/text_server_adv/dynamic_font_adv.cpp1003
-rw-r--r--modules/text_server_adv/dynamic_font_adv.h191
-rw-r--r--modules/text_server_adv/font_adv.h94
-rw-r--r--modules/text_server_adv/icu_data/icudata_stub.cpp63
-rw-r--r--modules/text_server_adv/register_types.cpp (renamed from modules/arkit/register_types.cpp)18
-rw-r--r--modules/text_server_adv/register_types.h40
-rw-r--r--modules/text_server_adv/script_iterator.cpp110
-rw-r--r--modules/text_server_adv/script_iterator.h61
-rw-r--r--modules/text_server_adv/text_server_adv.cpp2579
-rw-r--r--modules/text_server_adv/text_server_adv.h248
-rw-r--r--modules/text_server_fb/SCsub13
-rw-r--r--modules/text_server_fb/bitmap_font_fb.cpp356
-rw-r--r--modules/text_server_fb/bitmap_font_fb.h107
-rw-r--r--modules/text_server_fb/config.py11
-rw-r--r--modules/text_server_fb/dynamic_font_fb.cpp685
-rw-r--r--modules/text_server_fb/dynamic_font_fb.h169
-rw-r--r--modules/text_server_fb/font_fb.h (renamed from modules/gdscript/gdscript_functions.h)159
-rw-r--r--modules/text_server_fb/register_types.cpp43
-rw-r--r--modules/text_server_fb/register_types.h40
-rw-r--r--modules/text_server_fb/text_server_fb.cpp1383
-rw-r--r--modules/text_server_fb/text_server_fb.h193
-rw-r--r--modules/tga/image_loader_tga.cpp12
-rw-r--r--modules/tga/image_loader_tga.h4
-rw-r--r--modules/tga/register_types.cpp4
-rw-r--r--modules/tga/register_types.h4
-rw-r--r--modules/theora/SCsub16
-rw-r--r--modules/theora/register_types.cpp4
-rw-r--r--modules/theora/register_types.h4
-rw-r--r--modules/theora/video_stream_theora.cpp13
-rw-r--r--modules/theora/video_stream_theora.h8
-rw-r--r--modules/tinyexr/SCsub17
-rw-r--r--modules/tinyexr/image_loader_tinyexr.cpp6
-rw-r--r--modules/tinyexr/image_loader_tinyexr.h4
-rw-r--r--modules/tinyexr/image_saver_tinyexr.cpp4
-rw-r--r--modules/tinyexr/image_saver_tinyexr.h4
-rw-r--r--modules/tinyexr/register_types.cpp4
-rw-r--r--modules/tinyexr/register_types.h4
-rw-r--r--modules/upnp/SCsub15
-rw-r--r--modules/upnp/register_types.cpp6
-rw-r--r--modules/upnp/register_types.h4
-rw-r--r--modules/upnp/upnp.cpp8
-rw-r--r--modules/upnp/upnp.h7
-rw-r--r--modules/upnp/upnp_device.cpp6
-rw-r--r--modules/upnp/upnp_device.h7
-rw-r--r--modules/vhacd/SCsub17
-rw-r--r--modules/vhacd/register_types.cpp4
-rw-r--r--modules/vhacd/register_types.h4
-rw-r--r--modules/visual_script/doc_classes/VisualScript.xml134
-rw-r--r--modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml56
-rw-r--r--modules/visual_script/doc_classes/VisualScriptLists.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptPropertyGet.xml2
-rw-r--r--modules/visual_script/icons/VisualScript.svg7
-rw-r--r--modules/visual_script/register_types.cpp6
-rw-r--r--modules/visual_script/register_types.h4
-rw-r--r--modules/visual_script/visual_script.cpp1094
-rw-r--r--modules/visual_script/visual_script.h132
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.cpp137
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.h13
-rw-r--r--modules/visual_script/visual_script_editor.cpp1866
-rw-r--r--modules/visual_script/visual_script_editor.h21
-rw-r--r--modules/visual_script/visual_script_expression.cpp10
-rw-r--r--modules/visual_script/visual_script_expression.h4
-rw-r--r--modules/visual_script/visual_script_flow_control.cpp6
-rw-r--r--modules/visual_script/visual_script_flow_control.h4
-rw-r--r--modules/visual_script/visual_script_func_nodes.cpp75
-rw-r--r--modules/visual_script/visual_script_func_nodes.h4
-rw-r--r--modules/visual_script/visual_script_nodes.cpp27
-rw-r--r--modules/visual_script/visual_script_nodes.h4
-rw-r--r--modules/visual_script/visual_script_property_selector.cpp17
-rw-r--r--modules/visual_script/visual_script_property_selector.h4
-rw-r--r--modules/visual_script/visual_script_yield_nodes.cpp4
-rw-r--r--modules/visual_script/visual_script_yield_nodes.h4
-rw-r--r--modules/vorbis/SCsub20
-rw-r--r--modules/vorbis/register_types.cpp4
-rw-r--r--modules/vorbis/register_types.h4
-rw-r--r--modules/webm/SCsub15
-rw-r--r--modules/webm/doc_classes/VideoStreamWebm.xml1
-rw-r--r--modules/webm/libvpx/SCsub2
-rw-r--r--modules/webm/register_types.cpp4
-rw-r--r--modules/webm/register_types.h4
-rw-r--r--modules/webm/video_stream_webm.cpp6
-rw-r--r--modules/webm/video_stream_webm.h4
-rw-r--r--modules/webp/SCsub16
-rw-r--r--modules/webp/image_loader_webp.cpp8
-rw-r--r--modules/webp/image_loader_webp.h4
-rw-r--r--modules/webp/register_types.cpp4
-rw-r--r--modules/webp/register_types.h4
-rw-r--r--modules/webrtc/SCsub6
-rw-r--r--modules/webrtc/library_godot_webrtc.js433
-rw-r--r--modules/webrtc/register_types.cpp6
-rw-r--r--modules/webrtc/register_types.h4
-rw-r--r--modules/webrtc/webrtc_data_channel.cpp6
-rw-r--r--modules/webrtc/webrtc_data_channel.h4
-rw-r--r--modules/webrtc/webrtc_data_channel_gdnative.cpp4
-rw-r--r--modules/webrtc/webrtc_data_channel_gdnative.h4
-rw-r--r--modules/webrtc/webrtc_data_channel_js.cpp249
-rw-r--r--modules/webrtc/webrtc_data_channel_js.h14
-rw-r--r--modules/webrtc/webrtc_multiplayer.cpp4
-rw-r--r--modules/webrtc/webrtc_multiplayer.h4
-rw-r--r--modules/webrtc/webrtc_peer_connection.cpp4
-rw-r--r--modules/webrtc/webrtc_peer_connection.h4
-rw-r--r--modules/webrtc/webrtc_peer_connection_gdnative.cpp4
-rw-r--r--modules/webrtc/webrtc_peer_connection_gdnative.h4
-rw-r--r--modules/webrtc/webrtc_peer_connection_js.cpp248
-rw-r--r--modules/webrtc/webrtc_peer_connection_js.h27
-rw-r--r--modules/websocket/SCsub40
-rw-r--r--modules/websocket/editor_debugger_server_websocket.cpp6
-rw-r--r--modules/websocket/editor_debugger_server_websocket.h4
-rw-r--r--modules/websocket/emws_client.cpp150
-rw-r--r--modules/websocket/emws_client.h16
-rw-r--r--modules/websocket/emws_peer.cpp42
-rw-r--r--modules/websocket/emws_peer.h22
-rw-r--r--modules/websocket/emws_server.cpp4
-rw-r--r--modules/websocket/emws_server.h6
-rw-r--r--modules/websocket/library_godot_websocket.js188
-rw-r--r--modules/websocket/packet_buffer.h6
-rw-r--r--modules/websocket/register_types.cpp8
-rw-r--r--modules/websocket/register_types.h4
-rw-r--r--modules/websocket/remote_debugger_peer_websocket.cpp6
-rw-r--r--modules/websocket/remote_debugger_peer_websocket.h4
-rw-r--r--modules/websocket/websocket_client.cpp4
-rw-r--r--modules/websocket/websocket_client.h6
-rw-r--r--modules/websocket/websocket_macros.h4
-rw-r--r--modules/websocket/websocket_multiplayer_peer.cpp4
-rw-r--r--modules/websocket/websocket_multiplayer_peer.h8
-rw-r--r--modules/websocket/websocket_peer.cpp4
-rw-r--r--modules/websocket/websocket_peer.h6
-rw-r--r--modules/websocket/websocket_server.cpp4
-rw-r--r--modules/websocket/websocket_server.h6
-rw-r--r--modules/websocket/wsl_client.cpp6
-rw-r--r--modules/websocket/wsl_client.h6
-rw-r--r--modules/websocket/wsl_peer.cpp4
-rw-r--r--modules/websocket/wsl_peer.h8
-rw-r--r--modules/websocket/wsl_server.cpp6
-rw-r--r--modules/websocket/wsl_server.h4
-rw-r--r--modules/webxr/SCsub11
-rw-r--r--modules/webxr/config.py14
-rw-r--r--modules/webxr/doc_classes/WebXRInterface.xml257
-rw-r--r--modules/webxr/godot_webxr.h85
-rw-r--r--modules/webxr/native/library_godot_webxr.js672
-rw-r--r--modules/webxr/native/webxr.externs.js499
-rw-r--r--modules/webxr/register_types.cpp47
-rw-r--r--modules/webxr/register_types.h (renamed from modules/assimp/register_types.h)14
-rw-r--r--modules/webxr/webxr_interface.cpp71
-rw-r--r--modules/webxr/webxr_interface.h65
-rw-r--r--modules/webxr/webxr_interface_js.cpp460
-rw-r--r--modules/webxr/webxr_interface_js.h (renamed from modules/arkit/arkit_interface.h)119
-rw-r--r--modules/xatlas_unwrap/SCsub16
-rw-r--r--modules/xatlas_unwrap/register_types.cpp12
-rw-r--r--modules/xatlas_unwrap/register_types.h4
768 files changed, 59126 insertions, 33748 deletions
diff --git a/modules/SCsub b/modules/SCsub
index edfc4ed9c6..64da3bd0be 100644
--- a/modules/SCsub
+++ b/modules/SCsub
@@ -45,11 +45,6 @@ for name, path in env.module_list.items():
else:
SConscript(path + "/SCsub") # Custom.
- # Some modules are not linked automatically but can be enabled optionally
- # on iOS, so we handle those specially.
- if env["platform"] == "iphone" and name in ["arkit", "camera"]:
- continue
-
lib = env_modules.add_library("module_%s" % name, env.modules_sources)
env.Prepend(LIBS=[lib])
if env["vsproj"]:
diff --git a/modules/arkit/SCsub b/modules/arkit/SCsub
deleted file mode 100644
index 7e103d6565..0000000000
--- a/modules/arkit/SCsub
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/env python
-
-Import("env")
-Import("env_modules")
-
-env_arkit = env_modules.Clone()
-
-# (iOS) Enable module support
-env_arkit.Append(CCFLAGS=["-fmodules", "-fcxx-modules"])
-
-# (iOS) Build as separate static library
-modules_sources = []
-env_arkit.add_source_files(modules_sources, "*.cpp")
-env_arkit.add_source_files(modules_sources, "*.mm")
-mod_lib = env_modules.add_library("#bin/libgodot_arkit_module" + env["LIBSUFFIX"], modules_sources)
diff --git a/modules/arkit/arkit_interface.mm b/modules/arkit/arkit_interface.mm
deleted file mode 100644
index e8fa023ac7..0000000000
--- a/modules/arkit/arkit_interface.mm
+++ /dev/null
@@ -1,791 +0,0 @@
-/*************************************************************************/
-/* arkit_interface.mm */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "core/input/input.h"
-#include "core/os/os.h"
-#include "scene/resources/surface_tool.h"
-#include "servers/rendering/rendering_server_globals.h"
-
-#import <ARKit/ARKit.h>
-#import <UIKit/UIKit.h>
-
-#include <dlfcn.h>
-
-#include "arkit_interface.h"
-#include "arkit_session_delegate.h"
-
-// just a dirty workaround for now, declare these as globals. I'll probably encapsulate ARSession and associated logic into an mm object and change ARKitInterface to a normal cpp object that consumes it.
-API_AVAILABLE(ios(11.0))
-ARSession *ar_session;
-
-ARKitSessionDelegate *ar_delegate;
-NSTimeInterval last_timestamp;
-
-/* this is called when we initialize or when we come back from having our app pushed to the background, just (re)start our session */
-void ARKitInterface::start_session() {
- // We're active...
- session_was_started = true;
-
- // Ignore this if we're not initialized...
- if (initialized) {
- print_line("Starting ARKit session");
-
- if (@available(iOS 11, *)) {
- Class ARWorldTrackingConfigurationClass = NSClassFromString(@"ARWorldTrackingConfiguration");
- ARWorldTrackingConfiguration *configuration = [ARWorldTrackingConfigurationClass new];
-
- configuration.lightEstimationEnabled = light_estimation_is_enabled;
- if (plane_detection_is_enabled) {
- if (@available(iOS 11.3, *)) {
- configuration.planeDetection = ARPlaneDetectionVertical | ARPlaneDetectionHorizontal;
- } else {
- configuration.planeDetection = ARPlaneDetectionHorizontal;
- }
- } else {
- configuration.planeDetection = 0;
- }
-
- // make sure our camera is on
- if (feed.is_valid()) {
- feed->set_active(true);
- }
-
- [ar_session runWithConfiguration:configuration];
- }
- }
-}
-
-void ARKitInterface::stop_session() {
- session_was_started = false;
-
- // Ignore this if we're not initialized...
- if (initialized) {
- // make sure our camera is off
- if (feed.is_valid()) {
- feed->set_active(false);
- }
-
- if (@available(iOS 11.0, *)) {
- [ar_session pause];
- }
- }
-}
-
-void ARKitInterface::notification(int p_what) {
- // TODO, this is not being called, need to find out why, possibly because this is not a node.
- // in that case we need to find a way to get these notifications!
- switch (p_what) {
- case DisplayServer::WINDOW_EVENT_FOCUS_IN: {
- print_line("Focus in");
-
- start_session();
- }; break;
- case DisplayServer::WINDOW_EVENT_FOCUS_OUT: {
- print_line("Focus out");
-
- stop_session();
- }; break;
- default:
- break;
- }
-}
-
-bool ARKitInterface::get_anchor_detection_is_enabled() const {
- return plane_detection_is_enabled;
-}
-
-void ARKitInterface::set_anchor_detection_is_enabled(bool p_enable) {
- if (plane_detection_is_enabled != p_enable) {
- plane_detection_is_enabled = p_enable;
-
- // Restart our session (this will be ignore if we're not initialised)
- if (session_was_started) {
- start_session();
- }
- }
-}
-
-int ARKitInterface::get_camera_feed_id() {
- if (feed.is_null()) {
- return 0;
- } else {
- return feed->get_id();
- }
-}
-
-bool ARKitInterface::get_light_estimation_is_enabled() const {
- return light_estimation_is_enabled;
-}
-
-void ARKitInterface::set_light_estimation_is_enabled(bool p_enable) {
- if (light_estimation_is_enabled != p_enable) {
- light_estimation_is_enabled = p_enable;
-
- // Restart our session (this will be ignore if we're not initialised)
- if (session_was_started) {
- start_session();
- }
- }
-}
-
-real_t ARKitInterface::get_ambient_intensity() const {
- return ambient_intensity;
-}
-
-real_t ARKitInterface::get_ambient_color_temperature() const {
- return ambient_color_temperature;
-}
-
-StringName ARKitInterface::get_name() const {
- return "ARKit";
-}
-
-int ARKitInterface::get_capabilities() const {
- return ARKitInterface::XR_MONO + ARKitInterface::XR_AR;
-}
-
-Array ARKitInterface::raycast(Vector2 p_screen_coord) {
- if (@available(iOS 11, *)) {
- Array arr;
- Size2 screen_size = DisplayServer::get_singleton()->screen_get_size();
- CGPoint point;
- point.x = p_screen_coord.x / screen_size.x;
- point.y = p_screen_coord.y / screen_size.y;
-
- ///@TODO maybe give more options here, for now we're taking just ARAchors into account that were found during plane detection keeping their size into account
-
- NSArray<ARHitTestResult *> *results = [ar_session.currentFrame hitTest:point types:ARHitTestResultTypeExistingPlaneUsingExtent];
-
- for (ARHitTestResult *result in results) {
- Transform transform;
-
- matrix_float4x4 m44 = result.worldTransform;
- transform.basis.elements[0].x = m44.columns[0][0];
- transform.basis.elements[1].x = m44.columns[0][1];
- transform.basis.elements[2].x = m44.columns[0][2];
- transform.basis.elements[0].y = m44.columns[1][0];
- transform.basis.elements[1].y = m44.columns[1][1];
- transform.basis.elements[2].y = m44.columns[1][2];
- transform.basis.elements[0].z = m44.columns[2][0];
- transform.basis.elements[1].z = m44.columns[2][1];
- transform.basis.elements[2].z = m44.columns[2][2];
- transform.origin.x = m44.columns[3][0];
- transform.origin.y = m44.columns[3][1];
- transform.origin.z = m44.columns[3][2];
-
- /* important, NOT scaled to world_scale !! */
- arr.push_back(transform);
- }
-
- return arr;
- } else {
- return Array();
- }
-}
-
-void ARKitInterface::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_notification", "what"), &ARKitInterface::_notification);
-
- ClassDB::bind_method(D_METHOD("set_light_estimation_is_enabled", "enable"), &ARKitInterface::set_light_estimation_is_enabled);
- ClassDB::bind_method(D_METHOD("get_light_estimation_is_enabled"), &ARKitInterface::get_light_estimation_is_enabled);
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "light_estimation"), "set_light_estimation_is_enabled", "get_light_estimation_is_enabled");
-
- ClassDB::bind_method(D_METHOD("get_ambient_intensity"), &ARKitInterface::get_ambient_intensity);
- ClassDB::bind_method(D_METHOD("get_ambient_color_temperature"), &ARKitInterface::get_ambient_color_temperature);
-
- ClassDB::bind_method(D_METHOD("raycast", "screen_coord"), &ARKitInterface::raycast);
-}
-
-bool ARKitInterface::is_stereo() {
- // this is a mono device...
- return false;
-}
-
-bool ARKitInterface::is_initialized() const {
- return initialized;
-}
-
-bool ARKitInterface::initialize() {
- XRServer *xr_server = XRServer::get_singleton();
- ERR_FAIL_NULL_V(xr_server, false);
-
- if (@available(iOS 11, *)) {
- if (!initialized) {
- print_line("initializing ARKit");
-
- // create our ar session and delegate
- Class ARSessionClass = NSClassFromString(@"ARSession");
- if (ARSessionClass == Nil) {
- void *arkit_handle = dlopen("/System/Library/Frameworks/ARKit.framework/ARKit", RTLD_NOW);
- if (arkit_handle) {
- ARSessionClass = NSClassFromString(@"ARSession");
- } else {
- print_line("ARKit init failed");
- return false;
- }
- }
- ar_session = [ARSessionClass new];
- ar_delegate = [ARKitSessionDelegate new];
- ar_delegate.arkit_interface = this;
- ar_session.delegate = ar_delegate;
-
- // reset our transform
- transform = Transform();
-
- // make this our primary interface
- xr_server->set_primary_interface(this);
-
- // make sure we have our feed setup
- if (feed.is_null()) {
- feed.instance();
- feed->set_name("ARKit");
-
- CameraServer *cs = CameraServer::get_singleton();
- if (cs != NULL) {
- cs->add_feed(feed);
- }
- }
- feed->set_active(true);
-
- // yeah!
- initialized = true;
-
- // Start our session...
- start_session();
- }
-
- return true;
- } else {
- return false;
- }
-}
-
-void ARKitInterface::uninitialize() {
- if (initialized) {
- XRServer *xr_server = XRServer::get_singleton();
- if (xr_server != NULL) {
- // no longer our primary interface
- xr_server->clear_primary_interface_if(this);
- }
-
- if (feed.is_valid()) {
- CameraServer *cs = CameraServer::get_singleton();
- if ((cs != NULL)) {
- cs->remove_feed(feed);
- }
- feed.unref();
- }
-
- remove_all_anchors();
-
- if (@available(iOS 11.0, *)) {
- ar_session = nil;
- }
-
- ar_delegate = nil;
- initialized = false;
- session_was_started = false;
- }
-}
-
-Size2 ARKitInterface::get_render_targetsize() {
- // _THREAD_SAFE_METHOD_
-
- Size2 target_size = DisplayServer::get_singleton()->screen_get_size();
-
- return target_size;
-}
-
-Transform ARKitInterface::get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) {
- // _THREAD_SAFE_METHOD_
-
- Transform transform_for_eye;
-
- XRServer *xr_server = XRServer::get_singleton();
- ERR_FAIL_NULL_V(xr_server, transform_for_eye);
-
- if (initialized) {
- float world_scale = xr_server->get_world_scale();
-
- // just scale our origin point of our transform, note that we really shouldn't be using world_scale in ARKit but....
- transform_for_eye = transform;
- transform_for_eye.origin *= world_scale;
-
- transform_for_eye = p_cam_transform * xr_server->get_reference_frame() * transform_for_eye;
- } else {
- // huh? well just return what we got....
- transform_for_eye = p_cam_transform;
- }
-
- return transform_for_eye;
-}
-
-CameraMatrix ARKitInterface::get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) {
- // Remember our near and far, it will be used in process when we obtain our projection from our ARKit session.
- z_near = p_z_near;
- z_far = p_z_far;
-
- return projection;
-}
-
-void ARKitInterface::commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) {
- // _THREAD_SAFE_METHOD_
-
- // We must have a valid render target
- ERR_FAIL_COND(!p_render_target.is_valid());
-
- // Because we are rendering to our device we must use our main viewport!
- ERR_FAIL_COND(p_screen_rect == Rect2());
-
- // get the size of our screen
- // Rect2 screen_rect = p_screen_rect;
-
- // screen_rect.position.x += screen_rect.size.x;
- // screen_rect.size.x = -screen_rect.size.x;
- // screen_rect.position.y += screen_rect.size.y;
- // screen_rect.size.y = -screen_rect.size.y;
-
- // VSG::rasterizer->set_current_render_target(RID());
- // VSG::rasterizer->blit_render_target_to_screen(p_render_target, screen_rect, 0);
-}
-
-XRPositionalTracker *ARKitInterface::get_anchor_for_uuid(const unsigned char *p_uuid) {
- if (anchors == NULL) {
- num_anchors = 0;
- max_anchors = 10;
- anchors = (anchor_map *)malloc(sizeof(anchor_map) * max_anchors);
- }
-
- ERR_FAIL_NULL_V(anchors, NULL);
-
- for (unsigned int i = 0; i < num_anchors; i++) {
- if (memcmp(anchors[i].uuid, p_uuid, 16) == 0) {
- return anchors[i].tracker;
- }
- }
-
- if (num_anchors + 1 == max_anchors) {
- max_anchors += 10;
- anchors = (anchor_map *)realloc(anchors, sizeof(anchor_map) * max_anchors);
- ERR_FAIL_NULL_V(anchors, NULL);
- }
-
- XRPositionalTracker *new_tracker = memnew(XRPositionalTracker);
- new_tracker->set_type(XRServer::TRACKER_ANCHOR);
-
- char tracker_name[256];
- sprintf(tracker_name, "Anchor %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", p_uuid[0], p_uuid[1], p_uuid[2], p_uuid[3], p_uuid[4], p_uuid[5], p_uuid[6], p_uuid[7], p_uuid[8], p_uuid[9], p_uuid[10], p_uuid[11], p_uuid[12], p_uuid[13], p_uuid[14], p_uuid[15]);
-
- String name = tracker_name;
- print_line("Adding tracker " + name);
- new_tracker->set_name(name);
-
- // add our tracker
- XRServer::get_singleton()->add_tracker(new_tracker);
- anchors[num_anchors].tracker = new_tracker;
- memcpy(anchors[num_anchors].uuid, p_uuid, 16);
- num_anchors++;
-
- return new_tracker;
-}
-
-void ARKitInterface::remove_anchor_for_uuid(const unsigned char *p_uuid) {
- if (anchors != NULL) {
- for (unsigned int i = 0; i < num_anchors; i++) {
- if (memcmp(anchors[i].uuid, p_uuid, 16) == 0) {
- // remove our tracker
- XRServer::get_singleton()->remove_tracker(anchors[i].tracker);
- memdelete(anchors[i].tracker);
-
- // bring remaining forward
- for (unsigned int j = i + 1; j < num_anchors; j++) {
- anchors[j - 1] = anchors[j];
- };
-
- // decrease count
- num_anchors--;
- return;
- }
- }
- }
-}
-
-void ARKitInterface::remove_all_anchors() {
- if (anchors != NULL) {
- for (unsigned int i = 0; i < num_anchors; i++) {
- // remove our tracker
- XRServer::get_singleton()->remove_tracker(anchors[i].tracker);
- memdelete(anchors[i].tracker);
- };
-
- free(anchors);
- anchors = NULL;
- num_anchors = 0;
- }
-}
-
-void ARKitInterface::process() {
- // _THREAD_SAFE_METHOD_
-
- if (@available(iOS 11.0, *)) {
- if (initialized) {
- // get our next ARFrame
- ARFrame *current_frame = ar_session.currentFrame;
- if (last_timestamp != current_frame.timestamp) {
- // only process if we have a new frame
- last_timestamp = current_frame.timestamp;
-
- // get some info about our screen and orientation
- Size2 screen_size = DisplayServer::get_singleton()->screen_get_size();
- UIInterfaceOrientation orientation = UIInterfaceOrientationUnknown;
-
- if (@available(iOS 13, *)) {
- orientation = [UIApplication sharedApplication].delegate.window.windowScene.interfaceOrientation;
-#if !defined(TARGET_OS_SIMULATOR) || !TARGET_OS_SIMULATOR
- } else {
- orientation = [[UIApplication sharedApplication] statusBarOrientation];
-#endif
- }
-
- // Grab our camera image for our backbuffer
- CVPixelBufferRef pixelBuffer = current_frame.capturedImage;
- if ((CVPixelBufferGetPlaneCount(pixelBuffer) == 2) && (feed != NULL)) {
- // Plane 0 is our Y and Plane 1 is our CbCr buffer
-
- // ignored, we check each plane separately
- // image_width = CVPixelBufferGetWidth(pixelBuffer);
- // image_height = CVPixelBufferGetHeight(pixelBuffer);
-
- // printf("Pixel buffer %i - %i\n", image_width, image_height);
-
- CVPixelBufferLockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);
-
- // get our buffers
- unsigned char *dataY = (unsigned char *)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
- unsigned char *dataCbCr = (unsigned char *)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);
-
- if (dataY == NULL) {
- print_line("Couldn't access Y pixel buffer data");
- } else if (dataCbCr == NULL) {
- print_line("Couldn't access CbCr pixel buffer data");
- } else {
- Ref<Image> img[2];
- size_t extraLeft, extraRight, extraTop, extraBottom;
-
- CVPixelBufferGetExtendedPixels(pixelBuffer, &extraLeft, &extraRight, &extraTop, &extraBottom);
-
- {
- // do Y
- size_t new_width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 0);
- size_t new_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 0);
- size_t bytes_per_row = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0);
-
- if ((image_width[0] != new_width) || (image_height[0] != new_height)) {
- printf("- Camera padding l:%lu r:%lu t:%lu b:%lu\n", extraLeft, extraRight, extraTop, extraBottom);
- printf("- Camera Y plane size: %lu, %lu - %lu\n", new_width, new_height, bytes_per_row);
-
- image_width[0] = new_width;
- image_height[0] = new_height;
- img_data[0].resize(new_width * new_height);
- }
-
- uint8_t *w = img_data[0].ptrw();
- if (new_width == bytes_per_row) {
- memcpy(w, dataY, new_width * new_height);
- } else {
- size_t offset_a = 0;
- size_t offset_b = extraLeft + (extraTop * bytes_per_row);
- for (size_t r = 0; r < new_height; r++) {
- memcpy(w + offset_a, dataY + offset_b, new_width);
- offset_a += new_width;
- offset_b += bytes_per_row;
- }
- }
-
- img[0].instance();
- img[0]->create(new_width, new_height, 0, Image::FORMAT_R8, img_data[0]);
- }
-
- {
- // do CbCr
- size_t new_width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 1);
- size_t new_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 1);
- size_t bytes_per_row = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0);
-
- if ((image_width[1] != new_width) || (image_height[1] != new_height)) {
- printf("- Camera CbCr plane size: %lu, %lu - %lu\n", new_width, new_height, bytes_per_row);
-
- image_width[1] = new_width;
- image_height[1] = new_height;
- img_data[1].resize(2 * new_width * new_height);
- }
-
- uint8_t *w = img_data[1].ptrw();
- if ((2 * new_width) == bytes_per_row) {
- memcpy(w, dataCbCr, 2 * new_width * new_height);
- } else {
- size_t offset_a = 0;
- size_t offset_b = extraLeft + (extraTop * bytes_per_row);
- for (size_t r = 0; r < new_height; r++) {
- memcpy(w + offset_a, dataCbCr + offset_b, 2 * new_width);
- offset_a += 2 * new_width;
- offset_b += bytes_per_row;
- }
- }
-
- img[1].instance();
- img[1]->create(new_width, new_height, 0, Image::FORMAT_RG8, img_data[1]);
- }
-
- // set our texture...
- feed->set_YCbCr_imgs(img[0], img[1]);
-
- // now build our transform to display this as a background image that matches our camera
- CGAffineTransform affine_transform = [current_frame displayTransformForOrientation:orientation viewportSize:CGSizeMake(screen_size.width, screen_size.height)];
-
- // we need to invert this, probably row v.s. column notation
- affine_transform = CGAffineTransformInvert(affine_transform);
-
- if (orientation != UIInterfaceOrientationPortrait) {
- affine_transform.b = -affine_transform.b;
- affine_transform.d = -affine_transform.d;
- affine_transform.ty = 1.0 - affine_transform.ty;
- } else {
- affine_transform.c = -affine_transform.c;
- affine_transform.a = -affine_transform.a;
- affine_transform.tx = 1.0 - affine_transform.tx;
- }
-
- Transform2D display_transform = Transform2D(
- affine_transform.a, affine_transform.b,
- affine_transform.c, affine_transform.d,
- affine_transform.tx, affine_transform.ty);
-
- feed->set_transform(display_transform);
- }
-
- // and unlock
- CVPixelBufferUnlockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);
- }
-
- // Record light estimation to apply to our scene
- if (light_estimation_is_enabled) {
- ambient_intensity = current_frame.lightEstimate.ambientIntensity;
-
- ///@TODO it's there, but not there.. what to do with this...
- // https://developer.apple.com/documentation/arkit/arlightestimate?language=objc
- // ambient_color_temperature = current_frame.lightEstimate.ambientColorTemperature;
- }
-
- // Process our camera
- ARCamera *camera = current_frame.camera;
-
- // strangely enough we have to states, rolling them up into one
- if (camera.trackingState == ARTrackingStateNotAvailable) {
- // no tracking, would be good if we black out the screen or something...
- tracking_state = XRInterface::XR_NOT_TRACKING;
- } else {
- if (camera.trackingState == ARTrackingStateNormal) {
- tracking_state = XRInterface::XR_NORMAL_TRACKING;
- } else if (camera.trackingStateReason == ARTrackingStateReasonExcessiveMotion) {
- tracking_state = XRInterface::XR_EXCESSIVE_MOTION;
- } else if (camera.trackingStateReason == ARTrackingStateReasonInsufficientFeatures) {
- tracking_state = XRInterface::XR_INSUFFICIENT_FEATURES;
- } else {
- tracking_state = XRInterface::XR_UNKNOWN_TRACKING;
- }
-
- // copy our current frame transform
- matrix_float4x4 m44 = camera.transform;
- if (orientation == UIInterfaceOrientationLandscapeLeft) {
- transform.basis.elements[0].x = m44.columns[0][0];
- transform.basis.elements[1].x = m44.columns[0][1];
- transform.basis.elements[2].x = m44.columns[0][2];
- transform.basis.elements[0].y = m44.columns[1][0];
- transform.basis.elements[1].y = m44.columns[1][1];
- transform.basis.elements[2].y = m44.columns[1][2];
- } else if (orientation == UIInterfaceOrientationPortrait) {
- transform.basis.elements[0].x = m44.columns[1][0];
- transform.basis.elements[1].x = m44.columns[1][1];
- transform.basis.elements[2].x = m44.columns[1][2];
- transform.basis.elements[0].y = -m44.columns[0][0];
- transform.basis.elements[1].y = -m44.columns[0][1];
- transform.basis.elements[2].y = -m44.columns[0][2];
- } else if (orientation == UIInterfaceOrientationLandscapeRight) {
- transform.basis.elements[0].x = -m44.columns[0][0];
- transform.basis.elements[1].x = -m44.columns[0][1];
- transform.basis.elements[2].x = -m44.columns[0][2];
- transform.basis.elements[0].y = -m44.columns[1][0];
- transform.basis.elements[1].y = -m44.columns[1][1];
- transform.basis.elements[2].y = -m44.columns[1][2];
- } else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
- // this may not be correct
- transform.basis.elements[0].x = m44.columns[1][0];
- transform.basis.elements[1].x = m44.columns[1][1];
- transform.basis.elements[2].x = m44.columns[1][2];
- transform.basis.elements[0].y = m44.columns[0][0];
- transform.basis.elements[1].y = m44.columns[0][1];
- transform.basis.elements[2].y = m44.columns[0][2];
- }
- transform.basis.elements[0].z = m44.columns[2][0];
- transform.basis.elements[1].z = m44.columns[2][1];
- transform.basis.elements[2].z = m44.columns[2][2];
- transform.origin.x = m44.columns[3][0];
- transform.origin.y = m44.columns[3][1];
- transform.origin.z = m44.columns[3][2];
-
- // copy our current frame projection, investigate using projectionMatrixWithViewportSize:orientation:zNear:zFar: so we can set our own near and far
- m44 = [camera projectionMatrixForOrientation:orientation viewportSize:CGSizeMake(screen_size.width, screen_size.height) zNear:z_near zFar:z_far];
- projection.matrix[0][0] = m44.columns[0][0];
- projection.matrix[1][0] = m44.columns[1][0];
- projection.matrix[2][0] = m44.columns[2][0];
- projection.matrix[3][0] = m44.columns[3][0];
- projection.matrix[0][1] = m44.columns[0][1];
- projection.matrix[1][1] = m44.columns[1][1];
- projection.matrix[2][1] = m44.columns[2][1];
- projection.matrix[3][1] = m44.columns[3][1];
- projection.matrix[0][2] = m44.columns[0][2];
- projection.matrix[1][2] = m44.columns[1][2];
- projection.matrix[2][2] = m44.columns[2][2];
- projection.matrix[3][2] = m44.columns[3][2];
- projection.matrix[0][3] = m44.columns[0][3];
- projection.matrix[1][3] = m44.columns[1][3];
- projection.matrix[2][3] = m44.columns[2][3];
- projection.matrix[3][3] = m44.columns[3][3];
- }
- }
- }
- }
-}
-
-void ARKitInterface::_add_or_update_anchor(GodotARAnchor *p_anchor) {
- // _THREAD_SAFE_METHOD_
-
- if (@available(iOS 11.0, *)) {
- ARAnchor *anchor = (ARAnchor *)p_anchor;
-
- unsigned char uuid[16];
- [anchor.identifier getUUIDBytes:uuid];
-
- XRPositionalTracker *tracker = get_anchor_for_uuid(uuid);
- if (tracker != NULL) {
- // lets update our mesh! (using Arjens code as is for now)
- // we should also probably limit how often we do this...
-
- // can we safely cast this?
- ARPlaneAnchor *planeAnchor = (ARPlaneAnchor *)anchor;
-
- if (@available(iOS 11.3, *)) {
- if (planeAnchor.geometry.triangleCount > 0) {
- Ref<SurfaceTool> surftool;
- surftool.instance();
- surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
-
- for (int j = planeAnchor.geometry.triangleCount * 3 - 1; j >= 0; j--) {
- int16_t index = planeAnchor.geometry.triangleIndices[j];
- simd_float3 vrtx = planeAnchor.geometry.vertices[index];
- simd_float2 textcoord = planeAnchor.geometry.textureCoordinates[index];
- surftool->add_uv(Vector2(textcoord[0], textcoord[1]));
- surftool->add_color(Color(0.8, 0.8, 0.8));
- surftool->add_vertex(Vector3(vrtx[0], vrtx[1], vrtx[2]));
- }
-
- surftool->generate_normals();
- tracker->set_mesh(surftool->commit());
- } else {
- Ref<Mesh> nomesh;
- tracker->set_mesh(nomesh);
- }
- } else {
- Ref<Mesh> nomesh;
- tracker->set_mesh(nomesh);
- }
-
- // Note, this also contains a scale factor which gives us an idea of the size of the anchor
- // We may extract that in our XRAnchor class
- Basis b;
- matrix_float4x4 m44 = anchor.transform;
- b.elements[0].x = m44.columns[0][0];
- b.elements[1].x = m44.columns[0][1];
- b.elements[2].x = m44.columns[0][2];
- b.elements[0].y = m44.columns[1][0];
- b.elements[1].y = m44.columns[1][1];
- b.elements[2].y = m44.columns[1][2];
- b.elements[0].z = m44.columns[2][0];
- b.elements[1].z = m44.columns[2][1];
- b.elements[2].z = m44.columns[2][2];
- tracker->set_orientation(b);
- tracker->set_rw_position(Vector3(m44.columns[3][0], m44.columns[3][1], m44.columns[3][2]));
- }
- }
-}
-
-void ARKitInterface::_remove_anchor(GodotARAnchor *p_anchor) {
- // _THREAD_SAFE_METHOD_
-
- if (@available(iOS 11.0, *)) {
- ARAnchor *anchor = (ARAnchor *)p_anchor;
-
- unsigned char uuid[16];
- [anchor.identifier getUUIDBytes:uuid];
-
- remove_anchor_for_uuid(uuid);
- }
-}
-
-ARKitInterface::ARKitInterface() {
- initialized = false;
- session_was_started = false;
- plane_detection_is_enabled = false;
- light_estimation_is_enabled = false;
- if (@available(iOS 11.0, *)) {
- ar_session = nil;
- }
- z_near = 0.01;
- z_far = 1000.0;
- projection.set_perspective(60.0, 1.0, z_near, z_far, false);
- anchors = NULL;
- num_anchors = 0;
- ambient_intensity = 1.0;
- ambient_color_temperature = 1.0;
- image_width[0] = 0;
- image_width[1] = 0;
- image_height[0] = 0;
- image_height[1] = 0;
-}
-
-ARKitInterface::~ARKitInterface() {
- remove_all_anchors();
-
- // and make sure we cleanup if we haven't already
- if (is_initialized()) {
- uninitialize();
- }
-}
diff --git a/modules/assimp/SCsub b/modules/assimp/SCsub
deleted file mode 100644
index f1d0c742b4..0000000000
--- a/modules/assimp/SCsub
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/usr/bin/env python
-
-Import("env")
-Import("env_modules")
-
-env_assimp = env_modules.Clone()
-
-# Force bundled version for now, there's no released version of Assimp with
-# support for ArmaturePopulate which we use from their master branch.
-if True: # env['builtin_assimp']:
- thirdparty_dir = "#thirdparty/assimp"
-
- env_assimp.Prepend(CPPPATH=["#thirdparty/assimp"])
- env_assimp.Prepend(CPPPATH=["#thirdparty/assimp/code"])
- env_assimp.Prepend(CPPPATH=["#thirdparty/assimp/include"])
-
- # env_assimp.Append(CPPDEFINES=['ASSIMP_DOUBLE_PRECISION']) # TODO default to what godot is compiled with for future double support
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_SINGLETHREADED"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_BOOST_WORKAROUND"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_OWN_ZLIB"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_EXPORT"])
-
- # Importers we don't need
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_3D_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_3DS_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_3MF_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_AC_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_AMF_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_ASE_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_ASSBIN_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_B3D_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_BLEND_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_BVH_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_C4D_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_COB_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_COLLADA_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_CSM_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_DXF_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_GLTF2_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_GLTF_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_HMP_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_IFC_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_IRR_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_IRRMESH_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_LWO_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_LWS_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_M3D_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MD2_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MD3_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MD5_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MD5_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MDC_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MDL_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MMD_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MS3D_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_NDO_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_NFF_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_OBJ_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_OFF_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_OGRE_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_OPENGEX_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_PLY_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_Q3BSP_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_Q3D_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_RAW_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_SIB_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_SMD_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_STEP_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_STL_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_TERRAGEN_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_X3D_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_XGL_IMPORTER"])
- env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_X_IMPORTER"])
-
- if env["platform"] == "windows":
- env_assimp.Append(CPPDEFINES=["PLATFORM_WINDOWS"])
- env_assimp.Append(CPPDEFINES=[("PLATFORM", "WINDOWS")])
- elif env["platform"] == "linuxbsd":
- env_assimp.Append(CPPDEFINES=["PLATFORM_LINUX"])
- env_assimp.Append(CPPDEFINES=[("PLATFORM", "LINUX")])
- elif env["platform"] == "osx":
- env_assimp.Append(CPPDEFINES=["PLATFORM_DARWIN"])
- env_assimp.Append(CPPDEFINES=[("PLATFORM", "DARWIN")])
-
- env_thirdparty = env_assimp.Clone()
- env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/CApi/*.cpp"))
- env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/Common/*.cpp"))
- env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/PostProcessing/*.cpp"))
- env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/Material/*.cpp"))
- env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/FBX/*.cpp"))
-
-# Godot's own source files
-env_assimp.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/assimp/config.py b/modules/assimp/config.py
deleted file mode 100644
index 53b8f2f2e3..0000000000
--- a/modules/assimp/config.py
+++ /dev/null
@@ -1,6 +0,0 @@
-def can_build(env, platform):
- return env["tools"]
-
-
-def configure(env):
- pass
diff --git a/modules/assimp/editor_scene_importer_assimp.cpp b/modules/assimp/editor_scene_importer_assimp.cpp
deleted file mode 100644
index e5becfd559..0000000000
--- a/modules/assimp/editor_scene_importer_assimp.cpp
+++ /dev/null
@@ -1,1486 +0,0 @@
-/*************************************************************************/
-/* editor_scene_importer_assimp.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_assimp.h"
-#include "core/io/image_loader.h"
-#include "editor/import/resource_importer_scene.h"
-#include "import_utils.h"
-#include "scene/3d/camera_3d.h"
-#include "scene/3d/light_3d.h"
-#include "scene/3d/mesh_instance_3d.h"
-#include "scene/main/node.h"
-#include "scene/resources/material.h"
-#include "scene/resources/surface_tool.h"
-
-#include <assimp/matrix4x4.h>
-#include <assimp/postprocess.h>
-#include <assimp/scene.h>
-#include <assimp/Importer.hpp>
-#include <assimp/LogStream.hpp>
-
-// move into assimp
-aiBone *get_bone_by_name(const aiScene *scene, aiString bone_name) {
- for (unsigned int mesh_id = 0; mesh_id < scene->mNumMeshes; ++mesh_id) {
- aiMesh *mesh = scene->mMeshes[mesh_id];
-
- // iterate over all the bones on the mesh for this node only!
- for (unsigned int boneIndex = 0; boneIndex < mesh->mNumBones; boneIndex++) {
- aiBone *bone = mesh->mBones[boneIndex];
- if (bone->mName == bone_name) {
- printf("matched bone by name: %s\n", bone->mName.C_Str());
- return bone;
- }
- }
- }
-
- return nullptr;
-}
-
-void EditorSceneImporterAssimp::get_extensions(List<String> *r_extensions) const {
- const String import_setting_string = "filesystem/import/open_asset_import/";
-
- Map<String, ImportFormat> import_format;
- {
- Vector<String> exts;
- exts.push_back("fbx");
- ImportFormat import = { exts, true };
- import_format.insert("fbx", import);
- }
- for (Map<String, ImportFormat>::Element *E = import_format.front(); E; E = E->next()) {
- _register_project_setting_import(E->key(), import_setting_string, E->get().extensions, r_extensions,
- E->get().is_default);
- }
-}
-
-void EditorSceneImporterAssimp::_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 EditorSceneImporterAssimp::get_import_flags() const {
- return IMPORT_SCENE;
-}
-
-void EditorSceneImporterAssimp::_bind_methods() {
-}
-
-Node *EditorSceneImporterAssimp::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps,
- List<String> *r_missing_deps, Error *r_err) {
- Assimp::Importer importer;
- importer.SetPropertyBool(AI_CONFIG_PP_FD_REMOVE, true);
- // Cannot remove pivot points because the static mesh will be in the wrong place
- importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, false);
- int32_t max_bone_weights = 4;
- //if (p_flags & IMPORT_ANIMATION_EIGHT_WEIGHTS) {
- // const int eight_bones = 8;
- // importer.SetPropertyBool(AI_CONFIG_PP_LBW_MAX_WEIGHTS, eight_bones);
- // max_bone_weights = eight_bones;
- //}
-
- importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_LINE | aiPrimitiveType_POINT);
-
- //importer.SetPropertyFloat(AI_CONFIG_PP_DB_THRESHOLD, 1.0f);
- int32_t post_process_Steps = aiProcess_CalcTangentSpace |
- aiProcess_GlobalScale |
- // imports models and listens to their file scale for CM to M conversions
- //aiProcess_FlipUVs |
- aiProcess_FlipWindingOrder |
- // very important for culling so that it is done in the correct order.
- //aiProcess_DropNormals |
- //aiProcess_GenSmoothNormals |
- //aiProcess_JoinIdenticalVertices |
- aiProcess_ImproveCacheLocality |
- //aiProcess_RemoveRedundantMaterials | // Causes a crash
- //aiProcess_SplitLargeMeshes |
- aiProcess_Triangulate |
- aiProcess_GenUVCoords |
- //aiProcess_FindDegenerates |
- //aiProcess_SortByPType |
- // aiProcess_FindInvalidData |
- aiProcess_TransformUVCoords |
- aiProcess_FindInstances |
- //aiProcess_FixInfacingNormals |
- //aiProcess_ValidateDataStructure |
- aiProcess_OptimizeMeshes |
- aiProcess_PopulateArmatureData |
- //aiProcess_OptimizeGraph |
- //aiProcess_Debone |
- // aiProcess_EmbedTextures |
- //aiProcess_SplitByBoneCount |
- 0;
- String g_path = ProjectSettings::get_singleton()->globalize_path(p_path);
- aiScene *scene = (aiScene *)importer.ReadFile(g_path.utf8().ptr(), post_process_Steps);
-
- ERR_FAIL_COND_V_MSG(scene == nullptr, nullptr, String("Open Asset Import failed to open: ") + String(importer.GetErrorString()));
-
- return _generate_scene(p_path, scene, p_flags, p_bake_fps, max_bone_weights);
-}
-
-template <class T>
-struct EditorSceneImporterAssetImportInterpolate {
- 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) {
- float t2 = t * t;
- 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. */
- real_t omt = (1.0 - t);
- real_t omt2 = omt * omt;
- real_t omt3 = omt2 * omt;
- real_t t2 = t * t;
- 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 EditorSceneImporterAssetImportInterpolate<Quat> {
- Quat lerp(const Quat &a, const Quat &b, float c) const {
- ERR_FAIL_COND_V_MSG(!a.is_normalized(), Quat(), "The quaternion \"a\" must be normalized.");
- ERR_FAIL_COND_V_MSG(!b.is_normalized(), Quat(), "The quaternion \"b\" must be normalized.");
-
- return a.slerp(b, c).normalized();
- }
-
- Quat catmull_rom(const Quat &p0, const Quat &p1, const Quat &p2, const Quat &p3, float c) {
- ERR_FAIL_COND_V_MSG(!p1.is_normalized(), Quat(), "The quaternion \"p1\" must be normalized.");
- ERR_FAIL_COND_V_MSG(!p2.is_normalized(), Quat(), "The quaternion \"p2\" must be normalized.");
-
- return p1.slerp(p2, c).normalized();
- }
-
- Quat bezier(Quat start, Quat control_1, Quat control_2, Quat end, float t) {
- ERR_FAIL_COND_V_MSG(!start.is_normalized(), Quat(), "The start quaternion must be normalized.");
- ERR_FAIL_COND_V_MSG(!end.is_normalized(), Quat(), "The end quaternion must be normalized.");
-
- return start.slerp(end, t).normalized();
- }
-};
-
-template <class T>
-T EditorSceneImporterAssimp::_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++;
- }
-
- EditorSceneImporterAssetImportInterpolate<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]);
-}
-
-aiBone *EditorSceneImporterAssimp::get_bone_from_stack(ImportState &state, aiString name) {
- List<aiBone *>::Element *iter;
- aiBone *bone = nullptr;
- for (iter = state.bone_stack.front(); iter; iter = iter->next()) {
- bone = (aiBone *)iter->get();
-
- if (bone && bone->mName == name) {
- state.bone_stack.erase(bone);
- return bone;
- }
- }
-
- return nullptr;
-}
-
-Node3D *
-EditorSceneImporterAssimp::_generate_scene(const String &p_path, aiScene *scene, const uint32_t p_flags, int p_bake_fps,
- const int32_t p_max_bone_weights) {
- ERR_FAIL_COND_V(scene == nullptr, nullptr);
-
- ImportState state;
- state.path = p_path;
- state.assimp_scene = scene;
- state.max_bone_weights = p_max_bone_weights;
- state.animation_player = nullptr;
- state.import_flags = p_flags;
-
- // populate light map
- for (unsigned int l = 0; l < scene->mNumLights; l++) {
- aiLight *ai_light = scene->mLights[l];
- ERR_CONTINUE(ai_light == nullptr);
- state.light_cache[AssimpUtils::get_assimp_string(ai_light->mName)] = l;
- }
-
- // fill camera cache
- for (unsigned int c = 0; c < scene->mNumCameras; c++) {
- aiCamera *ai_camera = scene->mCameras[c];
- ERR_CONTINUE(ai_camera == nullptr);
- state.camera_cache[AssimpUtils::get_assimp_string(ai_camera->mName)] = c;
- }
-
- if (scene->mRootNode) {
- state.nodes.push_back(scene->mRootNode);
-
- // make flat node tree - in order to make processing deterministic
- for (unsigned int i = 0; i < scene->mRootNode->mNumChildren; i++) {
- _generate_node(state, scene->mRootNode->mChildren[i]);
- }
-
- RegenerateBoneStack(state);
-
- Node *last_valid_parent = nullptr;
-
- List<const aiNode *>::Element *iter;
- for (iter = state.nodes.front(); iter; iter = iter->next()) {
- const aiNode *element_assimp_node = iter->get();
- const aiNode *parent_assimp_node = element_assimp_node->mParent;
-
- String node_name = AssimpUtils::get_assimp_string(element_assimp_node->mName);
- //print_verbose("node: " + node_name);
-
- Node3D *spatial = nullptr;
- Transform transform = AssimpUtils::assimp_matrix_transform(element_assimp_node->mTransformation);
-
- // retrieve this node bone
- aiBone *bone = get_bone_from_stack(state, element_assimp_node->mName);
-
- if (state.light_cache.has(node_name)) {
- spatial = create_light(state, node_name, transform);
- } else if (state.camera_cache.has(node_name)) {
- spatial = create_camera(state, node_name, transform);
- } else if (state.armature_nodes.find(element_assimp_node)) {
- // create skeleton
- print_verbose("Making skeleton: " + node_name);
- Skeleton3D *skeleton = memnew(Skeleton3D);
- spatial = skeleton;
- if (!state.armature_skeletons.has(element_assimp_node)) {
- state.armature_skeletons.insert(element_assimp_node, skeleton);
- }
- } else if (bone != nullptr) {
- continue;
- } else {
- spatial = memnew(Node3D);
- }
-
- ERR_CONTINUE_MSG(spatial == nullptr, "FBX Import - are we out of ram?");
- // we on purpose set the transform and name after creating the node.
-
- spatial->set_name(node_name);
- spatial->set_global_transform(transform);
-
- // first element is root
- if (iter == state.nodes.front()) {
- state.root = spatial;
- }
-
- // flat node map parent lookup tool
- state.flat_node_map.insert(element_assimp_node, spatial);
-
- Map<const aiNode *, Node3D *>::Element *parent_lookup = state.flat_node_map.find(parent_assimp_node);
-
- // note: this always fails on the root node :) keep that in mind this is by design
- if (parent_lookup) {
- Node3D *parent_node = parent_lookup->value();
-
- ERR_FAIL_COND_V_MSG(parent_node == nullptr, state.root,
- "Parent node invalid even though lookup successful, out of ram?");
-
- if (spatial != state.root) {
- parent_node->add_child(spatial);
- spatial->set_owner(state.root);
- } else {
- // required - think about it root never has a parent yet is valid, anything else without a parent is not valid.
- }
- } else if (spatial != state.root) {
- // if the ainode is not in the tree
- // parent it to the last good parent found
- if (last_valid_parent) {
- last_valid_parent->add_child(spatial);
- spatial->set_owner(state.root);
- } else {
- // this is a serious error?
- memdelete(spatial);
- }
- }
-
- // update last valid parent
- last_valid_parent = spatial;
- }
- print_verbose("node counts: " + itos(state.nodes.size()));
-
- // make clean bone stack
- RegenerateBoneStack(state);
-
- print_verbose("generating godot bone data");
-
- print_verbose("Godot bone stack count: " + itos(state.bone_stack.size()));
-
- // This is a list of bones, duplicates are from other meshes and must be dealt with properly
- for (List<aiBone *>::Element *element = state.bone_stack.front(); element; element = element->next()) {
- aiBone *bone = element->get();
-
- ERR_CONTINUE_MSG(!bone, "invalid bone read from assimp?");
-
- // Utilities for armature lookup - for now only FBX makes these
- aiNode *armature_for_bone = bone->mArmature;
-
- // Utilities for bone node lookup - for now only FBX makes these
- aiNode *bone_node = bone->mNode;
- aiNode *parent_node = bone_node->mParent;
-
- String bone_name = AssimpUtils::get_anim_string_from_assimp(bone->mName);
- ERR_CONTINUE_MSG(armature_for_bone == nullptr, "Armature for bone invalid: " + bone_name);
- Skeleton3D *skeleton = state.armature_skeletons[armature_for_bone];
-
- state.skeleton_bone_map[bone] = skeleton;
-
- if (bone_name.empty()) {
- bone_name = "untitled_bone_name";
- WARN_PRINT("Untitled bone name detected... report with file please");
- }
-
- // todo: this is where skin support goes
- if (skeleton && skeleton->find_bone(bone_name) == -1) {
- print_verbose("[Godot Glue] Imported bone" + bone_name);
- int boneIdx = skeleton->get_bone_count();
-
- Transform pform = AssimpUtils::assimp_matrix_transform(bone->mNode->mTransformation);
- skeleton->add_bone(bone_name);
- skeleton->set_bone_rest(boneIdx, pform);
-
- if (parent_node != nullptr) {
- int parent_bone_id = skeleton->find_bone(AssimpUtils::get_anim_string_from_assimp(parent_node->mName));
- int current_bone_id = boneIdx;
- skeleton->set_bone_parent(current_bone_id, parent_bone_id);
- }
- }
- }
-
- print_verbose("generating mesh phase from skeletal mesh");
-
- List<Node3D *> cleanup_template_nodes;
-
- for (Map<const aiNode *, Node3D *>::Element *key_value_pair = state.flat_node_map.front(); key_value_pair; key_value_pair = key_value_pair->next()) {
- const aiNode *assimp_node = key_value_pair->key();
- Node3D *mesh_template = key_value_pair->value();
-
- ERR_CONTINUE(assimp_node == nullptr);
- ERR_CONTINUE(mesh_template == nullptr);
-
- Node *parent_node = mesh_template->get_parent();
-
- if (mesh_template == state.root) {
- continue;
- }
-
- if (parent_node == nullptr) {
- print_error("Found invalid parent node!");
- continue; // root node
- }
-
- String node_name = AssimpUtils::get_assimp_string(assimp_node->mName);
- Transform node_transform = AssimpUtils::assimp_matrix_transform(assimp_node->mTransformation);
-
- if (assimp_node->mNumMeshes > 0) {
- MeshInstance3D *mesh = create_mesh(state, assimp_node, node_name, parent_node, node_transform);
- if (mesh) {
- parent_node->remove_child(mesh_template);
-
- // re-parent children
- List<Node *> children;
- // re-parent all children to new node
- // note: since get_child_count will change during execution we must build a list first to be safe.
- for (int childId = 0; childId < mesh_template->get_child_count(); childId++) {
- // get child
- Node *child = mesh_template->get_child(childId);
- children.push_back(child);
- }
-
- for (List<Node *>::Element *element = children.front(); element; element = element->next()) {
- // reparent the children to the real mesh node.
- mesh_template->remove_child(element->get());
- mesh->add_child(element->get());
- element->get()->set_owner(state.root);
- }
-
- // update mesh in list so that each mesh node is available
- // this makes the template unavailable which is the desired behaviour
- state.flat_node_map[assimp_node] = mesh;
-
- cleanup_template_nodes.push_back(mesh_template);
-
- // clean up this list we don't need it
- children.clear();
- }
- }
- }
-
- for (List<Node3D *>::Element *element = cleanup_template_nodes.front(); element; element = element->next()) {
- if (element->get()) {
- memdelete(element->get());
- }
- }
- }
-
- if (p_flags & IMPORT_ANIMATION && scene->mNumAnimations) {
- state.animation_player = memnew(AnimationPlayer);
- state.root->add_child(state.animation_player);
- state.animation_player->set_owner(state.root);
-
- for (uint32_t i = 0; i < scene->mNumAnimations; i++) {
- _import_animation(state, i, p_bake_fps);
- }
- }
-
- //
- // Cleanup operations
- //
-
- state.mesh_cache.clear();
- state.material_cache.clear();
- state.light_cache.clear();
- state.camera_cache.clear();
- state.assimp_node_map.clear();
- state.path_to_image_cache.clear();
- state.nodes.clear();
- state.flat_node_map.clear();
- state.armature_skeletons.clear();
- state.bone_stack.clear();
- return state.root;
-}
-
-void EditorSceneImporterAssimp::_insert_animation_track(ImportState &scene, const aiAnimation *assimp_anim, int track_id,
- int anim_fps, Ref<Animation> animation, float ticks_per_second,
- Skeleton3D *skeleton, const NodePath &node_path,
- const String &node_name, aiBone *track_bone) {
- const aiNodeAnim *assimp_track = assimp_anim->mChannels[track_id];
- //make transform track
- int track_idx = animation->get_track_count();
- animation->add_track(Animation::TYPE_TRANSFORM);
- animation->track_set_path(track_idx, node_path);
- //first determine animation length
-
- float increment = 1.0 / float(anim_fps);
- float time = 0.0;
-
- bool last = false;
-
- Vector<Vector3> pos_values;
- Vector<float> pos_times;
- Vector<Vector3> scale_values;
- Vector<float> scale_times;
- Vector<Quat> rot_values;
- Vector<float> rot_times;
-
- for (size_t p = 0; p < assimp_track->mNumPositionKeys; p++) {
- aiVector3D pos = assimp_track->mPositionKeys[p].mValue;
- pos_values.push_back(Vector3(pos.x, pos.y, pos.z));
- pos_times.push_back(assimp_track->mPositionKeys[p].mTime / ticks_per_second);
- }
-
- for (size_t r = 0; r < assimp_track->mNumRotationKeys; r++) {
- aiQuaternion quat = assimp_track->mRotationKeys[r].mValue;
- rot_values.push_back(Quat(quat.x, quat.y, quat.z, quat.w).normalized());
- rot_times.push_back(assimp_track->mRotationKeys[r].mTime / ticks_per_second);
- }
-
- for (size_t sc = 0; sc < assimp_track->mNumScalingKeys; sc++) {
- aiVector3D scale = assimp_track->mScalingKeys[sc].mValue;
- scale_values.push_back(Vector3(scale.x, scale.y, scale.z));
- scale_times.push_back(assimp_track->mScalingKeys[sc].mTime / ticks_per_second);
- }
-
- while (true) {
- Vector3 pos;
- Quat rot;
- Vector3 scale(1, 1, 1);
-
- if (pos_values.size()) {
- pos = _interpolate_track<Vector3>(pos_times, pos_values, time, AssetImportAnimation::INTERP_LINEAR);
- }
-
- if (rot_values.size()) {
- rot = _interpolate_track<Quat>(rot_times, rot_values, time,
- AssetImportAnimation::INTERP_LINEAR)
- .normalized();
- }
-
- if (scale_values.size()) {
- scale = _interpolate_track<Vector3>(scale_times, scale_values, time, AssetImportAnimation::INTERP_LINEAR);
- }
-
- if (skeleton) {
- int skeleton_bone = skeleton->find_bone(node_name);
-
- if (skeleton_bone >= 0 && track_bone) {
- Transform xform;
- xform.basis.set_quat_scale(rot, scale);
- xform.origin = pos;
-
- xform = skeleton->get_bone_rest(skeleton_bone).inverse() * xform;
-
- rot = xform.basis.get_rotation_quat();
- rot.normalize();
- scale = xform.basis.get_scale();
- pos = xform.origin;
- } else {
- ERR_FAIL_MSG("Skeleton bone lookup failed for skeleton: " + skeleton->get_name());
- }
- }
-
- animation->track_set_interpolation_type(track_idx, Animation::INTERPOLATION_LINEAR);
- animation->transform_track_insert_key(track_idx, time, pos, rot, scale);
-
- if (last) { //done this way so a key is always inserted past the end (for proper interpolation)
- break;
- }
- time += increment;
- if (time >= animation->get_length()) {
- last = true;
- }
- }
-}
-
-// I really do not like this but need to figure out a better way of removing it later.
-Node *EditorSceneImporterAssimp::get_node_by_name(ImportState &state, String name) {
- for (Map<const aiNode *, Node3D *>::Element *key_value_pair = state.flat_node_map.front(); key_value_pair; key_value_pair = key_value_pair->next()) {
- const aiNode *assimp_node = key_value_pair->key();
- Node3D *node = key_value_pair->value();
-
- String node_name = AssimpUtils::get_assimp_string(assimp_node->mName);
- if (name == node_name && node) {
- return node;
- }
- }
- return nullptr;
-}
-
-/* Bone stack is a fifo handler for multiple armatures since armatures aren't a thing in assimp (yet) */
-void EditorSceneImporterAssimp::RegenerateBoneStack(ImportState &state) {
- state.bone_stack.clear();
- // build bone stack list
- for (unsigned int mesh_id = 0; mesh_id < state.assimp_scene->mNumMeshes; ++mesh_id) {
- aiMesh *mesh = state.assimp_scene->mMeshes[mesh_id];
-
- // iterate over all the bones on the mesh for this node only!
- for (unsigned int boneIndex = 0; boneIndex < mesh->mNumBones; boneIndex++) {
- aiBone *bone = mesh->mBones[boneIndex];
-
- // doubtful this is required right now but best to check
- if (!state.bone_stack.find(bone)) {
- //print_verbose("[assimp] bone stack added: " + String(bone->mName.C_Str()) );
- state.bone_stack.push_back(bone);
- }
- }
- }
-}
-
-/* Bone stack is a fifo handler for multiple armatures since armatures aren't a thing in assimp (yet) */
-void EditorSceneImporterAssimp::RegenerateBoneStack(ImportState &state, aiMesh *mesh) {
- state.bone_stack.clear();
- // iterate over all the bones on the mesh for this node only!
- for (unsigned int boneIndex = 0; boneIndex < mesh->mNumBones; boneIndex++) {
- aiBone *bone = mesh->mBones[boneIndex];
- if (state.bone_stack.find(bone) == nullptr) {
- state.bone_stack.push_back(bone);
- }
- }
-}
-
-// animation tracks are per bone
-
-void EditorSceneImporterAssimp::_import_animation(ImportState &state, int p_animation_index, int p_bake_fps) {
- ERR_FAIL_INDEX(p_animation_index, (int)state.assimp_scene->mNumAnimations);
-
- const aiAnimation *anim = state.assimp_scene->mAnimations[p_animation_index];
- String name = AssimpUtils::get_anim_string_from_assimp(anim->mName);
- if (name == String()) {
- name = "Animation " + itos(p_animation_index + 1);
- }
- print_verbose("import animation: " + name);
- float ticks_per_second = anim->mTicksPerSecond;
-
- if (state.assimp_scene->mMetaData != nullptr && Math::is_equal_approx(ticks_per_second, 0.0f)) {
- int32_t time_mode = 0;
- state.assimp_scene->mMetaData->Get("TimeMode", time_mode);
- ticks_per_second = AssimpUtils::get_fbx_fps(time_mode, state.assimp_scene);
- }
-
- //?
- //if ((p_path.get_file().get_extension().to_lower() == "glb" || p_path.get_file().get_extension().to_lower() == "gltf") && Math::is_equal_approx(ticks_per_second, 0.0f)) {
- // ticks_per_second = 1000.0f;
- //}
-
- if (Math::is_equal_approx(ticks_per_second, 0.0f)) {
- ticks_per_second = 25.0f;
- }
-
- Ref<Animation> animation;
- animation.instance();
- animation->set_name(name);
- animation->set_length(anim->mDuration / ticks_per_second);
-
- if (name.begins_with("loop") || name.ends_with("loop") || name.begins_with("cycle") || name.ends_with("cycle")) {
- animation->set_loop(true);
- }
-
- // generate bone stack for animation import
- RegenerateBoneStack(state);
-
- //regular tracks
- for (size_t i = 0; i < anim->mNumChannels; i++) {
- const aiNodeAnim *track = anim->mChannels[i];
- String node_name = AssimpUtils::get_assimp_string(track->mNodeName);
- print_verbose("track name import: " + node_name);
- if (track->mNumRotationKeys == 0 && track->mNumPositionKeys == 0 && track->mNumScalingKeys == 0) {
- continue; //do not bother
- }
-
- Skeleton3D *skeleton = nullptr;
- NodePath node_path;
- aiBone *bone = nullptr;
-
- // Import skeleton bone animation for this track
- // Any bone will do, no point in processing more than just what is in the skeleton
- {
- bone = get_bone_from_stack(state, track->mNodeName);
-
- if (bone) {
- // get skeleton by bone
- skeleton = state.armature_skeletons[bone->mArmature];
-
- if (skeleton) {
- String path = state.root->get_path_to(skeleton);
- path += ":" + node_name;
- node_path = path;
-
- if (node_path != NodePath()) {
- _insert_animation_track(state, anim, i, p_bake_fps, animation, ticks_per_second, skeleton,
- node_path, node_name, bone);
- } else {
- print_error("Failed to find valid node path for animation");
- }
- }
- }
- }
-
- // not a bone
- // note this is flaky it uses node names which is unreliable
- Node *allocated_node = get_node_by_name(state, node_name);
- // todo: implement skeleton grabbing for node based animations too :)
- // check if node exists, if it does then also apply animation track for node and bones above are all handled.
- // this is now inclusive animation handling so that
- // we import all the data and do not miss anything.
- if (allocated_node) {
- node_path = state.root->get_path_to(allocated_node);
-
- if (node_path != NodePath()) {
- _insert_animation_track(state, anim, i, p_bake_fps, animation, ticks_per_second, skeleton,
- node_path, node_name, nullptr);
- }
- }
- }
-
- //blend shape tracks
-
- for (size_t i = 0; i < anim->mNumMorphMeshChannels; i++) {
- const aiMeshMorphAnim *anim_mesh = anim->mMorphMeshChannels[i];
-
- const String prop_name = AssimpUtils::get_assimp_string(anim_mesh->mName);
- const String mesh_name = prop_name.split("*")[0];
-
- ERR_CONTINUE(prop_name.split("*").size() != 2);
-
- Node *item = get_node_by_name(state, mesh_name);
- ERR_CONTINUE_MSG(!item, "failed to look up node by name");
- const MeshInstance3D *mesh_instance = Object::cast_to<MeshInstance3D>(item);
- ERR_CONTINUE(mesh_instance == nullptr);
-
- String base_path = state.root->get_path_to(mesh_instance);
-
- Ref<Mesh> mesh = mesh_instance->get_mesh();
- ERR_CONTINUE(mesh.is_null());
-
- //add the tracks for this mesh
- int base_track = animation->get_track_count();
- for (int j = 0; j < mesh->get_blend_shape_count(); j++) {
- animation->add_track(Animation::TYPE_VALUE);
- animation->track_set_path(base_track + j, base_path + ":blend_shapes/" + mesh->get_blend_shape_name(j));
- }
-
- for (size_t k = 0; k < anim_mesh->mNumKeys; k++) {
- for (size_t j = 0; j < anim_mesh->mKeys[k].mNumValuesAndWeights; j++) {
- float t = anim_mesh->mKeys[k].mTime / ticks_per_second;
- float w = anim_mesh->mKeys[k].mWeights[j];
-
- animation->track_insert_key(base_track + j, t, w);
- }
- }
- }
-
- if (animation->get_track_count()) {
- state.animation_player->add_animation(name, animation);
- }
-}
-
-//
-// Mesh Generation from indices ? why do we need so much mesh code
-// [debt needs looked into]
-Ref<Mesh>
-EditorSceneImporterAssimp::_generate_mesh_from_surface_indices(ImportState &state, const Vector<int> &p_surface_indices,
- const aiNode *assimp_node, Ref<Skin> &skin,
- Skeleton3D *&skeleton_assigned) {
- Ref<ArrayMesh> mesh;
- mesh.instance();
- bool has_uvs = false;
- bool compress_vert_data = state.import_flags & IMPORT_USE_COMPRESSION;
- uint32_t mesh_flags = compress_vert_data ? Mesh::ARRAY_COMPRESS_DEFAULT : 0;
-
- Map<String, uint32_t> morph_mesh_string_lookup;
-
- for (int i = 0; i < p_surface_indices.size(); i++) {
- const unsigned int mesh_idx = p_surface_indices[0];
- const aiMesh *ai_mesh = state.assimp_scene->mMeshes[mesh_idx];
- for (size_t j = 0; j < ai_mesh->mNumAnimMeshes; j++) {
- String ai_anim_mesh_name = AssimpUtils::get_assimp_string(ai_mesh->mAnimMeshes[j]->mName);
- if (!morph_mesh_string_lookup.has(ai_anim_mesh_name)) {
- morph_mesh_string_lookup.insert(ai_anim_mesh_name, j);
- mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED);
- if (ai_anim_mesh_name.empty()) {
- ai_anim_mesh_name = String("morph_") + itos(j);
- }
- mesh->add_blend_shape(ai_anim_mesh_name);
- }
- }
- }
- //
- // Process Vertex Weights
- //
- for (int i = 0; i < p_surface_indices.size(); i++) {
- const unsigned int mesh_idx = p_surface_indices[i];
- const aiMesh *ai_mesh = state.assimp_scene->mMeshes[mesh_idx];
-
- Map<uint32_t, Vector<BoneInfo>> vertex_weights;
-
- if (ai_mesh->mNumBones > 0) {
- for (size_t b = 0; b < ai_mesh->mNumBones; b++) {
- aiBone *bone = ai_mesh->mBones[b];
-
- if (!skeleton_assigned) {
- print_verbose("Assigned mesh skeleton during mesh creation");
- skeleton_assigned = state.skeleton_bone_map[bone];
-
- if (!skin.is_valid()) {
- print_verbose("Configured new skin");
- skin.instance();
- } else {
- print_verbose("Reusing existing skin!");
- }
- }
- // skeleton_assigned =
- String bone_name = AssimpUtils::get_assimp_string(bone->mName);
- int bone_index = skeleton_assigned->find_bone(bone_name);
- ERR_CONTINUE(bone_index == -1);
- for (size_t w = 0; w < bone->mNumWeights; w++) {
- aiVertexWeight ai_weights = bone->mWeights[w];
-
- BoneInfo bi;
- uint32_t vertex_index = ai_weights.mVertexId;
- bi.bone = bone_index;
- bi.weight = ai_weights.mWeight;
-
- if (!vertex_weights.has(vertex_index)) {
- vertex_weights[vertex_index] = Vector<BoneInfo>();
- }
-
- vertex_weights[vertex_index].push_back(bi);
- }
- }
- }
-
- //
- // Create mesh from data from assimp
- //
-
- Ref<SurfaceTool> st;
- st.instance();
- st->begin(Mesh::PRIMITIVE_TRIANGLES);
-
- for (size_t j = 0; j < ai_mesh->mNumVertices; j++) {
- // Get the texture coordinates if they exist
- if (ai_mesh->HasTextureCoords(0)) {
- has_uvs = true;
- st->add_uv(Vector2(ai_mesh->mTextureCoords[0][j].x, 1.0f - ai_mesh->mTextureCoords[0][j].y));
- }
-
- if (ai_mesh->HasTextureCoords(1)) {
- has_uvs = true;
- st->add_uv2(Vector2(ai_mesh->mTextureCoords[1][j].x, 1.0f - ai_mesh->mTextureCoords[1][j].y));
- }
-
- // Assign vertex colors
- if (ai_mesh->HasVertexColors(0)) {
- Color color = Color(ai_mesh->mColors[0]->r, ai_mesh->mColors[0]->g, ai_mesh->mColors[0]->b,
- ai_mesh->mColors[0]->a);
- st->add_color(color);
- }
-
- // Work out normal calculations? - this needs work it doesn't work properly on huestos
- if (ai_mesh->mNormals != nullptr) {
- const aiVector3D normals = ai_mesh->mNormals[j];
- const Vector3 godot_normal = Vector3(normals.x, normals.y, normals.z);
- st->add_normal(godot_normal);
- if (ai_mesh->HasTangentsAndBitangents()) {
- const aiVector3D tangents = ai_mesh->mTangents[j];
- const Vector3 godot_tangent = Vector3(tangents.x, tangents.y, tangents.z);
- const aiVector3D bitangent = ai_mesh->mBitangents[j];
- const Vector3 godot_bitangent = Vector3(bitangent.x, bitangent.y, bitangent.z);
- float d = godot_normal.cross(godot_tangent).dot(godot_bitangent) > 0.0f ? 1.0f : -1.0f;
- st->add_tangent(Plane(tangents.x, tangents.y, tangents.z, d));
- }
- }
-
- // We have vertex weights right?
- if (vertex_weights.has(j)) {
- Vector<BoneInfo> bone_info = vertex_weights[j];
- Vector<int> bones;
- bones.resize(bone_info.size());
- Vector<float> weights;
- weights.resize(bone_info.size());
-
- // todo? do we really need to loop over all bones? - assimp may have helper to find all influences on this vertex.
- for (int k = 0; k < bone_info.size(); k++) {
- bones.write[k] = bone_info[k].bone;
- weights.write[k] = bone_info[k].weight;
- }
-
- st->add_bones(bones);
- st->add_weights(weights);
- }
-
- // Assign vertex
- const aiVector3D pos = ai_mesh->mVertices[j];
-
- // note we must include node offset transform as this is relative to world space not local space.
- Vector3 godot_pos = Vector3(pos.x, pos.y, pos.z);
- st->add_vertex(godot_pos);
- }
-
- // fire replacement for face handling
- for (size_t j = 0; j < ai_mesh->mNumFaces; j++) {
- const aiFace face = ai_mesh->mFaces[j];
- for (unsigned int k = 0; k < face.mNumIndices; k++) {
- st->add_index(face.mIndices[k]);
- }
- }
-
- if (ai_mesh->HasTangentsAndBitangents() == false && has_uvs) {
- st->generate_tangents();
- }
-
- aiMaterial *ai_material = state.assimp_scene->mMaterials[ai_mesh->mMaterialIndex];
- Ref<StandardMaterial3D> mat;
- mat.instance();
-
- int32_t mat_two_sided = 0;
- if (AI_SUCCESS == ai_material->Get(AI_MATKEY_TWOSIDED, mat_two_sided)) {
- if (mat_two_sided > 0) {
- mat->set_cull_mode(StandardMaterial3D::CULL_DISABLED);
- } else {
- mat->set_cull_mode(StandardMaterial3D::CULL_BACK);
- }
- }
-
- aiString mat_name;
- if (AI_SUCCESS == ai_material->Get(AI_MATKEY_NAME, mat_name)) {
- mat->set_name(AssimpUtils::get_assimp_string(mat_name));
- }
-
- // Culling handling for meshes
-
- // cull all back faces
- mat->set_cull_mode(StandardMaterial3D::CULL_DISABLED);
-
- // Now process materials
- aiTextureType base_color = aiTextureType_BASE_COLOR;
- {
- String filename, path;
- AssimpImageData image_data;
-
- if (AssimpUtils::GetAssimpTexture(state, ai_material, base_color, filename, path, image_data)) {
- AssimpUtils::set_texture_mapping_mode(image_data.map_mode, image_data.texture);
-
- // anything transparent must be culled
- if (image_data.raw_image->detect_alpha() != Image::ALPHA_NONE) {
- mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA_DEPTH_PRE_PASS);
- mat->set_cull_mode(StandardMaterial3D::CULL_DISABLED); // since you can see both sides in transparent mode
- }
-
- mat->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, image_data.texture);
- }
- }
-
- aiTextureType tex_diffuse = aiTextureType_DIFFUSE;
- {
- String filename, path;
- AssimpImageData image_data;
-
- if (AssimpUtils::GetAssimpTexture(state, ai_material, tex_diffuse, filename, path, image_data)) {
- AssimpUtils::set_texture_mapping_mode(image_data.map_mode, image_data.texture);
-
- // anything transparent must be culled
- if (image_data.raw_image->detect_alpha() != Image::ALPHA_NONE) {
- mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA_DEPTH_PRE_PASS);
- mat->set_cull_mode(StandardMaterial3D::CULL_DISABLED); // since you can see both sides in transparent mode
- }
-
- mat->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, image_data.texture);
- }
-
- aiColor4D clr_diffuse;
- if (AI_SUCCESS == ai_material->Get(AI_MATKEY_COLOR_DIFFUSE, clr_diffuse)) {
- if (Math::is_equal_approx(clr_diffuse.a, 1.0f) == false) {
- mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA_DEPTH_PRE_PASS);
- mat->set_cull_mode(StandardMaterial3D::CULL_DISABLED); // since you can see both sides in transparent mode
- }
- mat->set_albedo(Color(clr_diffuse.r, clr_diffuse.g, clr_diffuse.b, clr_diffuse.a));
- }
- }
-
- aiTextureType tex_normal = aiTextureType_NORMALS;
- {
- String filename, path;
- Ref<ImageTexture> texture;
- AssimpImageData image_data;
-
- // Process texture normal map
- if (AssimpUtils::GetAssimpTexture(state, ai_material, tex_normal, filename, path, image_data)) {
- AssimpUtils::set_texture_mapping_mode(image_data.map_mode, image_data.texture);
- mat->set_feature(StandardMaterial3D::Feature::FEATURE_NORMAL_MAPPING, true);
- mat->set_texture(StandardMaterial3D::TEXTURE_NORMAL, image_data.texture);
- } else {
- aiString texture_path;
- if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_NORMAL_TEXTURE, AI_PROPERTIES, texture_path)) {
- if (AssimpUtils::CreateAssimpTexture(state, texture_path, filename, path, image_data)) {
- mat->set_feature(StandardMaterial3D::Feature::FEATURE_NORMAL_MAPPING, true);
- mat->set_texture(StandardMaterial3D::TEXTURE_NORMAL, image_data.texture);
- }
- }
- }
- }
-
- aiTextureType tex_normal_camera = aiTextureType_NORMAL_CAMERA;
- {
- String filename, path;
- Ref<ImageTexture> texture;
- AssimpImageData image_data;
-
- // Process texture normal map
- if (AssimpUtils::GetAssimpTexture(state, ai_material, tex_normal_camera, filename, path, image_data)) {
- AssimpUtils::set_texture_mapping_mode(image_data.map_mode, image_data.texture);
- mat->set_feature(StandardMaterial3D::Feature::FEATURE_NORMAL_MAPPING, true);
- mat->set_texture(StandardMaterial3D::TEXTURE_NORMAL, image_data.texture);
- }
- }
-
- aiTextureType tex_emission_color = aiTextureType_EMISSION_COLOR;
- {
- String filename, path;
- Ref<ImageTexture> texture;
- AssimpImageData image_data;
-
- // Process texture normal map
- if (AssimpUtils::GetAssimpTexture(state, ai_material, tex_emission_color, filename, path, image_data)) {
- AssimpUtils::set_texture_mapping_mode(image_data.map_mode, image_data.texture);
- mat->set_feature(StandardMaterial3D::Feature::FEATURE_NORMAL_MAPPING, true);
- mat->set_texture(StandardMaterial3D::TEXTURE_NORMAL, image_data.texture);
- }
- }
-
- aiTextureType tex_metalness = aiTextureType_METALNESS;
- {
- String filename, path;
- Ref<ImageTexture> texture;
- AssimpImageData image_data;
-
- // Process texture normal map
- if (AssimpUtils::GetAssimpTexture(state, ai_material, tex_metalness, filename, path, image_data)) {
- AssimpUtils::set_texture_mapping_mode(image_data.map_mode, image_data.texture);
- mat->set_texture(StandardMaterial3D::TEXTURE_METALLIC, image_data.texture);
- }
- }
-
- aiTextureType tex_roughness = aiTextureType_DIFFUSE_ROUGHNESS;
- {
- String filename, path;
- Ref<ImageTexture> texture;
- AssimpImageData image_data;
-
- // Process texture normal map
- if (AssimpUtils::GetAssimpTexture(state, ai_material, tex_roughness, filename, path, image_data)) {
- AssimpUtils::set_texture_mapping_mode(image_data.map_mode, image_data.texture);
- mat->set_texture(StandardMaterial3D::TEXTURE_ROUGHNESS, image_data.texture);
- }
- }
-
- aiTextureType tex_emissive = aiTextureType_EMISSIVE;
- {
- String filename = "";
- String path = "";
- Ref<Image> texture;
- AssimpImageData image_data;
-
- if (AssimpUtils::GetAssimpTexture(state, ai_material, tex_emissive, filename, path, image_data)) {
- AssimpUtils::set_texture_mapping_mode(image_data.map_mode, image_data.texture);
- mat->set_feature(StandardMaterial3D::FEATURE_EMISSION, true);
- mat->set_texture(StandardMaterial3D::TEXTURE_EMISSION, image_data.texture);
- } else {
- // Process emission textures
- aiString texture_emissive_path;
- if (AI_SUCCESS ==
- ai_material->Get(AI_MATKEY_FBX_MAYA_EMISSION_TEXTURE, AI_PROPERTIES, texture_emissive_path)) {
- if (AssimpUtils::CreateAssimpTexture(state, texture_emissive_path, filename, path, image_data)) {
- mat->set_feature(StandardMaterial3D::FEATURE_EMISSION, true);
- mat->set_texture(StandardMaterial3D::TEXTURE_EMISSION, image_data.texture);
- }
- } else {
- float pbr_emission = 0.0f;
- if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_EMISSIVE_FACTOR, AI_NULL, pbr_emission)) {
- mat->set_emission(Color(pbr_emission, pbr_emission, pbr_emission, 1.0f));
- }
- }
- }
- }
-
- aiTextureType tex_specular = aiTextureType_SPECULAR;
- {
- String filename, path;
- Ref<ImageTexture> texture;
- AssimpImageData image_data;
-
- // Process texture normal map
- if (AssimpUtils::GetAssimpTexture(state, ai_material, tex_specular, filename, path, image_data)) {
- AssimpUtils::set_texture_mapping_mode(image_data.map_mode, image_data.texture);
- mat->set_texture(StandardMaterial3D::TEXTURE_METALLIC, image_data.texture);
- }
- }
-
- aiTextureType tex_ao_map = aiTextureType_AMBIENT_OCCLUSION;
- {
- String filename, path;
- Ref<ImageTexture> texture;
- AssimpImageData image_data;
-
- // Process texture normal map
- if (AssimpUtils::GetAssimpTexture(state, ai_material, tex_ao_map, filename, path, image_data)) {
- AssimpUtils::set_texture_mapping_mode(image_data.map_mode, image_data.texture);
- mat->set_feature(StandardMaterial3D::FEATURE_AMBIENT_OCCLUSION, true);
- mat->set_texture(StandardMaterial3D::TEXTURE_AMBIENT_OCCLUSION, image_data.texture);
- }
- }
-
- Array array_mesh = st->commit_to_arrays();
- Array morphs;
- morphs.resize(ai_mesh->mNumAnimMeshes);
- Mesh::PrimitiveType primitive = Mesh::PRIMITIVE_TRIANGLES;
-
- for (size_t j = 0; j < ai_mesh->mNumAnimMeshes; j++) {
- String ai_anim_mesh_name = AssimpUtils::get_assimp_string(ai_mesh->mAnimMeshes[j]->mName);
-
- if (ai_anim_mesh_name.empty()) {
- ai_anim_mesh_name = String("morph_") + itos(j);
- }
-
- Array array_copy;
- array_copy.resize(RenderingServer::ARRAY_MAX);
-
- for (int l = 0; l < RenderingServer::ARRAY_MAX; l++) {
- array_copy[l] = array_mesh[l].duplicate(true);
- }
-
- const size_t num_vertices = ai_mesh->mAnimMeshes[j]->mNumVertices;
- array_copy[Mesh::ARRAY_INDEX] = Variant();
- if (ai_mesh->mAnimMeshes[j]->HasPositions()) {
- PackedVector3Array vertices;
- vertices.resize(num_vertices);
- for (size_t l = 0; l < num_vertices; l++) {
- const aiVector3D ai_pos = ai_mesh->mAnimMeshes[j]->mVertices[l];
- Vector3 position = Vector3(ai_pos.x, ai_pos.y, ai_pos.z);
- vertices.ptrw()[l] = position;
- }
- PackedVector3Array new_vertices = array_copy[RenderingServer::ARRAY_VERTEX].duplicate(true);
- ERR_CONTINUE(vertices.size() != new_vertices.size());
- for (int32_t l = 0; l < new_vertices.size(); l++) {
- Vector3 *w = new_vertices.ptrw();
- w[l] = vertices[l];
- }
- array_copy[RenderingServer::ARRAY_VERTEX] = new_vertices;
- }
-
- int32_t color_set = 0;
- if (ai_mesh->mAnimMeshes[j]->HasVertexColors(color_set)) {
- PackedColorArray colors;
- colors.resize(num_vertices);
- for (size_t l = 0; l < num_vertices; l++) {
- const aiColor4D ai_color = ai_mesh->mAnimMeshes[j]->mColors[color_set][l];
- Color color = Color(ai_color.r, ai_color.g, ai_color.b, ai_color.a);
- colors.ptrw()[l] = color;
- }
- PackedColorArray new_colors = array_copy[RenderingServer::ARRAY_COLOR].duplicate(true);
- ERR_CONTINUE(colors.size() != new_colors.size());
- for (int32_t l = 0; l < colors.size(); l++) {
- Color *w = new_colors.ptrw();
- w[l] = colors[l];
- }
- array_copy[RenderingServer::ARRAY_COLOR] = new_colors;
- }
-
- if (ai_mesh->mAnimMeshes[j]->HasNormals()) {
- PackedVector3Array normals;
- normals.resize(num_vertices);
- for (size_t l = 0; l < num_vertices; l++) {
- const aiVector3D ai_normal = ai_mesh->mAnimMeshes[j]->mNormals[l];
- Vector3 normal = Vector3(ai_normal.x, ai_normal.y, ai_normal.z);
- normals.ptrw()[l] = normal;
- }
- PackedVector3Array new_normals = array_copy[RenderingServer::ARRAY_NORMAL].duplicate(true);
- ERR_CONTINUE(normals.size() != new_normals.size());
- for (int l = 0; l < normals.size(); l++) {
- Vector3 *w = new_normals.ptrw();
- w[l] = normals[l];
- }
- array_copy[RenderingServer::ARRAY_NORMAL] = new_normals;
- }
-
- if (ai_mesh->mAnimMeshes[j]->HasTangentsAndBitangents()) {
- PackedColorArray tangents;
- tangents.resize(num_vertices);
- Color *w = tangents.ptrw();
- for (size_t l = 0; l < num_vertices; l++) {
- AssimpUtils::calc_tangent_from_mesh(ai_mesh, j, l, l, w);
- }
- PackedFloat32Array new_tangents = array_copy[RenderingServer::ARRAY_TANGENT].duplicate(true);
- ERR_CONTINUE(new_tangents.size() != tangents.size() * 4);
- for (int32_t l = 0; l < tangents.size(); l++) {
- new_tangents.ptrw()[l + 0] = tangents[l].r;
- new_tangents.ptrw()[l + 1] = tangents[l].g;
- new_tangents.ptrw()[l + 2] = tangents[l].b;
- new_tangents.ptrw()[l + 3] = tangents[l].a;
- }
- array_copy[RenderingServer::ARRAY_TANGENT] = new_tangents;
- }
-
- morphs[j] = array_copy;
- }
- mesh->add_surface_from_arrays(primitive, array_mesh, morphs, Dictionary(), mesh_flags);
- mesh->surface_set_material(i, mat);
- mesh->surface_set_name(i, AssimpUtils::get_assimp_string(ai_mesh->mName));
- }
-
- return mesh;
-}
-
-/**
- * Create a new mesh for the node supplied
- */
-MeshInstance3D *
-EditorSceneImporterAssimp::create_mesh(ImportState &state, const aiNode *assimp_node, const String &node_name, Node *active_node, Transform node_transform) {
- /* MESH NODE */
- Ref<Mesh> mesh;
- Ref<Skin> skin;
- // see if we have mesh cache for this.
- Vector<int> surface_indices;
-
- RegenerateBoneStack(state);
-
- // Configure indices
- for (uint32_t i = 0; i < assimp_node->mNumMeshes; i++) {
- int mesh_index = assimp_node->mMeshes[i];
- // create list of mesh indexes
- surface_indices.push_back(mesh_index);
- }
-
- //surface_indices.sort();
- String mesh_key;
- for (int i = 0; i < surface_indices.size(); i++) {
- if (i > 0) {
- mesh_key += ":";
- }
- mesh_key += itos(surface_indices[i]);
- }
-
- Skeleton3D *skeleton = nullptr;
- aiNode *armature = nullptr;
-
- if (!state.mesh_cache.has(mesh_key)) {
- mesh = _generate_mesh_from_surface_indices(state, surface_indices, assimp_node, skin, skeleton);
- state.mesh_cache[mesh_key] = mesh;
- }
-
- MeshInstance3D *mesh_node = memnew(MeshInstance3D);
- mesh = state.mesh_cache[mesh_key];
- mesh_node->set_mesh(mesh);
-
- // if we have a valid skeleton set it up
- if (skin.is_valid()) {
- for (uint32_t i = 0; i < assimp_node->mNumMeshes; i++) {
- unsigned int mesh_index = assimp_node->mMeshes[i];
- const aiMesh *ai_mesh = state.assimp_scene->mMeshes[mesh_index];
-
- // please remember bone id relative to the skin is NOT the mesh relative index.
- // it is the index relative to the skeleton that is why
- // we have state.bone_id_map, it allows for duplicate bone id's too :)
- // hope this makes sense
-
- int bind_count = 0;
- for (unsigned int boneId = 0; boneId < ai_mesh->mNumBones; ++boneId) {
- aiBone *iterBone = ai_mesh->mBones[boneId];
-
- // used to reparent mesh to the correct armature later on if assigned.
- if (!armature) {
- print_verbose("Configured mesh armature, will reparent later to armature");
- armature = iterBone->mArmature;
- }
-
- if (skeleton) {
- int id = skeleton->find_bone(AssimpUtils::get_assimp_string(iterBone->mName));
- if (id != -1) {
- print_verbose("Set bind bone: mesh: " + itos(mesh_index) + " bone index: " + itos(id));
- Transform t = AssimpUtils::assimp_matrix_transform(iterBone->mOffsetMatrix);
-
- skin->add_bind(bind_count, t);
- skin->set_bind_bone(bind_count, id);
- bind_count++;
- }
- }
- }
- }
-
- print_verbose("Finished configuring bind pose for skin mesh");
- }
-
- // this code parents all meshes with bones to the armature they are for
- // GLTF2 specification relies on this and we are enforcing it for FBX.
- if (armature && state.flat_node_map[armature]) {
- Node *armature_parent = state.flat_node_map[armature];
- print_verbose("Parented mesh " + node_name + " to armature " + armature_parent->get_name());
- // static mesh handling
- armature_parent->add_child(mesh_node);
- // transform must be identity
- mesh_node->set_global_transform(Transform());
- mesh_node->set_name(node_name);
- mesh_node->set_owner(state.root);
- } else {
- // static mesh handling
- active_node->add_child(mesh_node);
- mesh_node->set_global_transform(node_transform);
- mesh_node->set_name(node_name);
- mesh_node->set_owner(state.root);
- }
-
- if (skeleton) {
- print_verbose("Attempted to set skeleton path!");
- mesh_node->set_skeleton_path(mesh_node->get_path_to(skeleton));
- mesh_node->set_skin(skin);
- }
-
- return mesh_node;
-}
-
-/**
- * Create a light for the scene
- * Automatically caches lights for lookup later
- */
-Node3D *EditorSceneImporterAssimp::create_light(
- ImportState &state,
- const String &node_name,
- Transform &look_at_transform) {
- Light3D *light = nullptr;
- aiLight *assimp_light = state.assimp_scene->mLights[state.light_cache[node_name]];
- ERR_FAIL_COND_V(!assimp_light, nullptr);
-
- if (assimp_light->mType == aiLightSource_DIRECTIONAL) {
- light = memnew(DirectionalLight3D);
- } else if (assimp_light->mType == aiLightSource_POINT) {
- light = memnew(OmniLight3D);
- } else if (assimp_light->mType == aiLightSource_SPOT) {
- light = memnew(SpotLight3D);
- }
- ERR_FAIL_COND_V(light == nullptr, nullptr);
-
- if (assimp_light->mType != aiLightSource_POINT) {
- Vector3 pos = Vector3(
- assimp_light->mPosition.x,
- assimp_light->mPosition.y,
- assimp_light->mPosition.z);
- Vector3 look_at = Vector3(
- assimp_light->mDirection.y,
- assimp_light->mDirection.x,
- assimp_light->mDirection.z)
- .normalized();
- Vector3 up = Vector3(
- assimp_light->mUp.x,
- assimp_light->mUp.y,
- assimp_light->mUp.z);
-
- look_at_transform.set_look_at(pos, look_at, up);
- }
- // properties for light variables should be put here.
- // not really hugely important yet but we will need them in the future
-
- light->set_color(
- Color(assimp_light->mColorDiffuse.r, assimp_light->mColorDiffuse.g, assimp_light->mColorDiffuse.b));
-
- return light;
-}
-
-/**
- * Create camera for the scene
- */
-Node3D *EditorSceneImporterAssimp::create_camera(
- ImportState &state,
- const String &node_name,
- Transform &look_at_transform) {
- aiCamera *camera = state.assimp_scene->mCameras[state.camera_cache[node_name]];
- ERR_FAIL_COND_V(!camera, nullptr);
-
- Camera3D *camera_node = memnew(Camera3D);
- ERR_FAIL_COND_V(!camera_node, nullptr);
- float near = camera->mClipPlaneNear;
- if (Math::is_equal_approx(near, 0.0f)) {
- near = 0.1f;
- }
- camera_node->set_perspective(Math::rad2deg(camera->mHorizontalFOV) * 2.0f, near, camera->mClipPlaneFar);
- Vector3 pos = Vector3(camera->mPosition.x, camera->mPosition.y, camera->mPosition.z);
- Vector3 look_at = Vector3(camera->mLookAt.y, camera->mLookAt.x, camera->mLookAt.z).normalized();
- Vector3 up = Vector3(camera->mUp.x, camera->mUp.y, camera->mUp.z);
-
- look_at_transform.set_look_at(pos + look_at_transform.origin, look_at, up);
- return camera_node;
-}
-
-/**
- * Generate node
- * Recursive call to iterate over all nodes
- */
-void EditorSceneImporterAssimp::_generate_node(
- ImportState &state,
- const aiNode *assimp_node) {
- ERR_FAIL_COND(assimp_node == nullptr);
- state.nodes.push_back(assimp_node);
- String parent_name = AssimpUtils::get_assimp_string(assimp_node->mParent->mName);
-
- // please note
- // duplicate bone names exist
- // this is why we only check if the bone exists
- // so everything else is useless but the name
- // please do not copy any other values from get_bone_by_name.
- aiBone *parent_bone = get_bone_by_name(state.assimp_scene, assimp_node->mParent->mName);
- aiBone *current_bone = get_bone_by_name(state.assimp_scene, assimp_node->mName);
-
- // is this an armature
- // parent null
- // and this is the first bone :)
- if (parent_bone == nullptr && current_bone) {
- state.armature_nodes.push_back(assimp_node->mParent);
- print_verbose("found valid armature: " + parent_name);
- }
-
- for (size_t i = 0; i < assimp_node->mNumChildren; i++) {
- _generate_node(state, assimp_node->mChildren[i]);
- }
-}
diff --git a/modules/assimp/editor_scene_importer_assimp.h b/modules/assimp/editor_scene_importer_assimp.h
deleted file mode 100644
index 7be80c4ad0..0000000000
--- a/modules/assimp/editor_scene_importer_assimp.h
+++ /dev/null
@@ -1,149 +0,0 @@
-/*************************************************************************/
-/* editor_scene_importer_assimp.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_ASSIMP_H
-#define EDITOR_SCENE_IMPORTER_ASSIMP_H
-
-#ifdef TOOLS_ENABLED
-#include "core/bind/core_bind.h"
-#include "core/io/resource_importer.h"
-#include "core/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 <assimp/matrix4x4.h>
-#include <assimp/scene.h>
-#include <assimp/types.h>
-#include <assimp/DefaultLogger.hpp>
-#include <assimp/LogStream.hpp>
-#include <assimp/Logger.hpp>
-#include <map>
-
-#include "import_state.h"
-#include "import_utils.h"
-
-using namespace AssimpImporter;
-
-class AssimpStream : public Assimp::LogStream {
-public:
- // Constructor
- AssimpStream() {}
-
- // Destructor
- ~AssimpStream() {}
- // Write something using your own functionality
- void write(const char *message) {
- print_verbose(String("Open Asset Import: ") + String(message).strip_edges());
- }
-};
-
-class EditorSceneImporterAssimp : public EditorSceneImporter {
-private:
- GDCLASS(EditorSceneImporterAssimp, EditorSceneImporter);
-
- struct AssetImportAnimation {
- enum Interpolation {
- INTERP_LINEAR,
- INTERP_STEP,
- INTERP_CATMULLROMSPLINE,
- INTERP_CUBIC_SPLINE
- };
- };
-
- struct BoneInfo {
- uint32_t bone;
- float weight;
- };
-
- Ref<Mesh> _generate_mesh_from_surface_indices(ImportState &state, const Vector<int> &p_surface_indices,
- const aiNode *assimp_node, Ref<Skin> &skin,
- Skeleton3D *&skeleton_assigned);
-
- // simple object creation functions
- Node3D *create_light(ImportState &state,
- const String &node_name,
- Transform &look_at_transform);
- Node3D *create_camera(
- ImportState &state,
- const String &node_name,
- Transform &look_at_transform);
- // non recursive - linear so must not use recursive arguments
- MeshInstance3D *create_mesh(ImportState &state, const aiNode *assimp_node, const String &node_name, Node *active_node, Transform node_transform);
- // recursive node generator
- void _generate_node(ImportState &state, const aiNode *assimp_node);
- void _insert_animation_track(ImportState &scene, const aiAnimation *assimp_anim, int track_id,
- int anim_fps, Ref<Animation> animation, float ticks_per_second,
- Skeleton3D *skeleton, const NodePath &node_path,
- const String &node_name, aiBone *track_bone);
-
- void _import_animation(ImportState &state, int p_animation_index, int p_bake_fps);
- Node *get_node_by_name(ImportState &state, String name);
- aiBone *get_bone_from_stack(ImportState &state, aiString name);
- Node3D *_generate_scene(const String &p_path, aiScene *scene, const uint32_t p_flags, int p_bake_fps, const int32_t p_max_bone_weights);
-
- template <class T>
- T _interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, float p_time, AssetImportAnimation::Interpolation p_interp);
- 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;
-
- struct ImportFormat {
- Vector<String> extensions;
- bool is_default;
- };
-
-protected:
- static void _bind_methods();
-
-public:
- EditorSceneImporterAssimp() {
- Assimp::DefaultLogger::create("", Assimp::Logger::VERBOSE);
- unsigned int severity = Assimp::Logger::Info | Assimp::Logger::Err | Assimp::Logger::Warn;
- Assimp::DefaultLogger::get()->attachStream(new AssimpStream(), severity);
- }
- ~EditorSceneImporterAssimp() {
- Assimp::DefaultLogger::kill();
- }
-
- virtual void get_extensions(List<String> *r_extensions) const override;
- virtual uint32_t get_import_flags() const override;
- virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override;
- Ref<Image> load_image(ImportState &state, const aiScene *p_scene, String p_path);
-
- static void RegenerateBoneStack(ImportState &state);
-
- void RegenerateBoneStack(ImportState &state, aiMesh *mesh);
-};
-#endif
-#endif
diff --git a/modules/assimp/godot_update_assimp.sh b/modules/assimp/godot_update_assimp.sh
deleted file mode 100755
index ff8ff59e97..0000000000
--- a/modules/assimp/godot_update_assimp.sh
+++ /dev/null
@@ -1,262 +0,0 @@
-rm -rf ../../thirdparty/assimp
-cd ../../thirdparty/
-git clone https://github.com/assimp/assimp.git
-cd assimp
-rm -rf code/3DSExporter.h
-rm -rf code/3DSLoader.h
-rm -rf code/3MFXmlTags.h
-rm -rf code/ABCImporter.h
-rm -rf code/ACLoader.h
-rm -rf code/AMFImporter_Macro.hpp
-rm -rf code/ASELoader.h
-rm -rf code/assbin_chunks.h
-rm -rf code/AssbinExporter.h
-rm -rf code/AssbinLoader.h
-rm -rf code/AssimpCExport.cpp
-rm -rf code/AssxmlExporter.h
-rm -rf code/B3DImporter.h
-# rm -rf code/BaseProcess.cpp
-# rm -rf code/BaseProcess.h
-# rm -rf code/Bitmap.cpp
-rm -rf code/BlenderBMesh.cpp
-rm -rf code/BlenderBMesh.h
-rm -rf code/BlenderCustomData.cpp
-rm -rf code/BlenderCustomData.h
-rm -rf code/BlenderIntermediate.h
-rm -rf code/BlenderLoader.h
-rm -rf code/BlenderModifier.h
-rm -rf code/BlenderSceneGen.h
-rm -rf code/BlenderTessellator.h
-rm -rf code/BVHLoader.h
-rm -rf code/C4DImporter.h
-# rm -rf code/CalcTangentsProcess.h
-# rm -rf code/CInterfaceIOWrapper.cpp
-# rm -rf code/CInterfaceIOWrapper.h
-rm -rf code/COBLoader.h
-rm -rf code/COBScene.h
-rm -rf code/ColladaExporter.h
-rm -rf code/ColladaLoader.h
-# rm -rf code/ComputeUVMappingProcess.h
-# rm -rf code/ConvertToLHProcess.h
-# rm -rf code/CreateAnimMesh.cpp
-rm -rf code/CSMLoader.h
-rm -rf code/D3MFExporter.h
-rm -rf code/D3MFImporter.h
-rm -rf code/D3MFOpcPackage.h
-# rm -rf code/DeboneProcess.h
-# rm -rf code/DefaultIOStream.cpp
-# rm -rf code/DefaultIOSystem.cpp
-# rm -rf code/DefaultProgressHandler.h
-# rm -rf code/DropFaceNormalsProcess.cpp
-# rm -rf code/DropFaceNormalsProcess.h
-rm -rf code/DXFHelper.h
-rm -rf code/DXFLoader.h
-# rm -rf code/EmbedTexturesProcess.cpp
-# rm -rf code/EmbedTexturesProcess.h
-# rm -rf code/FBXCommon.h
-# rm -rf code/FBXCompileConfig.h
-# rm -rf code/FBXDeformer.cpp
-# rm -rf code/FBXDocumentUtil.cpp
-# rm -rf code/FBXDocumentUtil.h
-# rm -rf code/FBXExporter.h
-# rm -rf code/FBXExportNode.h
-# rm -rf code/FBXExportProperty.h
-# rm -rf code/FBXImporter.cpp
-# rm -rf code/FBXImporter.h
-# rm -rf code/FBXImportSettings.h
-# rm -rf code/FBXMeshGeometry.h
-# rm -rf code/FBXModel.cpp
-# rm -rf code/FBXNodeAttribute.cpp
-# rm -rf code/FBXParser.h
-# rm -rf code/FBXProperties.cpp
-# rm -rf code/FBXProperties.h
-# rm -rf code/FBXTokenizer.cpp
-# rm -rf code/FBXTokenizer.h
-# rm -rf code/FBXUtil.cpp
-# rm -rf code/FBXUtil.h
-# rm -rf code/FileLogStream.h
-# rm -rf code/FindDegenerates.h
-# rm -rf code/FindInstancesProcess.h
-# rm -rf code/FindInvalidDataProcess.h
-rm -rf code/FIReader.hpp
-# rm -rf code/FixNormalsStep.cpp
-# rm -rf code/FixNormalsStep.h
-# rm -rf code/GenFaceNormalsProcess.cpp
-# rm -rf code/GenFaceNormalsProcess.h
-# rm -rf code/GenVertexNormalsProcess.cpp
-# rm -rf code/GenVertexNormalsProcess.h
-rm -rf code/glTF2Asset.h
-rm -rf code/glTF2Asset.inl
-rm -rf code/glTF2AssetWriter.inl
-rm -rf code/glTF2Exporter.cpp
-rm -rf code/glTF2Importer.cpp
-rm -rf code/glTF2AssetWriter.h
-rm -rf code/glTFAsset.h
-rm -rf code/glTFAsset.inl
-rm -rf code/glTFAssetWriter.inl
-rm -rf code/glTFExporter.cpp
-rm -rf code/glTFImporter.cpp
-rm -rf code/glTF2Exporter.h
-rm -rf code/glTF2Importer.h
-rm -rf code/glTFAssetWriter.h
-rm -rf code/glTFExporter.h
-rm -rf code/glTFImporter.h
-rm -rf code/HalfLifeFileData.h
-rm -rf code/HMPFileData.h
-rm -rf code/HMPLoader.h
-rm -rf code/HMPLoader.cpp
-rm -rf code/IFF.h
-# rm -rf code/Importer.h
-# rm -rf code/ImproveCacheLocality.h
-rm -rf code/IRRLoader.h
-rm -rf code/IRRMeshLoader.h
-rm -rf code/IRRShared.h
-# rm -rf code/JoinVerticesProcess.h
-# rm -rf code/LimitBoneWeightsProcess.cpp
-# rm -rf code/LimitBoneWeightsProcess.h
-rm -rf code/LWSLoader.h
-rm -rf code/makefile.mingw
-# rm -rf code/MakeVerboseFormat.cpp
-# rm -rf code/MakeVerboseFormat.h
-# rm -rf code/MaterialSystem.h
-rm -rf code/MD2FileData.h
-rm -rf code/MD2Loader.h
-rm -rf code/MD2NormalTable.h
-rm -rf code/MD3FileData.h
-rm -rf code/MD3Loader.h
-rm -rf code/MD4FileData.h
-rm -rf code/MD5Loader.h
-rm -rf code/MD5Parser.cpp
-rm -rf code/MDCFileData.h
-rm -rf code/MDCLoader.h
-rm -rf code/MDLDefaultColorMap.h
-# rm -rf code/MMDCpp14.h
-# rm -rf code/MMDImporter.h
-rm -rf code/MS3DLoader.h
-rm -rf code/NDOLoader.h
-rm -rf code/NFFLoader.h
-rm -rf code/ObjExporter.h
-rm -rf code/ObjFileImporter.h
-rm -rf code/ObjFileMtlImporter.h
-rm -rf code/ObjFileParser.h
-rm -rf code/ObjTools.h
-rm -rf code/ObjExporter.cpp
-rm -rf code/ObjFileImporter.cpp
-rm -rf code/ObjFileMtlImporter.cpp
-rm -rf code/ObjFileParser.cpp
-rm -rf code/OFFLoader.h
-rm -rf code/OFFLoader.cpp
-rm -rf code/OgreImporter.cpp
-rm -rf code/OgreImporter.h
-rm -rf code/OgreParsingUtils.h
-rm -rf code/OgreXmlSerializer.h
-rm -rf code/OgreXmlSerializer.cpp
-rm -rf code/OgreBinarySerializer.cpp
-rm -rf code/OpenGEXExporter.cpp
-rm -rf code/OpenGEXExporter.h
-rm -rf code/OpenGEXImporter.h
-rm -rf code/OpenGEXStructs.h
-rm -rf code/OpenGEXImporter.cpp
-# rm -rf code/OptimizeGraph.h
-# rm -rf code/OptimizeMeshes.cpp
-# rm -rf code/OptimizeMeshes.h
-rm -rf code/PlyExporter.h
-rm -rf code/PlyLoader.h
-# rm -rf code/PolyTools.h
-# rm -rf code/PostStepRegistry.cpp
-# rm -rf code/PretransformVertices.h
-rm -rf code/Q3BSPFileData.h
-rm -rf code/Q3BSPFileImporter.h
-rm -rf code/Q3BSPFileParser.cpp
-rm -rf code/Q3BSPFileParser.h
-rm -rf code/Q3BSPZipArchive.cpp
-rm -rf code/Q3BSPZipArchive.h
-rm -rf code/Q3DLoader.h
-rm -rf code/Q3DLoader.cpp
-rm -rf code/Q3BSPFileImporter.cpp
-rm -rf code/RawLoader.h
-# rm -rf code/RemoveComments.cpp
-# rm -rf code/RemoveRedundantMaterials.cpp
-# rm -rf code/RemoveRedundantMaterials.h
-# rm -rf code/RemoveVCProcess.h
-# rm -rf code/ScaleProcess.cpp
-# rm -rf code/ScaleProcess.h
-# rm -rf code/scene.cpp
-# rm -rf code/ScenePreprocessor.cpp
-# rm -rf code/ScenePreprocessor.h
-# rm -rf code/ScenePrivate.h
-# rm -rf code/SGSpatialSort.cpp
-rm -rf code/SIBImporter.h
-rm -rf code/SMDLoader.cpp
-# rm -rf code/simd.cpp
-# rm -rf code/simd.h
-# rm -rf code/SortByPTypeProcess.h
-# rm -rf code/SplitByBoneCountProcess.h
-# rm -rf code/SplitLargeMeshes.h
-# rm -rf code/StdOStreamLogStream.h
-rm -rf code/StepExporter.h
-rm -rf code/StepExporter.cpp
-rm -rf code/STLExporter.cpp
-rm -rf code/STLExporter.h
-rm -rf code/STLLoader.h
-rm -rf code/STLLoader.cpp
-# rm -rf code/TargetAnimation.cpp
-# rm -rf code/TargetAnimation.h
-rm -rf code/TerragenLoader.h
-rm -rf code/TerragenLoader.cpp
-# rm -rf code/TextureTransform.h
-# rm -rf code/TriangulateProcess.h
-rm -rf code/UnrealLoader.h
-# rm -rf code/ValidateDataStructure.h
-# rm -rf code/Version.cpp
-# rm -rf code/VertexTriangleAdjacency.cpp
-# rm -rf code/VertexTriangleAdjacency.h
-# rm -rf code/Win32DebugLogStream.h
-rm -rf code/X3DImporter_Macro.hpp
-rm -rf code/X3DImporter_Metadata.cpp
-rm -rf code/X3DImporter_Networking.cpp
-rm -rf code/X3DImporter_Texturing.cpp
-rm -rf code/X3DImporter_Shape.cpp
-rm -rf code/X3DImporter_Rendering.cpp
-rm -rf code/X3DImporter_Postprocess.cpp
-rm -rf code/X3DImporter_Light.cpp
-rm -rf code/X3DImporter_Group.cpp
-rm -rf code/X3DImporter_Geometry3D.cpp
-rm -rf code/X3DImporter_Geometry2D.cpp
-rm -rf code/X3DImporter.cpp
-rm -rf code/X3DExporter.cpp
-rm -rf code/X3DVocabulary.cpp
-rm -rf code/XFileExporter.h
-rm -rf code/XFileExporter.cpp
-rm -rf code/XFileHelper.h
-rm -rf code/XFileHelper.cpp
-rm -rf code/XFileImporter.h
-rm -rf code/XFileImporter.cpp
-rm -rf code/XFileParser.h
-rm -rf code/XFileParser.cpp
-rm -rf code/XGLLoader.h
-rm -rf code/XGLLoader.cpp
-rm -rf code/Importer
-rm -rf .git
-rm -rf cmake-modules
-rm -rf doc
-rm -rf packaging
-rm -rf port
-rm -rf samples
-rm -rf scripts
-rm -rf test
-rm -rf tools
-rm -rf contrib/zlib
-rm -rf contrib/android-cmake
-rm -rf contrib/gtest
-rm -rf contrib/clipper
-rm -rf contrib/irrXML
-rm -rf contrib/Open3DGC
-rm -rf contrib/openddlparser
-rm -rf contrib/poly2tri
-#rm -rf contrib/rapidjson
-rm -rf contrib/unzip
-rm -rf contrib/zip
-rm -rf contrib/stb_image
-rm .travis*
-
diff --git a/modules/assimp/import_state.h b/modules/assimp/import_state.h
deleted file mode 100644
index ee22800ac4..0000000000
--- a/modules/assimp/import_state.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/*************************************************************************/
-/* import_state.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_IMPORT_STATE_H
-#define EDITOR_SCENE_IMPORT_STATE_H
-
-#include "core/bind/core_bind.h"
-#include "core/io/resource_importer.h"
-#include "core/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 <assimp/matrix4x4.h>
-#include <assimp/scene.h>
-#include <assimp/types.h>
-#include <assimp/DefaultLogger.hpp>
-#include <assimp/LogStream.hpp>
-#include <assimp/Logger.hpp>
-
-namespace AssimpImporter {
-/** Import state is for global scene import data
- * This makes the code simpler and contains useful lookups.
- */
-struct ImportState {
- String path;
- Node3D *root;
- const aiScene *assimp_scene;
- uint32_t max_bone_weights;
-
- Map<String, Ref<Mesh>> mesh_cache;
- Map<int, Ref<Material>> material_cache;
- Map<String, int> light_cache;
- Map<String, int> camera_cache;
-
- // very useful for when you need to ask assimp for the bone mesh
-
- Map<const aiNode *, Node *> assimp_node_map;
- Map<String, Ref<Image>> path_to_image_cache;
-
- // Generation 3 - determinisitic iteration
- // to lower potential recursion errors
- List<const aiNode *> nodes;
- Map<const aiNode *, Node3D *> flat_node_map;
- AnimationPlayer *animation_player;
-
- // Generation 3 - deterministic armatures
- // list of armature nodes - flat and simple to parse
- // assimp node, node in godot
- List<aiNode *> armature_nodes;
- Map<const aiNode *, Skeleton3D *> armature_skeletons;
- Map<aiBone *, Skeleton3D *> skeleton_bone_map;
- // Generation 3 - deterministic bone handling
- // bones from the stack are popped when found
- // this means we can detect
- // what bones are for other armatures
- List<aiBone *> bone_stack;
-
- // EditorSceneImporter::ImportFlags
- uint32_t import_flags;
-};
-
-struct AssimpImageData {
- Ref<Image> raw_image;
- Ref<ImageTexture> texture;
- aiTextureMapMode map_mode[2];
-};
-
-/** Recursive state is used to push state into functions instead of specifying them
- * This makes the code easier to handle too and add extra arguments without breaking things
- */
-struct RecursiveState {
- RecursiveState() {} // do not construct :)
- RecursiveState(
- Transform &_node_transform,
- Skeleton3D *_skeleton,
- Node3D *_new_node,
- String &_node_name,
- aiNode *_assimp_node,
- Node *_parent_node,
- aiBone *_bone) :
- node_transform(_node_transform),
- skeleton(_skeleton),
- new_node(_new_node),
- node_name(_node_name),
- assimp_node(_assimp_node),
- parent_node(_parent_node),
- bone(_bone) {}
-
- Transform node_transform;
- Skeleton3D *skeleton = nullptr;
- Node3D *new_node = nullptr;
- String node_name;
- aiNode *assimp_node = nullptr;
- Node *parent_node = nullptr;
- aiBone *bone = nullptr;
-};
-} // namespace AssimpImporter
-
-#endif // EDITOR_SCENE_IMPORT_STATE_H
diff --git a/modules/assimp/import_utils.h b/modules/assimp/import_utils.h
deleted file mode 100644
index dc85d06fed..0000000000
--- a/modules/assimp/import_utils.h
+++ /dev/null
@@ -1,463 +0,0 @@
-/*************************************************************************/
-/* import_utils.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_IMPORTER_ASSIMP_H
-#define IMPORT_UTILS_IMPORTER_ASSIMP_H
-
-#include "core/io/image_loader.h"
-#include "import_state.h"
-
-#include <assimp/SceneCombiner.h>
-#include <assimp/cexport.h>
-#include <assimp/cimport.h>
-#include <assimp/matrix4x4.h>
-#include <assimp/pbrmaterial.h>
-#include <assimp/postprocess.h>
-#include <assimp/scene.h>
-#include <assimp/DefaultLogger.hpp>
-#include <assimp/Importer.hpp>
-#include <assimp/LogStream.hpp>
-#include <assimp/Logger.hpp>
-#include <string>
-
-using namespace AssimpImporter;
-
-#define AI_PROPERTIES aiTextureType_UNKNOWN, 0
-#define AI_NULL 0, 0
-#define AI_MATKEY_FBX_MAYA_BASE_COLOR_FACTOR "$raw.Maya|baseColor"
-#define AI_MATKEY_FBX_MAYA_METALNESS_FACTOR "$raw.Maya|metalness"
-#define AI_MATKEY_FBX_MAYA_DIFFUSE_ROUGHNESS_FACTOR "$raw.Maya|diffuseRoughness"
-
-#define AI_MATKEY_FBX_MAYA_EMISSION_TEXTURE "$raw.Maya|emissionColor|file"
-#define AI_MATKEY_FBX_MAYA_EMISSIVE_FACTOR "$raw.Maya|emission"
-#define AI_MATKEY_FBX_MAYA_METALNESS_TEXTURE "$raw.Maya|metalness|file"
-#define AI_MATKEY_FBX_MAYA_METALNESS_UV_XFORM "$raw.Maya|metalness|uvtrafo"
-#define AI_MATKEY_FBX_MAYA_DIFFUSE_ROUGHNESS_TEXTURE "$raw.Maya|diffuseRoughness|file"
-#define AI_MATKEY_FBX_MAYA_DIFFUSE_ROUGHNESS_UV_XFORM "$raw.Maya|diffuseRoughness|uvtrafo"
-#define AI_MATKEY_FBX_MAYA_BASE_COLOR_TEXTURE "$raw.Maya|baseColor|file"
-#define AI_MATKEY_FBX_MAYA_BASE_COLOR_UV_XFORM "$raw.Maya|baseColor|uvtrafo"
-#define AI_MATKEY_FBX_MAYA_NORMAL_TEXTURE "$raw.Maya|normalCamera|file"
-#define AI_MATKEY_FBX_MAYA_NORMAL_UV_XFORM "$raw.Maya|normalCamera|uvtrafo"
-
-#define AI_MATKEY_FBX_NORMAL_TEXTURE "$raw.Maya|normalCamera|file"
-#define AI_MATKEY_FBX_NORMAL_UV_XFORM "$raw.Maya|normalCamera|uvtrafo"
-
-#define AI_MATKEY_FBX_MAYA_STINGRAY_DISPLACEMENT_SCALING_FACTOR "$raw.Maya|displacementscaling"
-#define AI_MATKEY_FBX_MAYA_STINGRAY_BASE_COLOR_FACTOR "$raw.Maya|base_color"
-#define AI_MATKEY_FBX_MAYA_STINGRAY_EMISSIVE_FACTOR "$raw.Maya|emissive"
-#define AI_MATKEY_FBX_MAYA_STINGRAY_METALLIC_FACTOR "$raw.Maya|metallic"
-#define AI_MATKEY_FBX_MAYA_STINGRAY_ROUGHNESS_FACTOR "$raw.Maya|roughness"
-#define AI_MATKEY_FBX_MAYA_STINGRAY_EMISSIVE_INTENSITY_FACTOR "$raw.Maya|emissive_intensity"
-
-#define AI_MATKEY_FBX_MAYA_STINGRAY_NORMAL_TEXTURE "$raw.Maya|TEX_normal_map|file"
-#define AI_MATKEY_FBX_MAYA_STINGRAY_NORMAL_UV_XFORM "$raw.Maya|TEX_normal_map|uvtrafo"
-#define AI_MATKEY_FBX_MAYA_STINGRAY_COLOR_TEXTURE "$raw.Maya|TEX_color_map|file"
-#define AI_MATKEY_FBX_MAYA_STINGRAY_COLOR_UV_XFORM "$raw.Maya|TEX_color_map|uvtrafo"
-#define AI_MATKEY_FBX_MAYA_STINGRAY_METALLIC_TEXTURE "$raw.Maya|TEX_metallic_map|file"
-#define AI_MATKEY_FBX_MAYA_STINGRAY_METALLIC_UV_XFORM "$raw.Maya|TEX_metallic_map|uvtrafo"
-#define AI_MATKEY_FBX_MAYA_STINGRAY_ROUGHNESS_TEXTURE "$raw.Maya|TEX_roughness_map|file"
-#define AI_MATKEY_FBX_MAYA_STINGRAY_ROUGHNESS_UV_XFORM "$raw.Maya|TEX_roughness_map|uvtrafo"
-#define AI_MATKEY_FBX_MAYA_STINGRAY_EMISSIVE_TEXTURE "$raw.Maya|TEX_emissive_map|file"
-#define AI_MATKEY_FBX_MAYA_STINGRAY_EMISSIVE_UV_XFORM "$raw.Maya|TEX_emissive_map|uvtrafo"
-#define AI_MATKEY_FBX_MAYA_STINGRAY_AO_TEXTURE "$raw.Maya|TEX_ao_map|file"
-#define AI_MATKEY_FBX_MAYA_STINGRAY_AO_UV_XFORM "$raw.Maya|TEX_ao_map|uvtrafo"
-
-/**
- * Assimp Utils
- * Conversion tools / glue code to convert from assimp to godot
-*/
-class AssimpUtils {
-public:
- /**
- * calculate tangents for mesh data from assimp data
- */
- static void calc_tangent_from_mesh(const aiMesh *ai_mesh, int i, int tri_index, int index, Color *w) {
- const aiVector3D normals = ai_mesh->mAnimMeshes[i]->mNormals[tri_index];
- const Vector3 godot_normal = Vector3(normals.x, normals.y, normals.z);
- const aiVector3D tangent = ai_mesh->mAnimMeshes[i]->mTangents[tri_index];
- const Vector3 godot_tangent = Vector3(tangent.x, tangent.y, tangent.z);
- const aiVector3D bitangent = ai_mesh->mAnimMeshes[i]->mBitangents[tri_index];
- const Vector3 godot_bitangent = Vector3(bitangent.x, bitangent.y, bitangent.z);
- float d = godot_normal.cross(godot_tangent).dot(godot_bitangent) > 0.0f ? 1.0f : -1.0f;
- Color plane_tangent = Color(tangent.x, tangent.y, tangent.z, d);
- w[index] = plane_tangent;
- }
-
- 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 assimp string
- * automatically filters the string data
- */
- static String get_assimp_string(const aiString &p_string) {
- //convert an assimp String to a Godot String
- String name;
- name.parse_utf8(p_string.C_Str() /*,p_string.length*/);
- if (name.find(":") != -1) {
- String replaced_name = name.split(":")[1];
- print_verbose("Replacing " + name + " containing : with " + replaced_name);
- name = replaced_name;
- }
-
- return name;
- }
-
- static String get_anim_string_from_assimp(const aiString &p_string) {
- String name;
- name.parse_utf8(p_string.C_Str() /*,p_string.length*/);
- if (name.find(":") != -1) {
- String replaced_name = name.split(":")[1];
- print_verbose("Replacing " + name + " containing : with " + replaced_name);
- name = replaced_name;
- }
- return name;
- }
-
- /**
- * No filter logic get_raw_string_from_assimp
- * This just convers the aiString to a parsed utf8 string
- * Without removing special chars etc
- */
- static String get_raw_string_from_assimp(const aiString &p_string) {
- String name;
- name.parse_utf8(p_string.C_Str() /*,p_string.length*/);
- return name;
- }
-
- static Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) {
- return Ref<Animation>();
- }
-
- /**
- * Converts aiMatrix4x4 to godot Transform
- */
- static const Transform assimp_matrix_transform(const aiMatrix4x4 p_matrix) {
- aiMatrix4x4 matrix = p_matrix;
- Transform xform;
- xform.set(matrix.a1, matrix.a2, matrix.a3, matrix.b1, matrix.b2, matrix.b3, matrix.c1, matrix.c2, matrix.c3, matrix.a4, matrix.b4, matrix.c4);
- return xform;
- }
-
- /** Get fbx fps for time mode meta data
- */
- static float get_fbx_fps(int32_t time_mode, const aiScene *p_scene) {
- switch (time_mode) {
- case AssetImportFbx::TIME_MODE_DEFAULT:
- return 24; //hack
- 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:
- int32_t frame_rate = -1;
- p_scene->mMetaData->Get("FrameRate", frame_rate);
- return frame_rate;
- }
- return 0;
- }
-
- /**
- * Get global transform for the current node - so we can use world space rather than
- * local space coordinates
- * useful if you need global - although recommend using local wherever possible over global
- * as you could break fbx scaling :)
- */
- static Transform _get_global_assimp_node_transform(const aiNode *p_current_node) {
- aiNode const *current_node = p_current_node;
- Transform xform;
- while (current_node != nullptr) {
- xform = assimp_matrix_transform(current_node->mTransformation) * xform;
- current_node = current_node->mParent;
- }
- return xform;
- }
-
- /**
- * Find hardcoded textures from assimp which could be in many different directories
- */
- static void find_texture_path(const String &p_path, _Directory &dir, String &path, bool &found, String extension) {
- Vector<String> paths;
- paths.push_back(path.get_basename() + extension);
- paths.push_back(path + extension);
- paths.push_back(path);
- paths.push_back(p_path.get_base_dir().plus_file(path.get_file().get_basename() + extension));
- paths.push_back(p_path.get_base_dir().plus_file(path.get_file() + extension));
- paths.push_back(p_path.get_base_dir().plus_file(path.get_file()));
- paths.push_back(p_path.get_base_dir().plus_file("textures/" + path.get_file().get_basename() + extension));
- paths.push_back(p_path.get_base_dir().plus_file("textures/" + path.get_file() + extension));
- paths.push_back(p_path.get_base_dir().plus_file("textures/" + path.get_file()));
- paths.push_back(p_path.get_base_dir().plus_file("Textures/" + path.get_file().get_basename() + extension));
- paths.push_back(p_path.get_base_dir().plus_file("Textures/" + path.get_file() + extension));
- paths.push_back(p_path.get_base_dir().plus_file("Textures/" + path.get_file()));
- paths.push_back(p_path.get_base_dir().plus_file("../Textures/" + path.get_file() + extension));
- paths.push_back(p_path.get_base_dir().plus_file("../Textures/" + path.get_file().get_basename() + extension));
- paths.push_back(p_path.get_base_dir().plus_file("../Textures/" + path.get_file()));
- paths.push_back(p_path.get_base_dir().plus_file("../textures/" + path.get_file().get_basename() + extension));
- paths.push_back(p_path.get_base_dir().plus_file("../textures/" + path.get_file() + extension));
- paths.push_back(p_path.get_base_dir().plus_file("../textures/" + path.get_file()));
- paths.push_back(p_path.get_base_dir().plus_file("texture/" + path.get_file().get_basename() + extension));
- paths.push_back(p_path.get_base_dir().plus_file("texture/" + path.get_file() + extension));
- paths.push_back(p_path.get_base_dir().plus_file("texture/" + path.get_file()));
- paths.push_back(p_path.get_base_dir().plus_file("Texture/" + path.get_file().get_basename() + extension));
- paths.push_back(p_path.get_base_dir().plus_file("Texture/" + path.get_file() + extension));
- paths.push_back(p_path.get_base_dir().plus_file("Texture/" + path.get_file()));
- paths.push_back(p_path.get_base_dir().plus_file("../Texture/" + path.get_file() + extension));
- paths.push_back(p_path.get_base_dir().plus_file("../Texture/" + path.get_file().get_basename() + extension));
- paths.push_back(p_path.get_base_dir().plus_file("../Texture/" + path.get_file()));
- paths.push_back(p_path.get_base_dir().plus_file("../texture/" + path.get_file().get_basename() + extension));
- paths.push_back(p_path.get_base_dir().plus_file("../texture/" + path.get_file() + extension));
- paths.push_back(p_path.get_base_dir().plus_file("../texture/" + path.get_file()));
- for (int i = 0; i < paths.size(); i++) {
- if (dir.file_exists(paths[i])) {
- found = true;
- path = paths[i];
- return;
- }
- }
- }
-
- /** find the texture path for the supplied fbx path inside godot
- * very simple lookup for subfolders etc for a texture which may or may not be in a directory
- */
- static void find_texture_path(const String &r_p_path, String &r_path, bool &r_found) {
- _Directory dir;
-
- List<String> exts;
- ImageLoader::get_recognized_extensions(&exts);
-
- Vector<String> split_path = r_path.get_basename().split("*");
- if (split_path.size() == 2) {
- r_found = true;
- return;
- }
-
- if (dir.file_exists(r_p_path.get_base_dir() + r_path.get_file())) {
- r_path = r_p_path.get_base_dir() + r_path.get_file();
- r_found = true;
- return;
- }
-
- for (int32_t i = 0; i < exts.size(); i++) {
- if (r_found) {
- return;
- }
- find_texture_path(r_p_path, dir, r_path, r_found, "." + exts[i]);
- }
- }
-
- /**
- * 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);
- // FIXME: Commented out during Vulkan port.
- /*
- aiTextureMapMode tex_mode = map_mode[0];
-
- int32_t flags = Texture2D::FLAGS_DEFAULT;
- if (tex_mode == aiTextureMapMode_Wrap) {
- //Default
- } else if (tex_mode == aiTextureMapMode_Clamp) {
- flags = flags & ~Texture2D::FLAG_REPEAT;
- } else if (tex_mode == aiTextureMapMode_Mirror) {
- flags = flags | Texture2D::FLAG_MIRRORED_REPEAT;
- }
- texture->set_flags(flags);
- */
- }
-
- /**
- * Load or load from cache image :)
- */
- 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")) {
- ERR_FAIL_COND_V(Image::_png_mem_loader_func == nullptr, Ref<Image>());
- Ref<Image> img = Image::_png_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth);
- ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
- state.path_to_image_cache.insert(p_path, img);
- return img;
- } else if (tex->CheckFormat("jpg")) {
- ERR_FAIL_COND_V(Image::_jpg_mem_loader_func == nullptr, Ref<Image>());
- Ref<Image> img = Image::_jpg_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth);
- ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
- state.path_to_image_cache.insert(p_path, img);
- 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.instance();
- PackedByteArray arr;
- uint32_t size = tex->mWidth * tex->mHeight;
- arr.resize(size);
- memcpy(arr.ptrw(), 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.ptrw()[(4 * i) + 3] = arr[(4 * i) + 0];
- arr.ptrw()[(4 * i) + 0] = arr[(4 * i) + 1];
- arr.ptrw()[(4 * i) + 1] = arr[(4 * i) + 2];
- arr.ptrw()[(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<Texture2D> texture = ResourceLoader::load(p_path);
- ERR_FAIL_COND_V(texture.is_null(), Ref<Image>());
- Ref<Image> image = texture->get_data();
- 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.instance();
- image_state.texture->create_from_image(image_state.raw_image);
- // FIXME: Commented out during Vulkan port.
- //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;
- }
-};
-
-#endif // IMPORT_UTILS_IMPORTER_ASSIMP_H
diff --git a/modules/basis_universal/SCsub b/modules/basis_universal/SCsub
index dc7b176d24..351628a0e3 100644
--- a/modules/basis_universal/SCsub
+++ b/modules/basis_universal/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_basisu = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
# Not unbundled so far since not widespread as shared library
thirdparty_dir = "#thirdparty/basis_universal/"
tool_sources = [
@@ -41,8 +44,16 @@ if env["target"] == "debug":
env_thirdparty = env_basisu.Clone()
env_thirdparty.disable_warnings()
if env["tools"]:
- env_thirdparty.add_source_files(env.modules_sources, tool_sources)
-env_thirdparty.add_source_files(env.modules_sources, transcoder_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, tool_sources)
+env_thirdparty.add_source_files(thirdparty_obj, transcoder_sources)
+env.modules_sources += thirdparty_obj
# Godot source files
-env_basisu.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_basisu.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/basis_universal/register_types.cpp b/modules/basis_universal/register_types.cpp
index 27b299a65d..cf5581265b 100644
--- a/modules/basis_universal/register_types.cpp
+++ b/modules/basis_universal/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -216,7 +216,7 @@ static Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) {
format = basist::transcoder_texture_format::cTFETC2; // get this from renderer
imgfmt = Image::FORMAT_ETC2_RGBA8;
} else {
- //gles2 most likely, bad for normalmaps, nothing to do about this.
+ //gles2 most likely, bad for normal maps, nothing to do about this.
format = basist::transcoder_texture_format::cTFRGBA32;
imgfmt = Image::FORMAT_RGBA8;
}
diff --git a/modules/basis_universal/register_types.h b/modules/basis_universal/register_types.h
index 5053dc27ce..30b465e344 100644
--- a/modules/basis_universal/register_types.h
+++ b/modules/basis_universal/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/basis_universal/texture_basisu.cpp b/modules/basis_universal/texture_basisu.cpp
index 2ed0340927..66eb81d7f2 100644
--- a/modules/basis_universal/texture_basisu.cpp
+++ b/modules/basis_universal/texture_basisu.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -39,44 +39,36 @@
#include <transcoder/basisu_transcoder.h>
void TextureBasisU::_bind_methods() {
-
ClassDB::bind_method(D_METHOD("set_basisu_data", "data"), &TextureBasisU::set_basisu_data);
ClassDB::bind_method(D_METHOD("get_basisu_data"), &TextureBasisU::get_data);
ClassDB::bind_method(D_METHOD("import"), &TextureBasisU::import);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "basisu_data"), "set_basisu_data", "get_basisu_data");
-
};
int TextureBasisU::get_width() const {
-
return tex_size.x;
};
int TextureBasisU::get_height() const {
-
return tex_size.y;
};
RID TextureBasisU::get_rid() const {
-
return texture;
};
bool TextureBasisU::has_alpha() const {
-
return false;
};
void TextureBasisU::set_flags(uint32_t p_flags) {
-
flags = p_flags;
RenderingServer::get_singleton()->texture_set_flags(texture, p_flags);
};
uint32_t TextureBasisU::get_flags() const {
-
return flags;
};
@@ -95,12 +87,10 @@ void TextureBasisU::set_basisu_data(const Vector<uint8_t>& p_data) {
Image::Format imgfmt;
if (OS::get_singleton()->has_feature("s3tc")) {
-
format = basist::cTFBC3; // get this from renderer
imgfmt = Image::FORMAT_DXT5;
} else if (OS::get_singleton()->has_feature("etc2")) {
-
format = basist::cTFETC2;
imgfmt = Image::FORMAT_ETC2_RGBA8;
};
@@ -126,7 +116,6 @@ void TextureBasisU::set_basisu_data(const Vector<uint8_t>& p_data) {
int ofs = 0;
tr.start_transcoding(ptr, size);
for (int i=0; i<info.m_total_levels; i++) {
-
basist::basisu_image_level_info level;
tr.get_image_level_info(ptr, size, level, 0, i);
@@ -214,19 +203,16 @@ Error TextureBasisU::import(const Ref<Image>& p_img) {
Vector<uint8_t> TextureBasisU::get_basisu_data() const {
-
return data;
};
TextureBasisU::TextureBasisU() {
-
flags = FLAGS_DEFAULT;
texture = RenderingServer::get_singleton()->texture_create();
};
TextureBasisU::~TextureBasisU() {
-
RenderingServer::get_singleton()->free(texture);
};
diff --git a/modules/basis_universal/texture_basisu.h b/modules/basis_universal/texture_basisu.h
index 20ecf15a59..0a4783eaff 100644
--- a/modules/basis_universal/texture_basisu.h
+++ b/modules/basis_universal/texture_basisu.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -41,7 +41,6 @@
#if 0
class TextureBasisU : public Texture {
-
GDCLASS(TextureBasisU, Texture);
RES_BASE_EXTENSION("butex");
@@ -74,7 +73,6 @@ public:
TextureBasisU();
~TextureBasisU();
-
};
#endif
diff --git a/modules/bmp/image_loader_bmp.cpp b/modules/bmp/image_loader_bmp.cpp
index 757afeb9e3..c7fdf56af4 100644
--- a/modules/bmp/image_loader_bmp.cpp
+++ b/modules/bmp/image_loader_bmp.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,6 +30,8 @@
#include "image_loader_bmp.h"
+#include "core/io/file_access_memory.h"
+
Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image,
const uint8_t *p_buffer,
const uint8_t *p_color_buffer,
@@ -293,9 +295,21 @@ Error ImageLoaderBMP::load_image(Ref<Image> p_image, FileAccess *f,
return err;
}
-void ImageLoaderBMP::get_recognized_extensions(
- List<String> *p_extensions) const {
+void ImageLoaderBMP::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("bmp");
}
-ImageLoaderBMP::ImageLoaderBMP() {}
+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);
+ ERR_FAIL_COND_V_MSG(open_memfile_error, Ref<Image>(), "Could not create memfile for BMP image buffer.");
+ Ref<Image> img;
+ img.instance();
+ 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;
+}
+
+ImageLoaderBMP::ImageLoaderBMP() {
+ Image::_bmp_mem_loader_func = _bmp_mem_loader_func;
+}
diff --git a/modules/bmp/image_loader_bmp.h b/modules/bmp/image_loader_bmp.h
index 3f10a1c598..d3f12f0115 100644
--- a/modules/bmp/image_loader_bmp.h
+++ b/modules/bmp/image_loader_bmp.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bmp/register_types.cpp b/modules/bmp/register_types.cpp
index 6220e956d6..d36ce9cdaf 100644
--- a/modules/bmp/register_types.cpp
+++ b/modules/bmp/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bmp/register_types.h b/modules/bmp/register_types.h
index e7561dc32d..3ce81eba1b 100644
--- a/modules/bmp/register_types.h
+++ b/modules/bmp/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/SCsub b/modules/bullet/SCsub
index 21bdcca18e..bfac0df5b0 100644
--- a/modules/bullet/SCsub
+++ b/modules/bullet/SCsub
@@ -7,6 +7,8 @@ env_bullet = env_modules.Clone()
# Thirdparty source files
+thirdparty_obj = []
+
if env["builtin_bullet"]:
# Build only version 2 for now (as of 2.89)
# Sync file list with relevant upstream CMakeLists.txt for each folder.
@@ -208,8 +210,16 @@ if env["builtin_bullet"]:
env_thirdparty = env_bullet.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
# Godot source files
-env_bullet.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_bullet.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/bullet/area_bullet.cpp b/modules/bullet/area_bullet.cpp
index f8f7d79a11..c3bd84c329 100644
--- a/modules/bullet/area_bullet.cpp
+++ b/modules/bullet/area_bullet.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/area_bullet.h b/modules/bullet/area_bullet.h
index c0bcc858fe..a5fa678fec 100644
--- a/modules/bullet/area_bullet.h
+++ b/modules/bullet/area_bullet.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,7 +32,7 @@
#define AREABULLET_H
#include "collision_object_bullet.h"
-#include "core/vector.h"
+#include "core/templates/vector.h"
#include "servers/physics_server_3d.h"
#include "space_bullet.h"
diff --git a/modules/bullet/btRayShape.cpp b/modules/bullet/btRayShape.cpp
index a754ca6a89..1568cca63d 100644
--- a/modules/bullet/btRayShape.cpp
+++ b/modules/bullet/btRayShape.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/btRayShape.h b/modules/bullet/btRayShape.h
index d9ecde81e6..dcc4cc79c7 100644
--- a/modules/bullet/btRayShape.h
+++ b/modules/bullet/btRayShape.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp
index 8f64c11867..9144a781a0 100644
--- a/modules/bullet/bullet_physics_server.cpp
+++ b/modules/bullet/bullet_physics_server.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,9 +32,9 @@
#include "bullet_utilities.h"
#include "cone_twist_joint_bullet.h"
-#include "core/class_db.h"
-#include "core/error_macros.h"
-#include "core/ustring.h"
+#include "core/error/error_macros.h"
+#include "core/object/class_db.h"
+#include "core/string/ustring.h"
#include "generic_6dof_joint_bullet.h"
#include "hinge_joint_bullet.h"
#include "pin_joint_bullet.h"
@@ -625,14 +625,14 @@ uint32_t BulletPhysicsServer3D::body_get_user_flags(RID p_body) const {
return 0;
}
-void BulletPhysicsServer3D::body_set_param(RID p_body, BodyParameter p_param, float p_value) {
+void BulletPhysicsServer3D::body_set_param(RID p_body, BodyParameter p_param, real_t p_value) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_param(p_param, p_value);
}
-float BulletPhysicsServer3D::body_get_param(RID p_body, BodyParameter p_param) const {
+real_t BulletPhysicsServer3D::body_get_param(RID p_body, BodyParameter p_param) const {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0);
@@ -807,11 +807,11 @@ int BulletPhysicsServer3D::body_get_max_contacts_reported(RID p_body) const {
return body->get_max_collisions_detection();
}
-void BulletPhysicsServer3D::body_set_contacts_reported_depth_threshold(RID p_body, float p_threshold) {
+void BulletPhysicsServer3D::body_set_contacts_reported_depth_threshold(RID p_body, real_t p_threshold) {
// Not supported by bullet and even Godot
}
-float BulletPhysicsServer3D::body_get_contacts_reported_depth_threshold(RID p_body) const {
+real_t BulletPhysicsServer3D::body_get_contacts_reported_depth_threshold(RID p_body) const {
// Not supported by bullet and even Godot
return 0.;
}
@@ -862,7 +862,7 @@ bool BulletPhysicsServer3D::body_test_motion(RID p_body, const Transform &p_from
return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, r_result, p_exclude_raycast_shapes);
}
-int BulletPhysicsServer3D::body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, float p_margin) {
+int BulletPhysicsServer3D::body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0);
ERR_FAIL_COND_V(!body->get_space(), 0);
@@ -1221,7 +1221,7 @@ RID BulletPhysicsServer3D::joint_create_pin(RID p_body_A, const Vector3 &p_local
CreateThenReturnRID(joint_owner, joint);
}
-void BulletPhysicsServer3D::pin_joint_set_param(RID p_joint, PinJointParam p_param, float p_value) {
+void BulletPhysicsServer3D::pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
ERR_FAIL_COND(joint->get_type() != JOINT_PIN);
@@ -1229,7 +1229,7 @@ void BulletPhysicsServer3D::pin_joint_set_param(RID p_joint, PinJointParam p_par
pin_joint->set_param(p_param, p_value);
}
-float BulletPhysicsServer3D::pin_joint_get_param(RID p_joint, PinJointParam p_param) const {
+real_t BulletPhysicsServer3D::pin_joint_get_param(RID p_joint, PinJointParam p_param) const {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!joint, 0);
ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, 0);
@@ -1309,7 +1309,7 @@ RID BulletPhysicsServer3D::joint_create_hinge_simple(RID p_body_A, const Vector3
CreateThenReturnRID(joint_owner, joint);
}
-void BulletPhysicsServer3D::hinge_joint_set_param(RID p_joint, HingeJointParam p_param, float p_value) {
+void BulletPhysicsServer3D::hinge_joint_set_param(RID p_joint, HingeJointParam p_param, real_t p_value) {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
ERR_FAIL_COND(joint->get_type() != JOINT_HINGE);
@@ -1317,7 +1317,7 @@ void BulletPhysicsServer3D::hinge_joint_set_param(RID p_joint, HingeJointParam p
hinge_joint->set_param(p_param, p_value);
}
-float BulletPhysicsServer3D::hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const {
+real_t BulletPhysicsServer3D::hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!joint, 0);
ERR_FAIL_COND_V(joint->get_type() != JOINT_HINGE, 0);
@@ -1361,7 +1361,7 @@ RID BulletPhysicsServer3D::joint_create_slider(RID p_body_A, const Transform &p_
CreateThenReturnRID(joint_owner, joint);
}
-void BulletPhysicsServer3D::slider_joint_set_param(RID p_joint, SliderJointParam p_param, float p_value) {
+void BulletPhysicsServer3D::slider_joint_set_param(RID p_joint, SliderJointParam p_param, real_t p_value) {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
ERR_FAIL_COND(joint->get_type() != JOINT_SLIDER);
@@ -1369,7 +1369,7 @@ void BulletPhysicsServer3D::slider_joint_set_param(RID p_joint, SliderJointParam
slider_joint->set_param(p_param, p_value);
}
-float BulletPhysicsServer3D::slider_joint_get_param(RID p_joint, SliderJointParam p_param) const {
+real_t BulletPhysicsServer3D::slider_joint_get_param(RID p_joint, SliderJointParam p_param) const {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!joint, 0);
ERR_FAIL_COND_V(joint->get_type() != JOINT_SLIDER, 0);
@@ -1395,7 +1395,7 @@ RID BulletPhysicsServer3D::joint_create_cone_twist(RID p_body_A, const Transform
CreateThenReturnRID(joint_owner, joint);
}
-void BulletPhysicsServer3D::cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, float p_value) {
+void BulletPhysicsServer3D::cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, real_t p_value) {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
ERR_FAIL_COND(joint->get_type() != JOINT_CONE_TWIST);
@@ -1403,7 +1403,7 @@ void BulletPhysicsServer3D::cone_twist_joint_set_param(RID p_joint, ConeTwistJoi
coneTwist_joint->set_param(p_param, p_value);
}
-float BulletPhysicsServer3D::cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const {
+real_t BulletPhysicsServer3D::cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!joint, 0.);
ERR_FAIL_COND_V(joint->get_type() != JOINT_CONE_TWIST, 0.);
@@ -1431,7 +1431,7 @@ RID BulletPhysicsServer3D::joint_create_generic_6dof(RID p_body_A, const Transfo
CreateThenReturnRID(joint_owner, joint);
}
-void BulletPhysicsServer3D::generic_6dof_joint_set_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param, float p_value) {
+void BulletPhysicsServer3D::generic_6dof_joint_set_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param, real_t p_value) {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
ERR_FAIL_COND(joint->get_type() != JOINT_6DOF);
@@ -1439,7 +1439,7 @@ void BulletPhysicsServer3D::generic_6dof_joint_set_param(RID p_joint, Vector3::A
generic_6dof_joint->set_param(p_axis, p_param, p_value);
}
-float BulletPhysicsServer3D::generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param) {
+real_t BulletPhysicsServer3D::generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param) {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!joint, 0);
ERR_FAIL_COND_V(joint->get_type() != JOINT_6DOF, 0);
@@ -1463,22 +1463,6 @@ bool BulletPhysicsServer3D::generic_6dof_joint_get_flag(RID p_joint, Vector3::Ax
return generic_6dof_joint->get_flag(p_axis, p_flag);
}
-void BulletPhysicsServer3D::generic_6dof_joint_set_precision(RID p_joint, int p_precision) {
- JointBullet *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND(!joint);
- ERR_FAIL_COND(joint->get_type() != JOINT_6DOF);
- Generic6DOFJointBullet *generic_6dof_joint = static_cast<Generic6DOFJointBullet *>(joint);
- generic_6dof_joint->set_precision(p_precision);
-}
-
-int BulletPhysicsServer3D::generic_6dof_joint_get_precision(RID p_joint) {
- JointBullet *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND_V(!joint, 0);
- ERR_FAIL_COND_V(joint->get_type() != JOINT_6DOF, 0);
- Generic6DOFJointBullet *generic_6dof_joint = static_cast<Generic6DOFJointBullet *>(joint);
- return generic_6dof_joint->get_precision();
-}
-
void BulletPhysicsServer3D::free(RID p_rid) {
if (shape_owner.owns(p_rid)) {
ShapeBullet *shape = shape_owner.getornull(p_rid);
@@ -1541,7 +1525,7 @@ void BulletPhysicsServer3D::init() {
BulletPhysicsDirectBodyState3D::initSingleton();
}
-void BulletPhysicsServer3D::step(float p_deltaTime) {
+void BulletPhysicsServer3D::step(real_t p_deltaTime) {
if (!active) {
return;
}
@@ -1553,9 +1537,6 @@ void BulletPhysicsServer3D::step(float p_deltaTime) {
}
}
-void BulletPhysicsServer3D::sync() {
-}
-
void BulletPhysicsServer3D::flush_queries() {
if (!active) {
return;
diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h
index 6078babaf8..f2740c9c75 100644
--- a/modules/bullet/bullet_physics_server.h
+++ b/modules/bullet/bullet_physics_server.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,8 +32,8 @@
#define BULLET_PHYSICS_SERVER_H
#include "area_bullet.h"
-#include "core/rid.h"
-#include "core/rid_owner.h"
+#include "core/templates/rid.h"
+#include "core/templates/rid_owner.h"
#include "joint_bullet.h"
#include "rigid_body_bullet.h"
#include "servers/physics_server_3d.h"
@@ -207,8 +207,8 @@ public:
/// This is not supported by physics server
virtual uint32_t body_get_user_flags(RID p_body) const override;
- virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value) override;
- virtual float body_get_param(RID p_body, BodyParameter p_param) const override;
+ virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value) override;
+ virtual real_t body_get_param(RID p_body, BodyParameter p_param) const override;
virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin) override;
virtual real_t body_get_kinematic_safe_margin(RID p_body) const override;
@@ -241,8 +241,8 @@ public:
virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) override;
virtual int body_get_max_contacts_reported(RID p_body) const override;
- virtual void body_set_contacts_reported_depth_threshold(RID p_body, float p_threshold) override;
- virtual float body_get_contacts_reported_depth_threshold(RID p_body) const override;
+ virtual void body_set_contacts_reported_depth_threshold(RID p_body, real_t p_threshold) override;
+ virtual real_t body_get_contacts_reported_depth_threshold(RID p_body) const override;
virtual void body_set_omit_force_integration(RID p_body, bool p_omit) override;
virtual bool body_is_omitting_force_integration(RID p_body) const override;
@@ -256,7 +256,7 @@ public:
virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override;
virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override;
- virtual int body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, float p_margin = 0.001) override;
+ virtual int body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override;
/* SOFT BODY API */
@@ -337,8 +337,8 @@ public:
virtual RID joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) override;
- virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, float p_value) override;
- virtual float pin_joint_get_param(RID p_joint, PinJointParam p_param) const override;
+ virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) override;
+ virtual real_t pin_joint_get_param(RID p_joint, PinJointParam p_param) const override;
virtual void pin_joint_set_local_a(RID p_joint, const Vector3 &p_A) override;
virtual Vector3 pin_joint_get_local_a(RID p_joint) const override;
@@ -349,8 +349,8 @@ public:
virtual RID joint_create_hinge(RID p_body_A, const Transform &p_hinge_A, RID p_body_B, const Transform &p_hinge_B) override;
virtual RID joint_create_hinge_simple(RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) override;
- virtual void hinge_joint_set_param(RID p_joint, HingeJointParam p_param, float p_value) override;
- virtual float hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const override;
+ virtual void hinge_joint_set_param(RID p_joint, HingeJointParam p_param, real_t p_value) override;
+ virtual real_t hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const override;
virtual void hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_value) override;
virtual bool hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const override;
@@ -358,27 +358,24 @@ public:
/// Reference frame is A
virtual RID joint_create_slider(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override;
- virtual void slider_joint_set_param(RID p_joint, SliderJointParam p_param, float p_value) override;
- virtual float slider_joint_get_param(RID p_joint, SliderJointParam p_param) const override;
+ virtual void slider_joint_set_param(RID p_joint, SliderJointParam p_param, real_t p_value) override;
+ virtual real_t slider_joint_get_param(RID p_joint, SliderJointParam p_param) const override;
/// Reference frame is A
virtual RID joint_create_cone_twist(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override;
- virtual void cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, float p_value) override;
- virtual float cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const override;
+ virtual void cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, real_t p_value) override;
+ virtual real_t cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const override;
/// Reference frame is A
virtual RID joint_create_generic_6dof(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override;
- virtual void generic_6dof_joint_set_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param, float p_value) override;
- virtual float generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param) override;
+ virtual void generic_6dof_joint_set_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param, real_t p_value) override;
+ virtual real_t generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param) override;
virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag, bool p_enable) override;
virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag) override;
- virtual void generic_6dof_joint_set_precision(RID p_joint, int precision) override;
- virtual int generic_6dof_joint_get_precision(RID p_joint) override;
-
/* MISC */
virtual void free(RID p_rid) override;
@@ -396,8 +393,7 @@ public:
}
virtual void init() override;
- virtual void step(float p_deltaTime) override;
- virtual void sync() override;
+ virtual void step(real_t p_deltaTime) override;
virtual void flush_queries() override;
virtual void finish() override;
diff --git a/modules/bullet/bullet_types_converter.cpp b/modules/bullet/bullet_types_converter.cpp
index 09b90fe09e..7b21e4e4b2 100644
--- a/modules/bullet/bullet_types_converter.cpp
+++ b/modules/bullet/bullet_types_converter.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/bullet_types_converter.h b/modules/bullet/bullet_types_converter.h
index fef07c55b7..ca9b7175dd 100644
--- a/modules/bullet/bullet_types_converter.h
+++ b/modules/bullet/bullet_types_converter.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/bullet_utilities.h b/modules/bullet/bullet_utilities.h
index a5e33d9829..a7c0fafbea 100644
--- a/modules/bullet/bullet_utilities.h
+++ b/modules/bullet/bullet_utilities.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/collision_object_bullet.cpp b/modules/bullet/collision_object_bullet.cpp
index a3158a15e5..bce8ec8076 100644
--- a/modules/bullet/collision_object_bullet.cpp
+++ b/modules/bullet/collision_object_bullet.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/collision_object_bullet.h b/modules/bullet/collision_object_bullet.h
index f1423a69e4..bea28f2183 100644
--- a/modules/bullet/collision_object_bullet.h
+++ b/modules/bullet/collision_object_bullet.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,8 +33,8 @@
#include "core/math/transform.h"
#include "core/math/vector3.h"
-#include "core/object.h"
-#include "core/vset.h"
+#include "core/object/class_db.h"
+#include "core/templates/vset.h"
#include "shape_owner_bullet.h"
#include <LinearMath/btTransform.h>
diff --git a/modules/bullet/cone_twist_joint_bullet.cpp b/modules/bullet/cone_twist_joint_bullet.cpp
index b4735fa9e9..e785780c5b 100644
--- a/modules/bullet/cone_twist_joint_bullet.cpp
+++ b/modules/bullet/cone_twist_joint_bullet.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/cone_twist_joint_bullet.h b/modules/bullet/cone_twist_joint_bullet.h
index ed4baa9d1b..7d6bafd292 100644
--- a/modules/bullet/cone_twist_joint_bullet.h
+++ b/modules/bullet/cone_twist_joint_bullet.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/constraint_bullet.cpp b/modules/bullet/constraint_bullet.cpp
index c47a23e75f..e610727685 100644
--- a/modules/bullet/constraint_bullet.cpp
+++ b/modules/bullet/constraint_bullet.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/constraint_bullet.h b/modules/bullet/constraint_bullet.h
index 538808be51..6afd8c9b52 100644
--- a/modules/bullet/constraint_bullet.h
+++ b/modules/bullet/constraint_bullet.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/generic_6dof_joint_bullet.cpp b/modules/bullet/generic_6dof_joint_bullet.cpp
index 56a66dba45..43ad6c56d5 100644
--- a/modules/bullet/generic_6dof_joint_bullet.cpp
+++ b/modules/bullet/generic_6dof_joint_bullet.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -273,11 +273,3 @@ bool Generic6DOFJointBullet::get_flag(Vector3::Axis p_axis, PhysicsServer3D::G6D
ERR_FAIL_INDEX_V(p_axis, 3, false);
return flags[p_axis][p_flag];
}
-
-void Generic6DOFJointBullet::set_precision(int p_precision) {
- sixDOFConstraint->setOverrideNumSolverIterations(MAX(1, p_precision));
-}
-
-int Generic6DOFJointBullet::get_precision() const {
- return sixDOFConstraint->getOverrideNumSolverIterations();
-}
diff --git a/modules/bullet/generic_6dof_joint_bullet.h b/modules/bullet/generic_6dof_joint_bullet.h
index 316708bb11..62b8e85a81 100644
--- a/modules/bullet/generic_6dof_joint_bullet.h
+++ b/modules/bullet/generic_6dof_joint_bullet.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -68,9 +68,6 @@ public:
void set_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag, bool p_value);
bool get_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag) const;
-
- void set_precision(int p_precision);
- int get_precision() const;
};
#endif
diff --git a/modules/bullet/godot_collision_configuration.cpp b/modules/bullet/godot_collision_configuration.cpp
index ec7a1dbd9a..94f150b712 100644
--- a/modules/bullet/godot_collision_configuration.cpp
+++ b/modules/bullet/godot_collision_configuration.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/godot_collision_configuration.h b/modules/bullet/godot_collision_configuration.h
index ffad1b1bda..8ed55cb1da 100644
--- a/modules/bullet/godot_collision_configuration.h
+++ b/modules/bullet/godot_collision_configuration.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/godot_collision_dispatcher.cpp b/modules/bullet/godot_collision_dispatcher.cpp
index d919c85469..5d1e4d34d8 100644
--- a/modules/bullet/godot_collision_dispatcher.cpp
+++ b/modules/bullet/godot_collision_dispatcher.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/godot_collision_dispatcher.h b/modules/bullet/godot_collision_dispatcher.h
index 5a96268ee9..77472a9432 100644
--- a/modules/bullet/godot_collision_dispatcher.h
+++ b/modules/bullet/godot_collision_dispatcher.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,7 +31,7 @@
#ifndef GODOT_COLLISION_DISPATCHER_H
#define GODOT_COLLISION_DISPATCHER_H
-#include "core/int_types.h"
+#include <cstdint>
#include <btBulletDynamicsCommon.h>
diff --git a/modules/bullet/godot_motion_state.h b/modules/bullet/godot_motion_state.h
index 90d1614a77..0669d2739a 100644
--- a/modules/bullet/godot_motion_state.h
+++ b/modules/bullet/godot_motion_state.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/godot_ray_world_algorithm.cpp b/modules/bullet/godot_ray_world_algorithm.cpp
index a84f3511ba..a8291d4ab4 100644
--- a/modules/bullet/godot_ray_world_algorithm.cpp
+++ b/modules/bullet/godot_ray_world_algorithm.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/godot_ray_world_algorithm.h b/modules/bullet/godot_ray_world_algorithm.h
index 9786732d40..f705edef81 100644
--- a/modules/bullet/godot_ray_world_algorithm.h
+++ b/modules/bullet/godot_ray_world_algorithm.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp
index f82648d6ff..15d625afeb 100644
--- a/modules/bullet/godot_result_callbacks.cpp
+++ b/modules/bullet/godot_result_callbacks.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/godot_result_callbacks.h b/modules/bullet/godot_result_callbacks.h
index 1325542973..4f40f7ecfd 100644
--- a/modules/bullet/godot_result_callbacks.h
+++ b/modules/bullet/godot_result_callbacks.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/hinge_joint_bullet.cpp b/modules/bullet/hinge_joint_bullet.cpp
index 2338277565..4ceb98729f 100644
--- a/modules/bullet/hinge_joint_bullet.cpp
+++ b/modules/bullet/hinge_joint_bullet.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/hinge_joint_bullet.h b/modules/bullet/hinge_joint_bullet.h
index 120c40e5c0..06a95be374 100644
--- a/modules/bullet/hinge_joint_bullet.h
+++ b/modules/bullet/hinge_joint_bullet.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/joint_bullet.cpp b/modules/bullet/joint_bullet.cpp
index 6257ff0058..ac371658f5 100644
--- a/modules/bullet/joint_bullet.cpp
+++ b/modules/bullet/joint_bullet.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/joint_bullet.h b/modules/bullet/joint_bullet.h
index c70cea817e..5bb8b50961 100644
--- a/modules/bullet/joint_bullet.h
+++ b/modules/bullet/joint_bullet.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/pin_joint_bullet.cpp b/modules/bullet/pin_joint_bullet.cpp
index 1cfbc65c78..8e8ff57f11 100644
--- a/modules/bullet/pin_joint_bullet.cpp
+++ b/modules/bullet/pin_joint_bullet.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/pin_joint_bullet.h b/modules/bullet/pin_joint_bullet.h
index e7d05f34d4..6fbb6f7e02 100644
--- a/modules/bullet/pin_joint_bullet.h
+++ b/modules/bullet/pin_joint_bullet.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/register_types.cpp b/modules/bullet/register_types.cpp
index 009d0dff63..b5ad5749a6 100644
--- a/modules/bullet/register_types.cpp
+++ b/modules/bullet/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,8 +31,8 @@
#include "register_types.h"
#include "bullet_physics_server.h"
-#include "core/class_db.h"
-#include "core/project_settings.h"
+#include "core/config/project_settings.h"
+#include "core/object/class_db.h"
/**
@author AndreaCatania
diff --git a/modules/bullet/register_types.h b/modules/bullet/register_types.h
index 5a01a1422e..e405996705 100644
--- a/modules/bullet/register_types.h
+++ b/modules/bullet/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/rid_bullet.h b/modules/bullet/rid_bullet.h
index 3551ca05f9..0b74a0cc4d 100644
--- a/modules/bullet/rid_bullet.h
+++ b/modules/bullet/rid_bullet.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,7 +31,7 @@
#ifndef RID_BULLET_H
#define RID_BULLET_H
-#include "core/rid.h"
+#include "core/templates/rid.h"
/**
@author AndreaCatania
diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp
index 76c0e0e607..a5093afe9d 100644
--- a/modules/bullet/rigid_body_bullet.cpp
+++ b/modules/bullet/rigid_body_bullet.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -56,11 +56,11 @@ Vector3 BulletPhysicsDirectBodyState3D::get_total_gravity() const {
return gVec;
}
-float BulletPhysicsDirectBodyState3D::get_total_angular_damp() const {
+real_t BulletPhysicsDirectBodyState3D::get_total_angular_damp() const {
return body->btBody->getAngularDamping();
}
-float BulletPhysicsDirectBodyState3D::get_total_linear_damp() const {
+real_t BulletPhysicsDirectBodyState3D::get_total_linear_damp() const {
return body->btBody->getLinearDamping();
}
@@ -74,7 +74,7 @@ Basis BulletPhysicsDirectBodyState3D::get_principal_inertia_axes() const {
return Basis();
}
-float BulletPhysicsDirectBodyState3D::get_inverse_mass() const {
+real_t BulletPhysicsDirectBodyState3D::get_inverse_mass() const {
return body->btBody->getInvMass();
}
@@ -158,7 +158,7 @@ Vector3 BulletPhysicsDirectBodyState3D::get_contact_local_normal(int p_contact_i
return body->collisions[p_contact_idx].hitNormal;
}
-float BulletPhysicsDirectBodyState3D::get_contact_impulse(int p_contact_idx) const {
+real_t BulletPhysicsDirectBodyState3D::get_contact_impulse(int p_contact_idx) const {
return body->collisions[p_contact_idx].appliedImpulse;
}
@@ -264,6 +264,7 @@ RigidBodyBullet::RigidBodyBullet() :
btRigidBody::btRigidBodyConstructionInfo cInfo(mass, godotMotionState, nullptr, localInertia);
btBody = bulletnew(btRigidBody(cInfo));
+ btBody->setFriction(1.0);
reload_shapes();
setupBulletCollisionObject(btBody);
@@ -321,10 +322,8 @@ void RigidBodyBullet::set_space(SpaceBullet *p_space) {
if (space) {
can_integrate_forces = false;
isScratchedSpaceOverrideModificator = false;
-
- // Remove all eventual constraints
- assert_no_constraints();
-
+ // Remove any constraints
+ space->remove_rigid_body_constraints(this);
// Remove this object form the physics world
space->remove_rigid_body(this);
}
@@ -413,7 +412,7 @@ void RigidBodyBullet::on_collision_checker_end() {
isTransformChanged = btBody->isActive() && !btBody->isStaticOrKinematicObject();
}
-bool RigidBodyBullet::add_collision_object(RigidBodyBullet *p_otherObject, const Vector3 &p_hitWorldLocation, const Vector3 &p_hitLocalLocation, const Vector3 &p_hitNormal, const float &p_appliedImpulse, int p_other_shape_index, int p_local_shape_index) {
+bool RigidBodyBullet::add_collision_object(RigidBodyBullet *p_otherObject, const Vector3 &p_hitWorldLocation, const Vector3 &p_hitLocalLocation, const Vector3 &p_hitNormal, const real_t &p_appliedImpulse, int p_other_shape_index, int p_local_shape_index) {
if (collisionsCount >= maxCollisionsDetection) {
return false;
}
@@ -442,12 +441,6 @@ bool RigidBodyBullet::was_colliding(RigidBodyBullet *p_other_object) {
return false;
}
-void RigidBodyBullet::assert_no_constraints() {
- if (btBody->getNumConstraintRefs()) {
- WARN_PRINT("A body with a joints is destroyed. Please check the implementation in order to destroy the joint before the body.");
- }
-}
-
void RigidBodyBullet::set_activation_state(bool p_active) {
if (p_active) {
btBody->activate();
@@ -717,12 +710,12 @@ bool RigidBodyBullet::is_axis_locked(PhysicsServer3D::BodyAxis p_axis) const {
}
void RigidBodyBullet::reload_axis_lock() {
- btBody->setLinearFactor(btVector3(float(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_X)), float(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Y)), float(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Z))));
+ btBody->setLinearFactor(btVector3(btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_X)), btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Y)), btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Z))));
if (PhysicsServer3D::BODY_MODE_CHARACTER == mode) {
/// When character angular is always locked
btBody->setAngularFactor(btVector3(0., 0., 0.));
} else {
- btBody->setAngularFactor(btVector3(float(!is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_X)), float(!is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_Y)), float(!is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_Z))));
+ btBody->setAngularFactor(btVector3(btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_X)), btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_Y)), btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_Z))));
}
}
@@ -743,7 +736,7 @@ void RigidBodyBullet::set_continuous_collision_detection(bool p_enable) {
}
btBody->setCcdSweptSphereRadius(radius * 0.2);
} else {
- btBody->setCcdMotionThreshold(10000.0);
+ btBody->setCcdMotionThreshold(0.);
btBody->setCcdSweptSphereRadius(0.);
}
}
@@ -823,7 +816,7 @@ void RigidBodyBullet::reload_shapes() {
btBody->updateInertiaTensor();
reload_kinematic_shapes();
- set_continuous_collision_detection(btBody->getCcdMotionThreshold() < 9998.0);
+ set_continuous_collision_detection(is_continuous_collision_detection_enabled());
reload_body();
}
diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h
index c643611397..57b80cf50c 100644
--- a/modules/bullet/rigid_body_bullet.h
+++ b/modules/bullet/rigid_body_bullet.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -89,13 +89,13 @@ private:
public:
virtual Vector3 get_total_gravity() const override;
- virtual float get_total_angular_damp() const override;
- virtual float get_total_linear_damp() const override;
+ virtual real_t get_total_angular_damp() const override;
+ virtual real_t get_total_linear_damp() const override;
virtual Vector3 get_center_of_mass() const override;
virtual Basis get_principal_inertia_axes() const override;
// get the mass
- virtual float get_inverse_mass() const override;
+ virtual real_t get_inverse_mass() const override;
// get density of this body space
virtual Vector3 get_inverse_inertia() const override;
// get density of this body space
@@ -124,7 +124,7 @@ public:
virtual Vector3 get_contact_local_position(int p_contact_idx) const override;
virtual Vector3 get_contact_local_normal(int p_contact_idx) const override;
- virtual float get_contact_impulse(int p_contact_idx) const override;
+ virtual real_t get_contact_impulse(int p_contact_idx) const override;
virtual int get_contact_local_shape(int p_contact_idx) const override;
virtual RID get_contact_collider(int p_contact_idx) const override;
@@ -150,7 +150,7 @@ public:
Vector3 hitLocalLocation;
Vector3 hitWorldLocation;
Vector3 hitNormal;
- float appliedImpulse;
+ real_t appliedImpulse;
};
struct ForceIntegrationCallback {
@@ -264,11 +264,9 @@ public:
}
bool can_add_collision() { return collisionsCount < maxCollisionsDetection; }
- bool add_collision_object(RigidBodyBullet *p_otherObject, const Vector3 &p_hitWorldLocation, const Vector3 &p_hitLocalLocation, const Vector3 &p_hitNormal, const float &p_appliedImpulse, int p_other_shape_index, int p_local_shape_index);
+ bool add_collision_object(RigidBodyBullet *p_otherObject, const Vector3 &p_hitWorldLocation, const Vector3 &p_hitLocalLocation, const Vector3 &p_hitNormal, const real_t &p_appliedImpulse, int p_other_shape_index, int p_local_shape_index);
bool was_colliding(RigidBodyBullet *p_other_object);
- void assert_no_constraints();
-
void set_activation_state(bool p_active);
bool is_active() const;
diff --git a/modules/bullet/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp
index 340680c8d9..82876ab77c 100644
--- a/modules/bullet/shape_bullet.cpp
+++ b/modules/bullet/shape_bullet.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,7 +34,7 @@
#include "bullet_physics_server.h"
#include "bullet_types_converter.h"
#include "bullet_utilities.h"
-#include "core/project_settings.h"
+#include "core/config/project_settings.h"
#include "shape_owner_bullet.h"
#include <BulletCollision/CollisionDispatch/btInternalEdgeUtility.h>
@@ -275,7 +275,7 @@ void CapsuleShapeBullet::setup(real_t p_height, real_t p_radius) {
}
btCollisionShape *CapsuleShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
- return prepare(ShapeBullet::create_shape_capsule(radius * p_implicit_scale[0] + p_extra_edge, height * p_implicit_scale[1] + p_extra_edge));
+ return prepare(ShapeBullet::create_shape_capsule(radius * p_implicit_scale[0] + p_extra_edge, height * p_implicit_scale[1]));
}
/* Cylinder */
@@ -480,7 +480,11 @@ void HeightMapShapeBullet::set_data(const Variant &p_data) {
Vector<real_t> l_heights;
Variant l_heights_v = d["heights"];
+#ifdef REAL_T_IS_DOUBLE
+ if (l_heights_v.get_type() == Variant::PACKED_FLOAT64_ARRAY) {
+#else
if (l_heights_v.get_type() == Variant::PACKED_FLOAT32_ARRAY) {
+#endif
// Ready-to-use heights can be passed
l_heights = l_heights_v;
@@ -503,7 +507,7 @@ void HeightMapShapeBullet::set_data(const Variant &p_data) {
real_t *w = l_heights.ptrw();
const uint8_t *r = im_data.ptr();
- float *rp = (float *)r;
+ real_t *rp = (real_t *)r;
// At this point, `rp` could be used directly for Bullet, but I don't know how safe it would be.
for (int i = 0; i < l_heights.size(); ++i) {
@@ -511,7 +515,11 @@ void HeightMapShapeBullet::set_data(const Variant &p_data) {
}
} else {
+#ifdef REAL_T_IS_DOUBLE
+ ERR_FAIL_MSG("Expected PackedFloat64Array or float Image.");
+#else
ERR_FAIL_MSG("Expected PackedFloat32Array or float Image.");
+#endif
}
ERR_FAIL_COND(l_width <= 0);
diff --git a/modules/bullet/shape_bullet.h b/modules/bullet/shape_bullet.h
index a35a1d8a18..63475822de 100644
--- a/modules/bullet/shape_bullet.h
+++ b/modules/bullet/shape_bullet.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,7 +32,7 @@
#define SHAPE_BULLET_H
#include "core/math/geometry_3d.h"
-#include "core/variant.h"
+#include "core/variant/variant.h"
#include "rid_bullet.h"
#include "servers/physics_server_3d.h"
diff --git a/modules/bullet/shape_owner_bullet.cpp b/modules/bullet/shape_owner_bullet.cpp
index d63096d9a3..ea8821eaec 100644
--- a/modules/bullet/shape_owner_bullet.cpp
+++ b/modules/bullet/shape_owner_bullet.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/shape_owner_bullet.h b/modules/bullet/shape_owner_bullet.h
index f909632c99..4bd583e096 100644
--- a/modules/bullet/shape_owner_bullet.h
+++ b/modules/bullet/shape_owner_bullet.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/slider_joint_bullet.cpp b/modules/bullet/slider_joint_bullet.cpp
index 6d5d95d07a..45c892851b 100644
--- a/modules/bullet/slider_joint_bullet.cpp
+++ b/modules/bullet/slider_joint_bullet.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/slider_joint_bullet.h b/modules/bullet/slider_joint_bullet.h
index 6410b952ed..90964671c2 100644
--- a/modules/bullet/slider_joint_bullet.h
+++ b/modules/bullet/slider_joint_bullet.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp
index 6794d6c313..a490179964 100644
--- a/modules/bullet/soft_body_bullet.cpp
+++ b/modules/bullet/soft_body_bullet.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/soft_body_bullet.h b/modules/bullet/soft_body_bullet.h
index da8a2412ed..b15b72daf9 100644
--- a/modules/bullet/soft_body_bullet.h
+++ b/modules/bullet/soft_body_bullet.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp
index c581d1804e..79a5fdb3d2 100644
--- a/modules/bullet/space_bullet.cpp
+++ b/modules/bullet/space_bullet.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,8 +34,8 @@
#include "bullet_types_converter.h"
#include "bullet_utilities.h"
#include "constraint_bullet.h"
-#include "core/project_settings.h"
-#include "core/ustring.h"
+#include "core/config/project_settings.h"
+#include "core/string/ustring.h"
#include "godot_collision_configuration.h"
#include "godot_collision_dispatcher.h"
#include "rigid_body_bullet.h"
@@ -117,7 +117,7 @@ bool BulletPhysicsDirectSpaceState::intersect_ray(const Vector3 &p_from, const V
}
}
-int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Transform &p_xform, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
+int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Transform &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
if (p_result_max <= 0) {
return 0;
}
@@ -152,7 +152,7 @@ int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Tra
return btQuery.m_count;
}
-bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, float p_margin, float &r_closest_safe, float &r_closest_unsafe, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, ShapeRestInfo *r_info) {
+bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &r_closest_safe, real_t &r_closest_unsafe, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, ShapeRestInfo *r_info) {
r_closest_safe = 0.0f;
r_closest_unsafe = 0.0f;
btVector3 bt_motion;
@@ -177,8 +177,10 @@ bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transf
bt_xform_to.getOrigin() += bt_motion;
if ((bt_xform_to.getOrigin() - bt_xform_from.getOrigin()).fuzzyZero()) {
+ r_closest_safe = 1.0f;
+ r_closest_unsafe = 1.0f;
bulletdelete(btShape);
- return false;
+ return true;
}
GodotClosestConvexResultCallback btResult(bt_xform_from.getOrigin(), bt_xform_to.getOrigin(), &p_exclude, p_collide_with_bodies, p_collide_with_areas);
@@ -212,7 +214,7 @@ bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transf
}
/// Returns the list of contacts pairs in this order: Local contact, other body contact
-bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform &p_shape_xform, float p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
+bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
if (p_result_max <= 0) {
return false;
}
@@ -248,7 +250,7 @@ bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform &
return btQuery.m_count;
}
-bool BulletPhysicsDirectSpaceState::rest_info(RID p_shape, const Transform &p_shape_xform, float p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
+bool BulletPhysicsDirectSpaceState::rest_info(RID p_shape, const Transform &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->getornull(p_shape);
ERR_FAIL_COND_V(!shape, false);
@@ -477,11 +479,25 @@ void SpaceBullet::add_rigid_body(RigidBodyBullet *p_body) {
}
}
+void SpaceBullet::remove_rigid_body_constraints(RigidBodyBullet *p_body) {
+ btRigidBody *btBody = p_body->get_bt_rigid_body();
+
+ int constraints = btBody->getNumConstraintRefs();
+ if (constraints > 0) {
+ ERR_PRINT("A body connected to joints was removed.");
+ for (int i = 0; i < constraints; i++) {
+ dynamicsWorld->removeConstraint(btBody->getConstraintRef(i));
+ }
+ }
+}
+
void SpaceBullet::remove_rigid_body(RigidBodyBullet *p_body) {
+ btRigidBody *btBody = p_body->get_bt_rigid_body();
+
if (p_body->is_static()) {
- dynamicsWorld->removeCollisionObject(p_body->get_bt_rigid_body());
+ dynamicsWorld->removeCollisionObject(btBody);
} else {
- dynamicsWorld->removeRigidBody(p_body->get_bt_rigid_body());
+ dynamicsWorld->removeRigidBody(btBody);
}
}
@@ -825,20 +841,32 @@ void SpaceBullet::check_body_collision() {
Vector3 collisionWorldPosition;
Vector3 collisionLocalPosition;
Vector3 normalOnB;
- float appliedImpulse = pt.m_appliedImpulse;
+ real_t appliedImpulse = pt.m_appliedImpulse;
B_TO_G(pt.m_normalWorldOnB, normalOnB);
+ // The pt.m_index only contains the shape index when more than one collision shape is used
+ // and only if the collision shape is not a concave collision shape.
+ // A value of -1 in pt.m_partId indicates the pt.m_index is a shape index.
+ int shape_index_a = 0;
+ if (bodyA->get_shape_count() > 1 && pt.m_partId0 == -1) {
+ shape_index_a = pt.m_index0;
+ }
+ int shape_index_b = 0;
+ if (bodyB->get_shape_count() > 1 && pt.m_partId1 == -1) {
+ shape_index_b = pt.m_index1;
+ }
+
if (bodyA->can_add_collision()) {
B_TO_G(pt.getPositionWorldOnB(), collisionWorldPosition);
/// pt.m_localPointB Doesn't report the exact point in local space
B_TO_G(pt.getPositionWorldOnB() - contactManifold->getBody1()->getWorldTransform().getOrigin(), collisionLocalPosition);
- bodyA->add_collision_object(bodyB, collisionWorldPosition, collisionLocalPosition, normalOnB, appliedImpulse, pt.m_index1, pt.m_index0);
+ bodyA->add_collision_object(bodyB, collisionWorldPosition, collisionLocalPosition, normalOnB, appliedImpulse, shape_index_b, shape_index_a);
}
if (bodyB->can_add_collision()) {
B_TO_G(pt.getPositionWorldOnA(), collisionWorldPosition);
/// pt.m_localPointA Doesn't report the exact point in local space
B_TO_G(pt.getPositionWorldOnA() - contactManifold->getBody0()->getWorldTransform().getOrigin(), collisionLocalPosition);
- bodyB->add_collision_object(bodyA, collisionWorldPosition, collisionLocalPosition, normalOnB * -1, appliedImpulse * -1, pt.m_index0, pt.m_index1);
+ bodyB->add_collision_object(bodyA, collisionWorldPosition, collisionLocalPosition, normalOnB * -1, appliedImpulse * -1, shape_index_a, shape_index_b);
}
#ifdef DEBUG_ENABLED
@@ -1034,7 +1062,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f
return has_penetration;
}
-int SpaceBullet::test_ray_separation(RigidBodyBullet *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, float p_margin) {
+int SpaceBullet::test_ray_separation(RigidBodyBullet *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin) {
btTransform body_transform;
G_TO_B(p_transform, body_transform);
UNSCALE_BT_BASIS(body_transform);
diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h
index de281064af..1caa3c2a0c 100644
--- a/modules/bullet/space_bullet.h
+++ b/modules/bullet/space_bullet.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,8 +31,8 @@
#ifndef SPACE_BULLET_H
#define SPACE_BULLET_H
-#include "core/variant.h"
-#include "core/vector.h"
+#include "core/templates/vector.h"
+#include "core/variant/variant.h"
#include "godot_result_callbacks.h"
#include "rid_bullet.h"
#include "servers/physics_server_3d.h"
@@ -78,11 +78,11 @@ public:
virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_ray = false) override;
- virtual int intersect_shape(const RID &p_shape, const Transform &p_xform, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
- virtual bool cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, float p_margin, float &r_closest_safe, float &r_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr) override;
+ virtual int intersect_shape(const RID &p_shape, const Transform &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
+ virtual bool cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &r_closest_safe, real_t &r_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr) override;
/// Returns the list of contacts pairs in this order: Local contact, other body contact
- virtual bool collide_shape(RID p_shape, const Transform &p_shape_xform, float p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
- virtual bool rest_info(RID p_shape, const Transform &p_shape_xform, float p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
+ virtual bool collide_shape(RID p_shape, const Transform &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
+ virtual bool rest_info(RID p_shape, const Transform &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
virtual Vector3 get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const override;
};
@@ -151,6 +151,7 @@ public:
void reload_collision_filters(AreaBullet *p_area);
void add_rigid_body(RigidBodyBullet *p_body);
+ void remove_rigid_body_constraints(RigidBodyBullet *p_body);
void remove_rigid_body(RigidBodyBullet *p_body);
void reload_collision_filters(RigidBodyBullet *p_body);
@@ -167,7 +168,7 @@ public:
BulletPhysicsDirectSpaceState *get_direct_state();
void set_debug_contacts(int p_amount) { contactDebug.resize(p_amount); }
- _FORCE_INLINE_ bool is_debugging_contacts() const { return !contactDebug.empty(); }
+ _FORCE_INLINE_ bool is_debugging_contacts() const { return !contactDebug.is_empty(); }
_FORCE_INLINE_ void reset_debug_contact_count() {
contactDebugCount = 0;
}
@@ -188,7 +189,7 @@ public:
real_t get_angular_damp() const { return angular_damp; }
bool test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes);
- int test_ray_separation(RigidBodyBullet *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, float p_margin);
+ int test_ray_separation(RigidBodyBullet *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin);
private:
void create_empty_world(bool p_create_soft_world);
diff --git a/modules/camera/SCsub b/modules/camera/SCsub
index 631a65bde2..de97724d09 100644
--- a/modules/camera/SCsub
+++ b/modules/camera/SCsub
@@ -5,17 +5,7 @@ Import("env_modules")
env_camera = env_modules.Clone()
-if env["platform"] == "iphone":
- # (iOS) Enable module support
- env_camera.Append(CCFLAGS=["-fmodules", "-fcxx-modules"])
-
- # (iOS) Build as separate static library
- modules_sources = []
- env_camera.add_source_files(modules_sources, "register_types.cpp")
- env_camera.add_source_files(modules_sources, "camera_ios.mm")
- mod_lib = env_modules.add_library("#bin/libgodot_camera_module" + env["LIBSUFFIX"], modules_sources)
-
-elif env["platform"] == "windows":
+if env["platform"] == "windows":
env_camera.add_source_files(env.modules_sources, "register_types.cpp")
env_camera.add_source_files(env.modules_sources, "camera_win.cpp")
diff --git a/modules/camera/camera_ios.mm b/modules/camera/camera_ios.mm
deleted file mode 100644
index e4cb928805..0000000000
--- a/modules/camera/camera_ios.mm
+++ /dev/null
@@ -1,445 +0,0 @@
-/*************************************************************************/
-/* camera_ios.mm */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-///@TODO this is a near duplicate of CameraOSX, we should find a way to combine those to minimize code duplication!!!!
-// If you fix something here, make sure you fix it there as wel!
-
-#include "camera_ios.h"
-#include "servers/camera/camera_feed.h"
-
-#import <AVFoundation/AVFoundation.h>
-#import <UIKit/UIKit.h>
-
-//////////////////////////////////////////////////////////////////////////
-// MyCaptureSession - This is a little helper class so we can capture our frames
-
-@interface MyCaptureSession : AVCaptureSession <AVCaptureVideoDataOutputSampleBufferDelegate> {
- Ref<CameraFeed> feed;
- size_t width[2];
- size_t height[2];
- Vector<uint8_t> img_data[2];
-
- AVCaptureDeviceInput *input;
- AVCaptureVideoDataOutput *output;
-}
-
-@end
-
-@implementation MyCaptureSession
-
-- (id)initForFeed:(Ref<CameraFeed>)p_feed andDevice:(AVCaptureDevice *)p_device {
- if (self = [super init]) {
- NSError *error;
- feed = p_feed;
- width[0] = 0;
- height[0] = 0;
- width[1] = 0;
- height[1] = 0;
-
- // prepare our device
- [p_device lockForConfiguration:&error];
-
- [p_device setFocusMode:AVCaptureFocusModeLocked];
- [p_device setExposureMode:AVCaptureExposureModeLocked];
- [p_device setWhiteBalanceMode:AVCaptureWhiteBalanceModeLocked];
-
- [p_device unlockForConfiguration];
-
- [self beginConfiguration];
-
- // setup our capture
- self.sessionPreset = AVCaptureSessionPreset1280x720;
-
- input = [AVCaptureDeviceInput deviceInputWithDevice:p_device error:&error];
- if (!input) {
- print_line("Couldn't get input device for camera");
- } else {
- [self addInput:input];
- }
-
- output = [AVCaptureVideoDataOutput new];
- if (!output) {
- print_line("Couldn't get output device for camera");
- } else {
- NSDictionary *settings = @{ (NSString *)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) };
- output.videoSettings = settings;
-
- // discard if the data output queue is blocked (as we process the still image)
- [output setAlwaysDiscardsLateVideoFrames:YES];
-
- // now set ourselves as the delegate to receive new frames. Note that we're doing this on the main thread at the moment, we may need to change this..
- [output setSampleBufferDelegate:self queue:dispatch_get_main_queue()];
-
- [self addOutput:output];
- }
-
- [self commitConfiguration];
-
- // kick off our session..
- [self startRunning];
- };
- return self;
-}
-
-- (void)cleanup {
- // stop running
- [self stopRunning];
-
- // cleanup
- [self beginConfiguration];
-
- if (input) {
- [self removeInput:input];
- // don't release this
- input = nil;
- }
-
- if (output) {
- [self removeOutput:output];
- [output setSampleBufferDelegate:nil queue:NULL];
- output = nil;
- }
-
- [self commitConfiguration];
-}
-
-- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
- // This gets called every time our camera has a new image for us to process.
- // May need to investigate in a way to throttle this if we get more images then we're rendering frames..
-
- // For now, version 1, we're just doing the bare minimum to make this work...
-
- CVImageBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
- // int width = CVPixelBufferGetWidth(pixelBuffer);
- // int height = CVPixelBufferGetHeight(pixelBuffer);
-
- // It says that we need to lock this on the documentation pages but it's not in the samples
- // need to lock our base address so we can access our pixel buffers, better safe then sorry?
- CVPixelBufferLockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);
-
- // get our buffers
- unsigned char *dataY = (unsigned char *)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
- unsigned char *dataCbCr = (unsigned char *)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);
- if (dataY == NULL) {
- print_line("Couldn't access Y pixel buffer data");
- } else if (dataCbCr == NULL) {
- print_line("Couldn't access CbCr pixel buffer data");
- } else {
- UIInterfaceOrientation orientation = UIInterfaceOrientationUnknown;
-
- if (@available(iOS 13, *)) {
- orientation = [UIApplication sharedApplication].delegate.window.windowScene.interfaceOrientation;
-#if !defined(TARGET_OS_SIMULATOR) || !TARGET_OS_SIMULATOR
- } else {
- orientation = [[UIApplication sharedApplication] statusBarOrientation];
-#endif
- }
-
- Ref<Image> img[2];
-
- {
- // do Y
- size_t new_width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 0);
- size_t new_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 0);
-
- if ((width[0] != new_width) || (height[0] != new_height)) {
- width[0] = new_width;
- height[0] = new_height;
- img_data[0].resize(new_width * new_height);
- }
-
- uint8_t *w = img_data[0].ptrw();
- memcpy(w, dataY, new_width * new_height);
-
- img[0].instance();
- img[0]->create(new_width, new_height, 0, Image::FORMAT_R8, img_data[0]);
- }
-
- {
- // do CbCr
- size_t new_width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 1);
- size_t new_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 1);
-
- if ((width[1] != new_width) || (height[1] != new_height)) {
- width[1] = new_width;
- height[1] = new_height;
- img_data[1].resize(2 * new_width * new_height);
- }
-
- uint8_t *w = img_data[1].ptrw();
- memcpy(w, dataCbCr, 2 * new_width * new_height);
-
- ///TODO GLES2 doesn't support FORMAT_RG8, need to do some form of conversion
- img[1].instance();
- img[1]->create(new_width, new_height, 0, Image::FORMAT_RG8, img_data[1]);
- }
-
- // set our texture...
- feed->set_YCbCr_imgs(img[0], img[1]);
-
- // update our matrix to match the orientation, note, before changing anything
- // here, be aware that the project orientation settings must match your xcode
- // settings or this will go wrong!
- Transform2D display_transform;
- switch (orientation) {
- case UIInterfaceOrientationPortrait: {
- display_transform = Transform2D(0.0, -1.0, -1.0, 0.0, 1.0, 1.0);
- } break;
- case UIInterfaceOrientationLandscapeRight: {
- display_transform = Transform2D(1.0, 0.0, 0.0, -1.0, 0.0, 1.0);
- } break;
- case UIInterfaceOrientationLandscapeLeft: {
- display_transform = Transform2D(-1.0, 0.0, 0.0, 1.0, 1.0, 0.0);
- } break;
- default: {
- display_transform = Transform2D(0.0, 1.0, 1.0, 0.0, 0.0, 0.0);
- } break;
- }
-
- //TODO: this is correct for the camera on the back, I have a feeling this needs to be inversed for the camera on the front!
- feed->set_transform(display_transform);
- }
-
- // and unlock
- CVPixelBufferUnlockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);
-}
-
-@end
-
-//////////////////////////////////////////////////////////////////////////
-// CameraFeedIOS - Subclass for camera feeds in iOS
-
-class CameraFeedIOS : public CameraFeed {
-private:
- AVCaptureDevice *device;
- MyCaptureSession *capture_session;
-
-public:
- bool get_is_arkit() const;
- AVCaptureDevice *get_device() const;
-
- CameraFeedIOS();
- ~CameraFeedIOS();
-
- void set_device(AVCaptureDevice *p_device);
-
- bool activate_feed();
- void deactivate_feed();
-};
-
-AVCaptureDevice *CameraFeedIOS::get_device() const {
- return device;
-};
-
-CameraFeedIOS::CameraFeedIOS() {
- capture_session = NULL;
- device = NULL;
- transform = Transform2D(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); /* should re-orientate this based on device orientation */
-};
-
-void CameraFeedIOS::set_device(AVCaptureDevice *p_device) {
- device = p_device;
-
- // get some info
- NSString *device_name = p_device.localizedName;
- name = device_name.UTF8String;
- position = CameraFeed::FEED_UNSPECIFIED;
- if ([p_device position] == AVCaptureDevicePositionBack) {
- position = CameraFeed::FEED_BACK;
- } else if ([p_device position] == AVCaptureDevicePositionFront) {
- position = CameraFeed::FEED_FRONT;
- };
-};
-
-CameraFeedIOS::~CameraFeedIOS() {
- if (capture_session) {
- capture_session = nil;
- };
-
- if (device) {
- device = nil;
- };
-};
-
-bool CameraFeedIOS::activate_feed() {
- if (capture_session) {
- // already recording!
- } else {
- // start camera capture
- capture_session = [[MyCaptureSession alloc] initForFeed:this andDevice:device];
- };
-
- return true;
-};
-
-void CameraFeedIOS::deactivate_feed() {
- // end camera capture if we have one
- if (capture_session) {
- [capture_session cleanup];
- capture_session = nil;
- };
-};
-
-//////////////////////////////////////////////////////////////////////////
-// MyDeviceNotifications - This is a little helper class gets notifications
-// when devices are connected/disconnected
-
-@interface MyDeviceNotifications : NSObject {
- CameraIOS *camera_server;
-}
-
-@end
-
-@implementation MyDeviceNotifications
-
-- (void)devices_changed:(NSNotification *)notification {
- camera_server->update_feeds();
-}
-
-- (id)initForServer:(CameraIOS *)p_server {
- if (self = [super init]) {
- camera_server = p_server;
-
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(devices_changed:) name:AVCaptureDeviceWasConnectedNotification object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(devices_changed:) name:AVCaptureDeviceWasDisconnectedNotification object:nil];
- };
- return self;
-}
-
-- (void)dealloc {
- // remove notifications
- [[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureDeviceWasConnectedNotification object:nil];
- [[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureDeviceWasDisconnectedNotification object:nil];
-}
-
-@end
-
-MyDeviceNotifications *device_notifications = nil;
-
-//////////////////////////////////////////////////////////////////////////
-// CameraIOS - Subclass for our camera server on iPhone
-
-void CameraIOS::update_feeds() {
- // this way of doing things is deprecated but still works,
- // rewrite to using AVCaptureDeviceDiscoverySession
-
- NSMutableArray *deviceTypes = [NSMutableArray array];
-
- if (@available(iOS 10, *)) {
- [deviceTypes addObject:AVCaptureDeviceTypeBuiltInWideAngleCamera];
- [deviceTypes addObject:AVCaptureDeviceTypeBuiltInTelephotoCamera];
-
- if (@available(iOS 10.2, *)) {
- [deviceTypes addObject:AVCaptureDeviceTypeBuiltInDualCamera];
- }
-
- if (@available(iOS 11.1, *)) {
- [deviceTypes addObject:AVCaptureDeviceTypeBuiltInTrueDepthCamera];
- }
-
- AVCaptureDeviceDiscoverySession *session = [AVCaptureDeviceDiscoverySession
- discoverySessionWithDeviceTypes:deviceTypes
- mediaType:AVMediaTypeVideo
- position:AVCaptureDevicePositionUnspecified];
-
- // remove devices that are gone..
- for (int i = feeds.size() - 1; i >= 0; i--) {
- Ref<CameraFeedIOS> feed(feeds[i]);
-
- if (feed.is_null()) {
- // feed not managed by us
- } else if (![session.devices containsObject:feed->get_device()]) {
- // remove it from our array, this will also destroy it ;)
- remove_feed(feed);
- };
- };
-
- // add new devices..
- for (AVCaptureDevice *device in session.devices) {
- bool found = false;
-
- for (int i = 0; i < feeds.size() && !found; i++) {
- Ref<CameraFeedIOS> feed(feeds[i]);
-
- if (feed.is_null()) {
- // feed not managed by us
- } else if (feed->get_device() == device) {
- found = true;
- };
- };
-
- if (!found) {
- Ref<CameraFeedIOS> newfeed;
- newfeed.instance();
- newfeed->set_device(device);
- add_feed(newfeed);
- };
- };
- }
-};
-
-CameraIOS::CameraIOS() {
- // check if we have our usage description
- NSString *usage_desc = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSCameraUsageDescription"];
- if (usage_desc == NULL) {
- // don't initialise if we don't get anything
- print_line("No NSCameraUsageDescription key in pList, no access to cameras.");
- return;
- } else if (usage_desc.length == 0) {
- // don't initialise if we don't get anything
- print_line("Empty NSCameraUsageDescription key in pList, no access to cameras.");
- return;
- }
-
- // now we'll request access.
- // If this is the first time the user will be prompted with the string (iOS will read it).
- // Once a decision is made it is returned. If the user wants to change it later on they
- // need to go into setting.
- print_line("Requesting Camera permissions");
-
- [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo
- completionHandler:^(BOOL granted) {
- if (granted) {
- print_line("Access to cameras granted!");
-
- // Find available cameras we have at this time
- update_feeds();
-
- // should only have one of these....
- device_notifications = [[MyDeviceNotifications alloc] initForServer:this];
- } else {
- print_line("No access to cameras!");
- }
- }];
-};
-
-CameraIOS::~CameraIOS() {
- device_notifications = nil;
-};
diff --git a/modules/camera/camera_osx.h b/modules/camera/camera_osx.h
index a07b83c6af..964b7c1edc 100644
--- a/modules/camera/camera_osx.h
+++ b/modules/camera/camera_osx.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/camera/camera_osx.mm b/modules/camera/camera_osx.mm
index 306632a016..3d2053ad23 100644
--- a/modules/camera/camera_osx.mm
+++ b/modules/camera/camera_osx.mm
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/camera/camera_win.cpp b/modules/camera/camera_win.cpp
index 1646644be3..226a642dcf 100644
--- a/modules/camera/camera_win.cpp
+++ b/modules/camera/camera_win.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/camera/camera_win.h b/modules/camera/camera_win.h
index bbc8880c12..671e7d5beb 100644
--- a/modules/camera/camera_win.h
+++ b/modules/camera/camera_win.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/camera/config.py b/modules/camera/config.py
index 87d7542741..8a22751aa7 100644
--- a/modules/camera/config.py
+++ b/modules/camera/config.py
@@ -1,5 +1,5 @@
def can_build(env, platform):
- return platform == "iphone" or platform == "osx" or platform == "windows"
+ return platform == "osx" or platform == "windows"
def configure(env):
diff --git a/modules/camera/register_types.cpp b/modules/camera/register_types.cpp
index 3b6c916914..0d33ff9ddc 100644
--- a/modules/camera/register_types.cpp
+++ b/modules/camera/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,9 +33,6 @@
#if defined(WINDOWS_ENABLED)
#include "camera_win.h"
#endif
-#if defined(IPHONE_ENABLED)
-#include "camera_ios.h"
-#endif
#if defined(OSX_ENABLED)
#include "camera_osx.h"
#endif
@@ -44,9 +41,6 @@ void register_camera_types() {
#if defined(WINDOWS_ENABLED)
CameraServer::make_default<CameraWindows>();
#endif
-#if defined(IPHONE_ENABLED)
- CameraServer::make_default<CameraIOS>();
-#endif
#if defined(OSX_ENABLED)
CameraServer::make_default<CameraOSX>();
#endif
diff --git a/modules/camera/register_types.h b/modules/camera/register_types.h
index e34f84bf2c..0ae9aa2c0b 100644
--- a/modules/camera/register_types.h
+++ b/modules/camera/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp
index 47982d519a..f0a2f17ba9 100644
--- a/modules/csg/csg.cpp
+++ b/modules/csg/csg.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,7 +32,7 @@
#include "core/math/geometry_2d.h"
#include "core/math/math_funcs.h"
-#include "core/sort_array.h"
+#include "core/templates/sort_array.h"
// Static helper functions.
diff --git a/modules/csg/csg.h b/modules/csg/csg.h
index 34ee239c17..1612c16a32 100644
--- a/modules/csg/csg.h
+++ b/modules/csg/csg.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,16 +31,16 @@
#ifndef CSG_H
#define CSG_H
-#include "core/list.h"
-#include "core/map.h"
#include "core/math/aabb.h"
#include "core/math/plane.h"
#include "core/math/transform.h"
#include "core/math/vector2.h"
#include "core/math/vector3.h"
-#include "core/oa_hash_map.h"
-#include "core/reference.h"
-#include "core/vector.h"
+#include "core/object/reference.h"
+#include "core/templates/list.h"
+#include "core/templates/map.h"
+#include "core/templates/oa_hash_map.h"
+#include "core/templates/vector.h"
#include "scene/resources/material.h"
struct CSGBrush {
diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/csg_gizmos.cpp
index cce72770f5..e23442ef99 100644
--- a/modules/csg/csg_gizmos.cpp
+++ b/modules/csg/csg_gizmos.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -56,8 +56,7 @@ String CSGShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo,
}
if (Object::cast_to<CSGBox3D>(cs)) {
- static const char *hname[3] = { "Width", "Height", "Depth" };
- return hname[p_idx];
+ return "Size";
}
if (Object::cast_to<CSGCylinder3D>(cs)) {
@@ -81,14 +80,7 @@ Variant CSGShape3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int
if (Object::cast_to<CSGBox3D>(cs)) {
CSGBox3D *s = Object::cast_to<CSGBox3D>(cs);
- switch (p_idx) {
- case 0:
- return s->get_width();
- case 1:
- return s->get_height();
- case 2:
- return s->get_depth();
- }
+ return s->get_size();
}
if (Object::cast_to<CSGCylinder3D>(cs)) {
@@ -123,7 +115,7 @@ void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Ca
Geometry3D::get_closest_points_between_segments(Vector3(), Vector3(4096, 0, 0), sg[0], sg[1], ra, rb);
float d = ra.x;
if (Node3DEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
+ d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
}
if (d < 0.001) {
@@ -142,24 +134,16 @@ void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Ca
Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
float d = ra[p_idx];
if (Node3DEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
+ d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
}
if (d < 0.001) {
d = 0.001;
}
- switch (p_idx) {
- case 0:
- s->set_width(d * 2);
- break;
- case 1:
- s->set_height(d * 2);
- break;
- case 2:
- s->set_depth(d * 2);
- break;
- }
+ Vector3 h = s->get_size();
+ h[p_idx] = d * 2;
+ s->set_size(h);
}
if (Object::cast_to<CSGCylinder3D>(cs)) {
@@ -171,7 +155,7 @@ void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Ca
Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
float d = axis.dot(ra);
if (Node3DEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
+ d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
}
if (d < 0.001) {
@@ -194,7 +178,7 @@ void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Ca
Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
float d = axis.dot(ra);
if (Node3DEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
+ d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
}
if (d < 0.001) {
@@ -229,38 +213,14 @@ void CSGShape3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx,
if (Object::cast_to<CSGBox3D>(cs)) {
CSGBox3D *s = Object::cast_to<CSGBox3D>(cs);
if (p_cancel) {
- switch (p_idx) {
- case 0:
- s->set_width(p_restore);
- break;
- case 1:
- s->set_height(p_restore);
- break;
- case 2:
- s->set_depth(p_restore);
- break;
- }
+ s->set_size(p_restore);
return;
}
UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Change Box Shape Extents"));
- static const char *method[3] = { "set_width", "set_height", "set_depth" };
- float current = 0;
- switch (p_idx) {
- case 0:
- current = s->get_width();
- break;
- case 1:
- current = s->get_height();
- break;
- case 2:
- current = s->get_depth();
- break;
- }
-
- ur->add_do_method(s, method[p_idx], current);
- ur->add_undo_method(s, method[p_idx], p_restore);
+ ur->create_action(TTR("Change Box Shape Size"));
+ ur->add_do_method(s, "set_size", s->get_size());
+ ur->add_undo_method(s, "set_size", p_restore);
ur->commit_action();
}
@@ -319,7 +279,7 @@ bool CSGShape3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
return Object::cast_to<CSGSphere3D>(p_spatial) || Object::cast_to<CSGBox3D>(p_spatial) || Object::cast_to<CSGCylinder3D>(p_spatial) || Object::cast_to<CSGTorus3D>(p_spatial) || Object::cast_to<CSGMesh3D>(p_spatial) || Object::cast_to<CSGPolygon3D>(p_spatial);
}
-String CSGShape3DGizmoPlugin::get_name() const {
+String CSGShape3DGizmoPlugin::get_gizmo_name() const {
return "CSGShape3D";
}
@@ -408,9 +368,13 @@ void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
CSGBox3D *s = Object::cast_to<CSGBox3D>(cs);
Vector<Vector3> handles;
- handles.push_back(Vector3(s->get_width() * 0.5, 0, 0));
- handles.push_back(Vector3(0, s->get_height() * 0.5, 0));
- handles.push_back(Vector3(0, 0, s->get_depth() * 0.5));
+
+ for (int i = 0; i < 3; i++) {
+ Vector3 h;
+ h[i] = s->get_size()[i] / 2;
+ handles.push_back(h);
+ }
+
p_gizmo->add_handles(handles, handles_material);
}
diff --git a/modules/csg/csg_gizmos.h b/modules/csg/csg_gizmos.h
index 83ee847caf..8f7da35de3 100644
--- a/modules/csg/csg_gizmos.h
+++ b/modules/csg/csg_gizmos.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -40,7 +40,7 @@ class CSGShape3DGizmoPlugin : public EditorNode3DGizmoPlugin {
public:
bool has_gizmo(Node3D *p_spatial) override;
- String get_name() const override;
+ String get_gizmo_name() const override;
int get_priority() const override;
bool is_selectable_when_hidden() const override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index 8f2ebc7232..e348f8a568 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -701,7 +701,7 @@ CSGPrimitive3D::CSGPrimitive3D() {
CSGBrush *CSGMesh3D::_build_brush() {
if (!mesh.is_valid()) {
- return nullptr;
+ return memnew(CSGBrush);
}
Vector<Vector3> vertices;
@@ -719,7 +719,7 @@ CSGBrush *CSGMesh3D::_build_brush() {
if (arrays.size() == 0) {
_make_dirty();
- ERR_FAIL_COND_V(arrays.size() == 0, nullptr);
+ ERR_FAIL_COND_V(arrays.size() == 0, memnew(CSGBrush));
}
Vector<Vector3> avertices = arrays[Mesh::ARRAY_VERTEX];
@@ -840,7 +840,7 @@ CSGBrush *CSGMesh3D::_build_brush() {
}
if (vertices.size() == 0) {
- return nullptr;
+ return memnew(CSGBrush);
}
return _create_brush_from_arrays(vertices, uvs, smooth, materials);
@@ -927,25 +927,27 @@ CSGBrush *CSGSphere3D::_build_brush() {
bool *invertw = invert.ptrw();
int face = 0;
+ const double lat_step = Math_TAU / rings;
+ const double lon_step = Math_TAU / radial_segments;
for (int i = 1; i <= rings; i++) {
- double lat0 = Math_PI * (-0.5 + (double)(i - 1) / rings);
+ double lat0 = lat_step * (i - 1) - Math_TAU / 4;
double z0 = Math::sin(lat0);
double zr0 = Math::cos(lat0);
double u0 = double(i - 1) / rings;
- double lat1 = Math_PI * (-0.5 + (double)i / rings);
+ double lat1 = lat_step * i - Math_TAU / 4;
double z1 = Math::sin(lat1);
double zr1 = Math::cos(lat1);
double u1 = double(i) / rings;
for (int j = radial_segments; j >= 1; j--) {
- double lng0 = 2 * Math_PI * (double)(j - 1) / radial_segments;
+ double lng0 = lon_step * (j - 1);
double x0 = Math::cos(lng0);
double y0 = Math::sin(lng0);
double v0 = double(i - 1) / radial_segments;
- double lng1 = 2 * Math_PI * (double)(j) / radial_segments;
+ double lng1 = lon_step * j;
double x1 = Math::cos(lng1);
double y1 = Math::sin(lng1);
double v1 = double(i) / radial_segments;
@@ -1125,7 +1127,7 @@ CSGBrush *CSGBox3D::_build_brush() {
int face = 0;
- Vector3 vertex_mul(width * 0.5, height * 0.5, depth * 0.5);
+ Vector3 vertex_mul = size / 2;
{
for (int i = 0; i < 6; i++) {
@@ -1194,55 +1196,25 @@ CSGBrush *CSGBox3D::_build_brush() {
}
void CSGBox3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_width", "width"), &CSGBox3D::set_width);
- ClassDB::bind_method(D_METHOD("get_width"), &CSGBox3D::get_width);
-
- ClassDB::bind_method(D_METHOD("set_height", "height"), &CSGBox3D::set_height);
- ClassDB::bind_method(D_METHOD("get_height"), &CSGBox3D::get_height);
-
- ClassDB::bind_method(D_METHOD("set_depth", "depth"), &CSGBox3D::set_depth);
- ClassDB::bind_method(D_METHOD("get_depth"), &CSGBox3D::get_depth);
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &CSGBox3D::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &CSGBox3D::get_size);
ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGBox3D::set_material);
ClassDB::bind_method(D_METHOD("get_material"), &CSGBox3D::get_material);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "width", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_width", "get_width");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_height", "get_height");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_depth", "get_depth");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material");
}
-void CSGBox3D::set_width(const float p_width) {
- width = p_width;
- _make_dirty();
- update_gizmo();
- _change_notify("width");
-}
-
-float CSGBox3D::get_width() const {
- return width;
-}
-
-void CSGBox3D::set_height(const float p_height) {
- height = p_height;
- _make_dirty();
- update_gizmo();
- _change_notify("height");
-}
-
-float CSGBox3D::get_height() const {
- return height;
-}
-
-void CSGBox3D::set_depth(const float p_depth) {
- depth = p_depth;
+void CSGBox3D::set_size(const Vector3 &p_size) {
+ size = p_size;
_make_dirty();
update_gizmo();
- _change_notify("depth");
+ _change_notify("size");
}
-float CSGBox3D::get_depth() const {
- return depth;
+Vector3 CSGBox3D::get_size() const {
+ return size;
}
void CSGBox3D::set_material(const Ref<Material> &p_material) {
@@ -1255,13 +1227,6 @@ Ref<Material> CSGBox3D::get_material() const {
return material;
}
-CSGBox3D::CSGBox3D() {
- // defaults
- width = 2.0;
- height = 2.0;
- depth = 2.0;
-}
-
///////////////
CSGBrush *CSGCylinder3D::_build_brush() {
@@ -1303,8 +1268,8 @@ CSGBrush *CSGCylinder3D::_build_brush() {
float inc = float(i) / sides;
float inc_n = float((i + 1)) / sides;
- float ang = inc * Math_PI * 2.0;
- float ang_n = inc_n * Math_PI * 2.0;
+ float ang = inc * Math_TAU;
+ float ang_n = inc_n * Math_TAU;
Vector3 base(Math::cos(ang), 0, Math::sin(ang));
Vector3 base_n(Math::cos(ang_n), 0, Math::sin(ang_n));
@@ -1502,7 +1467,7 @@ CSGBrush *CSGTorus3D::_build_brush() {
float max_radius = outer_radius;
if (min_radius == max_radius) {
- return nullptr; //sorry, can't
+ return memnew(CSGBrush); //sorry, can't
}
if (min_radius > max_radius) {
@@ -1545,8 +1510,8 @@ CSGBrush *CSGTorus3D::_build_brush() {
float inci = float(i) / sides;
float inci_n = float((i + 1)) / sides;
- float angi = inci * Math_PI * 2.0;
- float angi_n = inci_n * Math_PI * 2.0;
+ float angi = inci * Math_TAU;
+ float angi_n = inci_n * Math_TAU;
Vector3 normali = Vector3(Math::cos(angi), 0, Math::sin(angi));
Vector3 normali_n = Vector3(Math::cos(angi_n), 0, Math::sin(angi_n));
@@ -1555,8 +1520,8 @@ CSGBrush *CSGTorus3D::_build_brush() {
float incj = float(j) / ring_sides;
float incj_n = float((j + 1)) / ring_sides;
- float angj = incj * Math_PI * 2.0;
- float angj_n = incj_n * Math_PI * 2.0;
+ float angj = incj * Math_TAU;
+ float angj_n = incj_n * Math_TAU;
Vector2 normalj = Vector2(Math::cos(angj), Math::sin(angj)) * radius + Vector2(min_radius + radius, 0);
Vector2 normalj_n = Vector2(Math::cos(angj_n), Math::sin(angj_n)) * radius + Vector2(min_radius + radius, 0);
@@ -1721,7 +1686,7 @@ CSGBrush *CSGPolygon3D::_build_brush() {
// set our bounding box
if (polygon.size() < 3) {
- return nullptr;
+ return memnew(CSGBrush);
}
Vector<Point2> final_polygon = polygon;
@@ -1733,7 +1698,7 @@ CSGBrush *CSGPolygon3D::_build_brush() {
Vector<int> triangles = Geometry2D::triangulate_polygon(final_polygon);
if (triangles.size() < 3) {
- return nullptr;
+ return memnew(CSGBrush);
}
Path3D *path = nullptr;
@@ -1767,15 +1732,15 @@ CSGBrush *CSGPolygon3D::_build_brush() {
if (mode == MODE_PATH) {
if (!has_node(path_node)) {
- return nullptr;
+ return memnew(CSGBrush);
}
Node *n = get_node(path_node);
if (!n) {
- return nullptr;
+ return memnew(CSGBrush);
}
path = Object::cast_to<Path3D>(n);
if (!path) {
- return nullptr;
+ return memnew(CSGBrush);
}
if (path != path_cache) {
@@ -1793,10 +1758,10 @@ CSGBrush *CSGPolygon3D::_build_brush() {
}
curve = path->get_curve();
if (curve.is_null()) {
- return nullptr;
+ return memnew(CSGBrush);
}
if (curve->get_baked_length() <= 0) {
- return nullptr;
+ return memnew(CSGBrush);
}
}
CSGBrush *brush = memnew(CSGBrush);
@@ -1928,8 +1893,8 @@ CSGBrush *CSGPolygon3D::_build_brush() {
float inci = float(i) / spin_sides;
float inci_n = float((i + 1)) / spin_sides;
- float angi = -(inci * spin_degrees / 360.0) * Math_PI * 2.0;
- float angi_n = -(inci_n * spin_degrees / 360.0) * Math_PI * 2.0;
+ float angi = -Math::deg2rad(inci * spin_degrees);
+ float angi_n = -Math::deg2rad(inci_n * spin_degrees);
Vector3 normali = Vector3(Math::cos(angi), 0, Math::sin(angi));
Vector3 normali_n = Vector3(Math::cos(angi_n), 0, Math::sin(angi_n));
diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h
index d93693f145..7dff8b6d3b 100644
--- a/modules/csg/csg_shape.h
+++ b/modules/csg/csg_shape.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -240,27 +240,19 @@ class CSGBox3D : public CSGPrimitive3D {
virtual CSGBrush *_build_brush() override;
Ref<Material> material;
- float width;
- float height;
- float depth;
+ Vector3 size = Vector3(2, 2, 2);
protected:
static void _bind_methods();
public:
- void set_width(const float p_width);
- float get_width() const;
-
- void set_height(const float p_height);
- float get_height() const;
-
- void set_depth(const float p_depth);
- float get_depth() const;
+ void set_size(const Vector3 &p_size);
+ Vector3 get_size() const;
void set_material(const Ref<Material> &p_material);
Ref<Material> get_material() const;
- CSGBox3D();
+ CSGBox3D() {}
};
class CSGCylinder3D : public CSGPrimitive3D {
diff --git a/modules/csg/doc_classes/CSGBox3D.xml b/modules/csg/doc_classes/CSGBox3D.xml
index 492bf68c44..b1d0454b76 100644
--- a/modules/csg/doc_classes/CSGBox3D.xml
+++ b/modules/csg/doc_classes/CSGBox3D.xml
@@ -11,17 +11,11 @@
<methods>
</methods>
<members>
- <member name="depth" type="float" setter="set_depth" getter="get_depth" default="2.0">
- Depth of the box measured from the center of the box.
- </member>
- <member name="height" type="float" setter="set_height" getter="get_height" default="2.0">
- Height of the box measured from the center of the box.
- </member>
<member name="material" type="Material" setter="set_material" getter="get_material">
The material used to render the box.
</member>
- <member name="width" type="float" setter="set_width" getter="get_width" default="2.0">
- Width of the box measured from the center of the box.
+ <member name="size" type="Vector3" setter="set_size" getter="get_size" default="Vector3( 2, 2, 2 )">
+ The box's width, height and depth.
</member>
</members>
<constants>
diff --git a/modules/csg/icons/CSGBox3D.svg b/modules/csg/icons/CSGBox3D.svg
index 67e34df444..ceef9196a7 100644
--- a/modules/csg/icons/CSGBox3D.svg
+++ b/modules/csg/icons/CSGBox3D.svg
@@ -1,6 +1 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1036.4)">
-<path transform="translate(0 1036.4)" d="m12 9c-0.55401 0-1 0.44599-1 1v1h2v2h1c0.55401 0 1-0.44599 1-1v-2c0-0.55401-0.44599-1-1-1h-2zm1 4h-2v-2h-1c-0.55401 0-1 0.44599-1 1v2c0 0.55401 0.44599 1 1 1h2c0.55401 0 1-0.44599 1-1v-1z" fill="#84c2ff"/>
-<path transform="translate(0 1036.4)" d="m8 0.94531-7 3.5v7.2227l7 3.5 0.29492-0.14844c-0.18282-0.30101-0.29492-0.64737-0.29492-1.0195v-2c0-0.72651 0.40824-1.3664 1-1.7168v-1.6699l4-2v1.3867h1c0.36419 0 0.70336 0.10754 1 0.2832v-3.8379zm0 2.1152 3.9395 1.9707-3.9395 1.9688-3.9395-1.9688zm-5 3.5527 4 2v3.9414l-4-2.002z" fill="#fc9c9c" stroke-width="1.0667"/>
-</g>
-</svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#84c2ff"/><path d="m8 .94531-7 3.5v7.2227l7 3.5.29492-.14844c-.18282-.30101-.29492-.64737-.29492-1.0195v-2c0-.72651.40824-1.3664 1-1.7168v-1.6699l4-2v1.3867h1c.36419 0 .70336.10754 1 .2832v-3.8379zm0 2.1152 3.9395 1.9707-3.9395 1.9688-3.9395-1.9688zm-5 3.5527 4 2v3.9414l-4-2.002z" fill="#fc9c9c" stroke-width="1.0667"/></svg>
diff --git a/modules/csg/icons/CSGCapsule3D.svg b/modules/csg/icons/CSGCapsule3D.svg
index 92a7b5a870..14e582ee84 100644
--- a/modules/csg/icons/CSGCapsule3D.svg
+++ b/modules/csg/icons/CSGCapsule3D.svg
@@ -1,6 +1 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g>
-<path d="m8 1c-2.7527 0-5 2.2418-5 4.9902v4.0176c0 2.7484 2.2473 4.9922 5 4.9922 0.092943 0 0.18367-0.008623 0.27539-0.013672-0.17055-0.29341-0.27539-0.62792-0.27539-0.98633v-2c0-0.72887 0.41095-1.3691 1.0059-1.7188v-0.28125c0.34771-0.034464 0.68259-0.10691 1.0156-0.19922 0.10394-0.99856 0.95603-1.8008 1.9785-1.8008h1v-2.0098c0-2.7484-2.2473-4.9902-5-4.9902zm-1.0059 2.127v4.8574c-0.66556-0.1047-1.2974-0.37231-1.9941-0.66211v-1.3223c0-1.3474 0.79841-2.4642 1.9941-2.873zm2.0117 0c1.1957 0.4088 1.9941 1.5256 1.9941 2.873v1.3457c-0.68406 0.3054-1.3142 0.57292-1.9941 0.66602v-4.8848zm-4.0059 6.334c0.67836 0.2231 1.3126 0.44599 1.9941 0.52539v2.8848c-1.1957-0.4092-1.9941-1.5237-1.9941-2.8711v-0.53906z" fill="#fc9c9c"/>
-<path d="m12 9c-0.55401 0-1 0.44599-1 1v1h2v2h1c0.55401 0 1-0.44599 1-1v-2c0-0.55401-0.44599-1-1-1zm1 4h-2v-2h-1c-0.55401 0-1 0.44599-1 1v2c0 0.55401 0.44599 1 1 1h2c0.55401 0 1-0.44599 1-1z" fill="#84c2ff"/>
-</g>
-</svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-2.7527 0-5 2.2418-5 4.9902v4.0176c0 2.7484 2.2473 4.9922 5 4.9922.092943 0 .18367-.008623.27539-.013672-.17055-.29341-.27539-.62792-.27539-.98633v-2c0-.72887.41095-1.3691 1.0059-1.7188v-.28125c.34771-.034464.68259-.10691 1.0156-.19922.10394-.99856.95603-1.8008 1.9785-1.8008h1v-2.0098c0-2.7484-2.2473-4.9902-5-4.9902zm-1.0059 2.127v4.8574c-.66556-.1047-1.2974-.37231-1.9941-.66211v-1.3223c0-1.3474.79841-2.4642 1.9941-2.873zm2.0117 0c1.1957.4088 1.9941 1.5256 1.9941 2.873v1.3457c-.68406.3054-1.3142.57292-1.9941.66602v-4.8848zm-4.0059 6.334c.67836.2231 1.3126.44599 1.9941.52539v2.8848c-1.1957-.4092-1.9941-1.5237-1.9941-2.8711v-.53906z" fill="#fc9c9c"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#84c2ff"/></svg>
diff --git a/modules/csg/icons/CSGCombiner3D.svg b/modules/csg/icons/CSGCombiner3D.svg
index cce2902e24..50ce4179d9 100644
--- a/modules/csg/icons/CSGCombiner3D.svg
+++ b/modules/csg/icons/CSGCombiner3D.svg
@@ -1,8 +1 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1036.4)">
-<path transform="translate(0 1036.4)" d="m12 9c-0.55401 0-1 0.44599-1 1v1h2v2h1c0.55401 0 1-0.44599 1-1v-2c0-0.55401-0.44599-1-1-1h-2zm1 4h-2v-2h-1c-0.55401 0-1 0.44599-1 1v2c0 0.55401 0.44599 1 1 1h2c0.55401 0 1-0.44599 1-1v-1z" fill="#84c2ff"/>
-<g fill="#fc9c9c">
-<path transform="translate(0 1036.4)" d="m3 1c-1.1046 0-2 0.89543-2 2h2zm2 0v2h2v-2zm4 0v2h2v-2zm4 0v2h2c0-1.1046-0.89543-2-2-2zm-12 4v2h2v-2zm12 0v2h2v-2zm-12 4v2h2v-2zm0 4c0 1.1046 0.89543 2 2 2v-2zm4 0v2h2v-2z" fill="#fc9c9c"/>
-</g>
-</g>
-</svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#84c2ff"/><path d="m3 1c-1.1046 0-2 .89543-2 2h2zm2 0v2h2v-2zm4 0v2h2v-2zm4 0v2h2c0-1.1046-.89543-2-2-2zm-12 4v2h2v-2zm12 0v2h2v-2zm-12 4v2h2v-2zm0 4c0 1.1046.89543 2 2 2v-2zm4 0v2h2v-2z" fill="#fc9c9c"/></svg>
diff --git a/modules/csg/icons/CSGCylinder3D.svg b/modules/csg/icons/CSGCylinder3D.svg
index 645a74c79b..c84594928a 100644
--- a/modules/csg/icons/CSGCylinder3D.svg
+++ b/modules/csg/icons/CSGCylinder3D.svg
@@ -1,6 +1 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 14.999999 14.999999" xmlns="http://www.w3.org/2000/svg">
-<g>
-<path transform="scale(.9375)" d="m8 1c-1.7469 0-3.328 0.22648-4.5586 0.63672-0.61528 0.20512-1.1471 0.45187-1.5898 0.80078-0.44272 0.34891-0.85156 0.88101-0.85156 1.5625v8c0 0.68149 0.40884 1.2155 0.85156 1.5645 0.44272 0.34891 0.97457 0.59577 1.5898 0.80078 1.2306 0.41024 2.8117 0.63477 4.5586 0.63477 0.095648 0 0.18467-0.008426 0.2793-0.009766-0.1722-0.29446-0.2793-0.62995-0.2793-0.99023v-1c-1.5668 0-2.9867-0.2195-3.9277-0.5332-0.46329-0.15435-0.90474-0.33752-1.0723-0.4668v-5.8125c0.1468 0.058667 0.2835 0.12515 0.44141 0.17773 1.2306 0.41024 2.8117 0.63477 4.5586 0.63477s3.328-0.22453 4.5586-0.63477c0.15791-0.052267 0.29461-0.11864 0.44141-0.17773v1.8125h1c0.36396 0 0.70348 0.10774 1 0.2832v-4.2832c0-0.68149-0.40884-1.2136-0.85156-1.5625-0.44272-0.34891-0.97457-0.59566-1.5898-0.80078-1.2306-0.41024-2.8117-0.63672-4.5586-0.63672zm0 2c1.5668 0 2.9867 0.22145 3.9277 0.53516 0.46368 0.15456 0.80138 0.33741 0.96875 0.4668-0.16752 0.12928-0.50546 0.3105-0.96875 0.46484-0.94102 0.31371-2.361 0.5332-3.9277 0.5332s-2.9867-0.2195-3.9277-0.5332c-0.46329-0.15435-0.80123-0.33556-0.96875-0.46484 0.16737-0.12939 0.50507-0.31224 0.96875-0.4668 0.94102-0.31371 2.361-0.53516 3.9277-0.53516z" fill="#fc9c9c" stroke-width="1.0667"/>
-<path d="m11.25 8.4375c-0.51938 0-0.9375 0.41812-0.9375 0.9375v0.9375h1.875v1.875h0.9375c0.51938 0 0.9375-0.41812 0.9375-0.9375v-1.875c0-0.51938-0.41812-0.9375-0.9375-0.9375zm0.9375 3.75h-1.875v-1.875h-0.9375c-0.51938 0-0.9375 0.41812-0.9375 0.9375v1.875c0 0.51938 0.41812 0.9375 0.9375 0.9375h1.875c0.51938 0 0.9375-0.41812 0.9375-0.9375z" fill="#84c2ff"/>
-</g>
-</svg>
+<svg height="16" viewBox="0 0 14.999999 14.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-1.7469 0-3.328.22648-4.5586.63672-.61528.20512-1.1471.45187-1.5898.80078-.44272.34891-.85156.88101-.85156 1.5625v8c0 .68149.40884 1.2155.85156 1.5645.44272.34891.97457.59577 1.5898.80078 1.2306.41024 2.8117.63477 4.5586.63477.095648 0 .18467-.008426.2793-.009766-.1722-.29446-.2793-.62995-.2793-.99023v-1c-1.5668 0-2.9867-.2195-3.9277-.5332-.46329-.15435-.90474-.33752-1.0723-.4668v-5.8125c.1468.058667.2835.12515.44141.17773 1.2306.41024 2.8117.63477 4.5586.63477s3.328-.22453 4.5586-.63477c.15791-.052267.29461-.11864.44141-.17773v1.8125h1c.36396 0 .70348.10774 1 .2832v-4.2832c0-.68149-.40884-1.2136-.85156-1.5625-.44272-.34891-.97457-.59566-1.5898-.80078-1.2306-.41024-2.8117-.63672-4.5586-.63672zm0 2c1.5668 0 2.9867.22145 3.9277.53516.46368.15456.80138.33741.96875.4668-.16752.12928-.50546.3105-.96875.46484-.94102.31371-2.361.5332-3.9277.5332s-2.9867-.2195-3.9277-.5332c-.46329-.15435-.80123-.33556-.96875-.46484.16737-.12939.50507-.31224.96875-.4668.94102-.31371 2.361-.53516 3.9277-.53516z" fill="#fc9c9c" stroke-width="1.0667" transform="scale(.9375)"/><path d="m11.25 8.4375c-.51938 0-.9375.41812-.9375.9375v.9375h1.875v1.875h.9375c.51938 0 .9375-.41812.9375-.9375v-1.875c0-.51938-.41812-.9375-.9375-.9375zm.9375 3.75h-1.875v-1.875h-.9375c-.51938 0-.9375.41812-.9375.9375v1.875c0 .51938.41812.9375.9375.9375h1.875c.51938 0 .9375-.41812.9375-.9375z" fill="#84c2ff"/></svg>
diff --git a/modules/csg/icons/CSGMesh3D.svg b/modules/csg/icons/CSGMesh3D.svg
index 6e940a4aa5..962e71f6ae 100644
--- a/modules/csg/icons/CSGMesh3D.svg
+++ b/modules/csg/icons/CSGMesh3D.svg
@@ -1,6 +1 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g>
-<path d="m3 1c-1.1046 0-2 0.89543-2 2 5.649e-4 0.71397 0.38169 1.3735 1 1.7305v6.541c-0.61771 0.35663-0.99874 1.0152-1 1.7285 0 1.1046 0.89543 2 2 2 0.71397-5.65e-4 1.3735-0.38169 1.7305-1h3.2695v-2h-3.2715c-0.17478-0.30301-0.42598-0.55488-0.72852-0.73047v-5.8555l4.916 4.916c0.31428-0.20669 0.68609-0.33008 1.084-0.33008 0-0.3979 0.12338-0.76971 0.33008-1.084l-4.916-4.916h5.8574c0.17478 0.30301 0.42598 0.55488 0.72852 0.73047v3.2695h2v-3.2715c0.61771-0.35663 0.99874-1.0152 1-1.7285 0-1.1046-0.89543-2-2-2-0.71397 5.648e-4 -1.3735 0.38169-1.7305 1h-6.541c-0.35663-0.61771-1.0152-0.99874-1.7285-1z" fill="#fc9c9c"/>
-<path d="m12 9c-0.55401 0-1 0.44599-1 1v1h2v2h1c0.55401 0 1-0.44599 1-1v-2c0-0.55401-0.44599-1-1-1zm1 4h-2v-2h-1c-0.55401 0-1 0.44599-1 1v2c0 0.55401 0.44599 1 1 1h2c0.55401 0 1-0.44599 1-1z" fill="#84c2ff"/>
-</g>
-</svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2 .0005649.71397.38169 1.3735 1 1.7305v6.541c-.61771.35663-.99874 1.0152-1 1.7285 0 1.1046.89543 2 2 2 .71397-.000565 1.3735-.38169 1.7305-1h3.2695v-2h-3.2715c-.17478-.30301-.42598-.55488-.72852-.73047v-5.8555l4.916 4.916c.31428-.20669.68609-.33008 1.084-.33008 0-.3979.12338-.76971.33008-1.084l-4.916-4.916h5.8574c.17478.30301.42598.55488.72852.73047v3.2695h2v-3.2715c.61771-.35663.99874-1.0152 1-1.7285 0-1.1046-.89543-2-2-2-.71397.0005648-1.3735.38169-1.7305 1h-6.541c-.35663-.61771-1.0152-.99874-1.7285-1z" fill="#fc9c9c"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#84c2ff"/></svg>
diff --git a/modules/csg/icons/CSGPolygon3D.svg b/modules/csg/icons/CSGPolygon3D.svg
index 71b03cb8e6..1d496e5fd9 100644
--- a/modules/csg/icons/CSGPolygon3D.svg
+++ b/modules/csg/icons/CSGPolygon3D.svg
@@ -1,6 +1 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1036.4)">
-<path transform="translate(0 1036.4)" d="m7.9629 1.002c-0.14254 0.00487-0.28238 0.04016-0.41016 0.10352l-6 3c-0.33878 0.16944-0.55276 0.51574-0.55273 0.89453v5.832c-0.105 0.61631 0.37487 1.1768 1 1.168h5v2c2.16e-5 0.67546 0.64487 1.1297 1.2617 0.95898-0.16118-0.28721-0.26172-0.61135-0.26172-0.95898v-2c0-0.72673 0.40794-1.3664 1-1.7168v-1.666l4-2v1.3828h1c0.36397 0 0.70348 0.10774 1 0.2832v-3.2773c6e-6 -0.00195 6e-6 -0.0039094 0-0.0058594 2.6e-5 -0.37879-0.21395-0.72509-0.55273-0.89453l-6-3c-0.15022-0.074574-0.31679-0.11017-0.48438-0.10352zm0.037109 2.1172l3.7637 1.8809-2.7637 1.3809v-1.3809c-5.52e-5 -0.55226-0.44774-0.99994-1-1h-1.7617l1.7617-0.88086zm-5 2.8809h4v4h-4v-4z" color="#000000" color-rendering="auto" dominant-baseline="auto" fill="#fc9c9c" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;isolation:auto;mix-blend-mode:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal"/>
-<path transform="translate(0 1036.4)" d="m12 9c-0.55401 0-1 0.44599-1 1v1h2v2h1c0.55401 0 1-0.44599 1-1v-2c0-0.55401-0.44599-1-1-1h-2zm1 4h-2v-2h-1c-0.55401 0-1 0.44599-1 1v2c0 0.55401 0.44599 1 1 1h2c0.55401 0 1-0.44599 1-1v-1z" fill="#84c2ff"/>
-</g>
-</svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.9629 1.002c-.14254.00487-.28238.04016-.41016.10352l-6 3c-.33878.16944-.55276.51574-.55273.89453v5.832c-.105.61631.37487 1.1768 1 1.168h5v2c.0000216.67546.64487 1.1297 1.2617.95898-.16118-.28721-.26172-.61135-.26172-.95898v-2c0-.72673.40794-1.3664 1-1.7168v-1.666l4-2v1.3828h1c.36397 0 .70348.10774 1 .2832v-3.2773c.000006-.00195.000006-.0039094 0-.0058594.000026-.37879-.21395-.72509-.55273-.89453l-6-3c-.15022-.074574-.31679-.11017-.48438-.10352zm.037109 2.1172 3.7637 1.8809-2.7637 1.3809v-1.3809c-.0000552-.55226-.44774-.99994-1-1h-1.7617l1.7617-.88086zm-5 2.8809h4v4h-4z" fill="#fc9c9c"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#84c2ff"/></svg>
diff --git a/modules/csg/icons/CSGSphere3D.svg b/modules/csg/icons/CSGSphere3D.svg
index f81b566993..639e38f49f 100644
--- a/modules/csg/icons/CSGSphere3D.svg
+++ b/modules/csg/icons/CSGSphere3D.svg
@@ -1,6 +1 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g>
-<path d="m8 1c-3.8541 0-7 3.1459-7 7 0 3.8542 3.1459 7 7 7 0.093042 0 0.18321-0.01004 0.27539-0.013672-0.17055-0.29341-0.27539-0.62792-0.27539-0.98633v-2c0-0.72673 0.40794-1.3664 1-1.7168v-0.33398c0.34074-0.019259 0.67728-0.069097 1.0156-0.10547 0.083091-1.0187 0.94713-1.8438 1.9844-1.8438h2c0.35841 0 0.69292 0.10484 0.98633 0.27539 0.003633-0.092184 0.013672-0.18235 0.013672-0.27539 0-3.8541-3.1459-7-7-7zm-1 2.0977v4.8711c-1.2931-0.071342-2.6061-0.29819-3.9434-0.69141 0.30081-2.0978 1.8852-3.7665 3.9434-4.1797zm2 0c2.0549 0.41253 3.637 2.0767 3.9414 4.1699-1.3046 0.36677-2.6158 0.60259-3.9414 0.6875v-4.8574zm-5.7793 6.2988c1.2733 0.31892 2.5337 0.50215 3.7793 0.5625v2.9414c-1.8291-0.36719-3.266-1.7339-3.7793-3.5039z" fill="#fc9c9c"/>
-<path d="m12 9c-0.55401 0-1 0.44599-1 1v1h2v2h1c0.55401 0 1-0.44599 1-1v-2c0-0.55401-0.44599-1-1-1zm1 4h-2v-2h-1c-0.55401 0-1 0.44599-1 1v2c0 0.55401 0.44599 1 1 1h2c0.55401 0 1-0.44599 1-1z" fill="#84c2ff"/>
-</g>
-</svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-3.8541 0-7 3.1459-7 7 0 3.8542 3.1459 7 7 7 .093042 0 .18321-.01004.27539-.013672-.17055-.29341-.27539-.62792-.27539-.98633v-2c0-.72673.40794-1.3664 1-1.7168v-.33398c.34074-.019259.67728-.069097 1.0156-.10547.083091-1.0187.94713-1.8438 1.9844-1.8438h2c.35841 0 .69292.10484.98633.27539.003633-.092184.013672-.18235.013672-.27539 0-3.8541-3.1459-7-7-7zm-1 2.0977v4.8711c-1.2931-.071342-2.6061-.29819-3.9434-.69141.30081-2.0978 1.8852-3.7665 3.9434-4.1797zm2 0c2.0549.41253 3.637 2.0767 3.9414 4.1699-1.3046.36677-2.6158.60259-3.9414.6875zm-5.7793 6.2988c1.2733.31892 2.5337.50215 3.7793.5625v2.9414c-1.8291-.36719-3.266-1.7339-3.7793-3.5039z" fill="#fc9c9c"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#84c2ff"/></svg>
diff --git a/modules/csg/icons/CSGTorus3D.svg b/modules/csg/icons/CSGTorus3D.svg
index 3d30aa47b2..eb8c0f37cb 100644
--- a/modules/csg/icons/CSGTorus3D.svg
+++ b/modules/csg/icons/CSGTorus3D.svg
@@ -1,6 +1 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1036.4)">
-<path transform="translate(0 1036.4)" d="m8 3c-1.8145 0-3.4691 0.41721-4.7461 1.1621-1.277 0.745-2.2539 1.9082-2.2539 3.3379 0 1.4298 0.9769 2.5949 2.2539 3.3398 1.277 0.7449 2.9316 1.1602 4.7461 1.1602 0-1.0907 0.90931-2 2-2 0-0.080836 0.013744-0.15778 0.023438-0.23633-0.61769 0.14673-1.3008 0.23633-2.0234 0.23633-1.4992 0-2.8437-0.36687-3.7383-0.88867-0.89456-0.5219-1.2617-1.108-1.2617-1.6113 0-0.5032 0.36716-1.0876 1.2617-1.6094 0.89456-0.5219 2.2391-0.89062 3.7383-0.89062s2.8437 0.36872 3.7383 0.89062c0.89456 0.5218 1.2617 1.1062 1.2617 1.6094 0 0.15978-0.053679 0.32822-0.13281 0.5h1.1328c0.32481 0 0.62893 0.088408 0.90234 0.23047 0.057552-0.23582 0.097656-0.47718 0.097656-0.73047 0-1.4297-0.9769-2.5929-2.2539-3.3379-1.277-0.7449-2.9316-1.1621-4.7461-1.1621z" color="#000000" color-rendering="auto" dominant-baseline="auto" fill="#fc9c9c" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;isolation:auto;mix-blend-mode:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal"/>
-<path transform="translate(0 1036.4)" d="m12 9c-0.55401 0-1 0.44599-1 1v1h2v2h1c0.55401 0 1-0.44599 1-1v-2c0-0.55401-0.44599-1-1-1h-2zm1 4h-2v-2h-1c-0.55401 0-1 0.44599-1 1v2c0 0.55401 0.44599 1 1 1h2c0.55401 0 1-0.44599 1-1v-1z" fill="#84c2ff"/>
-</g>
-</svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 3c-1.8145 0-3.4691.41721-4.7461 1.1621-1.277.745-2.2539 1.9082-2.2539 3.3379 0 1.4298.9769 2.5949 2.2539 3.3398s2.9316 1.1602 4.7461 1.1602c0-1.0907.90931-2 2-2 0-.080836.013744-.15778.023438-.23633-.61769.14673-1.3008.23633-2.0234.23633-1.4992 0-2.8437-.36687-3.7383-.88867-.89456-.5219-1.2617-1.108-1.2617-1.6113 0-.5032.36716-1.0876 1.2617-1.6094.89456-.5219 2.2391-.89062 3.7383-.89062s2.8437.36872 3.7383.89062c.89456.5218 1.2617 1.1062 1.2617 1.6094 0 .15978-.053679.32822-.13281.5h1.1328c.32481 0 .62893.088408.90234.23047.057552-.23582.097656-.47718.097656-.73047 0-1.4297-.9769-2.5929-2.2539-3.3379-1.277-.7449-2.9316-1.1621-4.7461-1.1621z" fill="#fc9c9c"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#84c2ff"/></svg>
diff --git a/modules/csg/register_types.cpp b/modules/csg/register_types.cpp
index a8bcc2fed1..e28f44d1eb 100644
--- a/modules/csg/register_types.cpp
+++ b/modules/csg/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/csg/register_types.h b/modules/csg/register_types.h
index 926e598561..8747b3fade 100644
--- a/modules/csg/register_types.h
+++ b/modules/csg/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/cvtt/SCsub b/modules/cvtt/SCsub
index 5438f7ebac..e56177d6e9 100644
--- a/modules/cvtt/SCsub
+++ b/modules/cvtt/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_cvtt = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
thirdparty_dir = "#thirdparty/cvtt/"
thirdparty_sources = [
"ConvectionKernels.cpp",
@@ -17,7 +20,15 @@ env_cvtt.Prepend(CPPPATH=[thirdparty_dir])
env_thirdparty = env_cvtt.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
# Godot source files
-env_cvtt.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_cvtt.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/cvtt/image_compress_cvtt.cpp b/modules/cvtt/image_compress_cvtt.cpp
index 2a4f836478..43faa52218 100644
--- a/modules/cvtt/image_compress_cvtt.cpp
+++ b/modules/cvtt/image_compress_cvtt.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,7 +32,7 @@
#include "core/os/os.h"
#include "core/os/thread.h"
-#include "core/print_string.h"
+#include "core/string/print_string.h"
#include <ConvectionKernels.h>
@@ -168,9 +168,10 @@ void image_compress_cvtt(Image *p_image, float p_lossy_quality, Image::UsedChann
flags |= cvtt::Flags::BC7_RespectPunchThrough;
- if (p_channels == Image::USED_CHANNELS_RG) { //guessing this is a normalmap
+ if (p_channels == Image::USED_CHANNELS_RG) { //guessing this is a normal map
flags |= cvtt::Flags::Uniform;
}
+ options.flags = flags;
Image::Format target_format = Image::FORMAT_BPTC_RGBA;
@@ -266,12 +267,13 @@ void image_compress_cvtt(Image *p_image, float p_lossy_quality, Image::UsedChann
job_queue.num_tasks = static_cast<uint32_t>(tasks.size());
for (int i = 0; i < num_job_threads; i++) {
- threads_wb[i] = Thread::create(_digest_job_queue, &job_queue);
+ threads_wb[i] = memnew(Thread);
+ threads_wb[i]->start(_digest_job_queue, &job_queue);
}
_digest_job_queue(&job_queue);
for (int i = 0; i < num_job_threads; i++) {
- Thread::wait_to_finish(threads_wb[i]);
+ threads_wb[i]->wait_to_finish();
memdelete(threads_wb[i]);
}
}
diff --git a/modules/cvtt/image_compress_cvtt.h b/modules/cvtt/image_compress_cvtt.h
index c1772199af..bef5653fa9 100644
--- a/modules/cvtt/image_compress_cvtt.h
+++ b/modules/cvtt/image_compress_cvtt.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,7 +31,7 @@
#ifndef IMAGE_COMPRESS_CVTT_H
#define IMAGE_COMPRESS_CVTT_H
-#include "core/image.h"
+#include "core/io/image.h"
void image_compress_cvtt(Image *p_image, float p_lossy_quality, Image::UsedChannels p_channels);
void image_decompress_cvtt(Image *p_image);
diff --git a/modules/cvtt/register_types.cpp b/modules/cvtt/register_types.cpp
index e4a01cc787..055b5dc6e3 100644
--- a/modules/cvtt/register_types.cpp
+++ b/modules/cvtt/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/cvtt/register_types.h b/modules/cvtt/register_types.h
index 36b5e332d6..e62e8c0e9a 100644
--- a/modules/cvtt/register_types.h
+++ b/modules/cvtt/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/dds/register_types.cpp b/modules/dds/register_types.cpp
index 3991964a28..1444d33171 100644
--- a/modules/dds/register_types.cpp
+++ b/modules/dds/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/dds/register_types.h b/modules/dds/register_types.h
index 3cb7b5c2a6..b84bcd06c8 100644
--- a/modules/dds/register_types.h
+++ b/modules/dds/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/dds/texture_loader_dds.cpp b/modules/dds/texture_loader_dds.cpp
index 2f4f7d7a4c..2865b3c9ae 100644
--- a/modules/dds/texture_loader_dds.cpp
+++ b/modules/dds/texture_loader_dds.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -373,7 +373,6 @@ RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path,
int colcount = size/4;
for(int i=0;i<colcount;i++) {
-
uint8_t r = wb[i*4+1];
uint8_t g = wb[i*4+2];
uint8_t b = wb[i*4+3];
@@ -392,7 +391,6 @@ RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path,
int colcount = size/3;
for(int i=0;i<colcount;i++) {
-
SWAP( wb[i*3+0],wb[i*3+2] );
}*/
} break;
diff --git a/modules/dds/texture_loader_dds.h b/modules/dds/texture_loader_dds.h
index ef08967df7..605e791969 100644
--- a/modules/dds/texture_loader_dds.h
+++ b/modules/dds/texture_loader_dds.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/denoise/SCsub b/modules/denoise/SCsub
index bf3bd7d073..97feea2b44 100644
--- a/modules/denoise/SCsub
+++ b/modules/denoise/SCsub
@@ -8,6 +8,9 @@ Import("env_modules")
env_oidn = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
thirdparty_dir = "#thirdparty/oidn/"
thirdparty_sources = [
"core/api.cpp",
@@ -106,7 +109,8 @@ env_oidn.Append(
env_thirdparty = env_oidn.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
weights_in_path = thirdparty_dir + "weights/rtlightmap_hdr.tza"
weights_out_path = thirdparty_dir + "weights/rtlightmap_hdr.gen.cpp"
@@ -114,5 +118,12 @@ weights_out_path = thirdparty_dir + "weights/rtlightmap_hdr.gen.cpp"
env_thirdparty.Depends(weights_out_path, weights_in_path)
env_thirdparty.CommandNoCache(weights_out_path, weights_in_path, resource_to_cpp.tza_to_cpp)
-env_oidn.add_source_files(env.modules_sources, "denoise_wrapper.cpp")
-env_modules.add_source_files(env.modules_sources, ["register_types.cpp", "lightmap_denoiser.cpp"])
+# Godot source files
+
+module_obj = []
+
+env_oidn.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/denoise/denoise_wrapper.cpp b/modules/denoise/denoise_wrapper.cpp
index c12c6d9c31..e71fce5958 100644
--- a/modules/denoise/denoise_wrapper.cpp
+++ b/modules/denoise/denoise_wrapper.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/denoise/denoise_wrapper.h b/modules/denoise/denoise_wrapper.h
index 2107df09c1..25e342bc93 100644
--- a/modules/denoise/denoise_wrapper.h
+++ b/modules/denoise/denoise_wrapper.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/denoise/lightmap_denoiser.cpp b/modules/denoise/lightmap_denoiser.cpp
index 29d02e8ee2..003bc832b0 100644
--- a/modules/denoise/lightmap_denoiser.cpp
+++ b/modules/denoise/lightmap_denoiser.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/denoise/lightmap_denoiser.h b/modules/denoise/lightmap_denoiser.h
index d01bbd10a5..f1992a1733 100644
--- a/modules/denoise/lightmap_denoiser.h
+++ b/modules/denoise/lightmap_denoiser.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,7 +31,7 @@
#ifndef LIGHTMAP_DENOISER_H
#define LIGHTMAP_DENOISER_H
-#include "core/object.h"
+#include "core/object/class_db.h"
#include "scene/3d/lightmapper.h"
struct OIDNDeviceImpl;
diff --git a/modules/denoise/register_types.cpp b/modules/denoise/register_types.cpp
index b78734a531..936e5f604d 100644
--- a/modules/denoise/register_types.cpp
+++ b/modules/denoise/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,7 +29,7 @@
/*************************************************************************/
#include "register_types.h"
-#include "core/engine.h"
+#include "core/config/engine.h"
#include "lightmap_denoiser.h"
void register_denoise_types() {
diff --git a/modules/denoise/register_types.h b/modules/denoise/register_types.h
index f0f1f44bfe..516a91b134 100644
--- a/modules/denoise/register_types.h
+++ b/modules/denoise/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/enet/SCsub b/modules/enet/SCsub
index c8f4b3885e..580e5a3eb0 100644
--- a/modules/enet/SCsub
+++ b/modules/enet/SCsub
@@ -7,6 +7,8 @@ env_enet = env_modules.Clone()
# Thirdparty source files
+thirdparty_obj = []
+
if env["builtin_enet"]:
thirdparty_dir = "#thirdparty/enet/"
thirdparty_sources = [
@@ -26,6 +28,16 @@ if env["builtin_enet"]:
env_thirdparty = env_enet.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
+
+# Godot source files
+
+module_obj = []
+
+env_enet.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-env_enet.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
index f46ef2d812..6c713fa1ce 100644
--- a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
+++ b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
@@ -5,6 +5,8 @@
</brief_description>
<description>
A PacketPeer implementation that should be passed to [member SceneTree.network_peer] after being initialized as either a client or server. Events can then be handled by connecting to [SceneTree] signals.
+ ENet's purpose is to provide a relatively thin, simple and robust network communication layer on top of UDP (User Datagram Protocol).
+ [b]Note:[/b] ENet only uses UDP, not TCP. When forwarding the server port to make your server accessible on the public Internet, you only need to forward the server port in UDP. You can use the [UPNP] class to try to forward the server port automatically when starting the server.
</description>
<tutorials>
<link title="High-level multiplayer">https://docs.godotengine.org/en/latest/tutorials/networking/high_level_multiplayer.html</link>
diff --git a/modules/enet/networked_multiplayer_enet.cpp b/modules/enet/networked_multiplayer_enet.cpp
index 64977ad237..66db9ab84e 100644
--- a/modules/enet/networked_multiplayer_enet.cpp
+++ b/modules/enet/networked_multiplayer_enet.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/enet/networked_multiplayer_enet.h b/modules/enet/networked_multiplayer_enet.h
index 722c7001fd..4baa48be5e 100644
--- a/modules/enet/networked_multiplayer_enet.h
+++ b/modules/enet/networked_multiplayer_enet.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/enet/register_types.cpp b/modules/enet/register_types.cpp
index 18051f756a..8da2d17e13 100644
--- a/modules/enet/register_types.cpp
+++ b/modules/enet/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,7 +29,7 @@
/*************************************************************************/
#include "register_types.h"
-#include "core/error_macros.h"
+#include "core/error/error_macros.h"
#include "networked_multiplayer_enet.h"
static bool enet_ok = false;
diff --git a/modules/enet/register_types.h b/modules/enet/register_types.h
index cac0a4f7ee..75f4cba61b 100644
--- a/modules/enet/register_types.h
+++ b/modules/enet/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/etc/SCsub b/modules/etc/SCsub
index 383bbf83c3..9b46f17916 100644
--- a/modules/etc/SCsub
+++ b/modules/etc/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_etc = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
# Not unbundled so far since not widespread as shared library
thirdparty_dir = "#thirdparty/etc2comp/"
thirdparty_sources = [
@@ -31,7 +34,15 @@ env_etc.Prepend(CPPPATH=[thirdparty_dir])
env_thirdparty = env_etc.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
# Godot source files
-env_etc.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_etc.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/etc/image_etc.cpp b/modules/etc/image_compress_etc.cpp
index d1ba3dc355..41cbbe3f54 100644
--- a/modules/etc/image_etc.cpp
+++ b/modules/etc/image_compress_etc.cpp
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* image_etc.cpp */
+/* image_compress_etc.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -28,13 +28,15 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "image_etc.h"
-#include "Etc.h"
-#include "EtcFilter.h"
-#include "core/image.h"
+#include "image_compress_etc.h"
+
+#include "core/io/image.h"
#include "core/os/copymem.h"
#include "core/os/os.h"
-#include "core/print_string.h"
+#include "core/string/print_string.h"
+
+#include <Etc.h>
+#include <EtcFilter.h>
static Image::Format _get_etc2_mode(Image::UsedChannels format) {
switch (format) {
@@ -106,7 +108,6 @@ static void _compress_etc(Image *p_img, float p_lossy_quality, bool force_etc1_f
// If VRAM compression is using ETC, but image has alpha, convert to RGBA4444 or LA8
// This saves space while maintaining the alpha channel
if (detected_channels == Image::USED_CHANNELS_RGBA) {
-
if (p_img->has_mipmaps()) {
// Image doesn't support mipmaps with RGBA4444 textures
p_img->clear_mipmaps();
@@ -114,7 +115,6 @@ static void _compress_etc(Image *p_img, float p_lossy_quality, bool force_etc1_f
p_img->convert(Image::FORMAT_RGBA4444);
return;
} else if (detected_channels == Image::USE_CHANNELS_LA) {
-
p_img->convert(Image::FORMAT_LA8);
return;
}
@@ -166,12 +166,12 @@ static void _compress_etc(Image *p_img, float p_lossy_quality, bool force_etc1_f
int encoding_time = 0;
float effort = 0.0; //default, reasonable time
- if (p_lossy_quality > 0.75) {
- effort = 0.4;
+ if (p_lossy_quality > 0.95) {
+ effort = 80;
} else if (p_lossy_quality > 0.85) {
- effort = 0.6;
- } else if (p_lossy_quality > 0.95) {
- effort = 0.8;
+ effort = 60;
+ } else if (p_lossy_quality > 0.75) {
+ effort = 40;
}
Etc::ErrorMetric error_metric = Etc::ErrorMetric::RGBX; // NOTE: we can experiment with other error metrics
diff --git a/modules/etc/image_etc.h b/modules/etc/image_compress_etc.h
index 7b4f26e127..44a06194e9 100644
--- a/modules/etc/image_etc.h
+++ b/modules/etc/image_compress_etc.h
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* image_etc.h */
+/* image_compress_etc.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -28,9 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef IMAGE_ETC1_H
-#define IMAGE_ETC1_H
+#ifndef IMAGE_COMPRESS_ETC_H
+#define IMAGE_COMPRESS_ETC_H
void _register_etc_compress_func();
-#endif // IMAGE_ETC_H
+#endif // IMAGE_COMPRESS_ETC_H
diff --git a/modules/etc/register_types.cpp b/modules/etc/register_types.cpp
index 0972857808..b165bccb3e 100644
--- a/modules/etc/register_types.cpp
+++ b/modules/etc/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,7 +30,7 @@
#include "register_types.h"
-#include "image_etc.h"
+#include "image_compress_etc.h"
#include "texture_loader_pkm.h"
static Ref<ResourceFormatPKM> resource_loader_pkm;
diff --git a/modules/etc/register_types.h b/modules/etc/register_types.h
index 247c7213af..e8cbb635ae 100644
--- a/modules/etc/register_types.h
+++ b/modules/etc/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/etc/texture_loader_pkm.cpp b/modules/etc/texture_loader_pkm.cpp
index c40e9612a8..b0ea109f76 100644
--- a/modules/etc/texture_loader_pkm.cpp
+++ b/modules/etc/texture_loader_pkm.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/etc/texture_loader_pkm.h b/modules/etc/texture_loader_pkm.h
index 6507e0bdec..67fbee3a7e 100644
--- a/modules/etc/texture_loader_pkm.h
+++ b/modules/etc/texture_loader_pkm.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/fbx/README.md b/modules/fbx/README.md
new file mode 100644
index 0000000000..2a2f186463
--- /dev/null
+++ b/modules/fbx/README.md
@@ -0,0 +1,196 @@
+# 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(
+ Transform chain[TransformationComp_MAXIMUM],
+ Transform &geometric_transform) {
+ // Maya pivots
+ Transform T = chain[TransformationComp_Translation];
+ Transform Roff = chain[TransformationComp_RotationOffset];
+ Transform Rp = chain[TransformationComp_RotationPivot];
+ Transform Rpre = chain[TransformationComp_PreRotation];
+ Transform R = chain[TransformationComp_Rotation];
+ Transform Rpost = chain[TransformationComp_PostRotation];
+ Transform Soff = chain[TransformationComp_ScalingOffset];
+ Transform Sp = chain[TransformationComp_ScalingPivot];
+ Transform S = chain[TransformationComp_Scaling];
+
+ // 3DS Max Pivots
+ Transform OT = chain[TransformationComp_GeometricTranslation];
+ Transform OR = chain[TransformationComp_GeometricRotation];
+ Transform 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
new file mode 100644
index 0000000000..84220a66fa
--- /dev/null
+++ b/modules/fbx/SCsub
@@ -0,0 +1,15 @@
+#!/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/"])
+
+# 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
new file mode 100644
index 0000000000..78929800b3
--- /dev/null
+++ b/modules/fbx/config.py
@@ -0,0 +1,16 @@
+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
new file mode 100644
index 0000000000..8c25d65871
--- /dev/null
+++ b/modules/fbx/data/fbx_anim_container.h
@@ -0,0 +1,46 @@
+/*************************************************************************/
+/* fbx_anim_container.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef 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/arkit/arkit_session_delegate.h b/modules/fbx/data/fbx_bone.cpp
index df98bf506e..38dada33af 100644
--- a/modules/arkit/arkit_session_delegate.h
+++ b/modules/fbx/data/fbx_bone.cpp
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* arkit_session_delegate.h */
+/* fbx_bone.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -28,23 +28,29 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef ARKIT_SESSION_DELEGATE_H
-#define ARKIT_SESSION_DELEGATE_H
+#include "fbx_bone.h"
-#import <ARKit/ARKit.h>
-#import <UIKit/UIKit.h>
+#include "fbx_node.h"
+#include "import_state.h"
-class ARKitInterface;
+Ref<FBXNode> FBXSkinDeformer::get_link(const ImportState &state) const {
+ print_verbose("bone name: " + bone->bone_name);
-@interface ARKitSessionDelegate : NSObject <ARSessionDelegate> {
- ARKitInterface *arkit_interface;
-}
+ // safe for when deformers must be polyfilled when skin has different count of binds to bones in the scene ;)
+ if (!cluster) {
+ return nullptr;
+ }
-@property(nonatomic) ARKitInterface *arkit_interface;
+ ERR_FAIL_COND_V_MSG(cluster->TargetNode() == nullptr, nullptr, "bone has invalid target node");
-- (void)session:(ARSession *)session didAddAnchors:(NSArray<ARAnchor *> *)anchors API_AVAILABLE(ios(11.0));
-- (void)session:(ARSession *)session didRemoveAnchors:(NSArray<ARAnchor *> *)anchors API_AVAILABLE(ios(11.0));
-- (void)session:(ARSession *)session didUpdateAnchors:(NSArray<ARAnchor *> *)anchors API_AVAILABLE(ios(11.0));
-@end
+ 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));
+ }
-#endif /* !ARKIT_SESSION_DELEGATE_H */
+ // the node in space this is for, like if it's FOR a target.
+ return link_node;
+}
diff --git a/modules/fbx/data/fbx_bone.h b/modules/fbx/data/fbx_bone.h
new file mode 100644
index 0000000000..efba147b89
--- /dev/null
+++ b/modules/fbx/data/fbx_bone.h
@@ -0,0 +1,90 @@
+/*************************************************************************/
+/* fbx_bone.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef 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 Reference {
+ 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
new file mode 100644
index 0000000000..5995097b2f
--- /dev/null
+++ b/modules/fbx/data/fbx_material.cpp
@@ -0,0 +1,464 @@
+/*************************************************************************/
+/* fbx_material.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "fbx_material.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) {
+ _Directory dir;
+ dir.open(p_base);
+
+ dir.list_dir_begin();
+ String n = dir.get_next();
+ while (n != String()) {
+ 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 != "") {
+ 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) {
+ _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 != String()) {
+ 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 != "") {
+ 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.instance();
+
+ // 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.instance(); // 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.instance();
+ 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->Props()->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->Props();
+ 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.instance();
+ }
+
+ 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_equal_approx(real_value->Value(), 0.0f)) {
+ print_verbose("clearcoat real value: " + rtos(real_value->Value()));
+ spatial_material->set_clearcoat_gloss(1.0 - real_value->Value());
+ } else {
+ print_error("unsupported value type for clearcoat gloss");
+ }
+ } break;
+ case PROPERTY_DESC_EMISSIVE: {
+ if (real_value && Math::is_equal_approx(real_value->Value(), 0.0f)) {
+ 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
new file mode 100644
index 0000000000..23310b8e1d
--- /dev/null
+++ b/modules/fbx/data/fbx_material.h
@@ -0,0 +1,285 @@
+/*************************************************************************/
+/* fbx_material.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef FBX_MATERIAL_H
+#define FBX_MATERIAL_H
+
+#include "tools/import_utils.h"
+
+#include "core/object/reference.h"
+#include "core/string/ustring.h"
+
+struct FBXMaterial : public Reference {
+ 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 : Reference {
+ 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
new file mode 100644
index 0000000000..883651943e
--- /dev/null
+++ b/modules/fbx/data/fbx_mesh_data.cpp
@@ -0,0 +1,1447 @@
+/*************************************************************************/
+/* fbx_mesh_data.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "fbx_mesh_data.h"
+
+#include "core/templates/local_vector.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;
+}
+
+typedef int Vertex;
+typedef int SurfaceId;
+typedef int PolygonId;
+typedef int DataIndex;
+
+struct SurfaceData {
+ Ref<SurfaceTool> surface_tool;
+ OrderedHashMap<Vertex, int> lookup_table; // proposed fix is to replace lookup_table[vertex_id] to give the position of the vertices_map[int] index.
+ LocalVector<Vertex> vertices_map; // this must be ordered the same as insertion <-- slow to do find() operation.
+ Ref<Material> material;
+ HashMap<PolygonId, Vector<DataIndex>> surface_polygon_vertex;
+ Array morphs;
+};
+
+EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression) {
+ mesh_geometry = p_mesh_geometry;
+ // todo: make this just use a uint64_t FBX ID this is a copy of our original materials unfortunately.
+ 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);
+
+ // Re organize polygon vertices to 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.instance();
+ 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->surface_tool,
+ *indices,
+ surface->vertices_map,
+ 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.instance();
+ 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<EditorSceneImporterMesh> mesh;
+ mesh.instance();
+
+ // 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.
+ int in_mesh_surface_id = 0;
+ 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);
+ }
+
+ in_mesh_surface_id += 1;
+ }
+
+ EditorSceneImporterMeshNode3D *godot_mesh = memnew(EditorSceneImporterMeshNode3D);
+ godot_mesh->set_mesh(mesh);
+ 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()) {
+ 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
+ real_t *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);
+ real_t *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 ((this_vert_poly_normal - vert_poly_normal).length_squared() > CMP_EPSILON) {
+ // 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 (((*this_vert_poly_uv) - vert_poly_uv).length_squared() > CMP_EPSILON) {
+ // 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(Ref<SurfaceTool> st, Vector<int> p_polygon_vertex, const Vector<Vertex> p_surface_vertex_map, const std::vector<Vector3> &p_vertices) const {
+ const int polygon_vertex_count = p_polygon_vertex.size();
+ 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[p_surface_vertex_map[p_polygon_vertex[i]]];
+ const Vector3 p2 = p_vertices[p_surface_vertex_map[p_polygon_vertex[(i + 1) % polygon_vertex_count]]];
+ const Vector3 p3 = p_vertices[p_surface_vertex_map[p_polygon_vertex[(i + 2) % polygon_vertex_count]]];
+
+ const Vector3 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[p_surface_vertex_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 retuned 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 = 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 = 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
new file mode 100644
index 0000000000..77510ff2ec
--- /dev/null
+++ b/modules/fbx/data/fbx_mesh_data.h
@@ -0,0 +1,184 @@
+/*************************************************************************/
+/* fbx_mesh_data.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef FBX_MESH_DATA_H
+#define FBX_MESH_DATA_H
+
+#include "core/templates/hash_map.h"
+#include "editor/import/resource_importer_scene.h"
+#include "editor/import/scene_importer_mesh_node_3d.h"
+#include "scene/3d/mesh_instance_3d.h"
+#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;
+
+struct VertexWeightMapping {
+ Vector<real_t> 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 : Reference {
+ 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;
+
+ EditorSceneImporterMeshNode3D *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;
+ EditorSceneImporterMeshNode3D *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(Ref<SurfaceTool> st, Vector<int> p_polygon_vertex, Vector<int> p_surface_vertex_map, 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 poligon 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_node.h b/modules/fbx/data/fbx_node.h
new file mode 100644
index 0000000000..a6f62f3388
--- /dev/null
+++ b/modules/fbx/data/fbx_node.h
@@ -0,0 +1,63 @@
+/*************************************************************************/
+/* fbx_node.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef FBX_NODE_H
+#define FBX_NODE_H
+
+#include "fbx_skeleton.h"
+#include "model_abstraction.h"
+#include "pivot_transform.h"
+
+#include "fbx_parser/FBXDocument.h"
+
+class Node3D;
+struct PivotTransform;
+
+struct FBXNode : Reference, ModelAbstraction {
+ uint64_t current_node_id = 0;
+ String node_name = String();
+ Node3D *godot_node = nullptr;
+
+ // used to parent the skeleton once the tree is built.
+ Ref<FBXSkeleton> skeleton_node = Ref<FBXSkeleton>();
+
+ void set_parent(Ref<FBXNode> p_parent) {
+ fbx_parent = p_parent;
+ }
+
+ 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
+};
+
+#endif // FBX_NODE_H
diff --git a/modules/fbx/data/fbx_skeleton.cpp b/modules/fbx/data/fbx_skeleton.cpp
new file mode 100644
index 0000000000..622b589feb
--- /dev/null
+++ b/modules/fbx/data/fbx_skeleton.cpp
@@ -0,0 +1,123 @@
+/*************************************************************************/
+/* fbx_skeleton.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "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; 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 (Map<int, Ref<FBXBone>>::Element *bone_element = bone_map.front(); bone_element; bone_element = bone_element->next()) {
+ 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));
+
+ // 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/fbx_skeleton.h b/modules/fbx/data/fbx_skeleton.h
new file mode 100644
index 0000000000..df937cde49
--- /dev/null
+++ b/modules/fbx/data/fbx_skeleton.h
@@ -0,0 +1,53 @@
+/*************************************************************************/
+/* fbx_skeleton.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef FBX_SKELETON_H
+#define FBX_SKELETON_H
+
+#include "fbx_bone.h"
+#include "fbx_node.h"
+#include "model_abstraction.h"
+
+#include "core/object/reference.h"
+#include "scene/3d/skeleton_3d.h"
+
+struct FBXNode;
+struct ImportState;
+struct FBXBone;
+
+struct FBXSkeleton : Reference {
+ Ref<FBXNode> fbx_node = Ref<FBXNode>();
+ Vector<Ref<FBXBone>> skeleton_bones = Vector<Ref<FBXBone>>();
+ Skeleton3D *skeleton = nullptr;
+
+ void init_skeleton(const ImportState &state);
+};
+
+#endif // FBX_SKELETON_H
diff --git a/modules/fbx/data/import_state.h b/modules/fbx/data/import_state.h
new file mode 100644
index 0000000000..83bc43faff
--- /dev/null
+++ b/modules/fbx/data/import_state.h
@@ -0,0 +1,113 @@
+/*************************************************************************/
+/* import_state.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef 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/core_bind.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
new file mode 100644
index 0000000000..528960ab49
--- /dev/null
+++ b/modules/fbx/data/model_abstraction.h
@@ -0,0 +1,52 @@
+/*************************************************************************/
+/* model_abstraction.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef 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
new file mode 100644
index 0000000000..1895af6f9f
--- /dev/null
+++ b/modules/fbx/data/pivot_transform.cpp
@@ -0,0 +1,307 @@
+/*************************************************************************/
+/* pivot_transform.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "pivot_transform.h"
+
+#include "tools/import_utils.h"
+
+void PivotTransform::ReadTransformChain() {
+ const FBXDocParser::PropertyTable *props = fbx_model->Props();
+ 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 = Quat();
+ }
+
+ 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 != Quat()) {
+ 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);
+ }
+}
+
+Transform PivotTransform::ComputeLocalTransform(Vector3 p_translation, Quat p_rotation, Vector3 p_scaling) const {
+ Transform 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
+ Transform Rpre = Transform(pre_rotation);
+ Transform R = Transform(p_rotation);
+ Transform Rpost = Transform(post_rotation);
+
+ return T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse();
+}
+
+Transform PivotTransform::ComputeGlobalTransform(Transform t) const {
+ Vector3 pos = t.origin;
+ Vector3 scale = t.basis.get_scale();
+ Quat rot = t.basis.get_rotation_quat();
+ return ComputeGlobalTransform(pos, rot, scale);
+}
+
+Transform PivotTransform::ComputeLocalTransform(Transform t) const {
+ Vector3 pos = t.origin;
+ Vector3 scale = t.basis.get_scale();
+ Quat rot = t.basis.get_rotation_quat();
+ return ComputeLocalTransform(pos, rot, scale);
+}
+
+Transform PivotTransform::ComputeGlobalTransform(Vector3 p_translation, Quat p_rotation, Vector3 p_scaling) const {
+ Transform T, Roff, Rp, Soff, Sp, S;
+
+ // 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
+ Transform Rpre = Transform(pre_rotation);
+ Transform R = Transform(p_rotation);
+ Transform Rpost = Transform(post_rotation);
+
+ Transform parent_global_xform;
+ Transform parent_local_scaling_m;
+
+ if (parent_transform.is_valid()) {
+ parent_global_xform = parent_transform->GlobalTransform;
+ parent_local_scaling_m = parent_transform->Local_Scaling_Matrix;
+ }
+
+ Transform local_rotation_m, parent_global_rotation_m;
+ Quat parent_global_rotation = parent_global_xform.basis.get_rotation_quat();
+ parent_global_rotation_m.basis.set_quat(parent_global_rotation);
+ local_rotation_m = Rpre * R * Rpost;
+
+ //Basis parent_global_rotation = Basis(parent_global_xform.get_basis().get_rotation_quat().normalized());
+
+ Transform 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.
+ Transform global_rotation_scale;
+ if (inherit_type == FBXDocParser::Transform_RrSs) {
+ global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_shear_scaling * local_shear_scaling;
+ } else if (inherit_type == FBXDocParser::Transform_RSrs) {
+ global_rotation_scale = parent_global_rotation_m * parent_shear_scaling * local_rotation_m * local_shear_scaling;
+ } else if (inherit_type == FBXDocParser::Transform_Rrs) {
+ Transform parent_global_shear_m_noLocal = parent_shear_scaling * parent_local_scaling_m.affine_inverse();
+ global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_global_shear_m_noLocal * local_shear_scaling;
+ }
+ Transform local_transform = T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse();
+ //Transform local_translation_pivoted = Transform(Basis(), LocalTransform.origin);
+
+ ERR_FAIL_COND_V_MSG(local_transform.basis.determinant() == 0, Transform(), "Det == 0 prevented in scene file");
+
+ // manual hack to force SSC not to be compensated for - until we can handle it properly with tests
+ return parent_global_xform * local_transform;
+}
+
+void PivotTransform::ComputePivotTransform() {
+ Transform T, Roff, Rp, Soff, Sp, S;
+
+ // 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
+ Transform Rpre = Transform(pre_rotation);
+ Transform R = Transform(rotation);
+ Transform Rpost = Transform(post_rotation);
+
+ Transform parent_global_xform;
+ Transform parent_local_scaling_m;
+
+ if (parent_transform.is_valid()) {
+ parent_global_xform = parent_transform->GlobalTransform;
+ parent_local_scaling_m = parent_transform->Local_Scaling_Matrix;
+ }
+
+ Transform local_rotation_m, parent_global_rotation_m;
+ Quat parent_global_rotation = parent_global_xform.basis.get_rotation_quat();
+ parent_global_rotation_m.basis.set_quat(parent_global_rotation);
+ local_rotation_m = Rpre * R * Rpost;
+
+ //Basis parent_global_rotation = Basis(parent_global_xform.get_basis().get_rotation_quat().normalized());
+
+ Transform 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.
+ Transform global_rotation_scale;
+ if (inherit_type == FBXDocParser::Transform_RrSs) {
+ global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_shear_scaling * local_shear_scaling;
+ } else if (inherit_type == FBXDocParser::Transform_RSrs) {
+ global_rotation_scale = parent_global_rotation_m * parent_shear_scaling * local_rotation_m * local_shear_scaling;
+ } else if (inherit_type == FBXDocParser::Transform_Rrs) {
+ Transform parent_global_shear_m_noLocal = parent_shear_scaling * parent_local_scaling_m.inverse();
+ global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_global_shear_m_noLocal * local_shear_scaling;
+ }
+ LocalTransform = Transform();
+ LocalTransform = T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse();
+
+ ERR_FAIL_COND_MSG(LocalTransform.basis.determinant() == 0, "invalid scale reset");
+
+ Transform local_translation_pivoted = Transform(Basis(), LocalTransform.origin);
+ GlobalTransform = Transform();
+ //GlobalTransform = parent_global_xform * LocalTransform;
+ Transform global_origin = Transform(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
new file mode 100644
index 0000000000..9996027870
--- /dev/null
+++ b/modules/fbx/data/pivot_transform.h
@@ -0,0 +1,115 @@
+/*************************************************************************/
+/* pivot_transform.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef PIVOT_TRANSFORM_H
+#define PIVOT_TRANSFORM_H
+
+#include "core/math/transform.h"
+#include "core/object/reference.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 : Reference, ModelAbstraction {
+ // at the end we want to keep geometric_ everything, post and pre rotation
+ // these are used during animation data processing / keyframe ingestion the rest can be simplified down / out.
+ Quat pre_rotation = Quat();
+ Quat post_rotation = Quat();
+ Quat rotation = Quat();
+ Quat geometric_rotation = Quat();
+ 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));
+ }
+
+ Transform ComputeGlobalTransform(Transform t) const;
+ Transform ComputeLocalTransform(Transform t) const;
+ Transform ComputeGlobalTransform(Vector3 p_translation, Quat p_rotation, Vector3 p_scaling) const;
+ Transform ComputeLocalTransform(Vector3 p_translation, Quat p_rotation, Vector3 p_scaling) const;
+
+ /* 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
+ Transform GlobalTransform = Transform();
+ Transform LocalTransform = Transform();
+ Transform Local_Scaling_Matrix = Transform(); // used for inherit type.
+ Transform GeometricTransform = Transform(); // 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/doc_classes/EditorSceneImporterFBX.xml b/modules/fbx/doc_classes/EditorSceneImporterFBX.xml
new file mode 100644
index 0000000000..da1a68c27c
--- /dev/null
+++ b/modules/fbx/doc_classes/EditorSceneImporterFBX.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="EditorSceneImporterFBX" inherits="EditorSceneImporter" version="4.0">
+ <brief_description>
+ FBX 3D asset importer.
+ </brief_description>
+ <description>
+ This is an FBX 3D asset importer with full support for most FBX features.
+ If exporting a FBX scene from Autodesk Maya, use these FBX export settings:
+ [codeblock]
+ - Smoothing Groups
+ - Smooth Mesh
+ - Triangluate (for meshes with blend shapes)
+ - Bake Animation
+ - Resample All
+ - Deformed Models
+ - Skins
+ - Blend Shapes
+ - Curve Filters
+ - Constant Key Reducer
+ - Auto Tangents Only
+ - *Do not check* Constraints (as it will break the file)
+ - Can check Embed Media (embeds textures into the exported FBX file)
+ - Note that when importing embedded media, the texture and mesh will be a single immutable file.
+ - You will have to re-export then re-import the FBX if the texture has changed.
+ - Units: Centimeters
+ - Up Axis: Y
+ - Binary format in FBX 2017
+ [/codeblock]
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/modules/fbx/editor_scene_importer_fbx.cpp b/modules/fbx/editor_scene_importer_fbx.cpp
new file mode 100644
index 0000000000..6576147b2b
--- /dev/null
+++ b/modules/fbx/editor_scene_importer_fbx.cpp
@@ -0,0 +1,1427 @@
+/*************************************************************************/
+/* editor_scene_importer_fbx.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "editor_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 "editor/import/scene_importer_mesh_node_3d.h"
+#include "scene/3d/bone_attachment_3d.h"
+#include "scene/3d/camera_3d.h"
+#include "scene/3d/light_3d.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/main/node.h"
+#include "scene/resources/material.h"
+
+#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 EditorSceneImporterFBX::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 EditorSceneImporterFBX::_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 EditorSceneImporterFBX::get_import_flags() const {
+ return IMPORT_SCENE;
+}
+
+Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_flags, 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, NULL);
+
+ {
+ 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_len());
+ 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);
+
+ // safer to check this way as there can be different formatted headers
+ if (fbx_header_string.find("Kaydara FBX Binary", 0) != -1) {
+ is_binary = true;
+ print_verbose("[doc] is binary");
+ FBXDocParser::TokenizeBinary(tokens, (const char *)data.ptrw(), (size_t)data.size());
+ } else {
+ print_verbose("[doc] is ascii");
+ FBXDocParser::Tokenize(tokens, (const char *)data.ptrw(), (size_t)data.size());
+ }
+
+ // 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);
+ 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::PropertyPtr app_vendor = p_document->GlobalSettingsPtr()->Props()
+ // p_document->Creator()
+ const FBXDocParser::PropertyTable *import_props = doc.GetMetadataProperties();
+ const FBXDocParser::PropertyPtr app_name = import_props->Get("Original|ApplicationName");
+ const FBXDocParser::PropertyPtr app_vendor = import_props->Get("Original|ApplicationVendor");
+ const FBXDocParser::PropertyPtr app_version = import_props->Get("Original|ApplicationVersion");
+ //
+ 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 {
+ 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 EditorSceneImporterAssetImportInterpolate {
+ 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 EditorSceneImporterAssetImportInterpolate<Quat> {
+ Quat lerp(const Quat &a, const Quat &b, float c) const {
+ ERR_FAIL_COND_V(!a.is_normalized(), Quat());
+ ERR_FAIL_COND_V(!b.is_normalized(), Quat());
+
+ return a.slerp(b, c).normalized();
+ }
+
+ Quat catmull_rom(const Quat &p0, const Quat &p1, const Quat &p2, const Quat &p3, float c) {
+ ERR_FAIL_COND_V(!p1.is_normalized(), Quat());
+ ERR_FAIL_COND_V(!p2.is_normalized(), Quat());
+
+ return p1.slerp(p2, c).normalized();
+ }
+
+ Quat bezier(Quat start, Quat control_1, Quat control_2, Quat end, float t) {
+ ERR_FAIL_COND_V(!start.is_normalized(), Quat());
+ ERR_FAIL_COND_V(!end.is_normalized(), Quat());
+
+ return start.slerp(end, t).normalized();
+ }
+};
+
+template <class T>
+T EditorSceneImporterFBX::_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++;
+ }
+
+ EditorSceneImporterAssetImportInterpolate<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 *EditorSceneImporterFBX::_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 = NULL;
+
+ // 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.instance();
+ 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.instance();
+
+ // make sure fake noFBXDocParser::PropertyPtr ptrde always has a transform too ;)
+ Ref<PivotTransform> pivot_transform;
+ pivot_transform.instance();
+ 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.instance();
+ 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.instance();
+ 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 (Map<uint64_t, Ref<FBXBone>>::Element *bone_element = state.fbx_bone_map.front(); bone_element; bone_element = bone_element->next()) {
+ 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.instance();
+ 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 (Map<uint64_t, Ref<FBXSkeleton>>::Element *skeleton_node = state.skeleton_map.front(); skeleton_node; skeleton_node = skeleton_node->next()) {
+ 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();
+ EditorSceneImporterMeshNode3D *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.instance();
+ 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, (p_flags & IMPORT_USE_COMPRESSION) != 0);
+ 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 (Map<uint64_t, Ref<FBXMeshData>>::Element *mesh_data = state.renderer_mesh_data.front(); mesh_data; mesh_data = mesh_data->next()) {
+ 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.instance();
+ 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 (Map<uint64_t, Ref<FBXMeshData>>::Element *mesh_data = state.renderer_mesh_data.front(); mesh_data; mesh_data = mesh_data->next()) {
+ Ref<FBXMeshData> mesh = mesh_data->value();
+ const uint64_t mesh_id = mesh_data->key();
+ EditorSceneImporterMeshNode3D *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);
+ state.animation_player->set_owner(state.root_owner);
+ }
+
+ Ref<Animation> animation;
+ animation.instance();
+ 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 quat_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()));
+ quat_rotation_order = target->RotationOrder();
+ }
+
+ uint64_t target_id = target->ID();
+ String target_name = ImportUtils::FBXNodeToName(target->Name());
+
+ const FBXDocParser::PropertyTable *properties = curve_node->Props();
+ 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 (Map<uint64_t, Map<StringName, FBXTrack>>::Element *track = AnimCurveNodes.front(); track; track = track->next()) {
+ // 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();
+ int track_idx = animation->add_track(Animation::TYPE_TRANSFORM);
+
+ // animation->track_set_path(track_idx, node_path);
+ // animation->track_set_path(track_idx, node_path);
+ Ref<FBXBone> bone;
+
+ // note we must not run the below code if the entry doesn't exist, it will create dummy entries which is very bad.
+ // 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];
+ }
+
+ Transform 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
+ 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);
+ NodePath path = bone_path;
+ animation->track_set_path(track_idx, 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);
+ NodePath path = node_path;
+ animation->track_set_path(track_idx, 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 bizzare 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 = model->Props();
+
+ 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<Quat> 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;
+
+ Quat post_rotation;
+ Quat 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));
+ }
+
+ Quat lastQuat = Quat();
+
+ for (std::pair<int64_t, Vector3> rotation_key : rotation_keys.keyframes) {
+ double animation_track_time = CONVERT_FBX_TIME(rotation_key.first);
+
+ //print_verbose("euler rotation key: " + rotation_key.second);
+ Quat rot_key_value = ImportUtils::EulerToQuaternion(quat_rotation_order, ImportUtils::deg2rad(rotation_key.second));
+
+ if (lastQuat != Quat() && rot_key_value.dot(lastQuat) < 0) {
+ rot_key_value.x = -rot_key_value.x;
+ rot_key_value.y = -rot_key_value.y;
+ rot_key_value.z = -rot_key_value.z;
+ rot_key_value.w = -rot_key_value.w;
+ }
+ // pre_post rotation possibly could fix orientation
+ Quat final_rotation = pre_rotation * rot_key_value * post_rotation;
+
+ lastQuat = final_rotation;
+
+ if (animation_track_time > max_duration) {
+ max_duration = animation_track_time;
+ }
+
+ rot_values.push_back(final_rotation);
+ rot_times.push_back(animation_track_time);
+ }
+
+ bool valid_rest = false;
+ Transform 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 Quat def_rot = rotation_keys.has_default ? ImportUtils::EulerToQuaternion(quat_rotation_order, ImportUtils::deg2rad(rotation_keys.default_value)) : bone_rest.basis.get_rotation_quat();
+ const Vector3 def_scale = scale_keys.has_default ? scale_keys.default_value : bone_rest.basis.get_scale();
+ print_verbose("track defaults: p(" + def_pos + ") s(" + def_scale + ") r(" + def_rot + ")");
+
+ while (true) {
+ Vector3 pos = def_pos;
+ Quat rot = def_rot;
+ 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<Quat>(rot_times, rot_values, time,
+ AssetImportAnimation::INTERP_LINEAR);
+ }
+
+ if (scale_values.size()) {
+ scale = _interpolate_track<Vector3>(scale_times, scale_values, time,
+ AssetImportAnimation::INTERP_LINEAR);
+ }
+
+ // node animations must also include pivots
+ if (skeleton_bone >= 0) {
+ Transform xform = Transform();
+ xform.basis.set_quat_scale(rot, scale);
+ xform.origin = pos;
+ const Transform t = bone_rest.affine_inverse() * xform;
+
+ // populate this again
+ rot = t.basis.get_rotation_quat();
+ rot.normalize();
+ scale = t.basis.get_scale();
+ pos = t.origin;
+ }
+
+ animation->transform_track_insert_key(track_idx, time, pos, rot, 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 (Map<uint64_t, Ref<FBXBone>>::Element *element = state.fbx_bone_map.front(); element; element = element->next()) {
+ Ref<FBXBone> bone = element->value();
+ bone->parent_bone.unref();
+ bone->node.unref();
+ bone->fbx_skeleton.unref();
+ }
+
+ for (Map<uint64_t, Ref<FBXSkeleton>>::Element *element = state.skeleton_map.front(); element; element = element->next()) {
+ 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 EditorSceneImporterFBX::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 .instanced() 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.instance();
+
+ // 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 EditorSceneImporterFBX::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.instance();
+ new_node->current_node_id = current_node_id;
+ new_node->node_name = ImportUtils::FBXNodeToName(model->Name());
+
+ Ref<PivotTransform> fbx_transform;
+ fbx_transform.instance();
+ 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);
+ }
+ }
+}
diff --git a/modules/fbx/editor_scene_importer_fbx.h b/modules/fbx/editor_scene_importer_fbx.h
new file mode 100644
index 0000000000..39f8648b0f
--- /dev/null
+++ b/modules/fbx/editor_scene_importer_fbx.h
@@ -0,0 +1,135 @@
+/*************************************************************************/
+/* editor_scene_importer_fbx.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef EDITOR_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/core_bind.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 EditorSceneImporterFBX : public EditorSceneImporter {
+private:
+ GDCLASS(EditorSceneImporterFBX, EditorSceneImporter);
+
+ 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:
+ EditorSceneImporterFBX() {}
+ ~EditorSceneImporterFBX() {}
+
+ virtual void get_extensions(List<String> *r_extensions) const override;
+ virtual uint32_t get_import_flags() const override;
+ virtual Node3D *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = NULL) override;
+};
+
+#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
new file mode 100644
index 0000000000..f759c9117c
--- /dev/null
+++ b/modules/fbx/fbx_parser/ByteSwapper.h
@@ -0,0 +1,282 @@
+/*************************************************************************/
+/* ByteSwapper.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+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 oder 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
new file mode 100644
index 0000000000..62b449614e
--- /dev/null
+++ b/modules/fbx/fbx_parser/CREDITS
@@ -0,0 +1,183 @@
+===============================================================
+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
new file mode 100644
index 0000000000..b11e2c7f55
--- /dev/null
+++ b/modules/fbx/fbx_parser/FBXAnimation.cpp
@@ -0,0 +1,290 @@
+/*************************************************************************/
+/* FBXAnimation.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+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 /*= NULL*/,
+ size_t whitelist_size /*= 0*/) :
+ Object(id, element, name), target(), doc(doc) {
+ const ScopePtr sc = GetRequiredScope(element);
+
+ // find target node
+ const char *whitelist[] = { "Model", "NodeAttribute", "Deformer" };
+ const std::vector<const Connection *> &conns = doc.GetConnectionsBySourceSequenced(ID(), whitelist, 3);
+
+ 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;
+ }
+
+ props = GetPropertyTable(doc, "AnimationCurveNode.FbxAnimCurveNode", element, sc, false);
+}
+
+// ------------------------------------------------------------------------------------------------
+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) {
+ const ScopePtr sc = GetRequiredScope(element);
+
+ // note: the props table here bears little importance and is usually absent
+ props = GetPropertyTable(doc, "AnimationLayer.FbxAnimLayer", element, sc, true);
+}
+
+// ------------------------------------------------------------------------------------------------
+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) {
+ const ScopePtr sc = GetRequiredScope(element);
+
+ // note: we don't currently use any of these properties so we shouldn't bother if it is missing
+ props = GetPropertyTable(doc, "AnimationStack.FbxAnimStack", element, sc, true);
+
+ // resolve attached animation layers
+ const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationLayer");
+ layers.reserve(conns.size());
+
+ 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() {
+ if (props != nullptr) {
+ delete props;
+ props = nullptr;
+ }
+}
+} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp b/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp
new file mode 100644
index 0000000000..1d2b7765c5
--- /dev/null
+++ b/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp
@@ -0,0 +1,467 @@
+/*************************************************************************/
+/* FBXBinaryTokenizer.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+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 {
+//enum Flag
+//{
+// e_unknown_0 = 1 << 0,
+// e_unknown_1 = 1 << 1,
+// e_unknown_2 = 1 << 2,
+// e_unknown_3 = 1 << 3,
+// e_unknown_4 = 1 << 4,
+// e_unknown_5 = 1 << 5,
+// e_unknown_6 = 1 << 6,
+// e_unknown_7 = 1 << 7,
+// e_unknown_8 = 1 << 8,
+// e_unknown_9 = 1 << 9,
+// e_unknown_10 = 1 << 10,
+// e_unknown_11 = 1 << 11,
+// e_unknown_12 = 1 << 12,
+// e_unknown_13 = 1 << 13,
+// e_unknown_14 = 1 << 14,
+// e_unknown_15 = 1 << 15,
+// e_unknown_16 = 1 << 16,
+// e_unknown_17 = 1 << 17,
+// e_unknown_18 = 1 << 18,
+// e_unknown_19 = 1 << 19,
+// e_unknown_20 = 1 << 20,
+// e_unknown_21 = 1 << 21,
+// e_unknown_22 = 1 << 22,
+// e_unknown_23 = 1 << 23,
+// e_flag_field_size_64_bit = 1 << 24, // Not sure what is
+// e_unknown_25 = 1 << 25,
+// e_unknown_26 = 1 << 26,
+// e_unknown_27 = 1 << 27,
+// e_unknown_28 = 1 << 28,
+// e_unknown_29 = 1 << 29,
+// e_unknown_30 = 1 << 30,
+// e_unknown_31 = 1 << 31
+//};
+//
+//bool check_flag(uint32_t flags, Flag to_check)
+//{
+// return (flags & to_check) != 0;
+//}
+// ------------------------------------------------------------------------------------------------
+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 = 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) {
+ if (Offset(cursor, end) < 1) {
+ TokenizeError("cannot ReadData, out of bounds reading length", input, cursor);
+ }
+
+ 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:
+ TokenizeError("cannot ReadData, unexpected type code: " + std::string(&type, 1), input, cursor);
+ }
+
+ if (cursor > end) {
+ TokenizeError("cannot ReadData, the remaining size is too small for the data type: " + std::string(&type, 1), input, cursor);
+ }
+
+ // 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) {
+ // 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);
+ } else if (end_offset < Offset(input, cursor)) {
+ TokenizeError("block offset is negative out of range", input, cursor);
+ }
+
+ // 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, *send;
+ 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);
+
+ 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);
+ }
+
+ // 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);
+ }
+ 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);
+ }
+ }
+ cursor += sentinel_block_length;
+ }
+
+ if (Offset(input, cursor) != end_offset) {
+ TokenizeError("scope length not reached, something is wrong", input, cursor);
+ }
+
+ 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) {
+ if (length < 0x1b) {
+ //TokenizeError("file is too short",0);
+ }
+
+ //uint32_t offset = 0x15;
+ /* const char* cursor = input + 0x15;
+ const uint32_t flags = ReadWord(input, cursor, input + length);
+ const uint8_t padding_0 = ReadByte(input, cursor, input + length); // unused
+ const uint8_t padding_1 = ReadByte(input, cursor, input + length); // unused*/
+
+ 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)) {
+ break;
+ }
+ }
+}
+} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXCommon.h b/modules/fbx/fbx_parser/FBXCommon.h
new file mode 100644
index 0000000000..641d6d351e
--- /dev/null
+++ b/modules/fbx/fbx_parser/FBXCommon.h
@@ -0,0 +1,110 @@
+/*************************************************************************/
+/* FBXCommon.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+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
new file mode 100644
index 0000000000..4b774e6b2a
--- /dev/null
+++ b/modules/fbx/fbx_parser/FBXDeformer.cpp
@@ -0,0 +1,279 @@
+/*************************************************************************/
+/* FBXDeformer.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+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.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) {
+ const ScopePtr sc = GetRequiredScope(element);
+
+ const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
+ props = GetPropertyTable(doc, "Deformer.Fbx" + classname, element, sc, true);
+}
+
+// ------------------------------------------------------------------------------------------------
+Deformer::~Deformer() {
+}
+
+Constraint::Constraint(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
+ Object(id, element, name) {
+ const ScopePtr sc = GetRequiredScope(element);
+ const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
+ // used something.fbx as this is a cache name.
+ props = GetPropertyTable(doc, "Something.Fbx" + classname, element, sc, true);
+}
+
+Constraint::~Constraint() {
+}
+
+// ------------------------------------------------------------------------------------------------
+Cluster::Cluster(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
+ Deformer(id, element, doc, name), valid_transformAssociateModel(false) {
+ 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), accuracy(0.0f) {
+ 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
new file mode 100644
index 0000000000..bcf7fa1565
--- /dev/null
+++ b/modules/fbx/fbx_parser/FBXDocument.cpp
@@ -0,0 +1,713 @@
+/*************************************************************************/
+/* FBXDocument.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+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), flags() {
+ // 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 supporte
+ 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) :
+ element(element), name(name), id(id) {
+}
+
+// ------------------------------------------------------------------------------------------------
+Object::~Object() {
+ // empty
+}
+
+// ------------------------------------------------------------------------------------------------
+FileGlobalSettings::FileGlobalSettings(const Document &doc, const PropertyTable *props) :
+ props(props), doc(doc) {
+ // empty
+}
+
+// ------------------------------------------------------------------------------------------------
+FileGlobalSettings::~FileGlobalSettings() {
+ if (props != nullptr) {
+ delete props;
+ props = nullptr;
+ }
+}
+
+// ------------------------------------------------------------------------------------------------
+Document::Document(const Parser &parser, const ImportSettings &settings) :
+ settings(settings), parser(parser), SafeToImport(false) {
+ // 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;
+ }
+
+ if (metadata_properties != nullptr) {
+ delete metadata_properties;
+ }
+ // clear globals import pointer
+ globals.reset();
+}
+
+// ------------------------------------------------------------------------------------------------
+static const unsigned int LowerSupportedVersion = 7300;
+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");
+ }
+
+ 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) {
+ PropertyTable *fileExportProps = const_cast<PropertyTable *>(GetPropertyTable(*this, "", scene_info, scene_info->Compound(), true));
+
+ if (fileExportProps) {
+ metadata_properties = fileExportProps;
+ }
+ }
+
+ 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");
+
+ const ScopePtr sc = parser.GetRootScope();
+ const ElementPtr ehead = sc->GetElement("GlobalSettings");
+ if (nullptr == ehead || !ehead->Compound()) {
+ DOMWarning("no GlobalSettings dictionary found");
+ globals = std::make_shared<FileGlobalSettings>(*this, new PropertyTable());
+ return;
+ }
+
+ const PropertyTable *props = GetPropertyTable(*this, "", ehead, ehead->Compound(), true);
+
+ //double v = PropertyGet<float>( *props, std::string("UnitScaleFactor"), 1.0 );
+
+ if (!props) {
+ DOMError("GlobalSettings dictionary contains no property table");
+ }
+
+ globals = std::make_shared<FileGlobalSettings>(*this, props);
+}
+
+// ------------------------------------------------------------------------------------------------
+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() {
+ const ScopePtr sc = parser.GetRootScope();
+ // read property templates from "Definitions" section
+ const ElementPtr edefs = sc->GetElement("Definitions");
+ if (!edefs || !edefs->Compound()) {
+ DOMWarning("no Definitions dictionary found");
+ return;
+ }
+
+ const ScopePtr sdefs = edefs->Compound();
+ const ElementCollection otypes = sdefs->GetCollection("ObjectType");
+ for (ElementMap::const_iterator it = otypes.first; it != otypes.second; ++it) {
+ const ElementPtr el = (*it).second;
+ const ScopePtr sc_2 = el->Compound();
+ if (!sc_2) {
+ DOMWarning("expected nested scope in ObjectType, ignoring", el);
+ continue;
+ }
+
+ const TokenList &tok = el->Tokens();
+ if (tok.empty()) {
+ DOMWarning("expected name for ObjectType element, ignoring", el);
+ continue;
+ }
+
+ const std::string &oname = ParseTokenAsString(tok[0]);
+
+ const ElementCollection templs = sc_2->GetCollection("PropertyTemplate");
+ for (ElementMap::const_iterator iter = templs.first; iter != templs.second; ++iter) {
+ const ElementPtr el_2 = (*iter).second;
+ const ScopePtr sc_3 = el_2->Compound();
+ if (!sc_3) {
+ DOMWarning("expected nested scope in PropertyTemplate, ignoring", el);
+ continue;
+ }
+
+ const TokenList &tok_2 = el_2->Tokens();
+ if (tok_2.empty()) {
+ DOMWarning("expected name for PropertyTemplate element, ignoring", el);
+ continue;
+ }
+
+ const std::string &pname = ParseTokenAsString(tok_2[0]);
+
+ const ElementPtr Properties70 = sc_3->GetElement("Properties70");
+ if (Properties70) {
+ // PropertyTable(const ElementPtr element, const PropertyTable* templateProps);
+ const PropertyTable *props = new PropertyTable(Properties70, nullptr);
+
+ templates[oname + "." + pname] = props;
+ }
+ }
+ }
+}
+
+// ------------------------------------------------------------------------------------------------
+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 wont 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
new file mode 100644
index 0000000000..b810197d7e
--- /dev/null
+++ b/modules/fbx/fbx_parser/FBXDocument.h
@@ -0,0 +1,1319 @@
+/*************************************************************************/
+/* FBXDocument.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/** @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.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:
+ 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;
+ const std::string name;
+ const uint64_t id = 0;
+};
+
+/** 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();
+
+ const PropertyTable *Props() const {
+ return props;
+ }
+
+private:
+ const PropertyTable *props;
+};
+
+/** DOM base class for FBX camera settings attached to a node */
+class CameraSwitcher : public NodeAttribute {
+public:
+ CameraSwitcher(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
+
+ virtual ~CameraSwitcher();
+
+ int CameraID() const {
+ return cameraId;
+ }
+
+ const std::string &CameraName() const {
+ return cameraName;
+ }
+
+ const std::string &CameraIndexName() const {
+ return cameraIndexName;
+ }
+
+private:
+ int cameraId;
+ std::string cameraName;
+ std::string cameraIndexName;
+};
+
+#define fbx_stringize(a) #a
+
+#define fbx_simple_property(name, type, default_value) \
+ type name() const { \
+ return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
+ }
+
+// XXX improve logging
+#define fbx_simple_enum_property(name, type, default_value) \
+ type name() const { \
+ const int ival = PropertyGet<int>(Props(), fbx_stringize(name), static_cast<int>(default_value)); \
+ if (ival < 0 || ival >= AI_CONCAT(type, _MAX)) { \
+ return static_cast<type>(default_value); \
+ } \
+ return static_cast<type>(ival); \
+ }
+
+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;
+ }
+
+ Transform GetBindPose() const {
+ return transform;
+ }
+
+private:
+ uint64_t target_id;
+ Transform 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;
+ }
+
+ const PropertyTable *Props() const {
+ return props;
+ }
+
+ /** 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;
+ const PropertyTable *props = nullptr;
+};
+
+class ModelLimbNode : public Model {
+public:
+ ModelLimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
+
+ virtual ~ModelLimbNode();
+};
+
+/** 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;
+ }
+
+ const PropertyTable *Props() const {
+ return props;
+ }
+
+ // 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;
+ const PropertyTable *props = nullptr;
+
+ 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;
+ float alpha;
+};
+
+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 PropertyTable *Props() const {
+ return props;
+ }
+
+ const uint8_t *Content() const {
+ return content;
+ }
+
+ uint64_t ContentLength() const {
+ return contentLength;
+ }
+
+ uint8_t *RelinquishContent() {
+ uint8_t *ptr = content;
+ content = 0;
+ 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;
+ const PropertyTable *props = nullptr;
+
+ 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 PropertyTable *Props() const {
+ return props;
+ }
+
+ const TextureMap &Textures() const {
+ return textures;
+ }
+
+ const LayeredTextureMap &LayeredTextures() const {
+ return layeredTextures;
+ }
+
+private:
+ std::string shading;
+ bool multilayer;
+ const PropertyTable *props;
+
+ 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 therefor) */
+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 PropertyTable *Props() const {
+ return props;
+ }
+
+ const AnimationMap &Curves() const;
+
+ /** Object the curve is assigned to, this can be NULL 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;
+ const PropertyTable *props;
+ 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();
+
+ const PropertyTable *Props() const {
+ //ai_assert(props.get());
+ return props;
+ }
+
+ /* the optional white list specifies a list of property names for which the caller
+ wants animations for. Curves not matching this list will not be added to the
+ animation layer. */
+ const AnimationCurveNodeList Nodes(const char *const *target_prop_whitelist = nullptr, size_t whitelist_size = 0) const;
+
+private:
+ const PropertyTable *props;
+ const Document &doc;
+};
+
+/** 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 PropertyTable *Props() const {
+ return props;
+ }
+
+ const AnimationLayerList &Layers() const {
+ return layers;
+ }
+
+private:
+ const PropertyTable *props = nullptr;
+ 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();
+
+ const PropertyTable *Props() const {
+ //ai_assert(props.get());
+ return props;
+ }
+
+private:
+ const PropertyTable *props;
+};
+
+/** 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();
+
+private:
+ const PropertyTable *props;
+};
+
+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;
+ 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 Transform &GetTransform() const {
+ return transform;
+ }
+
+ const Transform &TransformLink() const {
+ return transformLink;
+ }
+
+ const Model *TargetNode() const {
+ return node;
+ }
+
+ const Transform &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;
+
+ Transform transform;
+ Transform transformLink;
+ Transform transformAssociateModel;
+ SkinLinkMode link_mode;
+ bool valid_transformAssociateModel;
+ 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;
+ SkinType skinType;
+ 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 NULL.
+ 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;
+ const std::string prop;
+
+ uint64_t src, dest;
+ 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:
+ FileGlobalSettings(const Document &doc, const PropertyTable *props);
+
+ ~FileGlobalSettings();
+
+ const PropertyTable *Props() const {
+ return props;
+ }
+
+ 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 PropertyTable *props = nullptr;
+ 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 = nullptr;
+ 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
new file mode 100644
index 0000000000..835b66ab23
--- /dev/null
+++ b/modules/fbx/fbx_parser/FBXDocumentUtil.cpp
@@ -0,0 +1,172 @@
+/*************************************************************************/
+/* FBXDocumentUtil.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+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 /*= NULL*/) {
+ if (element) {
+ DOMError(message, element->KeyToken());
+ }
+ print_error("[FBX-DOM] " + String(message.c_str()));
+}
+
+void DOMError(const std::string &message, const std::shared_ptr<Element> element /*= NULL*/) {
+ 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 /*= NULL*/) {
+ 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 /*= NULL*/) {
+ if (element) {
+ DOMWarning(message, element->KeyToken());
+ return;
+ }
+ print_verbose("[FBX-DOM] warning:" + String(message.c_str()));
+}
+
+// ------------------------------------------------------------------------------------------------
+// fetch a property table and the corresponding property template
+const PropertyTable *GetPropertyTable(const Document &doc,
+ const std::string &templateName,
+ const ElementPtr element,
+ const ScopePtr sc,
+ bool no_warn /*= false*/) {
+ // todo: make this an abstraction
+ const ElementPtr Properties70 = sc->GetElement("Properties70");
+ const PropertyTable *templateProps = static_cast<const PropertyTable *>(nullptr);
+
+ if (templateName.length()) {
+ PropertyTemplateMap::const_iterator it = doc.Templates().find(templateName);
+ if (it != doc.Templates().end()) {
+ templateProps = (*it).second;
+ }
+ }
+
+ if (!Properties70 || !Properties70->Compound()) {
+ if (!no_warn) {
+ DOMWarning("property table (Properties70) not found", element);
+ }
+ if (templateProps) {
+ return templateProps;
+ } else {
+ return new const PropertyTable();
+ }
+ }
+
+ return new PropertyTable(Properties70, templateProps);
+}
+} // namespace Util
+} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXDocumentUtil.h b/modules/fbx/fbx_parser/FBXDocumentUtil.h
new file mode 100644
index 0000000000..daa9de4a33
--- /dev/null
+++ b/modules/fbx/fbx_parser/FBXDocumentUtil.h
@@ -0,0 +1,141 @@
+/*************************************************************************/
+/* FBXDocumentUtil.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+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);
+
+// fetch a property table and the corresponding property template
+const PropertyTable *GetPropertyTable(const Document &doc,
+ const std::string &templateName,
+ const ElementPtr element,
+ const ScopePtr sc,
+ bool no_warn = false);
+
+// ------------------------------------------------------------------------------------------------
+template <typename T>
+const T *ProcessSimpleConnection(const Connection &con,
+ 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
new file mode 100644
index 0000000000..97ce496eaf
--- /dev/null
+++ b/modules/fbx/fbx_parser/FBXImportSettings.h
@@ -0,0 +1,173 @@
+/*************************************************************************/
+/* FBXImportSettings.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+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 {
+ ImportSettings() :
+ strictMode(true), readAllLayers(true), readAllMaterials(true), readMaterials(true), readTextures(true), readCameras(true), readLights(true), readAnimations(true), readWeights(true), preservePivots(true), optimizeEmptyAnimationCurves(true), useLegacyEmbeddedTextureNaming(false), removeEmptyBones(true), convertToMeters(false) {
+ // empty
+ }
+
+ /** enable strict mode:
+ * - only accept fbx 2012, 2013 files
+ * - on the slightest error, give up.
+ *
+ * Basically, strict mode means that the fbx file will actually
+ * be validated. Strict mode is off by default. */
+ bool strictMode;
+
+ /** specifies whether all geometry layers are read and scanned for
+ * usable data channels. The FBX spec indicates that many readers
+ * will only read the first channel and that this is in some way
+ * the recommended way- in reality, however, it happens a lot that
+ * vertex data is spread among multiple layers. The default
+ * value for this option is true.*/
+ bool readAllLayers;
+
+ /** 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;
+
+ /** import materials (true) or skip them and assign a default
+ * material. The default value is true.*/
+ bool readMaterials;
+
+ /** import embedded textures? Default value is true.*/
+ bool readTextures;
+
+ /** import cameras? Default value is true.*/
+ bool readCameras;
+
+ /** import light sources? Default value is true.*/
+ bool readLights;
+
+ /** import animations (i.e. animation curves, the node
+ * skeleton is always imported). Default value is true. */
+ bool readAnimations;
+
+ /** read bones (vertex weights and deform info).
+ * Default value is true. */
+ bool readWeights;
+
+ /** preserve transformation pivots and offsets. Since these can
+ * not directly be represented in assimp, additional dummy
+ * nodes will be generated. Note that settings this to false
+ * can make animation import a lot slower. The default value
+ * is true.
+ *
+ * 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;
+
+ /** do not import animation curves that specify a constant
+ * values matching the corresponding node transformation.
+ * The default value is true. */
+ bool optimizeEmptyAnimationCurves;
+
+ /** use legacy naming for embedded textures eg: (*0, *1, *2)
+ */
+ bool useLegacyEmbeddedTextureNaming;
+
+ /** Empty bones shall be removed
+ */
+ bool removeEmptyBones;
+
+ /** Set to true to perform a conversion from cm to meter after the import
+ */
+ bool convertToMeters;
+};
+} // namespace FBXDocParser
+
+#endif // FBX_IMPORT_SETTINGS_H
diff --git a/modules/fbx/fbx_parser/FBXMaterial.cpp b/modules/fbx/fbx_parser/FBXMaterial.cpp
new file mode 100644
index 0000000000..9970a2b0b1
--- /dev/null
+++ b/modules/fbx/fbx_parser/FBXMaterial.cpp
@@ -0,0 +1,407 @@
+/*************************************************************************/
+/* FBXMaterial.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+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);
+ }
+
+ props = GetPropertyTable(doc, templateName, element, sc);
+
+ // 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() {
+ if (props != nullptr) {
+ delete props;
+ props = nullptr;
+ }
+}
+
+// ------------------------------------------------------------------------------------------------
+Texture::Texture(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
+ Object(id, element, name), uvScaling(1.0f, 1.0f), media(nullptr) {
+ 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));
+ }
+
+ props = GetPropertyTable(doc, "Texture.FbxFileTexture", element, sc);
+
+ // 3DS Max and FBX SDK use "Scaling" and "Translation" instead of "ModelUVScaling" and "ModelUVTranslation". Use these properties if available.
+ bool ok;
+ const Vector3 &scaling = PropertyGet<Vector3>(props, "Scaling", ok);
+ if (ok) {
+ uvScaling.x = scaling.x;
+ uvScaling.y = scaling.y;
+ }
+
+ const Vector3 &trans = PropertyGet<Vector3>(props, "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() {
+ if (props != nullptr) {
+ delete props;
+ props = nullptr;
+ }
+}
+
+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 != 0) {
+ blendMode = (BlendMode)ParseTokenAsInt(GetRequiredToken(BlendModes, 0));
+ }
+ if (Alphas != 0) {
+ 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), contentLength(0), content(0) {
+ 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;
+ auto 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());
+ }
+ }
+
+ props = GetPropertyTable(doc, "Video.FbxVideo", element, sc);
+}
+
+Video::~Video() {
+ if (content) {
+ delete[] content;
+ }
+
+ if (props != nullptr) {
+ delete props;
+ props = nullptr;
+ }
+}
+} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXMeshGeometry.cpp b/modules/fbx/fbx_parser/FBXMeshGeometry.cpp
new file mode 100644
index 0000000000..ccc06550fe
--- /dev/null
+++ b/modules/fbx/fbx_parser/FBXMeshGeometry.cpp
@@ -0,0 +1,485 @@
+/*************************************************************************/
+/* FBXMeshGeometry.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+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), skin() {
+ 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 vertexes, 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 vertexes 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");
+ // NOTE: this is a useful sanity check to ensure you're getting any color data which is not default.
+ // const Color first_color_check = m_colors.data[0];
+ // bool colors_are_all_the_same = true;
+ // size_t i = 1;
+ // for(i = 1; i < m_colors.data.size(); i++)
+ // {
+ // const Color current_color = m_colors.data[i];
+ // if(current_color.is_equal_approx(first_color_check))
+ // {
+ // continue;
+ // }
+ // else
+ // {
+ // colors_are_all_the_same = false;
+ // break;
+ // }
+ // }
+ //
+ // if(colors_are_all_the_same)
+ // {
+ // print_error("Color serialisation is not working for vertex colors some should be different in the test asset.");
+ // }
+ // else
+ // {
+ // print_verbose("Color array has unique colors at index: " + itos(i));
+ // }
+ }
+ }
+ }
+ }
+
+ 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 begining 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 != "") {
+ // 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 wont 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
new file mode 100644
index 0000000000..710e644c68
--- /dev/null
+++ b/modules/fbx/fbx_parser/FBXMeshGeometry.h
@@ -0,0 +1,263 @@
+/*************************************************************************/
+/* FBXMeshGeometry.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+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 NULL */
+ 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 verticies[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);
+ // Retuns 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
new file mode 100644
index 0000000000..767994441f
--- /dev/null
+++ b/modules/fbx/fbx_parser/FBXModel.cpp
@@ -0,0 +1,176 @@
+/*************************************************************************/
+/* FBXModel.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+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));
+ }
+
+ props = GetPropertyTable(doc, "Model.FbxNode", element, sc);
+ ResolveLinks(element, doc);
+}
+
+// ------------------------------------------------------------------------------------------------
+Model::~Model() {
+ if (props != nullptr) {
+ delete props;
+ props = nullptr;
+ }
+}
+
+ModelLimbNode::ModelLimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
+ 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
new file mode 100644
index 0000000000..2749fc9f4d
--- /dev/null
+++ b/modules/fbx/fbx_parser/FBXNodeAttribute.cpp
@@ -0,0 +1,183 @@
+/*************************************************************************/
+/* FBXNodeAttribute.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+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), props() {
+ const ScopePtr sc = GetRequiredScope(element);
+
+ const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
+
+ // hack on the deriving type but Null/LimbNode attributes are the only case in which
+ // the property table is by design absent and no warning should be generated
+ // for it.
+ const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode");
+ props = GetPropertyTable(doc, "NodeAttribute.Fbx" + classname, element, sc, is_null_or_limb);
+}
+
+// ------------------------------------------------------------------------------------------------
+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
new file mode 100644
index 0000000000..21472f5b7b
--- /dev/null
+++ b/modules/fbx/fbx_parser/FBXParseTools.h
@@ -0,0 +1,111 @@
+/*************************************************************************/
+/* FBXParseTools.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef 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 = 0, unsigned int *max_inout = 0) {
+ 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
new file mode 100644
index 0000000000..44c24ff926
--- /dev/null
+++ b/modules/fbx/fbx_parser/FBXParser.cpp
@@ -0,0 +1,1295 @@
+/*************************************************************************/
+/* FBXParser.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+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 "thirdparty/zlib/zlib.h"
+#include <stdlib.h> /* strtol */
+
+#include "ByteSwapper.h"
+#include "FBXParseTools.h"
+#include "FBXParser.h"
+#include "FBXTokenizer.h"
+#include "core/math/math_defs.h"
+#include "core/math/transform.h"
+#include "core/math/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()));
+ }
+
+ 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()));
+ }
+ }
+
+ if (n && n->Type() == TokenType_OPEN_BRACKET) {
+ compound = new_Scope(parser);
+ parser.scopes.push_back(compound);
+
+ // 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.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()));
+ }
+ }
+
+ TokenPtr n = parser.AdvanceToNextToken();
+ if (n == nullptr) {
+ print_error("unexpected end of file");
+ }
+
+ // 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()));
+ }
+
+ const std::string str = n->StringContents();
+
+ // 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), last(), current(), 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 http://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])));
+ }
+ // for debugging
+ /*for ( size_t i = 0; i < out.size(); i++ ) {
+ aiVector3D vec3( out[ i ] );
+ std::stringstream stream;
+ stream << " vec3.x = " << vec3.x << " vec3.y = " << vec3.y << " vec3.z = " << vec3.z << std::endl;
+ DefaultLogger::get()->info( stream.str() );
+ }*/
+ } 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);
+ }
+}
+
+// ------------------------------------------------------------------------------------------------
+Transform 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_equal_approx(0, value)) {
+ value = 0;
+ }
+ }
+
+ Transform 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 /*= NULL*/) {
+ 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 /*= NULL*/) {
+ 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");
+}
+
+// ------------------------------------------------------------------------------------------------
+// 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
new file mode 100644
index 0000000000..37d27d3dca
--- /dev/null
+++ b/modules/fbx/fbx_parser/FBXParser.h
@@ -0,0 +1,263 @@
+/*************************************************************************/
+/* FBXParser.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+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.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 (auto 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;
+ }
+
+private:
+ friend class Scope;
+ friend class Element;
+
+ TokenPtr AdvanceToNextToken();
+ TokenPtr LastToken() const;
+ TokenPtr CurrentToken() const;
+
+private:
+ 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)
+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
+Transform 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
new file mode 100644
index 0000000000..6d80b85e38
--- /dev/null
+++ b/modules/fbx/fbx_parser/FBXPose.cpp
@@ -0,0 +1,104 @@
+/*************************************************************************/
+/* FBXPose.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+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
new file mode 100644
index 0000000000..8ab94e1ef4
--- /dev/null
+++ b/modules/fbx/fbx_parser/FBXProperties.cpp
@@ -0,0 +1,237 @@
+/*************************************************************************/
+/* FBXProperties.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+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 NULL 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() :
+ templateProps(), element() {
+}
+
+// ------------------------------------------------------------------------------------------------
+PropertyTable::PropertyTable(const ElementPtr element, const PropertyTable *templateProps) :
+ templateProps(templateProps), element(element) {
+ const ScopePtr scope = GetRequiredScope(element);
+ ERR_FAIL_COND(!scope);
+ 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;
+ }
+}
+
+// ------------------------------------------------------------------------------------------------
+PropertyTable::~PropertyTable() {
+ for (PropertyMap::value_type &v : props) {
+ delete v.second;
+ }
+}
+
+// ------------------------------------------------------------------------------------------------
+PropertyPtr PropertyTable::Get(const std::string &name) const {
+ PropertyMap::const_iterator it = props.find(name);
+ if (it == props.end()) {
+ // 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
+ if (templateProps) {
+ return templateProps->Get(name);
+ }
+
+ 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
new file mode 100644
index 0000000000..27cacfaf76
--- /dev/null
+++ b/modules/fbx/fbx_parser/FBXProperties.h
@@ -0,0 +1,221 @@
+/*************************************************************************/
+/* FBXProperties.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+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, const PropertyTable *templateProps);
+ ~PropertyTable();
+
+ PropertyPtr Get(const std::string &name) const;
+
+ // PropertyTable's need not be coupled with FBX elements so this can be NULL
+ ElementPtr GetElement() const {
+ return element;
+ }
+
+ PropertyMap &GetProperties() const {
+ return props;
+ }
+
+ const LazyPropertyMap &GetLazyProperties() const {
+ return lazyProps;
+ }
+
+ const PropertyTable *TemplateProps() const {
+ return templateProps;
+ }
+
+ DirectPropertyMap GetUnparsedProperties() const;
+
+private:
+ LazyPropertyMap lazyProps;
+ mutable PropertyMap props;
+ const PropertyTable *templateProps = nullptr;
+ const ElementPtr element = nullptr;
+};
+
+// ------------------------------------------------------------------------------------------------
+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 (!useTemplate) {
+ result = false;
+ return T();
+ }
+ const PropertyTable *templ = in->TemplateProps();
+ if (nullptr == templ) {
+ result = false;
+ return T();
+ }
+ prop = templ->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
new file mode 100644
index 0000000000..ea4568fe32
--- /dev/null
+++ b/modules/fbx/fbx_parser/FBXTokenizer.cpp
@@ -0,0 +1,251 @@
+/*************************************************************************/
+/* FBXTokenizer.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+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) {
+ // 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);
+ }
+ 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
new file mode 100644
index 0000000000..1e7e5e6535
--- /dev/null
+++ b/modules/fbx/fbx_parser/FBXTokenizer.h
@@ -0,0 +1,203 @@
+/*************************************************************************/
+/* FBXTokenizer.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+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);
+
+/** 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);
+} // namespace FBXDocParser
+
+#endif // FBX_TOKENIZER_H
diff --git a/modules/fbx/fbx_parser/FBXUtil.cpp b/modules/fbx/fbx_parser/FBXUtil.cpp
new file mode 100644
index 0000000000..80ea5fab4c
--- /dev/null
+++ b/modules/fbx/fbx_parser/FBXUtil.cpp
@@ -0,0 +1,220 @@
+/*************************************************************************/
+/* FBXUtil.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+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 auto 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
new file mode 100644
index 0000000000..efc131831b
--- /dev/null
+++ b/modules/fbx/fbx_parser/FBXUtil.h
@@ -0,0 +1,122 @@
+/*************************************************************************/
+/* FBXUtil.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+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
new file mode 100644
index 0000000000..b42fc6efe6
--- /dev/null
+++ b/modules/fbx/fbx_parser/LICENSE
@@ -0,0 +1,39 @@
+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/assimp/register_types.cpp b/modules/fbx/register_types.cpp
index 6cb0fc982f..c0591dbc77 100644
--- a/modules/assimp/register_types.cpp
+++ b/modules/fbx/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,22 +31,22 @@
#include "register_types.h"
#include "editor/editor_node.h"
-#include "editor_scene_importer_assimp.h"
+#include "editor_scene_importer_fbx.h"
#ifdef TOOLS_ENABLED
static void _editor_init() {
- Ref<EditorSceneImporterAssimp> import_assimp;
- import_assimp.instance();
- ResourceImporterScene::get_singleton()->add_importer(import_assimp);
+ Ref<EditorSceneImporterFBX> import_fbx;
+ import_fbx.instance();
+ ResourceImporterScene::get_singleton()->add_importer(import_fbx);
}
#endif
-void register_assimp_types() {
+void register_fbx_types() {
#ifdef TOOLS_ENABLED
ClassDB::APIType prev_api = ClassDB::get_current_api();
ClassDB::set_current_api(ClassDB::API_EDITOR);
- ClassDB::register_class<EditorSceneImporterAssimp>();
+ ClassDB::register_class<EditorSceneImporterFBX>();
ClassDB::set_current_api(prev_api);
@@ -54,5 +54,5 @@ void register_assimp_types() {
#endif
}
-void unregister_assimp_types() {
+void unregister_fbx_types() {
}
diff --git a/modules/arkit/register_types.h b/modules/fbx/register_types.h
index f8939a1e3f..e5741afd72 100644
--- a/modules/arkit/register_types.h
+++ b/modules/fbx/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -28,10 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef ARKIT_REGISTER_TYPES_H
-#define ARKIT_REGISTER_TYPES_H
+#ifndef FBX_REGISTER_TYPES_H
+#define FBX_REGISTER_TYPES_H
-void register_arkit_types();
-void unregister_arkit_types();
+void register_fbx_types();
+void unregister_fbx_types();
-#endif // ARKIT_REGISTER_TYPES_H
+#endif // FBX_REGISTER_TYPES_H
diff --git a/modules/fbx/tools/import_utils.cpp b/modules/fbx/tools/import_utils.cpp
new file mode 100644
index 0000000000..c87dd1fd3a
--- /dev/null
+++ b/modules/fbx/tools/import_utils.cpp
@@ -0,0 +1,151 @@
+/*************************************************************************/
+/* import_utils.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "import_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_zyx(p_rotation);
+ break;
+
+ case FBXDocParser::Model::RotOrder_EulerXZY:
+ ret.set_euler_yzx(p_rotation);
+ break;
+
+ case FBXDocParser::Model::RotOrder_EulerYZX:
+ ret.set_euler_xzy(p_rotation);
+ break;
+
+ case FBXDocParser::Model::RotOrder_EulerYXZ:
+ ret.set_euler_zxy(p_rotation);
+ break;
+
+ case FBXDocParser::Model::RotOrder_EulerZXY:
+ ret.set_euler_yxz(p_rotation);
+ break;
+
+ case FBXDocParser::Model::RotOrder_EulerZYX:
+ ret.set_euler_xyz(p_rotation);
+ 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;
+}
+
+Quat 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_zyx();
+
+ case FBXDocParser::Model::RotOrder_EulerXZY:
+ return p_rotation.get_euler_yzx();
+
+ case FBXDocParser::Model::RotOrder_EulerYZX:
+ return p_rotation.get_euler_xzy();
+
+ case FBXDocParser::Model::RotOrder_EulerYXZ:
+ return p_rotation.get_euler_zxy();
+
+ case FBXDocParser::Model::RotOrder_EulerZXY:
+ return p_rotation.get_euler_yxz();
+
+ case FBXDocParser::Model::RotOrder_EulerZYX:
+ return p_rotation.get_euler_xyz();
+
+ 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 Quat &p_rotation) {
+ return BasisToEuler(mode, p_rotation);
+}
+
+Transform get_unscaled_transform(const Transform &p_initial, real_t p_scale) {
+ Transform unscaled = Transform(p_initial.basis, p_initial.origin * p_scale);
+ ERR_FAIL_COND_V_MSG(unscaled.basis.determinant() == 0, Transform(), "det is zero unscaled?");
+ return unscaled;
+}
+
+Vector3 get_poly_normal(const std::vector<Vector3> &p_vertices) {
+ ERR_FAIL_COND_V_MSG(p_vertices.size() < 3, Vector3(0, 0, 0), "At least 3 vertices are necesary");
+ // 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
new file mode 100644
index 0000000000..6261138812
--- /dev/null
+++ b/modules/fbx/tools/import_utils.h
@@ -0,0 +1,400 @@
+/*************************************************************************/
+/* import_utils.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef 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 Quat EulerToQuaternion(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation);
+
+ /// Converts basis into rotation order vector (in rad).
+ static Vector3 BasisToEuler(FBXDocParser::Model::RotOrder mode, const Basis &p_rotation);
+
+ /// Converts quaternion into rotation order vector (in rad).
+ static Vector3 QuaternionToEuler(FBXDocParser::Model::RotOrder mode, const Quat &p_rotation);
+
+ static void debug_xform(String name, const Transform &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_equal_approx(0, vector.x)) {
+ vector.x = 0;
+ }
+
+ if (Math::is_equal_approx(0, vector.y)) {
+ vector.y = 0;
+ }
+
+ if (Math::is_equal_approx(0, 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 == NULL);
+ // 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.instance();
+ // 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_data();
+ // 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.instance();
+ // 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, NULL, NULL, NULL, NULL, 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.
+Transform get_unscaled_transform(const Transform &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/fbx/tools/validation_tools.cpp b/modules/fbx/tools/validation_tools.cpp
new file mode 100644
index 0000000000..9dbd8bf544
--- /dev/null
+++ b/modules/fbx/tools/validation_tools.cpp
@@ -0,0 +1,48 @@
+/*************************************************************************/
+/* validation_tools.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "validation_tools.h"
+
+#ifdef TOOLS_ENABLED
+
+#include "core/string/print_string.h"
+#include "core/string/ustring.h"
+
+ValidationTracker::Entries *ValidationTracker::entries_singleton = memnew(ValidationTracker::Entries);
+
+// 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);
+}
+
+#endif // TOOLS_ENABLED
diff --git a/modules/fbx/tools/validation_tools.h b/modules/fbx/tools/validation_tools.h
new file mode 100644
index 0000000000..ced100aed2
--- /dev/null
+++ b/modules/fbx/tools/validation_tools.h
@@ -0,0 +1,92 @@
+/*************************************************************************/
+/* validation_tools.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef FBX_VALIDATION_TOOLS_H
+#define FBX_VALIDATION_TOOLS_H
+
+#ifdef TOOLS_ENABLED
+
+#include "core/io/json.h"
+#include "core/os/file_access.h"
+#include "core/string/ustring.h"
+#include "core/templates/local_vector.h"
+#include "core/templates/map.h"
+
+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 (Map<String, LocalVector<String>>::Element *element = validation_entries.front(); element; element = element->next()) {
+ 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;
+
+public:
+ static Entries *get_singleton() {
+ return entries_singleton;
+ }
+};
+
+#endif // TOOLS_ENABLED
+#endif // FBX_VALIDATION_TOOLS_H
diff --git a/modules/freetype/SCsub b/modules/freetype/SCsub
index bfc1658bb4..fc2535a6ca 100644
--- a/modules/freetype/SCsub
+++ b/modules/freetype/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_freetype = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_freetype"]:
thirdparty_dir = "#thirdparty/freetype/"
thirdparty_sources = [
@@ -84,6 +87,7 @@ if env["builtin_freetype"]:
env_thirdparty = env_freetype.Clone()
env_thirdparty.disable_warnings()
lib = env_thirdparty.add_library("freetype_builtin", thirdparty_sources)
+ thirdparty_obj += lib
# Needs to be appended to arrive after libscene in the linker call,
# but we don't want it to arrive *after* system libs, so manual hack
@@ -98,5 +102,13 @@ if env["builtin_freetype"]:
if not inserted:
env.Append(LIBS=[lib])
+
# Godot source files
-env_freetype.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_freetype.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/freetype/register_types.cpp b/modules/freetype/register_types.cpp
index 15fa193183..e4e6a4c146 100644
--- a/modules/freetype/register_types.cpp
+++ b/modules/freetype/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/freetype/register_types.h b/modules/freetype/register_types.h
index aa8088d2e8..7a4f64b54b 100644
--- a/modules/freetype/register_types.h
+++ b/modules/freetype/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/freetype/uwpdef.h b/modules/freetype/uwpdef.h
index 2f9b2f4a53..f829edea67 100644
--- a/modules/freetype/uwpdef.h
+++ b/modules/freetype/uwpdef.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnative/SCsub b/modules/gdnative/SCsub
index 0e2291c1f9..45354ce692 100644
--- a/modules/gdnative/SCsub
+++ b/modules/gdnative/SCsub
@@ -20,6 +20,7 @@ SConscript("net/SCsub")
SConscript("xr/SCsub")
SConscript("pluginscript/SCsub")
SConscript("videodecoder/SCsub")
+SConscript("text/SCsub")
import gdnative_builders
@@ -30,5 +31,3 @@ _, gensource = env_gdnative.CommandNoCache(
env.Run(gdnative_builders.build_gdnative_api_struct, "Generating GDNative API."),
)
env_gdnative.add_source_files(env.modules_sources, [gensource])
-
-env.use_ptrcall = True
diff --git a/modules/gdnative/android/android_gdn.cpp b/modules/gdnative/android/android_gdn.cpp
index bc39be1813..fe3b3e7e12 100644
--- a/modules/gdnative/android/android_gdn.cpp
+++ b/modules/gdnative/android/android_gdn.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -48,7 +48,7 @@ extern "C" {
JNIEnv *GDAPI godot_android_get_env() {
#ifdef __ANDROID__
- return ThreadAndroid::get_env();
+ return get_jni_env();
#else
return nullptr;
#endif
diff --git a/modules/gdnative/config.py b/modules/gdnative/config.py
index 7603e7d69d..fd860e9763 100644
--- a/modules/gdnative/config.py
+++ b/modules/gdnative/config.py
@@ -3,7 +3,7 @@ def can_build(env, platform):
def configure(env):
- env.use_ptrcall = True
+ pass
def get_doc_classes():
diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp
index bb2da70c3a..e3a359e09a 100644
--- a/modules/gdnative/gdnative.cpp
+++ b/modules/gdnative/gdnative.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,11 +30,11 @@
#include "gdnative.h"
-#include "core/global_constants.h"
+#include "core/config/project_settings.h"
+#include "core/core_constants.h"
#include "core/io/file_access_encrypted.h"
#include "core/os/file_access.h"
#include "core/os/os.h"
-#include "core/project_settings.h"
#include "scene/main/scene_tree.h"
@@ -286,7 +286,7 @@ bool GDNative::initialize() {
}
String lib_path = library->get_current_library_path();
- if (lib_path.empty()) {
+ if (lib_path.is_empty()) {
ERR_PRINT("No library set for this platform");
return false;
}
diff --git a/modules/gdnative/gdnative.h b/modules/gdnative/gdnative.h
index 6d26c2141d..765087d176 100644
--- a/modules/gdnative/gdnative.h
+++ b/modules/gdnative/gdnative.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,10 +31,10 @@
#ifndef GDNATIVE_H
#define GDNATIVE_H
+#include "core/io/resource.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/os/thread_safe.h"
-#include "core/resource.h"
#include "gdnative/gdnative.h"
#include "gdnative_api_struct.gen.h"
diff --git a/modules/gdnative/gdnative/aabb.cpp b/modules/gdnative/gdnative/aabb.cpp
index d5970e8004..5d3f224adc 100644
--- a/modules/gdnative/gdnative/aabb.cpp
+++ b/modules/gdnative/gdnative/aabb.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,195 +31,15 @@
#include "gdnative/aabb.h"
#include "core/math/aabb.h"
-#include "core/variant.h"
+
+static_assert(sizeof(godot_aabb) == sizeof(AABB), "AABB size mismatch");
#ifdef __cplusplus
extern "C" {
#endif
-static_assert(sizeof(godot_aabb) == sizeof(AABB), "AABB size mismatch");
-
-void GDAPI godot_aabb_new(godot_aabb *r_dest, const godot_vector3 *p_pos, const godot_vector3 *p_size) {
- const Vector3 *pos = (const Vector3 *)p_pos;
- const Vector3 *size = (const Vector3 *)p_size;
- AABB *dest = (AABB *)r_dest;
- *dest = AABB(*pos, *size);
-}
-
-godot_vector3 GDAPI godot_aabb_get_position(const godot_aabb *p_self) {
- godot_vector3 raw_ret;
- const AABB *self = (const AABB *)p_self;
- Vector3 *ret = (Vector3 *)&raw_ret;
- *ret = self->position;
- return raw_ret;
-}
-
-void GDAPI godot_aabb_set_position(const godot_aabb *p_self, const godot_vector3 *p_v) {
- AABB *self = (AABB *)p_self;
- const Vector3 *v = (const Vector3 *)p_v;
- self->position = *v;
-}
-
-godot_vector3 GDAPI godot_aabb_get_size(const godot_aabb *p_self) {
- godot_vector3 raw_ret;
- const AABB *self = (const AABB *)p_self;
- Vector3 *ret = (Vector3 *)&raw_ret;
- *ret = self->size;
- return raw_ret;
-}
-
-void GDAPI godot_aabb_set_size(const godot_aabb *p_self, const godot_vector3 *p_v) {
- AABB *self = (AABB *)p_self;
- const Vector3 *v = (const Vector3 *)p_v;
- self->size = *v;
-}
-
-godot_string GDAPI godot_aabb_as_string(const godot_aabb *p_self) {
- godot_string ret;
- const AABB *self = (const AABB *)p_self;
- memnew_placement(&ret, String(*self));
- return ret;
-}
-
-godot_aabb GDAPI godot_aabb_abs(const godot_aabb *p_self) {
- godot_aabb dest;
- const AABB *self = (const AABB *)p_self;
- *((AABB *)&dest) = self->abs();
- return dest;
-}
-
-godot_real GDAPI godot_aabb_get_area(const godot_aabb *p_self) {
- const AABB *self = (const AABB *)p_self;
- return self->get_area();
-}
-
-godot_bool GDAPI godot_aabb_has_no_area(const godot_aabb *p_self) {
- const AABB *self = (const AABB *)p_self;
- return self->has_no_area();
-}
-
-godot_bool GDAPI godot_aabb_has_no_surface(const godot_aabb *p_self) {
- const AABB *self = (const AABB *)p_self;
- return self->has_no_surface();
-}
-
-godot_bool GDAPI godot_aabb_intersects(const godot_aabb *p_self, const godot_aabb *p_with) {
- const AABB *self = (const AABB *)p_self;
- const AABB *with = (const AABB *)p_with;
- return self->intersects(*with);
-}
-
-godot_bool GDAPI godot_aabb_encloses(const godot_aabb *p_self, const godot_aabb *p_with) {
- const AABB *self = (const AABB *)p_self;
- const AABB *with = (const AABB *)p_with;
- return self->encloses(*with);
-}
-
-godot_aabb GDAPI godot_aabb_merge(const godot_aabb *p_self, const godot_aabb *p_with) {
- godot_aabb dest;
- const AABB *self = (const AABB *)p_self;
- const AABB *with = (const AABB *)p_with;
- *((AABB *)&dest) = self->merge(*with);
- return dest;
-}
-
-godot_aabb GDAPI godot_aabb_intersection(const godot_aabb *p_self, const godot_aabb *p_with) {
- godot_aabb dest;
- const AABB *self = (const AABB *)p_self;
- const AABB *with = (const AABB *)p_with;
- *((AABB *)&dest) = self->intersection(*with);
- return dest;
-}
-
-godot_bool GDAPI godot_aabb_intersects_plane(const godot_aabb *p_self, const godot_plane *p_plane) {
- const AABB *self = (const AABB *)p_self;
- const Plane *plane = (const Plane *)p_plane;
- return self->intersects_plane(*plane);
-}
-
-godot_bool GDAPI godot_aabb_intersects_segment(const godot_aabb *p_self, const godot_vector3 *p_from, const godot_vector3 *p_to) {
- const AABB *self = (const AABB *)p_self;
- const Vector3 *from = (const Vector3 *)p_from;
- const Vector3 *to = (const Vector3 *)p_to;
- return self->intersects_segment(*from, *to);
-}
-
-godot_bool GDAPI godot_aabb_has_point(const godot_aabb *p_self, const godot_vector3 *p_point) {
- const AABB *self = (const AABB *)p_self;
- const Vector3 *point = (const Vector3 *)p_point;
- return self->has_point(*point);
-}
-
-godot_vector3 GDAPI godot_aabb_get_support(const godot_aabb *p_self, const godot_vector3 *p_dir) {
- godot_vector3 dest;
- const AABB *self = (const AABB *)p_self;
- const Vector3 *dir = (const Vector3 *)p_dir;
- *((Vector3 *)&dest) = self->get_support(*dir);
- return dest;
-}
-
-godot_vector3 GDAPI godot_aabb_get_longest_axis(const godot_aabb *p_self) {
- godot_vector3 dest;
- const AABB *self = (const AABB *)p_self;
- *((Vector3 *)&dest) = self->get_longest_axis();
- return dest;
-}
-
-godot_int GDAPI godot_aabb_get_longest_axis_index(const godot_aabb *p_self) {
- const AABB *self = (const AABB *)p_self;
- return self->get_longest_axis_index();
-}
-
-godot_real GDAPI godot_aabb_get_longest_axis_size(const godot_aabb *p_self) {
- const AABB *self = (const AABB *)p_self;
- return self->get_longest_axis_size();
-}
-
-godot_vector3 GDAPI godot_aabb_get_shortest_axis(const godot_aabb *p_self) {
- godot_vector3 dest;
- const AABB *self = (const AABB *)p_self;
- *((Vector3 *)&dest) = self->get_shortest_axis();
- return dest;
-}
-
-godot_int GDAPI godot_aabb_get_shortest_axis_index(const godot_aabb *p_self) {
- const AABB *self = (const AABB *)p_self;
- return self->get_shortest_axis_index();
-}
-
-godot_real GDAPI godot_aabb_get_shortest_axis_size(const godot_aabb *p_self) {
- const AABB *self = (const AABB *)p_self;
- return self->get_shortest_axis_size();
-}
-
-godot_aabb GDAPI godot_aabb_expand(const godot_aabb *p_self, const godot_vector3 *p_to_point) {
- godot_aabb dest;
- const AABB *self = (const AABB *)p_self;
- const Vector3 *to_point = (const Vector3 *)p_to_point;
- *((AABB *)&dest) = self->expand(*to_point);
- return dest;
-}
-
-godot_aabb GDAPI godot_aabb_grow(const godot_aabb *p_self, const godot_real p_by) {
- godot_aabb dest;
- const AABB *self = (const AABB *)p_self;
-
- *((AABB *)&dest) = self->grow(p_by);
- return dest;
-}
-
-godot_vector3 GDAPI godot_aabb_get_endpoint(const godot_aabb *p_self, const godot_int p_idx) {
- godot_vector3 dest;
- const AABB *self = (const AABB *)p_self;
-
- *((Vector3 *)&dest) = self->get_endpoint(p_idx);
- return dest;
-}
-
-godot_bool GDAPI godot_aabb_operator_equal(const godot_aabb *p_self, const godot_aabb *p_b) {
- const AABB *self = (const AABB *)p_self;
- const AABB *b = (const AABB *)p_b;
- return *self == *b;
+void GDAPI godot_aabb_new(godot_aabb *p_self) {
+ memnew_placement(p_self, AABB);
}
#ifdef __cplusplus
diff --git a/modules/gdnative/gdnative/array.cpp b/modules/gdnative/gdnative/array.cpp
index 59953f5182..87a8c8e376 100644
--- a/modules/gdnative/gdnative/array.cpp
+++ b/modules/gdnative/gdnative/array.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,360 +30,23 @@
#include "gdnative/array.h"
-#include "core/array.h"
#include "core/os/memory.h"
+#include "core/variant/array.h"
-#include "core/color.h"
-
-#include "core/variant.h"
+static_assert(sizeof(godot_array) == sizeof(Array), "Array size mismatch");
#ifdef __cplusplus
extern "C" {
#endif
-static_assert(sizeof(godot_array) == sizeof(Array), "Array size mismatch");
-
-void GDAPI godot_array_new(godot_array *r_dest) {
- Array *dest = (Array *)r_dest;
- memnew_placement(dest, Array);
-}
-
-void GDAPI godot_array_new_copy(godot_array *r_dest, const godot_array *p_src) {
- Array *dest = (Array *)r_dest;
- const Array *src = (const Array *)p_src;
- memnew_placement(dest, Array(*src));
-}
-
-void GDAPI godot_array_new_packed_color_array(godot_array *r_dest, const godot_packed_color_array *p_pca) {
- Array *dest = (Array *)r_dest;
- Vector<Color> *pca = (Vector<Color> *)p_pca;
- memnew_placement(dest, Array);
- dest->resize(pca->size());
-
- for (int i = 0; i < dest->size(); i++) {
- Variant v = pca->operator[](i);
- dest->operator[](i) = v;
- }
-}
-
-void GDAPI godot_array_new_packed_vector3_array(godot_array *r_dest, const godot_packed_vector3_array *p_pv3a) {
- Array *dest = (Array *)r_dest;
- Vector<Vector3> *pca = (Vector<Vector3> *)p_pv3a;
- memnew_placement(dest, Array);
- dest->resize(pca->size());
-
- for (int i = 0; i < dest->size(); i++) {
- Variant v = pca->operator[](i);
- dest->operator[](i) = v;
- }
-}
-
-void GDAPI godot_array_new_packed_vector2_array(godot_array *r_dest, const godot_packed_vector2_array *p_pv2a) {
- Array *dest = (Array *)r_dest;
- Vector<Vector2> *pca = (Vector<Vector2> *)p_pv2a;
- memnew_placement(dest, Array);
- dest->resize(pca->size());
-
- for (int i = 0; i < dest->size(); i++) {
- Variant v = pca->operator[](i);
- dest->operator[](i) = v;
- }
-}
-
-void GDAPI godot_array_new_packed_string_array(godot_array *r_dest, const godot_packed_string_array *p_psa) {
- Array *dest = (Array *)r_dest;
- Vector<String> *pca = (Vector<String> *)p_psa;
- memnew_placement(dest, Array);
- dest->resize(pca->size());
-
- for (int i = 0; i < dest->size(); i++) {
- Variant v = pca->operator[](i);
- dest->operator[](i) = v;
- }
-}
-
-void GDAPI godot_array_new_packed_float32_array(godot_array *r_dest, const godot_packed_float32_array *p_pra) {
- Array *dest = (Array *)r_dest;
- Vector<float> *pca = (Vector<float> *)p_pra;
- memnew_placement(dest, Array);
- dest->resize(pca->size());
-
- for (int i = 0; i < dest->size(); i++) {
- Variant v = pca->operator[](i);
- dest->operator[](i) = v;
- }
-}
-
-void GDAPI godot_array_new_packed_float64_array(godot_array *r_dest, const godot_packed_float64_array *p_pra) {
- Array *dest = (Array *)r_dest;
- Vector<double> *pca = (Vector<double> *)p_pra;
- memnew_placement(dest, Array);
- dest->resize(pca->size());
-
- for (int i = 0; i < dest->size(); i++) {
- Variant v = pca->operator[](i);
- dest->operator[](i) = v;
- }
-}
-
-void GDAPI godot_array_new_packed_int32_array(godot_array *r_dest, const godot_packed_int32_array *p_pia) {
- Array *dest = (Array *)r_dest;
- Vector<int32_t> *pca = (Vector<int32_t> *)p_pia;
- memnew_placement(dest, Array);
- dest->resize(pca->size());
-
- for (int i = 0; i < dest->size(); i++) {
- Variant v = pca->operator[](i);
- dest->operator[](i) = v;
- }
-}
-
-void GDAPI godot_array_new_packed_int64_array(godot_array *r_dest, const godot_packed_int64_array *p_pia) {
- Array *dest = (Array *)r_dest;
- Vector<int64_t> *pca = (Vector<int64_t> *)p_pia;
- memnew_placement(dest, Array);
- dest->resize(pca->size());
-
- for (int i = 0; i < dest->size(); i++) {
- Variant v = pca->operator[](i);
- dest->operator[](i) = v;
- }
-}
-
-void GDAPI godot_array_new_packed_byte_array(godot_array *r_dest, const godot_packed_byte_array *p_pba) {
- Array *dest = (Array *)r_dest;
- Vector<uint8_t> *pca = (Vector<uint8_t> *)p_pba;
- memnew_placement(dest, Array);
- dest->resize(pca->size());
-
- for (int i = 0; i < dest->size(); i++) {
- Variant v = pca->operator[](i);
- dest->operator[](i) = v;
- }
-}
-
-void GDAPI godot_array_set(godot_array *p_self, const godot_int p_idx, const godot_variant *p_value) {
- Array *self = (Array *)p_self;
- Variant *val = (Variant *)p_value;
- self->operator[](p_idx) = *val;
-}
-
-godot_variant GDAPI godot_array_get(const godot_array *p_self, const godot_int p_idx) {
- godot_variant raw_dest;
- Variant *dest = (Variant *)&raw_dest;
- const Array *self = (const Array *)p_self;
- memnew_placement(dest, Variant(self->operator[](p_idx)));
- return raw_dest;
-}
-
-godot_variant GDAPI *godot_array_operator_index(godot_array *p_self, const godot_int p_idx) {
- Array *self = (Array *)p_self;
- return (godot_variant *)&self->operator[](p_idx);
-}
-
-const godot_variant GDAPI *godot_array_operator_index_const(const godot_array *p_self, const godot_int p_idx) {
- const Array *self = (const Array *)p_self;
- return (const godot_variant *)&self->operator[](p_idx);
-}
-
-void GDAPI godot_array_append(godot_array *p_self, const godot_variant *p_value) {
- Array *self = (Array *)p_self;
- Variant *val = (Variant *)p_value;
- self->append(*val);
-}
-
-void GDAPI godot_array_clear(godot_array *p_self) {
- Array *self = (Array *)p_self;
- self->clear();
-}
-
-godot_int GDAPI godot_array_count(const godot_array *p_self, const godot_variant *p_value) {
- const Array *self = (const Array *)p_self;
- const Variant *val = (const Variant *)p_value;
- return self->count(*val);
-}
-
-godot_bool GDAPI godot_array_empty(const godot_array *p_self) {
- const Array *self = (const Array *)p_self;
- return self->empty();
-}
-
-void GDAPI godot_array_erase(godot_array *p_self, const godot_variant *p_value) {
- Array *self = (Array *)p_self;
- const Variant *val = (const Variant *)p_value;
- self->erase(*val);
-}
-
-godot_variant GDAPI godot_array_front(const godot_array *p_self) {
- const Array *self = (const Array *)p_self;
- godot_variant v;
- Variant *val = (Variant *)&v;
- memnew_placement(val, Variant);
- *val = self->front();
- return v;
-}
-
-godot_variant GDAPI godot_array_back(const godot_array *p_self) {
- const Array *self = (const Array *)p_self;
- godot_variant v;
- Variant *val = (Variant *)&v;
- memnew_placement(val, Variant);
- *val = self->back();
- return v;
-}
-
-godot_int GDAPI godot_array_find(const godot_array *p_self, const godot_variant *p_what, const godot_int p_from) {
- const Array *self = (const Array *)p_self;
- const Variant *val = (const Variant *)p_what;
- return self->find(*val, p_from);
-}
-
-godot_int GDAPI godot_array_find_last(const godot_array *p_self, const godot_variant *p_what) {
- const Array *self = (const Array *)p_self;
- const Variant *val = (const Variant *)p_what;
- return self->find_last(*val);
-}
-
-godot_bool GDAPI godot_array_has(const godot_array *p_self, const godot_variant *p_value) {
- const Array *self = (const Array *)p_self;
- const Variant *val = (const Variant *)p_value;
- return self->has(*val);
-}
-
-godot_int GDAPI godot_array_hash(const godot_array *p_self) {
- const Array *self = (const Array *)p_self;
- return self->hash();
-}
-
-void GDAPI godot_array_insert(godot_array *p_self, const godot_int p_pos, const godot_variant *p_value) {
- Array *self = (Array *)p_self;
- const Variant *val = (const Variant *)p_value;
- self->insert(p_pos, *val);
-}
-
-void GDAPI godot_array_invert(godot_array *p_self) {
- Array *self = (Array *)p_self;
- self->invert();
-}
-
-godot_variant GDAPI godot_array_pop_back(godot_array *p_self) {
- Array *self = (Array *)p_self;
- godot_variant v;
- Variant *val = (Variant *)&v;
- memnew_placement(val, Variant);
- *val = self->pop_back();
- return v;
-}
-
-godot_variant GDAPI godot_array_pop_front(godot_array *p_self) {
- Array *self = (Array *)p_self;
- godot_variant v;
- Variant *val = (Variant *)&v;
- memnew_placement(val, Variant);
- *val = self->pop_front();
- return v;
-}
-
-void GDAPI godot_array_push_back(godot_array *p_self, const godot_variant *p_value) {
- Array *self = (Array *)p_self;
- const Variant *val = (const Variant *)p_value;
- self->push_back(*val);
-}
-
-void GDAPI godot_array_push_front(godot_array *p_self, const godot_variant *p_value) {
- Array *self = (Array *)p_self;
- const Variant *val = (const Variant *)p_value;
- self->push_front(*val);
-}
-
-void GDAPI godot_array_remove(godot_array *p_self, const godot_int p_idx) {
- Array *self = (Array *)p_self;
- self->remove(p_idx);
-}
-
-void GDAPI godot_array_resize(godot_array *p_self, const godot_int p_size) {
- Array *self = (Array *)p_self;
- self->resize(p_size);
-}
-
-godot_int GDAPI godot_array_rfind(const godot_array *p_self, const godot_variant *p_what, const godot_int p_from) {
- const Array *self = (const Array *)p_self;
- const Variant *val = (const Variant *)p_what;
- return self->rfind(*val, p_from);
-}
-
-godot_int GDAPI godot_array_size(const godot_array *p_self) {
- const Array *self = (const Array *)p_self;
- return self->size();
-}
-
-void GDAPI godot_array_sort(godot_array *p_self) {
- Array *self = (Array *)p_self;
- self->sort();
-}
-
-void GDAPI godot_array_sort_custom(godot_array *p_self, godot_object *p_obj, const godot_string *p_func) {
- Array *self = (Array *)p_self;
- const String *func = (const String *)p_func;
- self->sort_custom((Object *)p_obj, *func);
-}
-
-godot_int GDAPI godot_array_bsearch(godot_array *p_self, const godot_variant *p_value, const godot_bool p_before) {
- Array *self = (Array *)p_self;
- return self->bsearch(*(const Variant *)p_value, p_before);
-}
-
-godot_int GDAPI godot_array_bsearch_custom(godot_array *p_self, const godot_variant *p_value, godot_object *p_obj, const godot_string *p_func, const godot_bool p_before) {
- Array *self = (Array *)p_self;
- const String *func = (const String *)p_func;
- return self->bsearch_custom(*(const Variant *)p_value, (Object *)p_obj, *func, p_before);
+void GDAPI godot_array_new(godot_array *p_self) {
+ memnew_placement(p_self, Array);
}
void GDAPI godot_array_destroy(godot_array *p_self) {
((Array *)p_self)->~Array();
}
-godot_array GDAPI godot_array_duplicate(const godot_array *p_self, const godot_bool p_deep) {
- const Array *self = (const Array *)p_self;
- godot_array res;
- Array *val = (Array *)&res;
- memnew_placement(val, Array);
- *val = self->duplicate(p_deep);
- return res;
-}
-
-godot_array GDAPI godot_array_slice(const godot_array *p_self, const godot_int p_begin, const godot_int p_end, const godot_int p_step, const godot_bool p_deep) {
- const Array *self = (const Array *)p_self;
- godot_array res;
- Array *val = (Array *)&res;
- memnew_placement(val, Array);
- *val = self->slice(p_begin, p_end, p_step, p_deep);
- return res;
-}
-
-godot_variant GDAPI godot_array_max(const godot_array *p_self) {
- const Array *self = (const Array *)p_self;
- godot_variant v;
- Variant *val = (Variant *)&v;
- memnew_placement(val, Variant);
- *val = self->max();
- return v;
-}
-
-godot_variant GDAPI godot_array_min(const godot_array *p_self) {
- const Array *self = (const Array *)p_self;
- godot_variant v;
- Variant *val = (Variant *)&v;
- memnew_placement(val, Variant);
- *val = self->min();
- return v;
-}
-
-void GDAPI godot_array_shuffle(godot_array *p_self) {
- Array *self = (Array *)p_self;
- self->shuffle();
-}
-
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/basis.cpp b/modules/gdnative/gdnative/basis.cpp
index 990fd3795d..86a6d6216c 100644
--- a/modules/gdnative/gdnative/basis.cpp
+++ b/modules/gdnative/gdnative/basis.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,266 +31,15 @@
#include "gdnative/basis.h"
#include "core/math/basis.h"
-#include "core/variant.h"
+
+static_assert(sizeof(godot_basis) == sizeof(Basis), "Basis size mismatch");
#ifdef __cplusplus
extern "C" {
#endif
-static_assert(sizeof(godot_basis) == sizeof(Basis), "Basis size mismatch");
-
-void GDAPI godot_basis_new_with_rows(godot_basis *r_dest, const godot_vector3 *p_x_axis, const godot_vector3 *p_y_axis, const godot_vector3 *p_z_axis) {
- const Vector3 *x_axis = (const Vector3 *)p_x_axis;
- const Vector3 *y_axis = (const Vector3 *)p_y_axis;
- const Vector3 *z_axis = (const Vector3 *)p_z_axis;
- Basis *dest = (Basis *)r_dest;
- *dest = Basis(*x_axis, *y_axis, *z_axis);
-}
-
-void GDAPI godot_basis_new_with_axis_and_angle(godot_basis *r_dest, const godot_vector3 *p_axis, const godot_real p_phi) {
- const Vector3 *axis = (const Vector3 *)p_axis;
- Basis *dest = (Basis *)r_dest;
- *dest = Basis(*axis, p_phi);
-}
-
-void GDAPI godot_basis_new_with_euler(godot_basis *r_dest, const godot_vector3 *p_euler) {
- const Vector3 *euler = (const Vector3 *)p_euler;
- Basis *dest = (Basis *)r_dest;
- *dest = Basis(*euler);
-}
-
-godot_string GDAPI godot_basis_as_string(const godot_basis *p_self) {
- godot_string ret;
- const Basis *self = (const Basis *)p_self;
- memnew_placement(&ret, String(*self));
- return ret;
-}
-
-godot_basis GDAPI godot_basis_inverse(const godot_basis *p_self) {
- godot_basis dest;
- const Basis *self = (const Basis *)p_self;
- *((Basis *)&dest) = self->inverse();
- return dest;
-}
-
-godot_basis GDAPI godot_basis_transposed(const godot_basis *p_self) {
- godot_basis dest;
- const Basis *self = (const Basis *)p_self;
- *((Basis *)&dest) = self->transposed();
- return dest;
-}
-
-godot_basis GDAPI godot_basis_orthonormalized(const godot_basis *p_self) {
- godot_basis dest;
- const Basis *self = (const Basis *)p_self;
- *((Basis *)&dest) = self->orthonormalized();
- return dest;
-}
-
-godot_real GDAPI godot_basis_determinant(const godot_basis *p_self) {
- const Basis *self = (const Basis *)p_self;
- return self->determinant();
-}
-
-godot_basis GDAPI godot_basis_rotated(const godot_basis *p_self, const godot_vector3 *p_axis, const godot_real p_phi) {
- godot_basis dest;
- const Basis *self = (const Basis *)p_self;
- const Vector3 *axis = (const Vector3 *)p_axis;
- *((Basis *)&dest) = self->rotated(*axis, p_phi);
- return dest;
-}
-
-godot_basis GDAPI godot_basis_scaled(const godot_basis *p_self, const godot_vector3 *p_scale) {
- godot_basis dest;
- const Basis *self = (const Basis *)p_self;
- const Vector3 *scale = (const Vector3 *)p_scale;
- *((Basis *)&dest) = self->scaled(*scale);
- return dest;
-}
-
-godot_vector3 GDAPI godot_basis_get_scale(const godot_basis *p_self) {
- godot_vector3 dest;
- const Basis *self = (const Basis *)p_self;
- *((Vector3 *)&dest) = self->get_scale();
- return dest;
-}
-
-godot_quat GDAPI godot_basis_get_quat(const godot_basis *p_self) {
- godot_quat dest;
- const Basis *self = (const Basis *)p_self;
- *((Quat *)&dest) = self->get_quat();
- return dest;
-}
-
-void GDAPI godot_basis_set_quat(godot_basis *p_self, const godot_quat *p_quat) {
- Basis *self = (Basis *)p_self;
- const Quat *quat = (const Quat *)p_quat;
- self->set_quat(*quat);
-}
-
-void GDAPI godot_basis_set_axis_angle_scale(godot_basis *p_self, const godot_vector3 *p_axis, godot_real p_phi, const godot_vector3 *p_scale) {
- Basis *self = (Basis *)p_self;
- const Vector3 *axis = (const Vector3 *)p_axis;
- const Vector3 *scale = (const Vector3 *)p_scale;
- self->set_axis_angle_scale(*axis, p_phi, *scale);
-}
-
-void GDAPI godot_basis_set_euler_scale(godot_basis *p_self, const godot_vector3 *p_euler, const godot_vector3 *p_scale) {
- Basis *self = (Basis *)p_self;
- const Vector3 *euler = (const Vector3 *)p_euler;
- const Vector3 *scale = (const Vector3 *)p_scale;
- self->set_euler_scale(*euler, *scale);
-}
-
-void GDAPI godot_basis_set_quat_scale(godot_basis *p_self, const godot_quat *p_quat, const godot_vector3 *p_scale) {
- Basis *self = (Basis *)p_self;
- const Quat *quat = (const Quat *)p_quat;
- const Vector3 *scale = (const Vector3 *)p_scale;
- self->set_quat_scale(*quat, *scale);
-}
-
-godot_vector3 GDAPI godot_basis_get_euler(const godot_basis *p_self) {
- godot_vector3 dest;
- const Basis *self = (const Basis *)p_self;
- *((Vector3 *)&dest) = self->get_euler();
- return dest;
-}
-
-godot_real GDAPI godot_basis_tdotx(const godot_basis *p_self, const godot_vector3 *p_with) {
- const Basis *self = (const Basis *)p_self;
- const Vector3 *with = (const Vector3 *)p_with;
- return self->tdotx(*with);
-}
-
-godot_real GDAPI godot_basis_tdoty(const godot_basis *p_self, const godot_vector3 *p_with) {
- const Basis *self = (const Basis *)p_self;
- const Vector3 *with = (const Vector3 *)p_with;
- return self->tdoty(*with);
-}
-
-godot_real GDAPI godot_basis_tdotz(const godot_basis *p_self, const godot_vector3 *p_with) {
- const Basis *self = (const Basis *)p_self;
- const Vector3 *with = (const Vector3 *)p_with;
- return self->tdotz(*with);
-}
-
-godot_vector3 GDAPI godot_basis_xform(const godot_basis *p_self, const godot_vector3 *p_v) {
- godot_vector3 dest;
- const Basis *self = (const Basis *)p_self;
- const Vector3 *v = (const Vector3 *)p_v;
- *((Vector3 *)&dest) = self->xform(*v);
- return dest;
-}
-
-godot_vector3 GDAPI godot_basis_xform_inv(const godot_basis *p_self, const godot_vector3 *p_v) {
- godot_vector3 dest;
- const Basis *self = (const Basis *)p_self;
- const Vector3 *v = (const Vector3 *)p_v;
- *((Vector3 *)&dest) = self->xform_inv(*v);
- return dest;
-}
-
-godot_int GDAPI godot_basis_get_orthogonal_index(const godot_basis *p_self) {
- const Basis *self = (const Basis *)p_self;
- return self->get_orthogonal_index();
-}
-
-void GDAPI godot_basis_new(godot_basis *r_dest) {
- Basis *dest = (Basis *)r_dest;
- *dest = Basis();
-}
-
-void GDAPI godot_basis_new_with_euler_quat(godot_basis *r_dest, const godot_quat *p_euler) {
- Basis *dest = (Basis *)r_dest;
- const Quat *euler = (const Quat *)p_euler;
- *dest = Basis(*euler);
-}
-
-// p_elements is a pointer to an array of 3 (!!) vector3
-void GDAPI godot_basis_get_elements(const godot_basis *p_self, godot_vector3 *p_elements) {
- const Basis *self = (const Basis *)p_self;
- Vector3 *elements = (Vector3 *)p_elements;
- elements[0] = self->elements[0];
- elements[1] = self->elements[1];
- elements[2] = self->elements[2];
-}
-
-godot_vector3 GDAPI godot_basis_get_axis(const godot_basis *p_self, const godot_int p_axis) {
- godot_vector3 dest;
- Vector3 *d = (Vector3 *)&dest;
- const Basis *self = (const Basis *)p_self;
- *d = self->get_axis(p_axis);
- return dest;
-}
-
-void GDAPI godot_basis_set_axis(godot_basis *p_self, const godot_int p_axis, const godot_vector3 *p_value) {
- Basis *self = (Basis *)p_self;
- const Vector3 *value = (const Vector3 *)p_value;
- self->set_axis(p_axis, *value);
-}
-
-godot_vector3 GDAPI godot_basis_get_row(const godot_basis *p_self, const godot_int p_row) {
- godot_vector3 dest;
- Vector3 *d = (Vector3 *)&dest;
- const Basis *self = (const Basis *)p_self;
- *d = self->get_row(p_row);
- return dest;
-}
-
-void GDAPI godot_basis_set_row(godot_basis *p_self, const godot_int p_row, const godot_vector3 *p_value) {
- Basis *self = (Basis *)p_self;
- const Vector3 *value = (const Vector3 *)p_value;
- self->set_row(p_row, *value);
-}
-
-godot_bool GDAPI godot_basis_operator_equal(const godot_basis *p_self, const godot_basis *p_b) {
- const Basis *self = (const Basis *)p_self;
- const Basis *b = (const Basis *)p_b;
- return *self == *b;
-}
-
-godot_basis GDAPI godot_basis_operator_add(const godot_basis *p_self, const godot_basis *p_b) {
- godot_basis raw_dest;
- Basis *dest = (Basis *)&raw_dest;
- const Basis *self = (const Basis *)p_self;
- const Basis *b = (const Basis *)p_b;
- *dest = *self + *b;
- return raw_dest;
-}
-
-godot_basis GDAPI godot_basis_operator_subtract(const godot_basis *p_self, const godot_basis *p_b) {
- godot_basis raw_dest;
- Basis *dest = (Basis *)&raw_dest;
- const Basis *self = (const Basis *)p_self;
- const Basis *b = (const Basis *)p_b;
- *dest = *self - *b;
- return raw_dest;
-}
-
-godot_basis GDAPI godot_basis_operator_multiply_vector(const godot_basis *p_self, const godot_basis *p_b) {
- godot_basis raw_dest;
- Basis *dest = (Basis *)&raw_dest;
- const Basis *self = (const Basis *)p_self;
- const Basis *b = (const Basis *)p_b;
- *dest = *self * *b;
- return raw_dest;
-}
-
-godot_basis GDAPI godot_basis_operator_multiply_scalar(const godot_basis *p_self, const godot_real p_b) {
- godot_basis raw_dest;
- Basis *dest = (Basis *)&raw_dest;
- const Basis *self = (const Basis *)p_self;
- *dest = *self * p_b;
- return raw_dest;
-}
-
-godot_basis GDAPI godot_basis_slerp(const godot_basis *p_self, const godot_basis *p_b, const godot_real p_t) {
- godot_basis raw_dest;
- Basis *dest = (Basis *)&raw_dest;
- const Basis *self = (const Basis *)p_self;
- const Basis *b = (const Basis *)p_b;
- *dest = self->slerp(*b, p_t);
- return raw_dest;
+void GDAPI godot_basis_new(godot_basis *p_self) {
+ memnew_placement(p_self, Basis);
}
#ifdef __cplusplus
diff --git a/modules/gdnative/gdnative/callable.cpp b/modules/gdnative/gdnative/callable.cpp
index 868b324227..7c62b5928f 100644
--- a/modules/gdnative/gdnative/callable.cpp
+++ b/modules/gdnative/gdnative/callable.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,36 +30,17 @@
#include "gdnative/callable.h"
-#include "core/callable.h"
-#include "core/resource.h"
-#include "core/variant.h"
+#include "core/variant/callable.h"
+#include "core/variant/variant.h"
+
+static_assert(sizeof(godot_callable) == sizeof(Callable), "Callable size mismatch");
#ifdef __cplusplus
extern "C" {
#endif
-static_assert(sizeof(godot_callable) == sizeof(Callable), "Callable size mismatch");
-static_assert(sizeof(godot_signal) == sizeof(Signal), "Signal size mismatch");
-
-// Callable
-
-void GDAPI godot_callable_new_with_object(godot_callable *r_dest, const godot_object *p_object, const godot_string_name *p_method) {
- Callable *dest = (Callable *)r_dest;
- const Object *object = (const Object *)p_object;
- const StringName *method = (const StringName *)p_method;
- memnew_placement(dest, Callable(object, *method));
-}
-
-void GDAPI godot_callable_new_with_object_id(godot_callable *r_dest, uint64_t p_objectid, const godot_string_name *p_method) {
- Callable *dest = (Callable *)r_dest;
- const StringName *method = (const StringName *)p_method;
- memnew_placement(dest, Callable(ObjectID(p_objectid), *method));
-}
-
-void GDAPI godot_callable_new_copy(godot_callable *r_dest, const godot_callable *p_src) {
- Callable *dest = (Callable *)r_dest;
- const Callable *src = (const Callable *)p_src;
- memnew_placement(dest, Callable(*src));
+void GDAPI godot_callable_new(godot_callable *p_self) {
+ memnew_placement(p_self, Callable);
}
void GDAPI godot_callable_destroy(godot_callable *p_self) {
@@ -67,186 +48,6 @@ void GDAPI godot_callable_destroy(godot_callable *p_self) {
self->~Callable();
}
-godot_int GDAPI godot_callable_call(const godot_callable *p_self, const godot_variant **p_arguments, godot_int p_argcount, godot_variant *r_return_value) {
- const Callable *self = (const Callable *)p_self;
- const Variant **arguments = (const Variant **)p_arguments;
- Variant *return_value = (Variant *)r_return_value;
- Variant ret;
- Callable::CallError err;
- self->call(arguments, p_argcount, ret, err);
- if (return_value)
- (*return_value) = ret;
- return (godot_int)err.error;
-}
-
-void GDAPI godot_callable_call_deferred(const godot_callable *p_self, const godot_variant **p_arguments, godot_int p_argcount) {
- const Callable *self = (const Callable *)p_self;
- const Variant **arguments = (const Variant **)p_arguments;
- self->call_deferred(arguments, p_argcount);
-}
-
-godot_bool GDAPI godot_callable_is_null(const godot_callable *p_self) {
- const Callable *self = (const Callable *)p_self;
- return self->is_null();
-}
-
-godot_bool GDAPI godot_callable_is_custom(const godot_callable *p_self) {
- const Callable *self = (const Callable *)p_self;
- return self->is_custom();
-}
-
-godot_bool GDAPI godot_callable_is_standard(const godot_callable *p_self) {
- const Callable *self = (const Callable *)p_self;
- return self->is_standard();
-}
-
-godot_object GDAPI *godot_callable_get_object(const godot_callable *p_self) {
- const Callable *self = (const Callable *)p_self;
- return (godot_object *)self->get_object();
-}
-
-uint64_t GDAPI godot_callable_get_object_id(const godot_callable *p_self) {
- const Callable *self = (const Callable *)p_self;
- return (uint64_t)self->get_object_id();
-}
-
-godot_string_name GDAPI godot_callable_get_method(const godot_callable *p_self) {
- godot_string_name raw_dest;
- const Callable *self = (const Callable *)p_self;
- StringName *dest = (StringName *)&raw_dest;
- memnew_placement(dest, StringName(self->get_method()));
- return raw_dest;
-}
-
-uint32_t GDAPI godot_callable_hash(const godot_callable *p_self) {
- const Callable *self = (const Callable *)p_self;
- return self->hash();
-}
-
-godot_string GDAPI godot_callable_as_string(const godot_callable *p_self) {
- godot_string ret;
- const Callable *self = (const Callable *)p_self;
- memnew_placement(&ret, String(*self));
- return ret;
-}
-
-godot_bool GDAPI godot_callable_operator_equal(const godot_callable *p_self, const godot_callable *p_other) {
- const Callable *self = (const Callable *)p_self;
- const Callable *other = (const Callable *)p_other;
- return *self == *other;
-}
-
-godot_bool GDAPI godot_callable_operator_less(const godot_callable *p_self, const godot_callable *p_other) {
- const Callable *self = (const Callable *)p_self;
- const Callable *other = (const Callable *)p_other;
- return *self < *other;
-}
-
-// Signal
-
-void GDAPI godot_signal_new_with_object(godot_signal *r_dest, const godot_object *p_object, const godot_string_name *p_name) {
- Signal *dest = (Signal *)r_dest;
- const Object *object = (const Object *)p_object;
- const StringName *name = (const StringName *)p_name;
- memnew_placement(dest, Signal(object, *name));
-}
-
-void GDAPI godot_signal_new_with_object_id(godot_signal *r_dest, uint64_t p_objectid, const godot_string_name *p_name) {
- Signal *dest = (Signal *)r_dest;
- const StringName *name = (const StringName *)p_name;
- memnew_placement(dest, Signal(ObjectID(p_objectid), *name));
-}
-
-void GDAPI godot_signal_new_copy(godot_signal *r_dest, const godot_signal *p_src) {
- Signal *dest = (Signal *)r_dest;
- const Signal *src = (const Signal *)p_src;
- memnew_placement(dest, Signal(*src));
-}
-
-void GDAPI godot_signal_destroy(godot_signal *p_self) {
- Signal *self = (Signal *)p_self;
- self->~Signal();
-}
-
-godot_int GDAPI godot_signal_emit(const godot_signal *p_self, const godot_variant **p_arguments, godot_int p_argcount) {
- const Signal *self = (const Signal *)p_self;
- const Variant **arguments = (const Variant **)p_arguments;
- return (godot_int)self->emit(arguments, p_argcount);
-}
-
-godot_int GDAPI godot_signal_connect(godot_signal *p_self, const godot_callable *p_callable, const godot_array *p_binds, uint32_t p_flags) {
- Signal *self = (Signal *)p_self;
- const Callable *callable = (const Callable *)p_callable;
- const Array *binds_ar = (const Array *)p_binds;
- Vector<Variant> binds;
- for (int i = 0; i < binds_ar->size(); i++) {
- binds.push_back(binds_ar->get(i));
- }
- return (godot_int)self->connect(*callable, binds, p_flags);
-}
-
-void GDAPI godot_signal_disconnect(godot_signal *p_self, const godot_callable *p_callable) {
- Signal *self = (Signal *)p_self;
- const Callable *callable = (const Callable *)p_callable;
- self->disconnect(*callable);
-}
-
-godot_bool GDAPI godot_signal_is_null(const godot_signal *p_self) {
- const Signal *self = (const Signal *)p_self;
- return self->is_null();
-}
-
-godot_bool GDAPI godot_signal_is_connected(const godot_signal *p_self, const godot_callable *p_callable) {
- const Signal *self = (const Signal *)p_self;
- const Callable *callable = (const Callable *)p_callable;
- return self->is_connected(*callable);
-}
-
-godot_array GDAPI godot_signal_get_connections(const godot_signal *p_self) {
- godot_array raw_dest;
- const Signal *self = (const Signal *)p_self;
- Array *dest = (Array *)&raw_dest;
- memnew_placement(dest, Array(self->get_connections()));
- return raw_dest;
-}
-
-godot_object GDAPI *godot_signal_get_object(const godot_signal *p_self) {
- const Signal *self = (const Signal *)p_self;
- return (godot_object *)self->get_object();
-}
-
-uint64_t GDAPI godot_signal_get_object_id(const godot_signal *p_self) {
- const Signal *self = (const Signal *)p_self;
- return (uint64_t)self->get_object_id();
-}
-
-godot_string_name GDAPI godot_signal_get_name(const godot_signal *p_self) {
- godot_string_name raw_dest;
- const Signal *self = (const Signal *)p_self;
- StringName *dest = (StringName *)&raw_dest;
- memnew_placement(dest, StringName(self->get_name()));
- return raw_dest;
-}
-
-godot_string GDAPI godot_signal_as_string(const godot_signal *p_self) {
- godot_string ret;
- const Signal *self = (const Signal *)p_self;
- memnew_placement(&ret, String(*self));
- return ret;
-}
-
-godot_bool GDAPI godot_signal_operator_equal(const godot_signal *p_self, const godot_signal *p_other) {
- const Signal *self = (const Signal *)p_self;
- const Signal *other = (const Signal *)p_other;
- return *self == *other;
-}
-
-godot_bool GDAPI godot_signal_operator_less(const godot_signal *p_self, const godot_signal *p_other) {
- const Signal *self = (const Signal *)p_self;
- const Signal *other = (const Signal *)p_other;
- return *self < *other;
-}
-
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/color.cpp b/modules/gdnative/gdnative/color.cpp
index c75e74daba..784c8d439e 100644
--- a/modules/gdnative/gdnative/color.cpp
+++ b/modules/gdnative/gdnative/color.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,186 +30,16 @@
#include "gdnative/color.h"
-#include "core/color.h"
-#include "core/variant.h"
+#include "core/math/color.h"
+
+static_assert(sizeof(godot_color) == sizeof(Color), "Color size mismatch");
#ifdef __cplusplus
extern "C" {
#endif
-static_assert(sizeof(godot_color) == sizeof(Color), "Color size mismatch");
-
-void GDAPI godot_color_new_rgba(godot_color *r_dest, const godot_real p_r, const godot_real p_g, const godot_real p_b, const godot_real p_a) {
- Color *dest = (Color *)r_dest;
- *dest = Color(p_r, p_g, p_b, p_a);
-}
-
-void GDAPI godot_color_new_rgb(godot_color *r_dest, const godot_real p_r, const godot_real p_g, const godot_real p_b) {
- Color *dest = (Color *)r_dest;
- *dest = Color(p_r, p_g, p_b);
-}
-
-godot_real godot_color_get_r(const godot_color *p_self) {
- const Color *self = (const Color *)p_self;
- return self->r;
-}
-
-void godot_color_set_r(godot_color *p_self, const godot_real val) {
- Color *self = (Color *)p_self;
- self->r = val;
-}
-
-godot_real godot_color_get_g(const godot_color *p_self) {
- const Color *self = (const Color *)p_self;
- return self->g;
-}
-
-void godot_color_set_g(godot_color *p_self, const godot_real val) {
- Color *self = (Color *)p_self;
- self->g = val;
-}
-
-godot_real godot_color_get_b(const godot_color *p_self) {
- const Color *self = (const Color *)p_self;
- return self->b;
-}
-
-void godot_color_set_b(godot_color *p_self, const godot_real val) {
- Color *self = (Color *)p_self;
- self->b = val;
-}
-
-godot_real godot_color_get_a(const godot_color *p_self) {
- const Color *self = (const Color *)p_self;
- return self->a;
-}
-
-void godot_color_set_a(godot_color *p_self, const godot_real val) {
- Color *self = (Color *)p_self;
- self->a = val;
-}
-
-godot_real godot_color_get_h(const godot_color *p_self) {
- const Color *self = (const Color *)p_self;
- return self->get_h();
-}
-
-godot_real godot_color_get_s(const godot_color *p_self) {
- const Color *self = (const Color *)p_self;
- return self->get_s();
-}
-
-godot_real godot_color_get_v(const godot_color *p_self) {
- const Color *self = (const Color *)p_self;
- return self->get_v();
-}
-
-godot_string GDAPI godot_color_as_string(const godot_color *p_self) {
- godot_string ret;
- const Color *self = (const Color *)p_self;
- memnew_placement(&ret, String(*self));
- return ret;
-}
-
-godot_int GDAPI godot_color_to_rgba32(const godot_color *p_self) {
- const Color *self = (const Color *)p_self;
- return self->to_rgba32();
-}
-
-godot_int GDAPI godot_color_to_abgr32(const godot_color *p_self) {
- const Color *self = (const Color *)p_self;
- return self->to_abgr32();
-}
-
-godot_int GDAPI godot_color_to_abgr64(const godot_color *p_self) {
- const Color *self = (const Color *)p_self;
- return self->to_abgr64();
-}
-
-godot_int GDAPI godot_color_to_argb64(const godot_color *p_self) {
- const Color *self = (const Color *)p_self;
- return self->to_argb64();
-}
-
-godot_int GDAPI godot_color_to_rgba64(const godot_color *p_self) {
- const Color *self = (const Color *)p_self;
- return self->to_rgba64();
-}
-
-godot_int GDAPI godot_color_to_argb32(const godot_color *p_self) {
- const Color *self = (const Color *)p_self;
- return self->to_argb32();
-}
-
-godot_color GDAPI godot_color_inverted(const godot_color *p_self) {
- godot_color dest;
- const Color *self = (const Color *)p_self;
- *((Color *)&dest) = self->inverted();
- return dest;
-}
-
-godot_color GDAPI godot_color_contrasted(const godot_color *p_self) {
- godot_color dest;
- const Color *self = (const Color *)p_self;
- *((Color *)&dest) = self->contrasted();
- return dest;
-}
-
-godot_color GDAPI godot_color_lerp(const godot_color *p_self, const godot_color *p_b, const godot_real p_t) {
- godot_color dest;
- const Color *self = (const Color *)p_self;
- const Color *b = (const Color *)p_b;
- *((Color *)&dest) = self->lerp(*b, p_t);
- return dest;
-}
-
-godot_color GDAPI godot_color_blend(const godot_color *p_self, const godot_color *p_over) {
- godot_color dest;
- const Color *self = (const Color *)p_self;
- const Color *over = (const Color *)p_over;
- *((Color *)&dest) = self->blend(*over);
- return dest;
-}
-
-godot_color GDAPI godot_color_darkened(const godot_color *p_self, const godot_real p_amount) {
- godot_color dest;
- const Color *self = (const Color *)p_self;
- *((Color *)&dest) = self->darkened(p_amount);
- return dest;
-}
-
-godot_color GDAPI godot_color_from_hsv(const godot_color *p_self, const godot_real p_h, const godot_real p_s, const godot_real p_v, const godot_real p_a) {
- godot_color dest;
- const Color *self = (const Color *)p_self;
- *((Color *)&dest) = self->from_hsv(p_h, p_s, p_v, p_a);
- return dest;
-}
-
-godot_color GDAPI godot_color_lightened(const godot_color *p_self, const godot_real p_amount) {
- godot_color dest;
- const Color *self = (const Color *)p_self;
- *((Color *)&dest) = self->lightened(p_amount);
- return dest;
-}
-
-godot_string GDAPI godot_color_to_html(const godot_color *p_self, const godot_bool p_with_alpha) {
- godot_string dest;
- const Color *self = (const Color *)p_self;
-
- memnew_placement(&dest, String(self->to_html(p_with_alpha)));
- return dest;
-}
-
-godot_bool GDAPI godot_color_operator_equal(const godot_color *p_self, const godot_color *p_b) {
- const Color *self = (const Color *)p_self;
- const Color *b = (const Color *)p_b;
- return *self == *b;
-}
-
-godot_bool GDAPI godot_color_operator_less(const godot_color *p_self, const godot_color *p_b) {
- const Color *self = (const Color *)p_self;
- const Color *b = (const Color *)p_b;
- return *self < *b;
+void GDAPI godot_color_new(godot_color *p_self) {
+ memnew_placement(p_self, Color);
}
#ifdef __cplusplus
diff --git a/modules/gdnative/gdnative/dictionary.cpp b/modules/gdnative/gdnative/dictionary.cpp
index a126974815..d58e08f4b0 100644
--- a/modules/gdnative/gdnative/dictionary.cpp
+++ b/modules/gdnative/gdnative/dictionary.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,26 +30,16 @@
#include "gdnative/dictionary.h"
-#include "core/variant.h"
-// core/variant.h before to avoid compile errors with MSVC
-#include "core/dictionary.h"
-#include "core/io/json.h"
+#include "core/variant/dictionary.h"
+
+static_assert(sizeof(godot_dictionary) == sizeof(Dictionary), "Dictionary size mismatch");
#ifdef __cplusplus
extern "C" {
#endif
-static_assert(sizeof(godot_dictionary) == sizeof(Dictionary), "Dictionary size mismatch");
-
-void GDAPI godot_dictionary_new(godot_dictionary *r_dest) {
- Dictionary *dest = (Dictionary *)r_dest;
- memnew_placement(dest, Dictionary);
-}
-
-void GDAPI godot_dictionary_new_copy(godot_dictionary *r_dest, const godot_dictionary *p_src) {
- Dictionary *dest = (Dictionary *)r_dest;
- const Dictionary *src = (const Dictionary *)p_src;
- memnew_placement(dest, Dictionary(*src));
+void GDAPI godot_dictionary_new(godot_dictionary *p_self) {
+ memnew_placement(p_self, Dictionary);
}
void GDAPI godot_dictionary_destroy(godot_dictionary *p_self) {
@@ -57,135 +47,6 @@ void GDAPI godot_dictionary_destroy(godot_dictionary *p_self) {
self->~Dictionary();
}
-godot_dictionary GDAPI godot_dictionary_duplicate(const godot_dictionary *p_self, const godot_bool p_deep) {
- const Dictionary *self = (const Dictionary *)p_self;
- godot_dictionary res;
- Dictionary *val = (Dictionary *)&res;
- memnew_placement(val, Dictionary);
- *val = self->duplicate(p_deep);
- return res;
-}
-
-godot_int GDAPI godot_dictionary_size(const godot_dictionary *p_self) {
- const Dictionary *self = (const Dictionary *)p_self;
- return self->size();
-}
-
-godot_bool GDAPI godot_dictionary_empty(const godot_dictionary *p_self) {
- const Dictionary *self = (const Dictionary *)p_self;
- return self->empty();
-}
-
-void GDAPI godot_dictionary_clear(godot_dictionary *p_self) {
- Dictionary *self = (Dictionary *)p_self;
- self->clear();
-}
-
-godot_bool GDAPI godot_dictionary_has(const godot_dictionary *p_self, const godot_variant *p_key) {
- const Dictionary *self = (const Dictionary *)p_self;
- const Variant *key = (const Variant *)p_key;
- return self->has(*key);
-}
-
-godot_bool GDAPI godot_dictionary_has_all(const godot_dictionary *p_self, const godot_array *p_keys) {
- const Dictionary *self = (const Dictionary *)p_self;
- const Array *keys = (const Array *)p_keys;
- return self->has_all(*keys);
-}
-
-void GDAPI godot_dictionary_erase(godot_dictionary *p_self, const godot_variant *p_key) {
- Dictionary *self = (Dictionary *)p_self;
- const Variant *key = (const Variant *)p_key;
- self->erase(*key);
-}
-
-godot_int GDAPI godot_dictionary_hash(const godot_dictionary *p_self) {
- const Dictionary *self = (const Dictionary *)p_self;
- return self->hash();
-}
-
-godot_array GDAPI godot_dictionary_keys(const godot_dictionary *p_self) {
- godot_array dest;
- const Dictionary *self = (const Dictionary *)p_self;
- memnew_placement(&dest, Array(self->keys()));
- return dest;
-}
-
-godot_array GDAPI godot_dictionary_values(const godot_dictionary *p_self) {
- godot_array dest;
- const Dictionary *self = (const Dictionary *)p_self;
- memnew_placement(&dest, Array(self->values()));
- return dest;
-}
-
-godot_variant GDAPI godot_dictionary_get(const godot_dictionary *p_self, const godot_variant *p_key) {
- godot_variant raw_dest;
- Variant *dest = (Variant *)&raw_dest;
- const Dictionary *self = (const Dictionary *)p_self;
- const Variant *key = (const Variant *)p_key;
- memnew_placement(dest, Variant(self->operator[](*key)));
- return raw_dest;
-}
-
-void GDAPI godot_dictionary_set(godot_dictionary *p_self, const godot_variant *p_key, const godot_variant *p_value) {
- Dictionary *self = (Dictionary *)p_self;
- const Variant *key = (const Variant *)p_key;
- const Variant *value = (const Variant *)p_value;
- self->operator[](*key) = *value;
-}
-
-godot_variant GDAPI *godot_dictionary_operator_index(godot_dictionary *p_self, const godot_variant *p_key) {
- Dictionary *self = (Dictionary *)p_self;
- const Variant *key = (const Variant *)p_key;
- return (godot_variant *)&self->operator[](*key);
-}
-
-const godot_variant GDAPI *godot_dictionary_operator_index_const(const godot_dictionary *p_self, const godot_variant *p_key) {
- const Dictionary *self = (const Dictionary *)p_self;
- const Variant *key = (const Variant *)p_key;
- return (const godot_variant *)&self->operator[](*key);
-}
-
-godot_variant GDAPI *godot_dictionary_next(const godot_dictionary *p_self, const godot_variant *p_key) {
- Dictionary *self = (Dictionary *)p_self;
- const Variant *key = (const Variant *)p_key;
- return (godot_variant *)self->next(key);
-}
-
-godot_bool GDAPI godot_dictionary_operator_equal(const godot_dictionary *p_self, const godot_dictionary *p_b) {
- const Dictionary *self = (const Dictionary *)p_self;
- const Dictionary *b = (const Dictionary *)p_b;
- return *self == *b;
-}
-
-godot_string GDAPI godot_dictionary_to_json(const godot_dictionary *p_self) {
- godot_string raw_dest;
- String *dest = (String *)&raw_dest;
- const Dictionary *self = (const Dictionary *)p_self;
- memnew_placement(dest, String(JSON::print(Variant(*self))));
- return raw_dest;
-}
-
-// GDNative core 1.1
-
-godot_bool GDAPI godot_dictionary_erase_with_return(godot_dictionary *p_self, const godot_variant *p_key) {
- Dictionary *self = (Dictionary *)p_self;
- const Variant *key = (const Variant *)p_key;
- return self->erase(*key);
-}
-
-godot_variant GDAPI godot_dictionary_get_with_default(const godot_dictionary *p_self, const godot_variant *p_key, const godot_variant *p_default) {
- const Dictionary *self = (const Dictionary *)p_self;
- const Variant *key = (const Variant *)p_key;
- const Variant *def = (const Variant *)p_default;
-
- godot_variant raw_dest;
- Variant *dest = (Variant *)&raw_dest;
- memnew_placement(dest, Variant(self->get(*key, *def)));
-
- return raw_dest;
-}
-
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/gdnative.cpp b/modules/gdnative/gdnative/gdnative.cpp
index e94190b07b..c3d25f81c7 100644
--- a/modules/gdnative/gdnative/gdnative.cpp
+++ b/modules/gdnative/gdnative/gdnative.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,12 +30,12 @@
#include "gdnative/gdnative.h"
-#include "core/class_db.h"
-#include "core/engine.h"
-#include "core/error_macros.h"
-#include "core/global_constants.h"
+#include "core/config/engine.h"
+#include "core/core_constants.h"
+#include "core/error/error_macros.h"
+#include "core/object/class_db.h"
#include "core/os/os.h"
-#include "core/variant.h"
+#include "core/variant/variant.h"
#include "modules/gdnative/gdnative.h"
@@ -99,12 +99,12 @@ godot_class_constructor GDAPI godot_get_class_constructor(const char *p_classnam
godot_dictionary GDAPI godot_get_global_constants() {
godot_dictionary constants;
- godot_dictionary_new(&constants);
+ memnew_placement(&constants, Dictionary);
Dictionary *p_constants = (Dictionary *)&constants;
- const int constants_count = GlobalConstants::get_global_constant_count();
+ const int constants_count = CoreConstants::get_global_constant_count();
for (int i = 0; i < constants_count; ++i) {
- const char *name = GlobalConstants::get_global_constant_name(i);
- int value = GlobalConstants::get_global_constant_value(i);
+ const char *name = CoreConstants::get_global_constant_name(i);
+ int value = CoreConstants::get_global_constant_value(i);
(*p_constants)[name] = value;
}
return constants;
@@ -127,18 +127,6 @@ void GDAPI godot_free(void *p_ptr) {
memfree(p_ptr);
}
-void GDAPI godot_print_error(const char *p_description, const char *p_function, const char *p_file, int p_line) {
- _err_print_error(p_function, p_file, p_line, p_description, ERR_HANDLER_ERROR);
-}
-
-void GDAPI godot_print_warning(const char *p_description, const char *p_function, const char *p_file, int p_line) {
- _err_print_error(p_function, p_file, p_line, p_description, ERR_HANDLER_WARNING);
-}
-
-void GDAPI godot_print(const godot_string *p_message) {
- print_line(*(String *)p_message);
-}
-
void _gdnative_report_version_mismatch(const godot_object *p_library, const char *p_ext, godot_gdnative_api_version p_want, godot_gdnative_api_version p_have) {
String message = "Error loading GDNative file ";
GDNativeLibrary *library = (GDNativeLibrary *)p_library;
diff --git a/modules/gdnative/gdnative/node_path.cpp b/modules/gdnative/gdnative/node_path.cpp
index 88ed650ebe..02c2f9b22b 100644
--- a/modules/gdnative/gdnative/node_path.cpp
+++ b/modules/gdnative/gdnative/node_path.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,25 +30,16 @@
#include "gdnative/node_path.h"
-#include "core/node_path.h"
-#include "core/variant.h"
+#include "core/string/node_path.h"
+
+static_assert(sizeof(godot_node_path) == sizeof(NodePath), "NodePath size mismatch");
#ifdef __cplusplus
extern "C" {
#endif
-static_assert(sizeof(godot_node_path) == sizeof(NodePath), "NodePath size mismatch");
-
-void GDAPI godot_node_path_new(godot_node_path *r_dest, const godot_string *p_from) {
- NodePath *dest = (NodePath *)r_dest;
- const String *from = (const String *)p_from;
- memnew_placement(dest, NodePath(*from));
-}
-
-void GDAPI godot_node_path_new_copy(godot_node_path *r_dest, const godot_node_path *p_src) {
- NodePath *dest = (NodePath *)r_dest;
- const NodePath *src = (const NodePath *)p_src;
- memnew_placement(dest, NodePath(*src));
+void GDAPI godot_node_path_new(godot_node_path *p_self) {
+ memnew_placement(p_self, NodePath);
}
void GDAPI godot_node_path_destroy(godot_node_path *p_self) {
@@ -56,71 +47,6 @@ void GDAPI godot_node_path_destroy(godot_node_path *p_self) {
self->~NodePath();
}
-godot_string GDAPI godot_node_path_as_string(const godot_node_path *p_self) {
- godot_string ret;
- const NodePath *self = (const NodePath *)p_self;
- memnew_placement(&ret, String(*self));
- return ret;
-}
-
-godot_bool GDAPI godot_node_path_is_absolute(const godot_node_path *p_self) {
- const NodePath *self = (const NodePath *)p_self;
- return self->is_absolute();
-}
-
-godot_int GDAPI godot_node_path_get_name_count(const godot_node_path *p_self) {
- const NodePath *self = (const NodePath *)p_self;
- return self->get_name_count();
-}
-
-godot_string GDAPI godot_node_path_get_name(const godot_node_path *p_self, const godot_int p_idx) {
- godot_string dest;
- const NodePath *self = (const NodePath *)p_self;
-
- memnew_placement(&dest, String(self->get_name(p_idx)));
- return dest;
-}
-
-godot_int GDAPI godot_node_path_get_subname_count(const godot_node_path *p_self) {
- const NodePath *self = (const NodePath *)p_self;
- return self->get_subname_count();
-}
-
-godot_string GDAPI godot_node_path_get_subname(const godot_node_path *p_self, const godot_int p_idx) {
- godot_string dest;
- const NodePath *self = (const NodePath *)p_self;
-
- memnew_placement(&dest, String(self->get_subname(p_idx)));
- return dest;
-}
-
-godot_string GDAPI godot_node_path_get_concatenated_subnames(const godot_node_path *p_self) {
- godot_string dest;
- const NodePath *self = (const NodePath *)p_self;
- memnew_placement(&dest, String(self->get_concatenated_subnames()));
- return dest;
-}
-
-godot_bool GDAPI godot_node_path_is_empty(const godot_node_path *p_self) {
- const NodePath *self = (const NodePath *)p_self;
- return self->is_empty();
-}
-
-godot_bool GDAPI godot_node_path_operator_equal(const godot_node_path *p_self, const godot_node_path *p_b) {
- const NodePath *self = (const NodePath *)p_self;
- const NodePath *b = (const NodePath *)p_b;
- return *self == *b;
-}
-
-godot_node_path godot_node_path_get_as_property_path(const godot_node_path *p_self) {
- const NodePath *self = (const NodePath *)p_self;
- godot_node_path res;
- NodePath *val = (NodePath *)&res;
- memnew_placement(val, NodePath);
- *val = self->get_as_property_path();
- return res;
-}
-
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/packed_arrays.cpp b/modules/gdnative/gdnative/packed_arrays.cpp
index de93c1d9b3..9e4c6e6f38 100644
--- a/modules/gdnative/gdnative/packed_arrays.cpp
+++ b/modules/gdnative/gdnative/packed_arrays.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,997 +30,137 @@
#include "gdnative/packed_arrays.h"
-#include "core/array.h"
+#include "core/variant/variant.h"
-#include "core/variant.h"
-
-#include "core/color.h"
#include "core/math/vector2.h"
-#include "core/math/vector3.h"
+#include "core/math/vector3i.h"
+
+static_assert(sizeof(godot_packed_byte_array) == sizeof(PackedByteArray), "PackedByteArray size mismatch");
+static_assert(sizeof(godot_packed_int32_array) == sizeof(PackedInt32Array), "PackedInt32Array size mismatch");
+static_assert(sizeof(godot_packed_int64_array) == sizeof(PackedInt64Array), "PackedInt64Array size mismatch");
+static_assert(sizeof(godot_packed_float32_array) == sizeof(PackedFloat32Array), "PackedFloat32Array size mismatch");
+static_assert(sizeof(godot_packed_float64_array) == sizeof(PackedFloat64Array), "PackedFloat64Array size mismatch");
+static_assert(sizeof(godot_packed_string_array) == sizeof(PackedStringArray), "PackedStringArray size mismatch");
+static_assert(sizeof(godot_packed_vector2_array) == sizeof(PackedVector2Array), "PackedVector2Array size mismatch");
+static_assert(sizeof(godot_packed_vector2i_array) == sizeof(Vector<Vector2i>), "Vector<Vector2i> size mismatch");
+static_assert(sizeof(godot_packed_vector3_array) == sizeof(PackedVector3Array), "PackedVector3Array size mismatch");
+static_assert(sizeof(godot_packed_vector3i_array) == sizeof(Vector<Vector3i>), "Vector<Vector3i> size mismatch");
+static_assert(sizeof(godot_packed_color_array) == sizeof(PackedColorArray), "PackedColorArray size mismatch");
#ifdef __cplusplus
extern "C" {
#endif
-static_assert(sizeof(godot_packed_byte_array) == sizeof(Vector<uint8_t>), "Vector<uint8_t> size mismatch");
-static_assert(sizeof(godot_packed_int32_array) == sizeof(Vector<int32_t>), "Vector<int32_t> size mismatch");
-static_assert(sizeof(godot_packed_int64_array) == sizeof(Vector<int64_t>), "Vector<int64_t> size mismatch");
-static_assert(sizeof(godot_packed_float32_array) == sizeof(Vector<float>), "Vector<float> size mismatch");
-static_assert(sizeof(godot_packed_float64_array) == sizeof(Vector<double>), "Vector<double> size mismatch");
-static_assert(sizeof(godot_packed_string_array) == sizeof(Vector<String>), "Vector<String> size mismatch");
-static_assert(sizeof(godot_packed_vector2_array) == sizeof(Vector<Vector2>), "Vector<Vector2> size mismatch");
-static_assert(sizeof(godot_packed_vector3_array) == sizeof(Vector<Vector3>), "Vector<Vector3> size mismatch");
-static_assert(sizeof(godot_packed_color_array) == sizeof(Vector<Color>), "Vector<Color> size mismatch");
-
#define memnew_placement_custom(m_placement, m_class, m_constr) _post_initialize(new (m_placement, sizeof(m_class), "") m_constr)
// byte
-void GDAPI godot_packed_byte_array_new(godot_packed_byte_array *r_dest) {
- Vector<uint8_t> *dest = (Vector<uint8_t> *)r_dest;
- memnew_placement(dest, Vector<uint8_t>);
-}
-
-void GDAPI godot_packed_byte_array_new_copy(godot_packed_byte_array *r_dest, const godot_packed_byte_array *p_src) {
- Vector<uint8_t> *dest = (Vector<uint8_t> *)r_dest;
- const Vector<uint8_t> *src = (const Vector<uint8_t> *)p_src;
- memnew_placement(dest, Vector<uint8_t>(*src));
-}
-
-void GDAPI godot_packed_byte_array_new_with_array(godot_packed_byte_array *r_dest, const godot_array *p_a) {
- Vector<uint8_t> *dest = (Vector<uint8_t> *)r_dest;
- Array *a = (Array *)p_a;
- memnew_placement(dest, Vector<uint8_t>);
-
- dest->resize(a->size());
- for (int i = 0; i < a->size(); i++) {
- dest->set(i, (*a)[i]);
- }
-}
-
-const uint8_t GDAPI *godot_packed_byte_array_ptr(const godot_packed_byte_array *p_self) {
- const Vector<uint8_t> *self = (const Vector<uint8_t> *)p_self;
- return self->ptr();
-}
-
-uint8_t GDAPI *godot_packed_byte_array_ptrw(godot_packed_byte_array *p_self) {
- Vector<uint8_t> *self = (Vector<uint8_t> *)p_self;
- return self->ptrw();
-}
-
-void GDAPI godot_packed_byte_array_append(godot_packed_byte_array *p_self, const uint8_t p_data) {
- Vector<uint8_t> *self = (Vector<uint8_t> *)p_self;
- self->push_back(p_data);
-}
-
-void GDAPI godot_packed_byte_array_append_array(godot_packed_byte_array *p_self, const godot_packed_byte_array *p_array) {
- Vector<uint8_t> *self = (Vector<uint8_t> *)p_self;
- Vector<uint8_t> *array = (Vector<uint8_t> *)p_array;
- self->append_array(*array);
-}
-
-godot_error GDAPI godot_packed_byte_array_insert(godot_packed_byte_array *p_self, const godot_int p_idx, const uint8_t p_data) {
- Vector<uint8_t> *self = (Vector<uint8_t> *)p_self;
- return (godot_error)self->insert(p_idx, p_data);
-}
-
-godot_bool GDAPI godot_packed_byte_array_has(godot_packed_byte_array *p_self, const uint8_t p_value) {
- Vector<uint8_t> *self = (Vector<uint8_t> *)p_self;
- return (godot_bool)self->has(p_value);
-}
-
-void GDAPI godot_packed_byte_array_sort(godot_packed_byte_array *p_self) {
- Vector<uint8_t> *self = (Vector<uint8_t> *)p_self;
- self->sort();
-}
-
-void GDAPI godot_packed_byte_array_invert(godot_packed_byte_array *p_self) {
- Vector<uint8_t> *self = (Vector<uint8_t> *)p_self;
- self->invert();
-}
-
-void GDAPI godot_packed_byte_array_push_back(godot_packed_byte_array *p_self, const uint8_t p_data) {
- Vector<uint8_t> *self = (Vector<uint8_t> *)p_self;
- self->push_back(p_data);
-}
-
-void GDAPI godot_packed_byte_array_remove(godot_packed_byte_array *p_self, const godot_int p_idx) {
- Vector<uint8_t> *self = (Vector<uint8_t> *)p_self;
- self->remove(p_idx);
-}
-
-void GDAPI godot_packed_byte_array_resize(godot_packed_byte_array *p_self, const godot_int p_size) {
- Vector<uint8_t> *self = (Vector<uint8_t> *)p_self;
- self->resize(p_size);
-}
-
-void GDAPI godot_packed_byte_array_set(godot_packed_byte_array *p_self, const godot_int p_idx, const uint8_t p_data) {
- Vector<uint8_t> *self = (Vector<uint8_t> *)p_self;
- self->set(p_idx, p_data);
-}
-
-uint8_t GDAPI godot_packed_byte_array_get(const godot_packed_byte_array *p_self, const godot_int p_idx) {
- const Vector<uint8_t> *self = (const Vector<uint8_t> *)p_self;
- return self->get(p_idx);
-}
-
-godot_int GDAPI godot_packed_byte_array_size(const godot_packed_byte_array *p_self) {
- const Vector<uint8_t> *self = (const Vector<uint8_t> *)p_self;
- return self->size();
-}
-
-godot_bool GDAPI godot_packed_byte_array_empty(const godot_packed_byte_array *p_self) {
- const Vector<uint8_t> *self = (const Vector<uint8_t> *)p_self;
- return self->empty();
+void GDAPI godot_packed_byte_array_new(godot_packed_byte_array *p_self) {
+ memnew_placement(p_self, PackedByteArray);
}
void GDAPI godot_packed_byte_array_destroy(godot_packed_byte_array *p_self) {
- ((Vector<uint8_t> *)p_self)->~Vector();
+ ((PackedByteArray *)p_self)->~PackedByteArray();
}
// int32
-void GDAPI godot_packed_int32_array_new(godot_packed_int32_array *r_dest) {
- Vector<int32_t> *dest = (Vector<int32_t> *)r_dest;
- memnew_placement(dest, Vector<int32_t>);
-}
-
-void GDAPI godot_packed_int32_array_new_copy(godot_packed_int32_array *r_dest, const godot_packed_int32_array *p_src) {
- Vector<int32_t> *dest = (Vector<int32_t> *)r_dest;
- const Vector<int32_t> *src = (const Vector<int32_t> *)p_src;
- memnew_placement(dest, Vector<int32_t>(*src));
-}
-
-void GDAPI godot_packed_int32_array_new_with_array(godot_packed_int32_array *r_dest, const godot_array *p_a) {
- Vector<int32_t> *dest = (Vector<int32_t> *)r_dest;
- Array *a = (Array *)p_a;
- memnew_placement(dest, Vector<int32_t>);
-
- dest->resize(a->size());
- for (int i = 0; i < a->size(); i++) {
- dest->set(i, (*a)[i]);
- }
-}
-
-const int32_t GDAPI *godot_packed_int32_array_ptr(const godot_packed_int32_array *p_self) {
- const Vector<int32_t> *self = (const Vector<int32_t> *)p_self;
- return self->ptr();
-}
-
-int32_t GDAPI *godot_packed_int32_array_ptrw(godot_packed_int32_array *p_self) {
- Vector<int32_t> *self = (Vector<int32_t> *)p_self;
- return self->ptrw();
-}
-
-void GDAPI godot_packed_int32_array_append(godot_packed_int32_array *p_self, const int32_t p_data) {
- Vector<int32_t> *self = (Vector<int32_t> *)p_self;
- self->push_back(p_data);
-}
-
-void GDAPI godot_packed_int32_array_append_array(godot_packed_int32_array *p_self, const godot_packed_int32_array *p_array) {
- Vector<int32_t> *self = (Vector<int32_t> *)p_self;
- Vector<int32_t> *array = (Vector<int32_t> *)p_array;
- self->append_array(*array);
-}
-
-godot_error GDAPI godot_packed_int32_array_insert(godot_packed_int32_array *p_self, const godot_int p_idx, const int32_t p_data) {
- Vector<int32_t> *self = (Vector<int32_t> *)p_self;
- return (godot_error)self->insert(p_idx, p_data);
-}
-
-godot_bool GDAPI godot_packed_int32_array_has(godot_packed_int32_array *p_self, const int32_t p_value) {
- Vector<int32_t> *self = (Vector<int32_t> *)p_self;
- return (godot_bool)self->has(p_value);
-}
-
-void GDAPI godot_packed_int32_array_sort(godot_packed_int32_array *p_self) {
- Vector<int32_t> *self = (Vector<int32_t> *)p_self;
- self->sort();
-}
-
-void GDAPI godot_packed_int32_array_invert(godot_packed_int32_array *p_self) {
- Vector<int32_t> *self = (Vector<int32_t> *)p_self;
- self->invert();
-}
-
-void GDAPI godot_packed_int32_array_push_back(godot_packed_int32_array *p_self, const int32_t p_data) {
- Vector<int32_t> *self = (Vector<int32_t> *)p_self;
- self->push_back(p_data);
-}
-
-void GDAPI godot_packed_int32_array_remove(godot_packed_int32_array *p_self, const godot_int p_idx) {
- Vector<int32_t> *self = (Vector<int32_t> *)p_self;
- self->remove(p_idx);
-}
-
-void GDAPI godot_packed_int32_array_resize(godot_packed_int32_array *p_self, const godot_int p_size) {
- Vector<int32_t> *self = (Vector<int32_t> *)p_self;
- self->resize(p_size);
-}
-
-void GDAPI godot_packed_int32_array_set(godot_packed_int32_array *p_self, const godot_int p_idx, const int32_t p_data) {
- Vector<int32_t> *self = (Vector<int32_t> *)p_self;
- self->set(p_idx, p_data);
-}
-
-int32_t GDAPI godot_packed_int32_array_get(const godot_packed_int32_array *p_self, const godot_int p_idx) {
- const Vector<int32_t> *self = (const Vector<int32_t> *)p_self;
- return self->get(p_idx);
-}
-
-godot_int GDAPI godot_packed_int32_array_size(const godot_packed_int32_array *p_self) {
- const Vector<int32_t> *self = (const Vector<int32_t> *)p_self;
- return self->size();
-}
-
-godot_bool GDAPI godot_packed_int32_array_empty(const godot_packed_int32_array *p_self) {
- const Vector<int32_t> *self = (const Vector<int32_t> *)p_self;
- return self->empty();
+void GDAPI godot_packed_int32_array_new(godot_packed_int32_array *p_self) {
+ memnew_placement(p_self, PackedInt32Array);
}
void GDAPI godot_packed_int32_array_destroy(godot_packed_int32_array *p_self) {
- ((Vector<int32_t> *)p_self)->~Vector();
+ ((PackedInt32Array *)p_self)->~PackedInt32Array();
}
// int64
-void GDAPI godot_packed_int64_array_new(godot_packed_int64_array *r_dest) {
- Vector<int64_t> *dest = (Vector<int64_t> *)r_dest;
- memnew_placement(dest, Vector<int64_t>);
-}
-
-void GDAPI godot_packed_int64_array_new_copy(godot_packed_int64_array *r_dest, const godot_packed_int64_array *p_src) {
- Vector<int64_t> *dest = (Vector<int64_t> *)r_dest;
- const Vector<int64_t> *src = (const Vector<int64_t> *)p_src;
- memnew_placement(dest, Vector<int64_t>(*src));
-}
-
-void GDAPI godot_packed_int64_array_new_with_array(godot_packed_int64_array *r_dest, const godot_array *p_a) {
- Vector<int64_t> *dest = (Vector<int64_t> *)r_dest;
- Array *a = (Array *)p_a;
- memnew_placement(dest, Vector<int64_t>);
-
- dest->resize(a->size());
- for (int i = 0; i < a->size(); i++) {
- dest->set(i, (*a)[i]);
- }
-}
-
-const int64_t GDAPI *godot_packed_int64_array_ptr(const godot_packed_int64_array *p_self) {
- const Vector<int64_t> *self = (const Vector<int64_t> *)p_self;
- return self->ptr();
-}
-
-int64_t GDAPI *godot_packed_int64_array_ptrw(godot_packed_int64_array *p_self) {
- Vector<int64_t> *self = (Vector<int64_t> *)p_self;
- return self->ptrw();
-}
-
-void GDAPI godot_packed_int64_array_append(godot_packed_int64_array *p_self, const int64_t p_data) {
- Vector<int64_t> *self = (Vector<int64_t> *)p_self;
- self->push_back(p_data);
-}
-
-void GDAPI godot_packed_int64_array_append_array(godot_packed_int64_array *p_self, const godot_packed_int64_array *p_array) {
- Vector<int64_t> *self = (Vector<int64_t> *)p_self;
- Vector<int64_t> *array = (Vector<int64_t> *)p_array;
- self->append_array(*array);
-}
-
-godot_error GDAPI godot_packed_int64_array_insert(godot_packed_int64_array *p_self, const godot_int p_idx, const int64_t p_data) {
- Vector<int64_t> *self = (Vector<int64_t> *)p_self;
- return (godot_error)self->insert(p_idx, p_data);
-}
-
-godot_bool GDAPI godot_packed_int64_array_has(godot_packed_int64_array *p_self, const int64_t p_value) {
- Vector<int64_t> *self = (Vector<int64_t> *)p_self;
- return (godot_bool)self->has(p_value);
-}
-
-void GDAPI godot_packed_int64_array_sort(godot_packed_int64_array *p_self) {
- Vector<int64_t> *self = (Vector<int64_t> *)p_self;
- self->sort();
-}
-
-void GDAPI godot_packed_int64_array_invert(godot_packed_int64_array *p_self) {
- Vector<int64_t> *self = (Vector<int64_t> *)p_self;
- self->invert();
-}
-
-void GDAPI godot_packed_int64_array_push_back(godot_packed_int64_array *p_self, const int64_t p_data) {
- Vector<int64_t> *self = (Vector<int64_t> *)p_self;
- self->push_back(p_data);
-}
-
-void GDAPI godot_packed_int64_array_remove(godot_packed_int64_array *p_self, const godot_int p_idx) {
- Vector<int64_t> *self = (Vector<int64_t> *)p_self;
- self->remove(p_idx);
-}
-
-void GDAPI godot_packed_int64_array_resize(godot_packed_int64_array *p_self, const godot_int p_size) {
- Vector<int64_t> *self = (Vector<int64_t> *)p_self;
- self->resize(p_size);
-}
-
-void GDAPI godot_packed_int64_array_set(godot_packed_int64_array *p_self, const godot_int p_idx, const int64_t p_data) {
- Vector<int64_t> *self = (Vector<int64_t> *)p_self;
- self->set(p_idx, p_data);
-}
-
-int64_t GDAPI godot_packed_int64_array_get(const godot_packed_int64_array *p_self, const godot_int p_idx) {
- const Vector<int64_t> *self = (const Vector<int64_t> *)p_self;
- return self->get(p_idx);
-}
-
-godot_int GDAPI godot_packed_int64_array_size(const godot_packed_int64_array *p_self) {
- const Vector<int64_t> *self = (const Vector<int64_t> *)p_self;
- return self->size();
-}
-
-godot_bool GDAPI godot_packed_int64_array_empty(const godot_packed_int64_array *p_self) {
- const Vector<int64_t> *self = (const Vector<int64_t> *)p_self;
- return self->empty();
+void GDAPI godot_packed_int64_array_new(godot_packed_int64_array *p_self) {
+ memnew_placement(p_self, PackedInt64Array);
}
void GDAPI godot_packed_int64_array_destroy(godot_packed_int64_array *p_self) {
- ((Vector<int64_t> *)p_self)->~Vector();
+ ((PackedInt64Array *)p_self)->~PackedInt64Array();
}
// float32
-void GDAPI godot_packed_float32_array_new(godot_packed_float32_array *r_dest) {
- Vector<float> *dest = (Vector<float> *)r_dest;
- memnew_placement(dest, Vector<float>);
-}
-
-void GDAPI godot_packed_float32_array_new_copy(godot_packed_float32_array *r_dest, const godot_packed_float32_array *p_src) {
- Vector<float> *dest = (Vector<float> *)r_dest;
- const Vector<float> *src = (const Vector<float> *)p_src;
- memnew_placement(dest, Vector<float>(*src));
-}
-
-void GDAPI godot_packed_float32_array_new_with_array(godot_packed_float32_array *r_dest, const godot_array *p_a) {
- Vector<float> *dest = (Vector<float> *)r_dest;
- Array *a = (Array *)p_a;
- memnew_placement(dest, Vector<float>);
-
- dest->resize(a->size());
- for (int i = 0; i < a->size(); i++) {
- dest->set(i, (*a)[i]);
- }
-}
-
-const float GDAPI *godot_packed_float32_array_ptr(const godot_packed_float32_array *p_self) {
- const Vector<float> *self = (const Vector<float> *)p_self;
- return self->ptr();
-}
-
-float GDAPI *godot_packed_float32_array_ptrw(godot_packed_float32_array *p_self) {
- Vector<float> *self = (Vector<float> *)p_self;
- return self->ptrw();
-}
-
-void GDAPI godot_packed_float32_array_append(godot_packed_float32_array *p_self, const float p_data) {
- Vector<float> *self = (Vector<float> *)p_self;
- self->push_back(p_data);
-}
-
-void GDAPI godot_packed_float32_array_append_array(godot_packed_float32_array *p_self, const godot_packed_float32_array *p_array) {
- Vector<float> *self = (Vector<float> *)p_self;
- Vector<float> *array = (Vector<float> *)p_array;
- self->append_array(*array);
-}
-
-godot_error GDAPI godot_packed_float32_array_insert(godot_packed_float32_array *p_self, const godot_int p_idx, const float p_data) {
- Vector<float> *self = (Vector<float> *)p_self;
- return (godot_error)self->insert(p_idx, p_data);
-}
-
-godot_bool GDAPI godot_packed_float32_array_has(godot_packed_float32_array *p_self, const float p_value) {
- Vector<float> *self = (Vector<float> *)p_self;
- return (godot_bool)self->has(p_value);
-}
-
-void GDAPI godot_packed_float32_array_sort(godot_packed_float32_array *p_self) {
- Vector<float> *self = (Vector<float> *)p_self;
- self->sort();
-}
-
-void GDAPI godot_packed_float32_array_invert(godot_packed_float32_array *p_self) {
- Vector<float> *self = (Vector<float> *)p_self;
- self->invert();
-}
-
-void GDAPI godot_packed_float32_array_push_back(godot_packed_float32_array *p_self, const float p_data) {
- Vector<float> *self = (Vector<float> *)p_self;
- self->push_back(p_data);
-}
-
-void GDAPI godot_packed_float32_array_remove(godot_packed_float32_array *p_self, const godot_int p_idx) {
- Vector<float> *self = (Vector<float> *)p_self;
- self->remove(p_idx);
-}
-
-void GDAPI godot_packed_float32_array_resize(godot_packed_float32_array *p_self, const godot_int p_size) {
- Vector<float> *self = (Vector<float> *)p_self;
- self->resize(p_size);
-}
-
-void GDAPI godot_packed_float32_array_set(godot_packed_float32_array *p_self, const godot_int p_idx, const float p_data) {
- Vector<float> *self = (Vector<float> *)p_self;
- self->set(p_idx, p_data);
-}
-
-float GDAPI godot_packed_float32_array_get(const godot_packed_float32_array *p_self, const godot_int p_idx) {
- const Vector<float> *self = (const Vector<float> *)p_self;
- return self->get(p_idx);
-}
-
-godot_int GDAPI godot_packed_float32_array_size(const godot_packed_float32_array *p_self) {
- const Vector<float> *self = (const Vector<float> *)p_self;
- return self->size();
-}
-
-godot_bool GDAPI godot_packed_float32_array_empty(const godot_packed_float32_array *p_self) {
- const Vector<float> *self = (const Vector<float> *)p_self;
- return self->empty();
+void GDAPI godot_packed_float32_array_new(godot_packed_float32_array *p_self) {
+ memnew_placement(p_self, PackedFloat32Array);
}
void GDAPI godot_packed_float32_array_destroy(godot_packed_float32_array *p_self) {
- ((Vector<float> *)p_self)->~Vector();
+ ((PackedFloat32Array *)p_self)->~PackedFloat32Array();
}
// float64
-void GDAPI godot_packed_float64_array_new(godot_packed_float64_array *r_dest) {
- Vector<double> *dest = (Vector<double> *)r_dest;
- memnew_placement(dest, Vector<double>);
-}
-
-void GDAPI godot_packed_float64_array_new_copy(godot_packed_float64_array *r_dest, const godot_packed_float64_array *p_src) {
- Vector<double> *dest = (Vector<double> *)r_dest;
- const Vector<double> *src = (const Vector<double> *)p_src;
- memnew_placement(dest, Vector<double>(*src));
-}
-
-void GDAPI godot_packed_float64_array_new_with_array(godot_packed_float64_array *r_dest, const godot_array *p_a) {
- Vector<double> *dest = (Vector<double> *)r_dest;
- Array *a = (Array *)p_a;
- memnew_placement(dest, Vector<double>);
-
- dest->resize(a->size());
- for (int i = 0; i < a->size(); i++) {
- dest->set(i, (*a)[i]);
- }
-}
-
-const double GDAPI *godot_packed_float64_array_ptr(const godot_packed_float64_array *p_self) {
- const Vector<double> *self = (const Vector<double> *)p_self;
- return self->ptr();
-}
-
-double GDAPI *godot_packed_float64_array_ptrw(godot_packed_float64_array *p_self) {
- Vector<double> *self = (Vector<double> *)p_self;
- return self->ptrw();
-}
-
-void GDAPI godot_packed_float64_array_append(godot_packed_float64_array *p_self, const double p_data) {
- Vector<double> *self = (Vector<double> *)p_self;
- self->push_back(p_data);
-}
-
-void GDAPI godot_packed_float64_array_append_array(godot_packed_float64_array *p_self, const godot_packed_float64_array *p_array) {
- Vector<double> *self = (Vector<double> *)p_self;
- Vector<double> *array = (Vector<double> *)p_array;
- self->append_array(*array);
-}
-
-godot_error GDAPI godot_packed_float64_array_insert(godot_packed_float64_array *p_self, const godot_int p_idx, const double p_data) {
- Vector<double> *self = (Vector<double> *)p_self;
- return (godot_error)self->insert(p_idx, p_data);
-}
-
-godot_bool GDAPI godot_packed_float64_array_has(godot_packed_float64_array *p_self, const double p_value) {
- Vector<double> *self = (Vector<double> *)p_self;
- return (godot_bool)self->has(p_value);
-}
-
-void GDAPI godot_packed_float64_array_sort(godot_packed_float64_array *p_self) {
- Vector<double> *self = (Vector<double> *)p_self;
- self->sort();
-}
-
-void GDAPI godot_packed_float64_array_invert(godot_packed_float64_array *p_self) {
- Vector<double> *self = (Vector<double> *)p_self;
- self->invert();
-}
-
-void GDAPI godot_packed_float64_array_push_back(godot_packed_float64_array *p_self, const double p_data) {
- Vector<double> *self = (Vector<double> *)p_self;
- self->push_back(p_data);
-}
-
-void GDAPI godot_packed_float64_array_remove(godot_packed_float64_array *p_self, const godot_int p_idx) {
- Vector<double> *self = (Vector<double> *)p_self;
- self->remove(p_idx);
-}
-
-void GDAPI godot_packed_float64_array_resize(godot_packed_float64_array *p_self, const godot_int p_size) {
- Vector<double> *self = (Vector<double> *)p_self;
- self->resize(p_size);
-}
-
-void GDAPI godot_packed_float64_array_set(godot_packed_float64_array *p_self, const godot_int p_idx, const double p_data) {
- Vector<double> *self = (Vector<double> *)p_self;
- self->set(p_idx, p_data);
-}
-
-double GDAPI godot_packed_float64_array_get(const godot_packed_float64_array *p_self, const godot_int p_idx) {
- const Vector<double> *self = (const Vector<double> *)p_self;
- return self->get(p_idx);
-}
-
-godot_int GDAPI godot_packed_float64_array_size(const godot_packed_float64_array *p_self) {
- const Vector<double> *self = (const Vector<double> *)p_self;
- return self->size();
-}
-
-godot_bool GDAPI godot_packed_float64_array_empty(const godot_packed_float64_array *p_self) {
- const Vector<double> *self = (const Vector<double> *)p_self;
- return self->empty();
+void GDAPI godot_packed_float64_array_new(godot_packed_float64_array *p_self) {
+ memnew_placement(p_self, PackedFloat64Array);
}
void GDAPI godot_packed_float64_array_destroy(godot_packed_float64_array *p_self) {
- ((Vector<double> *)p_self)->~Vector();
+ ((PackedFloat64Array *)p_self)->~PackedFloat64Array();
}
// string
-void GDAPI godot_packed_string_array_new(godot_packed_string_array *r_dest) {
- Vector<String> *dest = (Vector<String> *)r_dest;
- memnew_placement(dest, Vector<String>);
-}
-
-void GDAPI godot_packed_string_array_new_copy(godot_packed_string_array *r_dest, const godot_packed_string_array *p_src) {
- Vector<String> *dest = (Vector<String> *)r_dest;
- const Vector<String> *src = (const Vector<String> *)p_src;
- memnew_placement(dest, Vector<String>(*src));
-}
-
-void GDAPI godot_packed_string_array_new_with_array(godot_packed_string_array *r_dest, const godot_array *p_a) {
- Vector<String> *dest = (Vector<String> *)r_dest;
- Array *a = (Array *)p_a;
- memnew_placement(dest, Vector<String>);
-
- dest->resize(a->size());
- for (int i = 0; i < a->size(); i++) {
- dest->set(i, (*a)[i]);
- }
-}
-
-const godot_string GDAPI *godot_packed_string_array_ptr(const godot_packed_string_array *p_self) {
- const Vector<String> *self = (const Vector<String> *)p_self;
- return (const godot_string *)self->ptr();
-}
-
-godot_string GDAPI *godot_packed_string_array_ptrw(godot_packed_string_array *p_self) {
- Vector<String> *self = (Vector<String> *)p_self;
- return (godot_string *)self->ptrw();
-}
-
-void GDAPI godot_packed_string_array_append(godot_packed_string_array *p_self, const godot_string *p_data) {
- Vector<String> *self = (Vector<String> *)p_self;
- String &s = *(String *)p_data;
- self->push_back(s);
-}
-
-void GDAPI godot_packed_string_array_append_array(godot_packed_string_array *p_self, const godot_packed_string_array *p_array) {
- Vector<String> *self = (Vector<String> *)p_self;
- Vector<String> *array = (Vector<String> *)p_array;
- self->append_array(*array);
-}
-
-godot_error GDAPI godot_packed_string_array_insert(godot_packed_string_array *p_self, const godot_int p_idx, const godot_string *p_data) {
- Vector<String> *self = (Vector<String> *)p_self;
- String &s = *(String *)p_data;
- return (godot_error)self->insert(p_idx, s);
-}
-
-godot_bool GDAPI godot_packed_string_array_has(godot_packed_string_array *p_self, const godot_string *p_value) {
- Vector<String> *self = (Vector<String> *)p_self;
- String &s = *(String *)p_value;
- return (godot_bool)self->has(s);
-}
-
-void GDAPI godot_packed_string_array_sort(godot_packed_string_array *p_self) {
- Vector<String> *self = (Vector<String> *)p_self;
- self->sort();
-}
-
-void GDAPI godot_packed_string_array_invert(godot_packed_string_array *p_self) {
- Vector<String> *self = (Vector<String> *)p_self;
- self->invert();
-}
-
-void GDAPI godot_packed_string_array_push_back(godot_packed_string_array *p_self, const godot_string *p_data) {
- Vector<String> *self = (Vector<String> *)p_self;
- String &s = *(String *)p_data;
- self->push_back(s);
-}
-
-void GDAPI godot_packed_string_array_remove(godot_packed_string_array *p_self, const godot_int p_idx) {
- Vector<String> *self = (Vector<String> *)p_self;
- self->remove(p_idx);
-}
-
-void GDAPI godot_packed_string_array_resize(godot_packed_string_array *p_self, const godot_int p_size) {
- Vector<String> *self = (Vector<String> *)p_self;
- self->resize(p_size);
-}
-
-void GDAPI godot_packed_string_array_set(godot_packed_string_array *p_self, const godot_int p_idx, const godot_string *p_data) {
- Vector<String> *self = (Vector<String> *)p_self;
- String &s = *(String *)p_data;
- self->set(p_idx, s);
-}
-
-godot_string GDAPI godot_packed_string_array_get(const godot_packed_string_array *p_self, const godot_int p_idx) {
- const Vector<String> *self = (const Vector<String> *)p_self;
- godot_string str;
- String *s = (String *)&str;
- memnew_placement(s, String);
- *s = self->get(p_idx);
- return str;
-}
-
-godot_int GDAPI godot_packed_string_array_size(const godot_packed_string_array *p_self) {
- const Vector<String> *self = (const Vector<String> *)p_self;
- return self->size();
-}
-
-godot_bool GDAPI godot_packed_string_array_empty(const godot_packed_string_array *p_self) {
- const Vector<String> *self = (const Vector<String> *)p_self;
- return self->empty();
+void GDAPI godot_packed_string_array_new(godot_packed_string_array *p_self) {
+ memnew_placement(p_self, PackedStringArray);
}
void GDAPI godot_packed_string_array_destroy(godot_packed_string_array *p_self) {
- ((Vector<String> *)p_self)->~Vector();
+ ((PackedStringArray *)p_self)->~PackedStringArray();
}
// vector2
-void GDAPI godot_packed_vector2_array_new(godot_packed_vector2_array *r_dest) {
- Vector<Vector2> *dest = (Vector<Vector2> *)r_dest;
- memnew_placement(dest, Vector<Vector2>);
-}
-
-void GDAPI godot_packed_vector2_array_new_copy(godot_packed_vector2_array *r_dest, const godot_packed_vector2_array *p_src) {
- Vector<Vector2> *dest = (Vector<Vector2> *)r_dest;
- const Vector<Vector2> *src = (const Vector<Vector2> *)p_src;
- memnew_placement(dest, Vector<Vector2>(*src));
-}
-
-void GDAPI godot_packed_vector2_array_new_with_array(godot_packed_vector2_array *r_dest, const godot_array *p_a) {
- Vector<Vector2> *dest = (Vector<Vector2> *)r_dest;
- Array *a = (Array *)p_a;
- memnew_placement(dest, Vector<Vector2>);
-
- dest->resize(a->size());
- for (int i = 0; i < a->size(); i++) {
- dest->set(i, (*a)[i]);
- }
-}
-
-const godot_vector2 GDAPI *godot_packed_vector2_array_ptr(const godot_packed_vector2_array *p_self) {
- const Vector<Vector2> *self = (const Vector<Vector2> *)p_self;
- return (const godot_vector2 *)self->ptr();
-}
-
-godot_vector2 GDAPI *godot_packed_vector2_array_ptrw(godot_packed_vector2_array *p_self) {
- Vector<Vector2> *self = (Vector<Vector2> *)p_self;
- return (godot_vector2 *)self->ptrw();
-}
-
-void GDAPI godot_packed_vector2_array_append(godot_packed_vector2_array *p_self, const godot_vector2 *p_data) {
- Vector<Vector2> *self = (Vector<Vector2> *)p_self;
- Vector2 &s = *(Vector2 *)p_data;
- self->push_back(s);
-}
-
-void GDAPI godot_packed_vector2_array_append_array(godot_packed_vector2_array *p_self, const godot_packed_vector2_array *p_array) {
- Vector<Vector2> *self = (Vector<Vector2> *)p_self;
- Vector<Vector2> *array = (Vector<Vector2> *)p_array;
- self->append_array(*array);
-}
-
-godot_error GDAPI godot_packed_vector2_array_insert(godot_packed_vector2_array *p_self, const godot_int p_idx, const godot_vector2 *p_data) {
- Vector<Vector2> *self = (Vector<Vector2> *)p_self;
- Vector2 &s = *(Vector2 *)p_data;
- return (godot_error)self->insert(p_idx, s);
-}
-
-godot_bool GDAPI godot_packed_vector2_array_has(godot_packed_vector2_array *p_self, const godot_vector2 *p_value) {
- Vector<Vector2> *self = (Vector<Vector2> *)p_self;
- Vector2 &v = *(Vector2 *)p_value;
- return (godot_bool)self->has(v);
-}
-
-void GDAPI godot_packed_vector2_array_sort(godot_packed_vector2_array *p_self) {
- Vector<Vector2> *self = (Vector<Vector2> *)p_self;
- self->sort();
-}
-
-void GDAPI godot_packed_vector2_array_invert(godot_packed_vector2_array *p_self) {
- Vector<Vector2> *self = (Vector<Vector2> *)p_self;
- self->invert();
-}
-
-void GDAPI godot_packed_vector2_array_push_back(godot_packed_vector2_array *p_self, const godot_vector2 *p_data) {
- Vector<Vector2> *self = (Vector<Vector2> *)p_self;
- Vector2 &s = *(Vector2 *)p_data;
- self->push_back(s);
-}
-
-void GDAPI godot_packed_vector2_array_remove(godot_packed_vector2_array *p_self, const godot_int p_idx) {
- Vector<Vector2> *self = (Vector<Vector2> *)p_self;
- self->remove(p_idx);
-}
-
-void GDAPI godot_packed_vector2_array_resize(godot_packed_vector2_array *p_self, const godot_int p_size) {
- Vector<Vector2> *self = (Vector<Vector2> *)p_self;
- self->resize(p_size);
-}
-
-void GDAPI godot_packed_vector2_array_set(godot_packed_vector2_array *p_self, const godot_int p_idx, const godot_vector2 *p_data) {
- Vector<Vector2> *self = (Vector<Vector2> *)p_self;
- Vector2 &s = *(Vector2 *)p_data;
- self->set(p_idx, s);
-}
-
-godot_vector2 GDAPI godot_packed_vector2_array_get(const godot_packed_vector2_array *p_self, const godot_int p_idx) {
- const Vector<Vector2> *self = (const Vector<Vector2> *)p_self;
- godot_vector2 v;
- Vector2 *s = (Vector2 *)&v;
- *s = self->get(p_idx);
- return v;
-}
-
-godot_int GDAPI godot_packed_vector2_array_size(const godot_packed_vector2_array *p_self) {
- const Vector<Vector2> *self = (const Vector<Vector2> *)p_self;
- return self->size();
-}
-
-godot_bool GDAPI godot_packed_vector2_array_empty(const godot_packed_vector2_array *p_self) {
- const Vector<Vector2> *self = (const Vector<Vector2> *)p_self;
- return self->empty();
+void GDAPI godot_packed_vector2_array_new(godot_packed_vector2_array *p_self) {
+ memnew_placement(p_self, PackedVector2Array);
}
void GDAPI godot_packed_vector2_array_destroy(godot_packed_vector2_array *p_self) {
- ((Vector<Vector2> *)p_self)->~Vector();
-}
-
-// vector3
-
-void GDAPI godot_packed_vector3_array_new(godot_packed_vector3_array *r_dest) {
- Vector<Vector3> *dest = (Vector<Vector3> *)r_dest;
- memnew_placement(dest, Vector<Vector3>);
+ ((PackedVector2Array *)p_self)->~PackedVector2Array();
}
-void GDAPI godot_packed_vector3_array_new_copy(godot_packed_vector3_array *r_dest, const godot_packed_vector3_array *p_src) {
- Vector<Vector3> *dest = (Vector<Vector3> *)r_dest;
- const Vector<Vector3> *src = (const Vector<Vector3> *)p_src;
- memnew_placement(dest, Vector<Vector3>(*src));
-}
-
-void GDAPI godot_packed_vector3_array_new_with_array(godot_packed_vector3_array *r_dest, const godot_array *p_a) {
- Vector<Vector3> *dest = (Vector<Vector3> *)r_dest;
- Array *a = (Array *)p_a;
- memnew_placement(dest, Vector<Vector3>);
-
- dest->resize(a->size());
- for (int i = 0; i < a->size(); i++) {
- dest->set(i, (*a)[i]);
- }
-}
-
-const godot_vector3 GDAPI *godot_packed_vector3_array_ptr(const godot_packed_vector3_array *p_self) {
- const Vector<Vector3> *self = (const Vector<Vector3> *)p_self;
- return (const godot_vector3 *)self->ptr();
-}
-
-godot_vector3 GDAPI *godot_packed_vector3_array_ptrw(godot_packed_vector3_array *p_self) {
- Vector<Vector3> *self = (Vector<Vector3> *)p_self;
- return (godot_vector3 *)self->ptrw();
-}
-
-void GDAPI godot_packed_vector3_array_append(godot_packed_vector3_array *p_self, const godot_vector3 *p_data) {
- Vector<Vector3> *self = (Vector<Vector3> *)p_self;
- Vector3 &s = *(Vector3 *)p_data;
- self->push_back(s);
-}
-
-void GDAPI godot_packed_vector3_array_append_array(godot_packed_vector3_array *p_self, const godot_packed_vector3_array *p_array) {
- Vector<Vector3> *self = (Vector<Vector3> *)p_self;
- Vector<Vector3> *array = (Vector<Vector3> *)p_array;
- self->append_array(*array);
-}
-
-godot_error GDAPI godot_packed_vector3_array_insert(godot_packed_vector3_array *p_self, const godot_int p_idx, const godot_vector3 *p_data) {
- Vector<Vector3> *self = (Vector<Vector3> *)p_self;
- Vector3 &s = *(Vector3 *)p_data;
- return (godot_error)self->insert(p_idx, s);
-}
-
-godot_bool GDAPI godot_packed_vector3_array_has(godot_packed_vector3_array *p_self, const godot_vector3 *p_value) {
- Vector<Vector3> *self = (Vector<Vector3> *)p_self;
- Vector3 &v = *(Vector3 *)p_value;
- return (godot_bool)self->has(v);
-}
-
-void GDAPI godot_packed_vector3_array_sort(godot_packed_vector3_array *p_self) {
- Vector<Vector3> *self = (Vector<Vector3> *)p_self;
- self->sort();
-}
-
-void GDAPI godot_packed_vector3_array_invert(godot_packed_vector3_array *p_self) {
- Vector<Vector3> *self = (Vector<Vector3> *)p_self;
- self->invert();
-}
-
-void GDAPI godot_packed_vector3_array_push_back(godot_packed_vector3_array *p_self, const godot_vector3 *p_data) {
- Vector<Vector3> *self = (Vector<Vector3> *)p_self;
- Vector3 &s = *(Vector3 *)p_data;
- self->push_back(s);
-}
+// vector2i
-void GDAPI godot_packed_vector3_array_remove(godot_packed_vector3_array *p_self, const godot_int p_idx) {
- Vector<Vector3> *self = (Vector<Vector3> *)p_self;
- self->remove(p_idx);
+void GDAPI godot_packed_vector2i_array_new(godot_packed_vector2i_array *p_self) {
+ memnew_placement(p_self, Vector<Vector2i>);
}
-void GDAPI godot_packed_vector3_array_resize(godot_packed_vector3_array *p_self, const godot_int p_size) {
- Vector<Vector3> *self = (Vector<Vector3> *)p_self;
- self->resize(p_size);
+void GDAPI godot_packed_vector2i_array_destroy(godot_packed_vector2i_array *p_self) {
+ ((Vector<Vector2i> *)p_self)->~Vector();
}
-void GDAPI godot_packed_vector3_array_set(godot_packed_vector3_array *p_self, const godot_int p_idx, const godot_vector3 *p_data) {
- Vector<Vector3> *self = (Vector<Vector3> *)p_self;
- Vector3 &s = *(Vector3 *)p_data;
- self->set(p_idx, s);
-}
-
-godot_vector3 GDAPI godot_packed_vector3_array_get(const godot_packed_vector3_array *p_self, const godot_int p_idx) {
- const Vector<Vector3> *self = (const Vector<Vector3> *)p_self;
- godot_vector3 v;
- Vector3 *s = (Vector3 *)&v;
- *s = self->get(p_idx);
- return v;
-}
-
-godot_int GDAPI godot_packed_vector3_array_size(const godot_packed_vector3_array *p_self) {
- const Vector<Vector3> *self = (const Vector<Vector3> *)p_self;
- return self->size();
-}
+// vector3
-godot_bool GDAPI godot_packed_vector3_array_empty(const godot_packed_vector3_array *p_self) {
- const Vector<Vector3> *self = (const Vector<Vector3> *)p_self;
- return self->empty();
+void GDAPI godot_packed_vector3_array_new(godot_packed_vector3_array *p_self) {
+ memnew_placement(p_self, PackedVector3Array);
}
void GDAPI godot_packed_vector3_array_destroy(godot_packed_vector3_array *p_self) {
- ((Vector<Vector3> *)p_self)->~Vector();
-}
-
-// color
-
-void GDAPI godot_packed_color_array_new(godot_packed_color_array *r_dest) {
- Vector<Color> *dest = (Vector<Color> *)r_dest;
- memnew_placement(dest, Vector<Color>);
-}
-
-void GDAPI godot_packed_color_array_new_copy(godot_packed_color_array *r_dest, const godot_packed_color_array *p_src) {
- Vector<Color> *dest = (Vector<Color> *)r_dest;
- const Vector<Color> *src = (const Vector<Color> *)p_src;
- memnew_placement(dest, Vector<Color>(*src));
-}
-
-void GDAPI godot_packed_color_array_new_with_array(godot_packed_color_array *r_dest, const godot_array *p_a) {
- Vector<Color> *dest = (Vector<Color> *)r_dest;
- Array *a = (Array *)p_a;
- memnew_placement(dest, Vector<Color>);
-
- dest->resize(a->size());
- for (int i = 0; i < a->size(); i++) {
- dest->set(i, (*a)[i]);
- }
-}
-
-const godot_color GDAPI *godot_packed_color_array_ptr(const godot_packed_color_array *p_self) {
- const Vector<Color> *self = (const Vector<Color> *)p_self;
- return (const godot_color *)self->ptr();
-}
-
-godot_color GDAPI *godot_packed_color_array_ptrw(godot_packed_color_array *p_self) {
- Vector<Color> *self = (Vector<Color> *)p_self;
- return (godot_color *)self->ptrw();
+ ((PackedVector3Array *)p_self)->~PackedVector3Array();
}
-void GDAPI godot_packed_color_array_append(godot_packed_color_array *p_self, const godot_color *p_data) {
- Vector<Color> *self = (Vector<Color> *)p_self;
- Color &s = *(Color *)p_data;
- self->push_back(s);
-}
-
-void GDAPI godot_packed_color_array_append_array(godot_packed_color_array *p_self, const godot_packed_color_array *p_array) {
- Vector<Color> *self = (Vector<Color> *)p_self;
- Vector<Color> *array = (Vector<Color> *)p_array;
- self->append_array(*array);
-}
-
-godot_error GDAPI godot_packed_color_array_insert(godot_packed_color_array *p_self, const godot_int p_idx, const godot_color *p_data) {
- Vector<Color> *self = (Vector<Color> *)p_self;
- Color &s = *(Color *)p_data;
- return (godot_error)self->insert(p_idx, s);
-}
+// vector3i
-godot_bool GDAPI godot_packed_color_array_has(godot_packed_color_array *p_self, const godot_color *p_value) {
- Vector<Color> *self = (Vector<Color> *)p_self;
- Color &c = *(Color *)p_value;
- return (godot_bool)self->has(c);
+void GDAPI godot_packed_vector3i_array_new(godot_packed_vector3i_array *p_self) {
+ memnew_placement(p_self, Vector<Vector3i>);
}
-void GDAPI godot_packed_color_array_sort(godot_packed_color_array *p_self) {
- Vector<Color> *self = (Vector<Color> *)p_self;
- self->sort();
+void GDAPI godot_packed_vector3i_array_destroy(godot_packed_vector3i_array *p_self) {
+ ((Vector<Vector3i> *)p_self)->~Vector();
}
-void GDAPI godot_packed_color_array_invert(godot_packed_color_array *p_self) {
- Vector<Color> *self = (Vector<Color> *)p_self;
- self->invert();
-}
-
-void GDAPI godot_packed_color_array_push_back(godot_packed_color_array *p_self, const godot_color *p_data) {
- Vector<Color> *self = (Vector<Color> *)p_self;
- Color &s = *(Color *)p_data;
- self->push_back(s);
-}
-
-void GDAPI godot_packed_color_array_remove(godot_packed_color_array *p_self, const godot_int p_idx) {
- Vector<Color> *self = (Vector<Color> *)p_self;
- self->remove(p_idx);
-}
-
-void GDAPI godot_packed_color_array_resize(godot_packed_color_array *p_self, const godot_int p_size) {
- Vector<Color> *self = (Vector<Color> *)p_self;
- self->resize(p_size);
-}
-
-void GDAPI godot_packed_color_array_set(godot_packed_color_array *p_self, const godot_int p_idx, const godot_color *p_data) {
- Vector<Color> *self = (Vector<Color> *)p_self;
- Color &s = *(Color *)p_data;
- self->set(p_idx, s);
-}
-
-godot_color GDAPI godot_packed_color_array_get(const godot_packed_color_array *p_self, const godot_int p_idx) {
- const Vector<Color> *self = (const Vector<Color> *)p_self;
- godot_color v;
- Color *s = (Color *)&v;
- *s = self->get(p_idx);
- return v;
-}
-
-godot_int GDAPI godot_packed_color_array_size(const godot_packed_color_array *p_self) {
- const Vector<Color> *self = (const Vector<Color> *)p_self;
- return self->size();
-}
+// color
-godot_bool GDAPI godot_packed_color_array_empty(const godot_packed_color_array *p_self) {
- const Vector<Color> *self = (const Vector<Color> *)p_self;
- return self->empty();
+void GDAPI godot_packed_color_array_new(godot_packed_color_array *p_self) {
+ memnew_placement(p_self, PackedColorArray);
}
void GDAPI godot_packed_color_array_destroy(godot_packed_color_array *p_self) {
- ((Vector<Color> *)p_self)->~Vector();
+ ((PackedColorArray *)p_self)->~PackedColorArray();
}
#ifdef __cplusplus
diff --git a/modules/gdnative/gdnative/plane.cpp b/modules/gdnative/gdnative/plane.cpp
index d4ed8d00f4..61d5e09fad 100644
--- a/modules/gdnative/gdnative/plane.cpp
+++ b/modules/gdnative/gdnative/plane.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,139 +31,15 @@
#include "gdnative/plane.h"
#include "core/math/plane.h"
-#include "core/variant.h"
+
+static_assert(sizeof(godot_plane) == sizeof(Plane), "Plane size mismatch");
#ifdef __cplusplus
extern "C" {
#endif
-static_assert(sizeof(godot_plane) == sizeof(Plane), "Plane size mismatch");
-
-void GDAPI godot_plane_new_with_reals(godot_plane *r_dest, const godot_real p_a, const godot_real p_b, const godot_real p_c, const godot_real p_d) {
- Plane *dest = (Plane *)r_dest;
- *dest = Plane(p_a, p_b, p_c, p_d);
-}
-
-void GDAPI godot_plane_new_with_vectors(godot_plane *r_dest, const godot_vector3 *p_v1, const godot_vector3 *p_v2, const godot_vector3 *p_v3) {
- const Vector3 *v1 = (const Vector3 *)p_v1;
- const Vector3 *v2 = (const Vector3 *)p_v2;
- const Vector3 *v3 = (const Vector3 *)p_v3;
- Plane *dest = (Plane *)r_dest;
- *dest = Plane(*v1, *v2, *v3);
-}
-
-void GDAPI godot_plane_new_with_normal(godot_plane *r_dest, const godot_vector3 *p_normal, const godot_real p_d) {
- const Vector3 *normal = (const Vector3 *)p_normal;
- Plane *dest = (Plane *)r_dest;
- *dest = Plane(*normal, p_d);
-}
-
-godot_string GDAPI godot_plane_as_string(const godot_plane *p_self) {
- godot_string ret;
- const Plane *self = (const Plane *)p_self;
- memnew_placement(&ret, String(*self));
- return ret;
-}
-
-godot_plane GDAPI godot_plane_normalized(const godot_plane *p_self) {
- godot_plane dest;
- const Plane *self = (const Plane *)p_self;
- *((Plane *)&dest) = self->normalized();
- return dest;
-}
-
-godot_vector3 GDAPI godot_plane_center(const godot_plane *p_self) {
- godot_vector3 dest;
- const Plane *self = (const Plane *)p_self;
- *((Vector3 *)&dest) = self->center();
- return dest;
-}
-
-godot_bool GDAPI godot_plane_is_point_over(const godot_plane *p_self, const godot_vector3 *p_point) {
- const Plane *self = (const Plane *)p_self;
- const Vector3 *point = (const Vector3 *)p_point;
- return self->is_point_over(*point);
-}
-
-godot_real GDAPI godot_plane_distance_to(const godot_plane *p_self, const godot_vector3 *p_point) {
- const Plane *self = (const Plane *)p_self;
- const Vector3 *point = (const Vector3 *)p_point;
- return self->distance_to(*point);
-}
-
-godot_bool GDAPI godot_plane_has_point(const godot_plane *p_self, const godot_vector3 *p_point, const godot_real p_epsilon) {
- const Plane *self = (const Plane *)p_self;
- const Vector3 *point = (const Vector3 *)p_point;
- return self->has_point(*point, p_epsilon);
-}
-
-godot_vector3 GDAPI godot_plane_project(const godot_plane *p_self, const godot_vector3 *p_point) {
- godot_vector3 dest;
- const Plane *self = (const Plane *)p_self;
- const Vector3 *point = (const Vector3 *)p_point;
- *((Vector3 *)&dest) = self->project(*point);
- return dest;
-}
-
-godot_bool GDAPI godot_plane_intersect_3(const godot_plane *p_self, godot_vector3 *r_dest, const godot_plane *p_b, const godot_plane *p_c) {
- const Plane *self = (const Plane *)p_self;
- const Plane *b = (const Plane *)p_b;
- const Plane *c = (const Plane *)p_c;
- Vector3 *dest = (Vector3 *)r_dest;
- return self->intersect_3(*b, *c, dest);
-}
-
-godot_bool GDAPI godot_plane_intersects_ray(const godot_plane *p_self, godot_vector3 *r_dest, const godot_vector3 *p_from, const godot_vector3 *p_dir) {
- const Plane *self = (const Plane *)p_self;
- const Vector3 *from = (const Vector3 *)p_from;
- const Vector3 *dir = (const Vector3 *)p_dir;
- Vector3 *dest = (Vector3 *)r_dest;
- return self->intersects_ray(*from, *dir, dest);
-}
-
-godot_bool GDAPI godot_plane_intersects_segment(const godot_plane *p_self, godot_vector3 *r_dest, const godot_vector3 *p_begin, const godot_vector3 *p_end) {
- const Plane *self = (const Plane *)p_self;
- const Vector3 *begin = (const Vector3 *)p_begin;
- const Vector3 *end = (const Vector3 *)p_end;
- Vector3 *dest = (Vector3 *)r_dest;
- return self->intersects_segment(*begin, *end, dest);
-}
-
-godot_plane GDAPI godot_plane_operator_neg(const godot_plane *p_self) {
- godot_plane raw_dest;
- Plane *dest = (Plane *)&raw_dest;
- const Plane *self = (const Plane *)p_self;
- *dest = -(*self);
- return raw_dest;
-}
-
-godot_bool GDAPI godot_plane_operator_equal(const godot_plane *p_self, const godot_plane *p_b) {
- const Plane *self = (const Plane *)p_self;
- const Plane *b = (const Plane *)p_b;
- return *self == *b;
-}
-
-void GDAPI godot_plane_set_normal(godot_plane *p_self, const godot_vector3 *p_normal) {
- Plane *self = (Plane *)p_self;
- const Vector3 *normal = (const Vector3 *)p_normal;
- self->set_normal(*normal);
-}
-
-godot_vector3 GDAPI godot_plane_get_normal(const godot_plane *p_self) {
- const Plane *self = (const Plane *)p_self;
- const Vector3 normal = self->get_normal();
- godot_vector3 *v3 = (godot_vector3 *)&normal;
- return *v3;
-}
-
-godot_real GDAPI godot_plane_get_d(const godot_plane *p_self) {
- const Plane *self = (const Plane *)p_self;
- return self->d;
-}
-
-void GDAPI godot_plane_set_d(godot_plane *p_self, const godot_real p_d) {
- Plane *self = (Plane *)p_self;
- self->d = p_d;
+void GDAPI godot_plane_new(godot_plane *p_self) {
+ memnew_placement(p_self, Plane);
}
#ifdef __cplusplus
diff --git a/modules/gdnative/gdnative/quat.cpp b/modules/gdnative/gdnative/quat.cpp
index de6308ad2a..87f1d7d8e5 100644
--- a/modules/gdnative/gdnative/quat.cpp
+++ b/modules/gdnative/gdnative/quat.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,205 +31,15 @@
#include "gdnative/quat.h"
#include "core/math/quat.h"
-#include "core/variant.h"
+
+static_assert(sizeof(godot_quat) == sizeof(Quat), "Quat size mismatch");
#ifdef __cplusplus
extern "C" {
#endif
-static_assert(sizeof(godot_quat) == sizeof(Quat), "Quat size mismatch");
-
-void GDAPI godot_quat_new(godot_quat *r_dest, const godot_real p_x, const godot_real p_y, const godot_real p_z, const godot_real p_w) {
- Quat *dest = (Quat *)r_dest;
- *dest = Quat(p_x, p_y, p_z, p_w);
-}
-
-void GDAPI godot_quat_new_with_axis_angle(godot_quat *r_dest, const godot_vector3 *p_axis, const godot_real p_angle) {
- const Vector3 *axis = (const Vector3 *)p_axis;
- Quat *dest = (Quat *)r_dest;
- *dest = Quat(*axis, p_angle);
-}
-
-void GDAPI godot_quat_new_with_basis(godot_quat *r_dest, const godot_basis *p_basis) {
- const Basis *basis = (const Basis *)p_basis;
- Quat *dest = (Quat *)r_dest;
- *dest = Quat(*basis);
-}
-
-void GDAPI godot_quat_new_with_euler(godot_quat *r_dest, const godot_vector3 *p_euler) {
- const Vector3 *euler = (const Vector3 *)p_euler;
- Quat *dest = (Quat *)r_dest;
- *dest = Quat(*euler);
-}
-
-godot_real GDAPI godot_quat_get_x(const godot_quat *p_self) {
- const Quat *self = (const Quat *)p_self;
- return self->x;
-}
-
-void GDAPI godot_quat_set_x(godot_quat *p_self, const godot_real val) {
- Quat *self = (Quat *)p_self;
- self->x = val;
-}
-
-godot_real GDAPI godot_quat_get_y(const godot_quat *p_self) {
- const Quat *self = (const Quat *)p_self;
- return self->y;
-}
-
-void GDAPI godot_quat_set_y(godot_quat *p_self, const godot_real val) {
- Quat *self = (Quat *)p_self;
- self->y = val;
-}
-
-godot_real GDAPI godot_quat_get_z(const godot_quat *p_self) {
- const Quat *self = (const Quat *)p_self;
- return self->z;
-}
-
-void GDAPI godot_quat_set_z(godot_quat *p_self, const godot_real val) {
- Quat *self = (Quat *)p_self;
- self->z = val;
-}
-
-godot_real GDAPI godot_quat_get_w(const godot_quat *p_self) {
- const Quat *self = (const Quat *)p_self;
- return self->w;
-}
-
-void GDAPI godot_quat_set_w(godot_quat *p_self, const godot_real val) {
- Quat *self = (Quat *)p_self;
- self->w = val;
-}
-
-godot_string GDAPI godot_quat_as_string(const godot_quat *p_self) {
- godot_string ret;
- const Quat *self = (const Quat *)p_self;
- memnew_placement(&ret, String(*self));
- return ret;
-}
-
-godot_real GDAPI godot_quat_length(const godot_quat *p_self) {
- const Quat *self = (const Quat *)p_self;
- return self->length();
-}
-
-godot_real GDAPI godot_quat_length_squared(const godot_quat *p_self) {
- const Quat *self = (const Quat *)p_self;
- return self->length_squared();
-}
-
-godot_quat GDAPI godot_quat_normalized(const godot_quat *p_self) {
- godot_quat dest;
- const Quat *self = (const Quat *)p_self;
- *((Quat *)&dest) = self->normalized();
- return dest;
-}
-
-godot_bool GDAPI godot_quat_is_normalized(const godot_quat *p_self) {
- const Quat *self = (const Quat *)p_self;
- return self->is_normalized();
-}
-
-godot_quat GDAPI godot_quat_inverse(const godot_quat *p_self) {
- godot_quat dest;
- const Quat *self = (const Quat *)p_self;
- *((Quat *)&dest) = self->inverse();
- return dest;
-}
-
-godot_real GDAPI godot_quat_dot(const godot_quat *p_self, const godot_quat *p_b) {
- const Quat *self = (const Quat *)p_self;
- const Quat *b = (const Quat *)p_b;
- return self->dot(*b);
-}
-
-godot_vector3 GDAPI godot_quat_xform(const godot_quat *p_self, const godot_vector3 *p_v) {
- godot_vector3 dest;
- const Quat *self = (const Quat *)p_self;
- const Vector3 *v = (const Vector3 *)p_v;
- *((Vector3 *)&dest) = self->xform(*v);
- return dest;
-}
-
-godot_quat GDAPI godot_quat_slerp(const godot_quat *p_self, const godot_quat *p_b, const godot_real p_t) {
- godot_quat dest;
- const Quat *self = (const Quat *)p_self;
- const Quat *b = (const Quat *)p_b;
- *((Quat *)&dest) = self->slerp(*b, p_t);
- return dest;
-}
-
-godot_quat GDAPI godot_quat_slerpni(const godot_quat *p_self, const godot_quat *p_b, const godot_real p_t) {
- godot_quat dest;
- const Quat *self = (const Quat *)p_self;
- const Quat *b = (const Quat *)p_b;
- *((Quat *)&dest) = self->slerpni(*b, p_t);
- return dest;
-}
-
-godot_quat GDAPI godot_quat_cubic_slerp(const godot_quat *p_self, const godot_quat *p_b, const godot_quat *p_pre_a, const godot_quat *p_post_b, const godot_real p_t) {
- godot_quat dest;
- const Quat *self = (const Quat *)p_self;
- const Quat *b = (const Quat *)p_b;
- const Quat *pre_a = (const Quat *)p_pre_a;
- const Quat *post_b = (const Quat *)p_post_b;
- *((Quat *)&dest) = self->cubic_slerp(*b, *pre_a, *post_b, p_t);
- return dest;
-}
-
-godot_quat GDAPI godot_quat_operator_multiply(const godot_quat *p_self, const godot_real p_b) {
- godot_quat raw_dest;
- Quat *dest = (Quat *)&raw_dest;
- const Quat *self = (const Quat *)p_self;
- *dest = *self * p_b;
- return raw_dest;
-}
-
-godot_quat GDAPI godot_quat_operator_add(const godot_quat *p_self, const godot_quat *p_b) {
- godot_quat raw_dest;
- Quat *dest = (Quat *)&raw_dest;
- const Quat *self = (const Quat *)p_self;
- const Quat *b = (const Quat *)p_b;
- *dest = *self + *b;
- return raw_dest;
-}
-
-godot_quat GDAPI godot_quat_operator_subtract(const godot_quat *p_self, const godot_quat *p_b) {
- godot_quat raw_dest;
- Quat *dest = (Quat *)&raw_dest;
- const Quat *self = (const Quat *)p_self;
- const Quat *b = (const Quat *)p_b;
- *dest = *self - *b;
- return raw_dest;
-}
-
-godot_quat GDAPI godot_quat_operator_divide(const godot_quat *p_self, const godot_real p_b) {
- godot_quat raw_dest;
- Quat *dest = (Quat *)&raw_dest;
- const Quat *self = (const Quat *)p_self;
- *dest = *self / p_b;
- return raw_dest;
-}
-
-godot_bool GDAPI godot_quat_operator_equal(const godot_quat *p_self, const godot_quat *p_b) {
- const Quat *self = (const Quat *)p_self;
- const Quat *b = (const Quat *)p_b;
- return *self == *b;
-}
-
-godot_quat GDAPI godot_quat_operator_neg(const godot_quat *p_self) {
- godot_quat raw_dest;
- Quat *dest = (Quat *)&raw_dest;
- const Quat *self = (const Quat *)p_self;
- *dest = -(*self);
- return raw_dest;
-}
-
-void GDAPI godot_quat_set_axis_angle(godot_quat *p_self, const godot_vector3 *p_axis, const godot_real p_angle) {
- Quat *self = (Quat *)p_self;
- const Vector3 *axis = (const Vector3 *)p_axis;
- self->set_axis_angle(*axis, p_angle);
+void GDAPI godot_quat_new(godot_quat *p_self) {
+ memnew_placement(p_self, Quat);
}
#ifdef __cplusplus
diff --git a/modules/gdnative/gdnative/rect2.cpp b/modules/gdnative/gdnative/rect2.cpp
index 516f4d75ce..086592ec22 100644
--- a/modules/gdnative/gdnative/rect2.cpp
+++ b/modules/gdnative/gdnative/rect2.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,300 +30,21 @@
#include "gdnative/rect2.h"
-#include "core/math/transform_2d.h"
-#include "core/variant.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include "core/math/rect2.h"
static_assert(sizeof(godot_rect2) == sizeof(Rect2), "Rect2 size mismatch");
static_assert(sizeof(godot_rect2i) == sizeof(Rect2i), "Rect2i size mismatch");
-// Rect2
-
-void GDAPI godot_rect2_new_with_position_and_size(godot_rect2 *r_dest, const godot_vector2 *p_pos, const godot_vector2 *p_size) {
- const Vector2 *position = (const Vector2 *)p_pos;
- const Vector2 *size = (const Vector2 *)p_size;
- Rect2 *dest = (Rect2 *)r_dest;
- *dest = Rect2(*position, *size);
-}
-
-void GDAPI godot_rect2_new(godot_rect2 *r_dest, const godot_real p_x, const godot_real p_y, const godot_real p_width, const godot_real p_height) {
- Rect2 *dest = (Rect2 *)r_dest;
- *dest = Rect2(p_x, p_y, p_width, p_height);
-}
-
-godot_string GDAPI godot_rect2_as_string(const godot_rect2 *p_self) {
- godot_string ret;
- const Rect2 *self = (const Rect2 *)p_self;
- memnew_placement(&ret, String(*self));
- return ret;
-}
-
-godot_rect2i GDAPI godot_rect2_as_rect2i(const godot_rect2 *p_self) {
- godot_rect2i dest;
- const Rect2 *self = (const Rect2 *)p_self;
- *((Rect2i *)&dest) = Rect2i(*self);
- return dest;
-}
-
-godot_real GDAPI godot_rect2_get_area(const godot_rect2 *p_self) {
- const Rect2 *self = (const Rect2 *)p_self;
- return self->get_area();
-}
-
-godot_bool GDAPI godot_rect2_intersects(const godot_rect2 *p_self, const godot_rect2 *p_b) {
- const Rect2 *self = (const Rect2 *)p_self;
- const Rect2 *b = (const Rect2 *)p_b;
- return self->intersects(*b);
-}
-
-godot_bool GDAPI godot_rect2_encloses(const godot_rect2 *p_self, const godot_rect2 *p_b) {
- const Rect2 *self = (const Rect2 *)p_self;
- const Rect2 *b = (const Rect2 *)p_b;
- return self->encloses(*b);
-}
-
-godot_bool GDAPI godot_rect2_has_no_area(const godot_rect2 *p_self) {
- const Rect2 *self = (const Rect2 *)p_self;
- return self->has_no_area();
-}
-
-godot_rect2 GDAPI godot_rect2_clip(const godot_rect2 *p_self, const godot_rect2 *p_b) {
- godot_rect2 dest;
- const Rect2 *self = (const Rect2 *)p_self;
- const Rect2 *b = (const Rect2 *)p_b;
- *((Rect2 *)&dest) = self->clip(*b);
- return dest;
-}
-
-godot_rect2 GDAPI godot_rect2_merge(const godot_rect2 *p_self, const godot_rect2 *p_b) {
- godot_rect2 dest;
- const Rect2 *self = (const Rect2 *)p_self;
- const Rect2 *b = (const Rect2 *)p_b;
- *((Rect2 *)&dest) = self->merge(*b);
- return dest;
-}
-
-godot_bool GDAPI godot_rect2_has_point(const godot_rect2 *p_self, const godot_vector2 *p_point) {
- const Rect2 *self = (const Rect2 *)p_self;
- const Vector2 *point = (const Vector2 *)p_point;
- return self->has_point(*point);
-}
-
-godot_rect2 GDAPI godot_rect2_grow(const godot_rect2 *p_self, const godot_real p_by) {
- godot_rect2 dest;
- const Rect2 *self = (const Rect2 *)p_self;
-
- *((Rect2 *)&dest) = self->grow(p_by);
- return dest;
-}
-
-godot_rect2 GDAPI godot_rect2_grow_individual(const godot_rect2 *p_self, const godot_real p_left, const godot_real p_top, const godot_real p_right, const godot_real p_bottom) {
- godot_rect2 dest;
- const Rect2 *self = (const Rect2 *)p_self;
- *((Rect2 *)&dest) = self->grow_individual(p_left, p_top, p_right, p_bottom);
- return dest;
-}
-
-godot_rect2 GDAPI godot_rect2_grow_margin(const godot_rect2 *p_self, const godot_int p_margin, const godot_real p_by) {
- godot_rect2 dest;
- const Rect2 *self = (const Rect2 *)p_self;
- *((Rect2 *)&dest) = self->grow_margin((Margin)p_margin, p_by);
- return dest;
-}
-
-godot_rect2 GDAPI godot_rect2_abs(const godot_rect2 *p_self) {
- godot_rect2 dest;
- const Rect2 *self = (const Rect2 *)p_self;
- *((Rect2 *)&dest) = self->abs();
- return dest;
-}
-
-godot_rect2 GDAPI godot_rect2_expand(const godot_rect2 *p_self, const godot_vector2 *p_to) {
- godot_rect2 dest;
- const Rect2 *self = (const Rect2 *)p_self;
- const Vector2 *to = (const Vector2 *)p_to;
- *((Rect2 *)&dest) = self->expand(*to);
- return dest;
-}
-
-godot_bool GDAPI godot_rect2_operator_equal(const godot_rect2 *p_self, const godot_rect2 *p_b) {
- const Rect2 *self = (const Rect2 *)p_self;
- const Rect2 *b = (const Rect2 *)p_b;
- return *self == *b;
-}
-
-godot_vector2 GDAPI godot_rect2_get_position(const godot_rect2 *p_self) {
- godot_vector2 dest;
- Vector2 *d = (Vector2 *)&dest;
- const Rect2 *self = (const Rect2 *)p_self;
- *d = self->get_position();
- return dest;
-}
-
-godot_vector2 GDAPI godot_rect2_get_size(const godot_rect2 *p_self) {
- godot_vector2 dest;
- Vector2 *d = (Vector2 *)&dest;
- const Rect2 *self = (const Rect2 *)p_self;
- *d = self->get_size();
- return dest;
-}
-
-void GDAPI godot_rect2_set_position(godot_rect2 *p_self, const godot_vector2 *p_pos) {
- Rect2 *self = (Rect2 *)p_self;
- const Vector2 *position = (const Vector2 *)p_pos;
- self->set_position(*position);
-}
-
-void GDAPI godot_rect2_set_size(godot_rect2 *p_self, const godot_vector2 *p_size) {
- Rect2 *self = (Rect2 *)p_self;
- const Vector2 *size = (const Vector2 *)p_size;
- self->set_size(*size);
-}
-
-// Rect2i
-
-void GDAPI godot_rect2i_new_with_position_and_size(godot_rect2i *r_dest, const godot_vector2i *p_pos, const godot_vector2i *p_size) {
- const Vector2i *position = (const Vector2i *)p_pos;
- const Vector2i *size = (const Vector2i *)p_size;
- Rect2i *dest = (Rect2i *)r_dest;
- *dest = Rect2i(*position, *size);
-}
-
-void GDAPI godot_rect2i_new(godot_rect2i *r_dest, const godot_int p_x, const godot_int p_y, const godot_int p_width, const godot_int p_height) {
- Rect2i *dest = (Rect2i *)r_dest;
- *dest = Rect2i(p_x, p_y, p_width, p_height);
-}
-
-godot_string GDAPI godot_rect2i_as_string(const godot_rect2i *p_self) {
- godot_string ret;
- const Rect2i *self = (const Rect2i *)p_self;
- memnew_placement(&ret, String(*self));
- return ret;
-}
-
-godot_rect2 GDAPI godot_rect2i_as_rect2(const godot_rect2i *p_self) {
- godot_rect2 dest;
- const Rect2i *self = (const Rect2i *)p_self;
- *((Rect2 *)&dest) = Rect2(*self);
- return dest;
-}
-
-godot_int GDAPI godot_rect2i_get_area(const godot_rect2i *p_self) {
- const Rect2i *self = (const Rect2i *)p_self;
- return self->get_area();
-}
-
-godot_bool GDAPI godot_rect2i_intersects(const godot_rect2i *p_self, const godot_rect2i *p_b) {
- const Rect2i *self = (const Rect2i *)p_self;
- const Rect2i *b = (const Rect2i *)p_b;
- return self->intersects(*b);
-}
-
-godot_bool GDAPI godot_rect2i_encloses(const godot_rect2i *p_self, const godot_rect2i *p_b) {
- const Rect2i *self = (const Rect2i *)p_self;
- const Rect2i *b = (const Rect2i *)p_b;
- return self->encloses(*b);
-}
-
-godot_bool GDAPI godot_rect2i_has_no_area(const godot_rect2i *p_self) {
- const Rect2i *self = (const Rect2i *)p_self;
- return self->has_no_area();
-}
-
-godot_rect2i GDAPI godot_rect2i_clip(const godot_rect2i *p_self, const godot_rect2i *p_b) {
- godot_rect2i dest;
- const Rect2i *self = (const Rect2i *)p_self;
- const Rect2i *b = (const Rect2i *)p_b;
- *((Rect2i *)&dest) = self->clip(*b);
- return dest;
-}
-
-godot_rect2i GDAPI godot_rect2i_merge(const godot_rect2i *p_self, const godot_rect2i *p_b) {
- godot_rect2i dest;
- const Rect2i *self = (const Rect2i *)p_self;
- const Rect2i *b = (const Rect2i *)p_b;
- *((Rect2i *)&dest) = self->merge(*b);
- return dest;
-}
-
-godot_bool GDAPI godot_rect2i_has_point(const godot_rect2i *p_self, const godot_vector2i *p_point) {
- const Rect2i *self = (const Rect2i *)p_self;
- const Vector2i *point = (const Vector2i *)p_point;
- return self->has_point(*point);
-}
-
-godot_rect2i GDAPI godot_rect2i_grow(const godot_rect2i *p_self, const godot_int p_by) {
- godot_rect2i dest;
- const Rect2i *self = (const Rect2i *)p_self;
-
- *((Rect2i *)&dest) = self->grow(p_by);
- return dest;
-}
-
-godot_rect2i GDAPI godot_rect2i_grow_individual(const godot_rect2i *p_self, const godot_int p_left, const godot_int p_top, const godot_int p_right, const godot_int p_bottom) {
- godot_rect2i dest;
- const Rect2i *self = (const Rect2i *)p_self;
- *((Rect2i *)&dest) = self->grow_individual(p_left, p_top, p_right, p_bottom);
- return dest;
-}
-
-godot_rect2i GDAPI godot_rect2i_grow_margin(const godot_rect2i *p_self, const godot_int p_margin, const godot_int p_by) {
- godot_rect2i dest;
- const Rect2i *self = (const Rect2i *)p_self;
- *((Rect2i *)&dest) = self->grow_margin((Margin)p_margin, p_by);
- return dest;
-}
-
-godot_rect2i GDAPI godot_rect2i_abs(const godot_rect2i *p_self) {
- godot_rect2i dest;
- const Rect2i *self = (const Rect2i *)p_self;
- *((Rect2i *)&dest) = self->abs();
- return dest;
-}
-
-godot_rect2i GDAPI godot_rect2i_expand(const godot_rect2i *p_self, const godot_vector2i *p_to) {
- godot_rect2i dest;
- const Rect2i *self = (const Rect2i *)p_self;
- const Vector2i *to = (const Vector2i *)p_to;
- *((Rect2i *)&dest) = self->expand(*to);
- return dest;
-}
-
-godot_bool GDAPI godot_rect2i_operator_equal(const godot_rect2i *p_self, const godot_rect2i *p_b) {
- const Rect2i *self = (const Rect2i *)p_self;
- const Rect2i *b = (const Rect2i *)p_b;
- return *self == *b;
-}
-
-godot_vector2i GDAPI godot_rect2i_get_position(const godot_rect2i *p_self) {
- godot_vector2i dest;
- Vector2i *d = (Vector2i *)&dest;
- const Rect2i *self = (const Rect2i *)p_self;
- *d = self->get_position();
- return dest;
-}
-
-godot_vector2i GDAPI godot_rect2i_get_size(const godot_rect2i *p_self) {
- godot_vector2i dest;
- Vector2i *d = (Vector2i *)&dest;
- const Rect2i *self = (const Rect2i *)p_self;
- *d = self->get_size();
- return dest;
-}
+#ifdef __cplusplus
+extern "C" {
+#endif
-void GDAPI godot_rect2i_set_position(godot_rect2i *p_self, const godot_vector2i *p_pos) {
- Rect2i *self = (Rect2i *)p_self;
- const Vector2i *position = (const Vector2i *)p_pos;
- self->set_position(*position);
+void GDAPI godot_rect2_new(godot_rect2 *p_self) {
+ memnew_placement(p_self, Rect2);
}
-void GDAPI godot_rect2i_set_size(godot_rect2i *p_self, const godot_vector2i *p_size) {
- Rect2i *self = (Rect2i *)p_self;
- const Vector2i *size = (const Vector2i *)p_size;
- self->set_size(*size);
+void GDAPI godot_rect2i_new(godot_rect2i *p_self) {
+ memnew_placement(p_self, Rect2i);
}
#ifdef __cplusplus
diff --git a/modules/gdnative/gdnative/rid.cpp b/modules/gdnative/gdnative/rid.cpp
index d7a63f33a7..5cab9a21ed 100644
--- a/modules/gdnative/gdnative/rid.cpp
+++ b/modules/gdnative/gdnative/rid.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,45 +30,17 @@
#include "gdnative/rid.h"
-#include "core/resource.h"
-#include "core/rid.h"
-#include "core/variant.h"
+#include "core/os/memory.h"
+#include "core/templates/rid.h"
+
+static_assert(sizeof(godot_rid) == sizeof(RID), "RID size mismatch");
#ifdef __cplusplus
extern "C" {
#endif
-static_assert(sizeof(godot_rid) == sizeof(RID), "RID size mismatch");
-
-void GDAPI godot_rid_new(godot_rid *r_dest) {
- RID *dest = (RID *)r_dest;
- memnew_placement(dest, RID);
-}
-
-godot_int GDAPI godot_rid_get_id(const godot_rid *p_self) {
- const RID *self = (const RID *)p_self;
- return self->get_id();
-}
-
-void GDAPI godot_rid_new_with_resource(godot_rid *r_dest, const godot_object *p_from) {
- const Resource *res_from = Object::cast_to<Resource>((Object *)p_from);
- godot_rid_new(r_dest);
- if (res_from) {
- RID *dest = (RID *)r_dest;
- *dest = RID(res_from->get_rid());
- }
-}
-
-godot_bool GDAPI godot_rid_operator_equal(const godot_rid *p_self, const godot_rid *p_b) {
- const RID *self = (const RID *)p_self;
- const RID *b = (const RID *)p_b;
- return *self == *b;
-}
-
-godot_bool GDAPI godot_rid_operator_less(const godot_rid *p_self, const godot_rid *p_b) {
- const RID *self = (const RID *)p_self;
- const RID *b = (const RID *)p_b;
- return *self < *b;
+void GDAPI godot_rid_new(godot_rid *p_self) {
+ memnew_placement(p_self, RID);
}
#ifdef __cplusplus
diff --git a/modules/gdnative/gdnative/signal.cpp b/modules/gdnative/gdnative/signal.cpp
new file mode 100644
index 0000000000..bcb4c93b62
--- /dev/null
+++ b/modules/gdnative/gdnative/signal.cpp
@@ -0,0 +1,53 @@
+/*************************************************************************/
+/* signal.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gdnative/signal.h"
+
+#include "core/variant/callable.h"
+#include "core/variant/variant.h"
+
+static_assert(sizeof(godot_signal) == sizeof(Signal), "Signal size mismatch");
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void GDAPI godot_signal_new(godot_signal *p_self) {
+ memnew_placement(p_self, Signal);
+}
+
+void GDAPI godot_signal_destroy(godot_signal *p_self) {
+ Signal *self = (Signal *)p_self;
+ self->~Signal();
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/gdnative/gdnative/string.cpp b/modules/gdnative/gdnative/string.cpp
index 1fa19f4ff5..19d95f2048 100644
--- a/modules/gdnative/gdnative/string.cpp
+++ b/modules/gdnative/gdnative/string.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,57 +30,15 @@
#include "gdnative/string.h"
-#include "core/string_name.h"
-#include "core/ustring.h"
-#include "core/variant.h"
+#include "core/string/ustring.h"
-#include <string.h>
+static_assert(sizeof(godot_string) == sizeof(String), "String size mismatch");
+static_assert(sizeof(godot_char_type) == sizeof(char32_t), "char32_t size mismatch");
#ifdef __cplusplus
extern "C" {
#endif
-static_assert(sizeof(godot_char16_string) == sizeof(Char16String), "Char16String size mismatch");
-static_assert(sizeof(godot_char_string) == sizeof(CharString), "CharString size mismatch");
-static_assert(sizeof(godot_string) == sizeof(String), "String size mismatch");
-static_assert(sizeof(godot_char_type) == sizeof(char32_t), "char32_t size mismatch");
-
-godot_int GDAPI godot_char_string_length(const godot_char_string *p_cs) {
- const CharString *cs = (const CharString *)p_cs;
-
- return cs->length();
-}
-
-const char GDAPI *godot_char_string_get_data(const godot_char_string *p_cs) {
- const CharString *cs = (const CharString *)p_cs;
-
- return cs->get_data();
-}
-
-void GDAPI godot_char_string_destroy(godot_char_string *p_cs) {
- CharString *cs = (CharString *)p_cs;
-
- cs->~CharString();
-}
-
-godot_int GDAPI godot_char16_string_length(const godot_char16_string *p_cs) {
- const Char16String *cs = (const Char16String *)p_cs;
-
- return cs->length();
-}
-
-const char16_t GDAPI *godot_char16_string_get_data(const godot_char16_string *p_cs) {
- const Char16String *cs = (const Char16String *)p_cs;
-
- return cs->get_data();
-}
-
-void GDAPI godot_char16_string_destroy(godot_char16_string *p_cs) {
- Char16String *cs = (Char16String *)p_cs;
-
- cs->~Char16String();
-}
-
void GDAPI godot_string_new(godot_string *r_dest) {
String *dest = (String *)r_dest;
memnew_placement(dest, String);
@@ -167,1206 +125,11 @@ void GDAPI godot_string_new_with_wide_chars_and_len(godot_string *r_dest, const
}
}
-const godot_char_type GDAPI *godot_string_operator_index(godot_string *p_self, const godot_int p_idx) {
- String *self = (String *)p_self;
- return &(self->operator[](p_idx));
-}
-
-godot_char_type GDAPI godot_string_operator_index_const(const godot_string *p_self, const godot_int p_idx) {
- const String *self = (const String *)p_self;
- return self->operator[](p_idx);
-}
-
-const godot_char_type GDAPI *godot_string_get_data(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- return self->get_data();
-}
-
-godot_bool GDAPI godot_string_operator_equal(const godot_string *p_self, const godot_string *p_b) {
- const String *self = (const String *)p_self;
- const String *b = (const String *)p_b;
- return *self == *b;
-}
-
-godot_bool GDAPI godot_string_operator_less(const godot_string *p_self, const godot_string *p_b) {
- const String *self = (const String *)p_self;
- const String *b = (const String *)p_b;
- return *self < *b;
-}
-
-godot_string GDAPI godot_string_operator_plus(const godot_string *p_self, const godot_string *p_b) {
- godot_string ret;
- const String *self = (const String *)p_self;
- const String *b = (const String *)p_b;
- memnew_placement(&ret, String(*self + *b));
- return ret;
-}
-
void GDAPI godot_string_destroy(godot_string *p_self) {
String *self = (String *)p_self;
self->~String();
}
-/* Standard size stuff */
-
-godot_int GDAPI godot_string_length(const godot_string *p_self) {
- const String *self = (const String *)p_self;
-
- return self->length();
-}
-
-/* Helpers */
-
-signed char GDAPI godot_string_casecmp_to(const godot_string *p_self, const godot_string *p_str) {
- const String *self = (const String *)p_self;
- const String *str = (const String *)p_str;
-
- return self->casecmp_to(*str);
-}
-
-signed char GDAPI godot_string_nocasecmp_to(const godot_string *p_self, const godot_string *p_str) {
- const String *self = (const String *)p_self;
- const String *str = (const String *)p_str;
-
- return self->nocasecmp_to(*str);
-}
-
-signed char GDAPI godot_string_naturalnocasecmp_to(const godot_string *p_self, const godot_string *p_str) {
- const String *self = (const String *)p_self;
- const String *str = (const String *)p_str;
-
- return self->naturalnocasecmp_to(*str);
-}
-
-godot_bool GDAPI godot_string_begins_with(const godot_string *p_self, const godot_string *p_string) {
- const String *self = (const String *)p_self;
- const String *string = (const String *)p_string;
-
- return self->begins_with(*string);
-}
-
-godot_bool GDAPI godot_string_begins_with_char_array(const godot_string *p_self, const char *p_char_array) {
- const String *self = (const String *)p_self;
-
- return self->begins_with(p_char_array);
-}
-
-godot_packed_string_array GDAPI godot_string_bigrams(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_packed_string_array ret;
- memnew_placement(&ret, Vector<String>(self->bigrams()));
- return ret;
-};
-
-godot_string GDAPI godot_string_chr(godot_char_type p_character) {
- godot_string result;
- memnew_placement(&result, String(String::chr(p_character)));
-
- return result;
-}
-
-godot_bool GDAPI godot_string_ends_with(const godot_string *p_self, const godot_string *p_string) {
- const String *self = (const String *)p_self;
- const String *string = (const String *)p_string;
-
- return self->ends_with(*string);
-}
-
-godot_bool GDAPI godot_string_ends_with_char_array(const godot_string *p_self, const char *p_char_array) {
- const String *self = (const String *)p_self;
-
- return self->ends_with(p_char_array);
-}
-
-godot_int GDAPI godot_string_count(const godot_string *p_self, const godot_string *p_what, godot_int p_from, godot_int p_to) {
- const String *self = (const String *)p_self;
- const String *what = (const String *)p_what;
-
- return self->count(*what, p_from, p_to);
-}
-
-godot_int GDAPI godot_string_countn(const godot_string *p_self, const godot_string *p_what, godot_int p_from, godot_int p_to) {
- const String *self = (const String *)p_self;
- const String *what = (const String *)p_what;
-
- return self->countn(*what, p_from, p_to);
-}
-
-godot_int GDAPI godot_string_find(const godot_string *p_self, const godot_string *p_what) {
- const String *self = (const String *)p_self;
- const String *what = (const String *)p_what;
-
- return self->find(*what);
-}
-
-godot_int GDAPI godot_string_find_from(const godot_string *p_self, const godot_string *p_what, godot_int p_from) {
- const String *self = (const String *)p_self;
- const String *what = (const String *)p_what;
-
- return self->find(*what, p_from);
-}
-
-godot_int GDAPI godot_string_findmk(const godot_string *p_self, const godot_packed_string_array *p_keys) {
- const String *self = (const String *)p_self;
- const Vector<String> *keys = (const Vector<String> *)p_keys;
- return self->findmk(*keys);
-}
-
-godot_int GDAPI godot_string_findmk_from(const godot_string *p_self, const godot_packed_string_array *p_keys, godot_int p_from) {
- const String *self = (const String *)p_self;
- const Vector<String> *keys = (const Vector<String> *)p_keys;
- return self->findmk(*keys, p_from);
-}
-
-godot_int GDAPI godot_string_findmk_from_in_place(const godot_string *p_self, const godot_packed_string_array *p_keys, godot_int p_from, godot_int *r_key) {
- const String *self = (const String *)p_self;
- const Vector<String> *keys = (const Vector<String> *)p_keys;
- int key;
- int ret = self->findmk(*keys, p_from, &key);
- if (r_key) {
- *r_key = key;
- }
- return ret;
-}
-
-godot_int GDAPI godot_string_findn(const godot_string *p_self, const godot_string *p_what) {
- const String *self = (const String *)p_self;
- const String *what = (const String *)p_what;
-
- return self->findn(*what);
-}
-
-godot_int GDAPI godot_string_findn_from(const godot_string *p_self, const godot_string *p_what, godot_int p_from) {
- const String *self = (const String *)p_self;
- const String *what = (const String *)p_what;
-
- return self->findn(*what, p_from);
-}
-
-godot_string GDAPI godot_string_format(const godot_string *p_self, const godot_variant *p_values) {
- const String *self = (const String *)p_self;
- const Variant *values = (const Variant *)p_values;
- godot_string result;
- memnew_placement(&result, String(self->format(*values)));
-
- return result;
-}
-
-godot_string GDAPI godot_string_format_with_custom_placeholder(const godot_string *p_self, const godot_variant *p_values, const char *p_placeholder) {
- const String *self = (const String *)p_self;
- const Variant *values = (const Variant *)p_values;
- String placeholder = String(p_placeholder);
- godot_string result;
- memnew_placement(&result, String(self->format(*values, placeholder)));
-
- return result;
-}
-
-godot_string GDAPI godot_string_hex_encode_buffer(const uint8_t *p_buffer, godot_int p_len) {
- godot_string result;
- memnew_placement(&result, String(String::hex_encode_buffer(p_buffer, p_len)));
-
- return result;
-}
-
-godot_string GDAPI godot_string_insert(const godot_string *p_self, godot_int p_at_pos, const godot_string *p_string) {
- const String *self = (const String *)p_self;
- const String *content = (const String *)p_string;
- godot_string result;
- memnew_placement(&result, String(self->insert(p_at_pos, *content)));
-
- return result;
-}
-
-godot_bool GDAPI godot_string_is_numeric(const godot_string *p_self) {
- const String *self = (const String *)p_self;
-
- return self->is_numeric();
-}
-
-godot_bool GDAPI godot_string_is_subsequence_of(const godot_string *p_self, const godot_string *p_string) {
- const String *self = (const String *)p_self;
- const String *string = (const String *)p_string;
-
- return self->is_subsequence_of(*string);
-}
-
-godot_bool GDAPI godot_string_is_subsequence_ofi(const godot_string *p_self, const godot_string *p_string) {
- const String *self = (const String *)p_self;
- const String *string = (const String *)p_string;
-
- return self->is_subsequence_ofi(*string);
-}
-
-godot_string GDAPI godot_string_lpad(const godot_string *p_self, godot_int p_min_length) {
- const String *self = (const String *)p_self;
- godot_string result;
- memnew_placement(&result, String(self->lpad(p_min_length)));
-
- return result;
-}
-
-godot_string GDAPI godot_string_lpad_with_custom_character(const godot_string *p_self, godot_int p_min_length, const godot_string *p_character) {
- const String *self = (const String *)p_self;
- const String *character = (const String *)p_character;
- godot_string result;
- memnew_placement(&result, String(self->lpad(p_min_length, *character)));
-
- return result;
-}
-
-godot_bool GDAPI godot_string_match(const godot_string *p_self, const godot_string *p_wildcard) {
- const String *self = (const String *)p_self;
- const String *wildcard = (const String *)p_wildcard;
-
- return self->match(*wildcard);
-}
-
-godot_bool GDAPI godot_string_matchn(const godot_string *p_self, const godot_string *p_wildcard) {
- const String *self = (const String *)p_self;
- const String *wildcard = (const String *)p_wildcard;
-
- return self->matchn(*wildcard);
-}
-
-godot_string GDAPI godot_string_md5(const uint8_t *p_md5) {
- godot_string result;
- memnew_placement(&result, String(String::md5(p_md5)));
-
- return result;
-}
-
-godot_string GDAPI godot_string_num(double p_num) {
- godot_string result;
- memnew_placement(&result, String(String::num(p_num)));
-
- return result;
-}
-
-godot_string GDAPI godot_string_num_int64(int64_t p_num, godot_int p_base) {
- godot_string result;
- memnew_placement(&result, String(String::num_int64(p_num, p_base)));
-
- return result;
-}
-
-godot_string GDAPI godot_string_num_int64_capitalized(int64_t p_num, godot_int p_base, godot_bool p_capitalize_hex) {
- godot_string result;
- memnew_placement(&result, String(String::num_int64(p_num, p_base, true)));
-
- return result;
-}
-
-godot_string GDAPI godot_string_num_real(double p_num) {
- godot_string result;
- memnew_placement(&result, String(String::num_real(p_num)));
-
- return result;
-}
-
-godot_string GDAPI godot_string_num_scientific(double p_num) {
- godot_string result;
- memnew_placement(&result, String(String::num_scientific(p_num)));
-
- return result;
-}
-
-godot_string GDAPI godot_string_num_with_decimals(double p_num, godot_int p_decimals) {
- godot_string result;
- memnew_placement(&result, String(String::num(p_num, p_decimals)));
-
- return result;
-}
-
-godot_string GDAPI godot_string_pad_decimals(const godot_string *p_self, godot_int p_digits) {
- const String *self = (const String *)p_self;
- godot_string result;
- memnew_placement(&result, String(self->pad_decimals(p_digits)));
-
- return result;
-}
-
-godot_string GDAPI godot_string_pad_zeros(const godot_string *p_self, godot_int p_digits) {
- const String *self = (const String *)p_self;
- godot_string result;
- memnew_placement(&result, String(self->pad_zeros(p_digits)));
-
- return result;
-}
-
-godot_string GDAPI godot_string_replace(const godot_string *p_self, const godot_string *p_key, const godot_string *p_with) {
- const String *self = (const String *)p_self;
- const String *key = (const String *)p_key;
- const String *with = (const String *)p_with;
- godot_string result;
- memnew_placement(&result, String(self->replace(*key, *with)));
-
- return result;
-}
-
-godot_string GDAPI godot_string_replacen(const godot_string *p_self, const godot_string *p_key, const godot_string *p_with) {
- const String *self = (const String *)p_self;
- const String *key = (const String *)p_key;
- const String *with = (const String *)p_with;
- godot_string result;
- memnew_placement(&result, String(self->replacen(*key, *with)));
-
- return result;
-}
-
-godot_int GDAPI godot_string_rfind(const godot_string *p_self, const godot_string *p_what) {
- const String *self = (const String *)p_self;
- const String *what = (const String *)p_what;
-
- return self->rfind(*what);
-}
-
-godot_int GDAPI godot_string_rfindn(const godot_string *p_self, const godot_string *p_what) {
- const String *self = (const String *)p_self;
- const String *what = (const String *)p_what;
-
- return self->rfindn(*what);
-}
-
-godot_int GDAPI godot_string_rfind_from(const godot_string *p_self, const godot_string *p_what, godot_int p_from) {
- const String *self = (const String *)p_self;
- const String *what = (const String *)p_what;
-
- return self->rfind(*what, p_from);
-}
-
-godot_int GDAPI godot_string_rfindn_from(const godot_string *p_self, const godot_string *p_what, godot_int p_from) {
- const String *self = (const String *)p_self;
- const String *what = (const String *)p_what;
-
- return self->rfindn(*what, p_from);
-}
-
-godot_string GDAPI godot_string_replace_first(const godot_string *p_self, const godot_string *p_key, const godot_string *p_with) {
- const String *self = (const String *)p_self;
- const String *key = (const String *)p_key;
- const String *with = (const String *)p_with;
- godot_string result;
- memnew_placement(&result, String(self->replace_first(*key, *with)));
-
- return result;
-}
-
-godot_string GDAPI godot_string_rpad(const godot_string *p_self, godot_int p_min_length) {
- const String *self = (const String *)p_self;
- godot_string result;
- memnew_placement(&result, String(self->rpad(p_min_length)));
-
- return result;
-}
-
-godot_string GDAPI godot_string_rpad_with_custom_character(const godot_string *p_self, godot_int p_min_length, const godot_string *p_character) {
- const String *self = (const String *)p_self;
- const String *character = (const String *)p_character;
- godot_string result;
- memnew_placement(&result, String(self->rpad(p_min_length, *character)));
-
- return result;
-}
-
-godot_real GDAPI godot_string_similarity(const godot_string *p_self, const godot_string *p_string) {
- const String *self = (const String *)p_self;
- const String *string = (const String *)p_string;
-
- return self->similarity(*string);
-}
-
-godot_string GDAPI godot_string_sprintf(const godot_string *p_self, const godot_array *p_values, godot_bool *p_error) {
- const String *self = (const String *)p_self;
- const Array *values = (const Array *)p_values;
-
- godot_string result;
- String return_value = self->sprintf(*values, p_error);
- memnew_placement(&result, String(return_value));
-
- return result;
-}
-
-godot_string GDAPI godot_string_substr(const godot_string *p_self, godot_int p_from, godot_int p_chars) {
- const String *self = (const String *)p_self;
- godot_string result;
- memnew_placement(&result, String(self->substr(p_from, p_chars)));
-
- return result;
-}
-
-godot_int GDAPI godot_string_to_int(const godot_string *p_self) {
- const String *self = (const String *)p_self;
-
- return self->to_int();
-}
-
-double GDAPI godot_string_to_float(const godot_string *p_self) {
- const String *self = (const String *)p_self;
-
- return self->to_float();
-}
-
-godot_string GDAPI godot_string_capitalize(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- memnew_placement(&result, String(self->capitalize()));
-
- return result;
-}
-
-godot_string GDAPI godot_string_camelcase_to_underscore(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- memnew_placement(&result, String(self->camelcase_to_underscore(false)));
-
- return result;
-}
-
-godot_string GDAPI godot_string_camelcase_to_underscore_lowercased(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- memnew_placement(&result, String(self->camelcase_to_underscore()));
-
- return result;
-}
-
-double GDAPI godot_string_char_to_float(const char *p_what) {
- return String::to_float(p_what);
-}
-
-double GDAPI godot_string_wchar_to_float(const wchar_t *p_str, const wchar_t **r_end) {
- return String::to_float(p_str, r_end);
-}
-
-godot_int GDAPI godot_string_char_to_int(const char *p_what) {
- return String::to_int(p_what);
-}
-
-godot_int GDAPI godot_string_wchar_to_int(const wchar_t *p_str) {
- return String::to_int(p_str);
-}
-
-godot_int GDAPI godot_string_char_to_int_with_len(const char *p_what, godot_int p_len) {
- return String::to_int(p_what, p_len);
-}
-
-godot_int GDAPI godot_string_wchar_to_int_with_len(const wchar_t *p_str, int p_len) {
- return String::to_int(p_str, p_len);
-}
-
-godot_int GDAPI godot_string_hex_to_int(const godot_string *p_self) {
- const String *self = (const String *)p_self;
-
- return self->hex_to_int(false);
-}
-
-godot_int GDAPI godot_string_hex_to_int_with_prefix(const godot_string *p_self) {
- const String *self = (const String *)p_self;
-
- return self->hex_to_int();
-}
-
-godot_string GDAPI godot_string_get_slice(const godot_string *p_self, const godot_string *p_splitter, godot_int p_slice) {
- const String *self = (const String *)p_self;
- const String *splitter = (const String *)p_splitter;
- godot_string result;
- memnew_placement(&result, String(self->get_slice(*splitter, p_slice)));
-
- return result;
-}
-
-godot_string GDAPI godot_string_get_slicec(const godot_string *p_self, godot_char_type p_splitter, godot_int p_slice) {
- const String *self = (const String *)p_self;
- godot_string result;
- memnew_placement(&result, String(self->get_slicec(p_splitter, p_slice)));
-
- return result;
-}
-
-godot_packed_string_array GDAPI godot_string_split(const godot_string *p_self, const godot_string *p_splitter) {
- const String *self = (const String *)p_self;
- const String *splitter = (const String *)p_splitter;
- godot_packed_string_array ret;
- memnew_placement(&ret, Vector<String>(self->split(*splitter, false)));
- return ret;
-}
-
-godot_packed_string_array GDAPI godot_string_split_allow_empty(const godot_string *p_self, const godot_string *p_splitter) {
- const String *self = (const String *)p_self;
- const String *splitter = (const String *)p_splitter;
- godot_packed_string_array ret;
- memnew_placement(&ret, Vector<String>(self->split(*splitter, true)));
- return ret;
-}
-
-godot_packed_string_array GDAPI godot_string_split_with_maxsplit(const godot_string *p_self, const godot_string *p_splitter, const godot_bool p_allow_empty, const godot_int p_maxsplit) {
- const String *self = (const String *)p_self;
- const String *splitter = (const String *)p_splitter;
- godot_packed_string_array ret;
- memnew_placement(&ret, Vector<String>(self->split(*splitter, p_allow_empty, p_maxsplit)));
- return ret;
-}
-
-godot_packed_string_array GDAPI godot_string_rsplit(const godot_string *p_self, const godot_string *p_splitter) {
- const String *self = (const String *)p_self;
- const String *splitter = (const String *)p_splitter;
-
- godot_packed_string_array ret;
- memnew_placement(&ret, Vector<String>(self->rsplit(*splitter, false)));
- return ret;
-}
-
-godot_packed_string_array GDAPI godot_string_rsplit_allow_empty(const godot_string *p_self, const godot_string *p_splitter) {
- const String *self = (const String *)p_self;
- const String *splitter = (const String *)p_splitter;
-
- godot_packed_string_array ret;
- memnew_placement(&ret, Vector<String>(self->rsplit(*splitter, true)));
- return ret;
-}
-
-godot_packed_string_array GDAPI godot_string_rsplit_with_maxsplit(const godot_string *p_self, const godot_string *p_splitter, const godot_bool p_allow_empty, const godot_int p_maxsplit) {
- const String *self = (const String *)p_self;
- const String *splitter = (const String *)p_splitter;
-
- godot_packed_string_array ret;
- memnew_placement(&ret, Vector<String>(self->rsplit(*splitter, p_allow_empty, p_maxsplit)));
- return ret;
-}
-
-godot_packed_float32_array GDAPI godot_string_split_floats(const godot_string *p_self, const godot_string *p_splitter) {
- const String *self = (const String *)p_self;
- const String *splitter = (const String *)p_splitter;
-
- godot_packed_float32_array ret;
- memnew_placement(&ret, Vector<float>(self->split_floats(*splitter, false)));
- return ret;
-}
-
-godot_packed_float32_array GDAPI godot_string_split_floats_allow_empty(const godot_string *p_self, const godot_string *p_splitter) {
- const String *self = (const String *)p_self;
- const String *splitter = (const String *)p_splitter;
-
- godot_packed_float32_array ret;
- memnew_placement(&ret, Vector<float>(self->split_floats(*splitter, true)));
- return ret;
-}
-
-godot_packed_float32_array GDAPI godot_string_split_floats_mk(const godot_string *p_self, const godot_packed_string_array *p_splitters) {
- const String *self = (const String *)p_self;
- const Vector<String> *splitters = (const Vector<String> *)p_splitters;
-
- godot_packed_float32_array ret;
- memnew_placement(&ret, Vector<float>(self->split_floats_mk(*splitters, false)));
- return ret;
-}
-
-godot_packed_float32_array GDAPI godot_string_split_floats_mk_allow_empty(const godot_string *p_self, const godot_packed_string_array *p_splitters) {
- const String *self = (const String *)p_self;
- const Vector<String> *splitters = (const Vector<String> *)p_splitters;
-
- godot_packed_float32_array ret;
- memnew_placement(&ret, Vector<float>(self->split_floats_mk(*splitters, true)));
- return ret;
-}
-
-godot_packed_int32_array GDAPI godot_string_split_ints(const godot_string *p_self, const godot_string *p_splitter) {
- const String *self = (const String *)p_self;
- const String *splitter = (const String *)p_splitter;
-
- godot_packed_int32_array ret;
- memnew_placement(&ret, Vector<int>(self->split_ints(*splitter, false)));
- return ret;
-}
-
-godot_packed_int32_array GDAPI godot_string_split_ints_allow_empty(const godot_string *p_self, const godot_string *p_splitter) {
- const String *self = (const String *)p_self;
- const String *splitter = (const String *)p_splitter;
-
- godot_packed_int32_array ret;
- memnew_placement(&ret, Vector<int>(self->split_ints(*splitter, true)));
- return ret;
-}
-
-godot_packed_int32_array GDAPI godot_string_split_ints_mk(const godot_string *p_self, const godot_packed_string_array *p_splitters) {
- const String *self = (const String *)p_self;
- const Vector<String> *splitters = (const Vector<String> *)p_splitters;
-
- godot_packed_int32_array ret;
- memnew_placement(&ret, Vector<int>(self->split_ints_mk(*splitters, false)));
- return ret;
-}
-
-godot_packed_int32_array GDAPI godot_string_split_ints_mk_allow_empty(const godot_string *p_self, const godot_packed_string_array *p_splitters) {
- const String *self = (const String *)p_self;
- const Vector<String> *splitters = (const Vector<String> *)p_splitters;
-
- godot_packed_int32_array ret;
- memnew_placement(&ret, Vector<int>(self->split_ints_mk(*splitters, true)));
- return ret;
-}
-
-godot_packed_string_array GDAPI godot_string_split_spaces(const godot_string *p_self) {
- const String *self = (const String *)p_self;
-
- godot_packed_string_array ret;
- memnew_placement(&ret, Vector<String>(self->split_spaces()));
- return ret;
-}
-
-godot_int GDAPI godot_string_get_slice_count(const godot_string *p_self, const godot_string *p_splitter) {
- const String *self = (const String *)p_self;
- const String *splitter = (const String *)p_splitter;
-
- return self->get_slice_count(*splitter);
-}
-
-godot_char_type GDAPI godot_string_char_lowercase(godot_char_type p_char) {
- return String::char_lowercase(p_char);
-}
-
-godot_char_type GDAPI godot_string_char_uppercase(godot_char_type p_char) {
- return String::char_uppercase(p_char);
-}
-
-godot_string GDAPI godot_string_to_lower(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- memnew_placement(&result, String(self->to_lower()));
-
- return result;
-}
-
-godot_string GDAPI godot_string_to_upper(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- memnew_placement(&result, String(self->to_upper()));
-
- return result;
-}
-
-godot_string GDAPI godot_string_get_basename(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- memnew_placement(&result, String(self->get_basename()));
-
- return result;
-}
-
-godot_string GDAPI godot_string_get_extension(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- memnew_placement(&result, String(self->get_extension()));
-
- return result;
-}
-
-godot_string GDAPI godot_string_left(const godot_string *p_self, godot_int p_pos) {
- const String *self = (const String *)p_self;
- godot_string result;
- memnew_placement(&result, String(self->left(p_pos)));
-
- return result;
-}
-
-godot_char_type GDAPI godot_string_ord_at(const godot_string *p_self, godot_int p_idx) {
- const String *self = (const String *)p_self;
-
- return self->ord_at(p_idx);
-}
-
-godot_string GDAPI godot_string_plus_file(const godot_string *p_self, const godot_string *p_file) {
- const String *self = (const String *)p_self;
- const String *file = (const String *)p_file;
- godot_string result;
- memnew_placement(&result, String(self->plus_file(*file)));
-
- return result;
-}
-
-godot_string GDAPI godot_string_right(const godot_string *p_self, godot_int p_pos) {
- const String *self = (const String *)p_self;
- godot_string result;
- memnew_placement(&result, String(self->right(p_pos)));
-
- return result;
-}
-
-godot_string GDAPI godot_string_repeat(const godot_string *p_self, godot_int p_count) {
- const String *self = (const String *)p_self;
- godot_string result;
- memnew_placement(&result, String(self->repeat(p_count)));
-
- return result;
-}
-
-godot_string GDAPI godot_string_strip_edges(const godot_string *p_self, godot_bool p_left, godot_bool p_right) {
- const String *self = (const String *)p_self;
- godot_string result;
- memnew_placement(&result, String(self->strip_edges(p_left, p_right)));
-
- return result;
-}
-
-godot_string GDAPI godot_string_strip_escapes(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- memnew_placement(&result, String(self->strip_escapes()));
-
- return result;
-}
-
-void GDAPI godot_string_erase(godot_string *p_self, godot_int p_pos, godot_int p_chars) {
- String *self = (String *)p_self;
-
- return self->erase(p_pos, p_chars);
-}
-
-godot_char_string GDAPI godot_string_ascii(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_char_string result;
-
- memnew_placement(&result, CharString(self->ascii()));
-
- return result;
-}
-
-godot_char_string GDAPI godot_string_latin1(const godot_string *p_self) {
- const String *self = (const String *)p_self;
-
- godot_char_string result;
-
- memnew_placement(&result, CharString(self->ascii(true)));
-
- return result;
-}
-
-godot_char_string GDAPI godot_string_utf8(const godot_string *p_self) {
- const String *self = (const String *)p_self;
-
- godot_char_string result;
-
- memnew_placement(&result, CharString(self->utf8()));
-
- return result;
-}
-
-godot_bool GDAPI godot_string_parse_utf8(godot_string *p_self, const char *p_utf8) {
- String *self = (String *)p_self;
-
- return self->parse_utf8(p_utf8);
-}
-
-godot_bool GDAPI godot_string_parse_utf8_with_len(godot_string *p_self, const char *p_utf8, godot_int p_len) {
- String *self = (String *)p_self;
-
- return self->parse_utf8(p_utf8, p_len);
-}
-
-godot_string GDAPI godot_string_chars_to_utf8(const char *p_utf8) {
- godot_string result;
- memnew_placement(&result, String(String::utf8(p_utf8)));
-
- return result;
-}
-
-godot_string GDAPI godot_string_chars_to_utf8_with_len(const char *p_utf8, godot_int p_len) {
- godot_string result;
- memnew_placement(&result, String(String::utf8(p_utf8, p_len)));
-
- return result;
-}
-
-godot_char16_string GDAPI godot_string_utf16(const godot_string *p_self) {
- const String *self = (const String *)p_self;
-
- godot_char16_string result;
-
- memnew_placement(&result, Char16String(self->utf16()));
-
- return result;
-}
-
-godot_bool GDAPI godot_string_parse_utf16(godot_string *p_self, const char16_t *p_utf16) {
- String *self = (String *)p_self;
-
- return self->parse_utf16(p_utf16);
-}
-
-godot_bool GDAPI godot_string_parse_utf16_with_len(godot_string *p_self, const char16_t *p_utf16, godot_int p_len) {
- String *self = (String *)p_self;
-
- return self->parse_utf16(p_utf16, p_len);
-}
-
-godot_string GDAPI godot_string_chars_to_utf16(const char16_t *p_utf16) {
- godot_string result;
- memnew_placement(&result, String(String::utf16(p_utf16)));
-
- return result;
-}
-
-godot_string GDAPI godot_string_chars_to_utf16_with_len(const char16_t *p_utf16, godot_int p_len) {
- godot_string result;
- memnew_placement(&result, String(String::utf16(p_utf16, p_len)));
-
- return result;
-}
-
-uint32_t GDAPI godot_string_hash(const godot_string *p_self) {
- const String *self = (const String *)p_self;
-
- return self->hash();
-}
-
-uint64_t GDAPI godot_string_hash64(const godot_string *p_self) {
- const String *self = (const String *)p_self;
-
- return self->hash64();
-}
-
-uint32_t GDAPI godot_string_hash_chars(const char *p_cstr) {
- return String::hash(p_cstr);
-}
-
-uint32_t GDAPI godot_string_hash_chars_with_len(const char *p_cstr, godot_int p_len) {
- return String::hash(p_cstr, p_len);
-}
-
-uint32_t GDAPI godot_string_hash_wide_chars(const wchar_t *p_str) {
- return String::hash(p_str);
-}
-
-uint32_t GDAPI godot_string_hash_wide_chars_with_len(const wchar_t *p_str, godot_int p_len) {
- return String::hash(p_str, p_len);
-}
-
-godot_packed_byte_array GDAPI godot_string_md5_buffer(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_packed_byte_array result;
- memnew_placement(&result, PackedByteArray(self->md5_buffer()));
- return result;
-}
-
-godot_string GDAPI godot_string_md5_text(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- memnew_placement(&result, String(self->md5_text()));
-
- return result;
-}
-
-godot_packed_byte_array GDAPI godot_string_sha1_buffer(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_packed_byte_array result;
- memnew_placement(&result, PackedByteArray(self->sha1_buffer()));
- return result;
-}
-
-godot_string GDAPI godot_string_sha1_text(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- memnew_placement(&result, String(self->sha1_text()));
-
- return result;
-}
-
-godot_packed_byte_array GDAPI godot_string_sha256_buffer(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_packed_byte_array result;
- memnew_placement(&result, PackedByteArray(self->sha256_buffer()));
- return result;
-}
-
-godot_string GDAPI godot_string_sha256_text(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- memnew_placement(&result, String(self->sha256_text()));
-
- return result;
-}
-
-godot_bool godot_string_empty(const godot_string *p_self) {
- const String *self = (const String *)p_self;
-
- return self->empty();
-}
-
-// path functions
-godot_string GDAPI godot_string_get_base_dir(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- String return_value = self->get_base_dir();
- memnew_placement(&result, String(return_value));
-
- return result;
-}
-
-godot_string GDAPI godot_string_get_file(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- String return_value = self->get_file();
- memnew_placement(&result, String(return_value));
-
- return result;
-}
-
-godot_string GDAPI godot_string_humanize_size(size_t p_size) {
- godot_string result;
- String return_value = String::humanize_size(p_size);
- memnew_placement(&result, String(return_value));
-
- return result;
-}
-
-godot_bool GDAPI godot_string_is_abs_path(const godot_string *p_self) {
- const String *self = (const String *)p_self;
-
- return self->is_abs_path();
-}
-
-godot_bool GDAPI godot_string_is_rel_path(const godot_string *p_self) {
- const String *self = (const String *)p_self;
-
- return self->is_rel_path();
-}
-
-godot_bool GDAPI godot_string_is_resource_file(const godot_string *p_self) {
- const String *self = (const String *)p_self;
-
- return self->is_resource_file();
-}
-
-godot_string GDAPI godot_string_path_to(const godot_string *p_self, const godot_string *p_path) {
- const String *self = (const String *)p_self;
- String *path = (String *)p_path;
- godot_string result;
- String return_value = self->path_to(*path);
- memnew_placement(&result, String(return_value));
-
- return result;
-}
-
-godot_string GDAPI godot_string_path_to_file(const godot_string *p_self, const godot_string *p_path) {
- const String *self = (const String *)p_self;
- String *path = (String *)p_path;
- godot_string result;
- String return_value = self->path_to_file(*path);
- memnew_placement(&result, String(return_value));
-
- return result;
-}
-
-godot_string GDAPI godot_string_simplify_path(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- String return_value = self->simplify_path();
- memnew_placement(&result, String(return_value));
-
- return result;
-}
-
-godot_string GDAPI godot_string_c_escape(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- String return_value = self->c_escape();
- memnew_placement(&result, String(return_value));
-
- return result;
-}
-
-godot_string GDAPI godot_string_c_escape_multiline(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- String return_value = self->c_escape_multiline();
- memnew_placement(&result, String(return_value));
-
- return result;
-}
-
-godot_string GDAPI godot_string_c_unescape(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- String return_value = self->c_unescape();
- memnew_placement(&result, String(return_value));
-
- return result;
-}
-
-godot_string GDAPI godot_string_http_escape(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- String return_value = self->http_escape();
- memnew_placement(&result, String(return_value));
-
- return result;
-}
-
-godot_string GDAPI godot_string_http_unescape(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- String return_value = self->http_unescape();
- memnew_placement(&result, String(return_value));
-
- return result;
-}
-
-godot_string GDAPI godot_string_json_escape(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- String return_value = self->json_escape();
- memnew_placement(&result, String(return_value));
-
- return result;
-}
-
-godot_string GDAPI godot_string_xml_escape(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- String return_value = self->xml_escape();
- memnew_placement(&result, String(return_value));
-
- return result;
-}
-
-godot_string GDAPI godot_string_xml_escape_with_quotes(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- String return_value = self->xml_escape(true);
- memnew_placement(&result, String(return_value));
-
- return result;
-}
-
-godot_string GDAPI godot_string_xml_unescape(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- String return_value = self->xml_unescape();
- memnew_placement(&result, String(return_value));
-
- return result;
-}
-
-godot_string GDAPI godot_string_percent_decode(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- String return_value = self->percent_decode();
- memnew_placement(&result, String(return_value));
-
- return result;
-}
-
-godot_string GDAPI godot_string_percent_encode(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- String return_value = self->percent_encode();
- memnew_placement(&result, String(return_value));
-
- return result;
-}
-
-godot_string GDAPI godot_string_join(const godot_string *p_self, const godot_packed_string_array *p_parts) {
- const String *self = (const String *)p_self;
- const Vector<String> *parts = (const Vector<String> *)p_parts;
- godot_string result;
- String return_value = self->join(*parts);
- memnew_placement(&result, String(return_value));
-
- return result;
-}
-
-godot_bool GDAPI godot_string_is_valid_filename(const godot_string *p_self) {
- const String *self = (const String *)p_self;
-
- return self->is_valid_filename();
-}
-
-godot_bool GDAPI godot_string_is_valid_float(const godot_string *p_self) {
- const String *self = (const String *)p_self;
-
- return self->is_valid_float();
-}
-
-godot_bool GDAPI godot_string_is_valid_hex_number(const godot_string *p_self, godot_bool p_with_prefix) {
- const String *self = (const String *)p_self;
-
- return self->is_valid_hex_number(p_with_prefix);
-}
-
-godot_bool GDAPI godot_string_is_valid_html_color(const godot_string *p_self) {
- const String *self = (const String *)p_self;
-
- return self->is_valid_html_color();
-}
-
-godot_bool GDAPI godot_string_is_valid_identifier(const godot_string *p_self) {
- const String *self = (const String *)p_self;
-
- return self->is_valid_identifier();
-}
-
-godot_bool GDAPI godot_string_is_valid_integer(const godot_string *p_self) {
- const String *self = (const String *)p_self;
-
- return self->is_valid_integer();
-}
-
-godot_bool GDAPI godot_string_is_valid_ip_address(const godot_string *p_self) {
- const String *self = (const String *)p_self;
-
- return self->is_valid_ip_address();
-}
-
-godot_string GDAPI godot_string_dedent(const godot_string *p_self) {
- const String *self = (const String *)p_self;
- godot_string result;
- String return_value = self->dedent();
- memnew_placement(&result, String(return_value));
-
- return result;
-}
-
-godot_string GDAPI godot_string_trim_prefix(const godot_string *p_self, const godot_string *p_prefix) {
- const String *self = (const String *)p_self;
- String *prefix = (String *)p_prefix;
- godot_string result;
- String return_value = self->trim_prefix(*prefix);
- memnew_placement(&result, String(return_value));
-
- return result;
-}
-
-godot_string GDAPI godot_string_trim_suffix(const godot_string *p_self, const godot_string *p_suffix) {
- const String *self = (const String *)p_self;
- String *suffix = (String *)p_suffix;
- godot_string result;
- String return_value = self->trim_suffix(*suffix);
- memnew_placement(&result, String(return_value));
-
- return result;
-}
-
-godot_string GDAPI godot_string_lstrip(const godot_string *p_self, const godot_string *p_chars) {
- const String *self = (const String *)p_self;
- String *chars = (String *)p_chars;
- godot_string result;
- String return_value = self->lstrip(*chars);
- memnew_placement(&result, String(return_value));
-
- return result;
-}
-
-godot_string GDAPI godot_string_rstrip(const godot_string *p_self, const godot_string *p_chars) {
- const String *self = (const String *)p_self;
- String *chars = (String *)p_chars;
- godot_string result;
- String return_value = self->rstrip(*chars);
- memnew_placement(&result, String(return_value));
-
- return result;
-}
-
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/string_name.cpp b/modules/gdnative/gdnative/string_name.cpp
index 7bbaaeeaa0..c9d2dd5bc3 100644
--- a/modules/gdnative/gdnative/string_name.cpp
+++ b/modules/gdnative/gdnative/string_name.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,55 +30,28 @@
#include "gdnative/string_name.h"
-#include "core/string_name.h"
-#include "core/ustring.h"
+#include "core/string/string_name.h"
-#include <string.h>
+static_assert(sizeof(godot_string_name) == sizeof(StringName), "StringName size mismatch");
#ifdef __cplusplus
extern "C" {
#endif
-static_assert(sizeof(godot_string_name) == sizeof(StringName), "StringName size mismatch");
-
-void GDAPI godot_string_name_new(godot_string_name *r_dest, const godot_string *p_name) {
+void GDAPI godot_string_name_new(godot_string_name *r_dest) {
StringName *dest = (StringName *)r_dest;
- const String *name = (const String *)p_name;
- memnew_placement(dest, StringName(*name));
+ memnew_placement(dest, StringName);
}
-void GDAPI godot_string_name_new_data(godot_string_name *r_dest, const char *p_name) {
+void GDAPI godot_string_name_new_copy(godot_string_name *r_dest, const godot_string_name *p_src) {
StringName *dest = (StringName *)r_dest;
- memnew_placement(dest, StringName(p_name));
-}
-
-godot_string GDAPI godot_string_name_get_name(const godot_string_name *p_self) {
- godot_string ret;
- const StringName *self = (const StringName *)p_self;
- memnew_placement(&ret, String(*self));
- return ret;
-}
-
-uint32_t GDAPI godot_string_name_get_hash(const godot_string_name *p_self) {
- const StringName *self = (const StringName *)p_self;
- return self->hash();
-}
-
-const void GDAPI *godot_string_name_get_data_unique_pointer(const godot_string_name *p_self) {
- const StringName *self = (const StringName *)p_self;
- return self->data_unique_pointer();
+ const StringName *src = (const StringName *)p_src;
+ memnew_placement(dest, StringName(*src));
}
-godot_bool GDAPI godot_string_name_operator_equal(const godot_string_name *p_self, const godot_string_name *p_other) {
- const StringName *self = (const StringName *)p_self;
- const StringName *other = (const StringName *)p_other;
- return self == other;
-}
-
-godot_bool GDAPI godot_string_name_operator_less(const godot_string_name *p_self, const godot_string_name *p_other) {
- const StringName *self = (const StringName *)p_self;
- const StringName *other = (const StringName *)p_other;
- return self < other;
+void GDAPI godot_string_name_new_with_latin1_chars(godot_string_name *r_dest, const char *p_contents) {
+ StringName *dest = (StringName *)r_dest;
+ memnew_placement(dest, StringName(p_contents));
}
void GDAPI godot_string_name_destroy(godot_string_name *p_self) {
diff --git a/modules/gdnative/gdnative/transform.cpp b/modules/gdnative/gdnative/transform.cpp
index d19de93e9b..eae981bd07 100644
--- a/modules/gdnative/gdnative/transform.cpp
+++ b/modules/gdnative/gdnative/transform.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,198 +31,15 @@
#include "gdnative/transform.h"
#include "core/math/transform.h"
-#include "core/variant.h"
+
+static_assert(sizeof(godot_transform) == sizeof(Transform), "Transform size mismatch");
#ifdef __cplusplus
extern "C" {
#endif
-static_assert(sizeof(godot_transform) == sizeof(Transform), "Transform size mismatch");
-
-void GDAPI godot_transform_new_with_axis_origin(godot_transform *r_dest, const godot_vector3 *p_x_axis, const godot_vector3 *p_y_axis, const godot_vector3 *p_z_axis, const godot_vector3 *p_origin) {
- const Vector3 *x_axis = (const Vector3 *)p_x_axis;
- const Vector3 *y_axis = (const Vector3 *)p_y_axis;
- const Vector3 *z_axis = (const Vector3 *)p_z_axis;
- const Vector3 *origin = (const Vector3 *)p_origin;
- Transform *dest = (Transform *)r_dest;
- dest->basis.set_axis(0, *x_axis);
- dest->basis.set_axis(1, *y_axis);
- dest->basis.set_axis(2, *z_axis);
- dest->origin = *origin;
-}
-
-void GDAPI godot_transform_new(godot_transform *r_dest, const godot_basis *p_basis, const godot_vector3 *p_origin) {
- const Basis *basis = (const Basis *)p_basis;
- const Vector3 *origin = (const Vector3 *)p_origin;
- Transform *dest = (Transform *)r_dest;
- *dest = Transform(*basis, *origin);
-}
-
-void GDAPI godot_transform_new_with_quat(godot_transform *r_dest, const godot_quat *p_quat) {
- const Quat *quat = (const Quat *)p_quat;
- Transform *dest = (Transform *)r_dest;
- *dest = Transform(*quat);
-}
-
-godot_basis GDAPI godot_transform_get_basis(const godot_transform *p_self) {
- godot_basis dest;
- const Transform *self = (const Transform *)p_self;
- *((Basis *)&dest) = self->basis;
- return dest;
-}
-
-void GDAPI godot_transform_set_basis(godot_transform *p_self, const godot_basis *p_v) {
- Transform *self = (Transform *)p_self;
- const Basis *v = (const Basis *)p_v;
- self->basis = *v;
-}
-
-godot_vector3 GDAPI godot_transform_get_origin(const godot_transform *p_self) {
- godot_vector3 dest;
- const Transform *self = (const Transform *)p_self;
- *((Vector3 *)&dest) = self->origin;
- return dest;
-}
-
-void GDAPI godot_transform_set_origin(godot_transform *p_self, const godot_vector3 *p_v) {
- Transform *self = (Transform *)p_self;
- const Vector3 *v = (const Vector3 *)p_v;
- self->origin = *v;
-}
-
-godot_string GDAPI godot_transform_as_string(const godot_transform *p_self) {
- godot_string ret;
- const Transform *self = (const Transform *)p_self;
- memnew_placement(&ret, String(*self));
- return ret;
-}
-
-godot_transform GDAPI godot_transform_inverse(const godot_transform *p_self) {
- godot_transform dest;
- const Transform *self = (const Transform *)p_self;
- *((Transform *)&dest) = self->inverse();
- return dest;
-}
-
-godot_transform GDAPI godot_transform_affine_inverse(const godot_transform *p_self) {
- godot_transform dest;
- const Transform *self = (const Transform *)p_self;
- *((Transform *)&dest) = self->affine_inverse();
- return dest;
-}
-
-godot_transform GDAPI godot_transform_orthonormalized(const godot_transform *p_self) {
- godot_transform dest;
- const Transform *self = (const Transform *)p_self;
- *((Transform *)&dest) = self->orthonormalized();
- return dest;
-}
-
-godot_transform GDAPI godot_transform_rotated(const godot_transform *p_self, const godot_vector3 *p_axis, const godot_real p_phi) {
- godot_transform dest;
- const Transform *self = (const Transform *)p_self;
- const Vector3 *axis = (const Vector3 *)p_axis;
- *((Transform *)&dest) = self->rotated(*axis, p_phi);
- return dest;
-}
-
-godot_transform GDAPI godot_transform_scaled(const godot_transform *p_self, const godot_vector3 *p_scale) {
- godot_transform dest;
- const Transform *self = (const Transform *)p_self;
- const Vector3 *scale = (const Vector3 *)p_scale;
- *((Transform *)&dest) = self->scaled(*scale);
- return dest;
-}
-
-godot_transform GDAPI godot_transform_translated(const godot_transform *p_self, const godot_vector3 *p_ofs) {
- godot_transform dest;
- const Transform *self = (const Transform *)p_self;
- const Vector3 *ofs = (const Vector3 *)p_ofs;
- *((Transform *)&dest) = self->translated(*ofs);
- return dest;
-}
-
-godot_transform GDAPI godot_transform_looking_at(const godot_transform *p_self, const godot_vector3 *p_target, const godot_vector3 *p_up) {
- godot_transform dest;
- const Transform *self = (const Transform *)p_self;
- const Vector3 *target = (const Vector3 *)p_target;
- const Vector3 *up = (const Vector3 *)p_up;
- *((Transform *)&dest) = self->looking_at(*target, *up);
- return dest;
-}
-
-godot_plane GDAPI godot_transform_xform_plane(const godot_transform *p_self, const godot_plane *p_v) {
- godot_plane raw_dest;
- Plane *dest = (Plane *)&raw_dest;
- const Transform *self = (const Transform *)p_self;
- const Plane *v = (const Plane *)p_v;
- *dest = self->xform(*v);
- return raw_dest;
-}
-
-godot_plane GDAPI godot_transform_xform_inv_plane(const godot_transform *p_self, const godot_plane *p_v) {
- godot_plane raw_dest;
- Plane *dest = (Plane *)&raw_dest;
- const Transform *self = (const Transform *)p_self;
- const Plane *v = (const Plane *)p_v;
- *dest = self->xform_inv(*v);
- return raw_dest;
-}
-
-void GDAPI godot_transform_new_identity(godot_transform *r_dest) {
- Transform *dest = (Transform *)r_dest;
- *dest = Transform();
-}
-
-godot_bool GDAPI godot_transform_operator_equal(const godot_transform *p_self, const godot_transform *p_b) {
- const Transform *self = (const Transform *)p_self;
- const Transform *b = (const Transform *)p_b;
- return *self == *b;
-}
-
-godot_transform GDAPI godot_transform_operator_multiply(const godot_transform *p_self, const godot_transform *p_b) {
- godot_transform raw_dest;
- Transform *dest = (Transform *)&raw_dest;
- const Transform *self = (const Transform *)p_self;
- const Transform *b = (const Transform *)p_b;
- *dest = *self * *b;
- return raw_dest;
-}
-
-godot_vector3 GDAPI godot_transform_xform_vector3(const godot_transform *p_self, const godot_vector3 *p_v) {
- godot_vector3 raw_dest;
- Vector3 *dest = (Vector3 *)&raw_dest;
- const Transform *self = (const Transform *)p_self;
- const Vector3 *v = (const Vector3 *)p_v;
- *dest = self->xform(*v);
- return raw_dest;
-}
-
-godot_vector3 GDAPI godot_transform_xform_inv_vector3(const godot_transform *p_self, const godot_vector3 *p_v) {
- godot_vector3 raw_dest;
- Vector3 *dest = (Vector3 *)&raw_dest;
- const Transform *self = (const Transform *)p_self;
- const Vector3 *v = (const Vector3 *)p_v;
- *dest = self->xform_inv(*v);
- return raw_dest;
-}
-
-godot_aabb GDAPI godot_transform_xform_aabb(const godot_transform *p_self, const godot_aabb *p_v) {
- godot_aabb raw_dest;
- AABB *dest = (AABB *)&raw_dest;
- const Transform *self = (const Transform *)p_self;
- const AABB *v = (const AABB *)p_v;
- *dest = self->xform(*v);
- return raw_dest;
-}
-
-godot_aabb GDAPI godot_transform_xform_inv_aabb(const godot_transform *p_self, const godot_aabb *p_v) {
- godot_aabb raw_dest;
- AABB *dest = (AABB *)&raw_dest;
- const Transform *self = (const Transform *)p_self;
- const AABB *v = (const AABB *)p_v;
- *dest = self->xform_inv(*v);
- return raw_dest;
+void GDAPI godot_transform_new(godot_transform *p_self) {
+ memnew_placement(p_self, Transform);
}
#ifdef __cplusplus
diff --git a/modules/gdnative/gdnative/transform2d.cpp b/modules/gdnative/gdnative/transform2d.cpp
index c0f7878eb0..e2c933f1ea 100644
--- a/modules/gdnative/gdnative/transform2d.cpp
+++ b/modules/gdnative/gdnative/transform2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,179 +31,15 @@
#include "gdnative/transform2d.h"
#include "core/math/transform_2d.h"
-#include "core/variant.h"
+
+static_assert(sizeof(godot_transform2d) == sizeof(Transform2D), "Transform2D size mismatch");
#ifdef __cplusplus
extern "C" {
#endif
-static_assert(sizeof(godot_transform2d) == sizeof(Transform2D), "Transform2D size mismatch");
-
-void GDAPI godot_transform2d_new(godot_transform2d *r_dest, const godot_real p_rot, const godot_vector2 *p_pos) {
- const Vector2 *pos = (const Vector2 *)p_pos;
- Transform2D *dest = (Transform2D *)r_dest;
- *dest = Transform2D(p_rot, *pos);
-}
-
-void GDAPI godot_transform2d_new_axis_origin(godot_transform2d *r_dest, const godot_vector2 *p_x_axis, const godot_vector2 *p_y_axis, const godot_vector2 *p_origin) {
- const Vector2 *x_axis = (const Vector2 *)p_x_axis;
- const Vector2 *y_axis = (const Vector2 *)p_y_axis;
- const Vector2 *origin = (const Vector2 *)p_origin;
- Transform2D *dest = (Transform2D *)r_dest;
- *dest = Transform2D(x_axis->x, x_axis->y, y_axis->x, y_axis->y, origin->x, origin->y);
-}
-
-godot_string GDAPI godot_transform2d_as_string(const godot_transform2d *p_self) {
- godot_string ret;
- const Transform2D *self = (const Transform2D *)p_self;
- memnew_placement(&ret, String(*self));
- return ret;
-}
-
-godot_transform2d GDAPI godot_transform2d_inverse(const godot_transform2d *p_self) {
- godot_transform2d dest;
- const Transform2D *self = (const Transform2D *)p_self;
- *((Transform2D *)&dest) = self->inverse();
- return dest;
-}
-
-godot_transform2d GDAPI godot_transform2d_affine_inverse(const godot_transform2d *p_self) {
- godot_transform2d dest;
- const Transform2D *self = (const Transform2D *)p_self;
- *((Transform2D *)&dest) = self->affine_inverse();
- return dest;
-}
-
-godot_real GDAPI godot_transform2d_get_rotation(const godot_transform2d *p_self) {
- const Transform2D *self = (const Transform2D *)p_self;
- return self->get_rotation();
-}
-
-godot_vector2 GDAPI godot_transform2d_get_origin(const godot_transform2d *p_self) {
- godot_vector2 dest;
- const Transform2D *self = (const Transform2D *)p_self;
- *((Vector2 *)&dest) = self->get_origin();
- return dest;
-}
-
-godot_vector2 GDAPI godot_transform2d_get_scale(const godot_transform2d *p_self) {
- godot_vector2 dest;
- const Transform2D *self = (const Transform2D *)p_self;
- *((Vector2 *)&dest) = self->get_scale();
- return dest;
-}
-
-godot_transform2d GDAPI godot_transform2d_orthonormalized(const godot_transform2d *p_self) {
- godot_transform2d dest;
- const Transform2D *self = (const Transform2D *)p_self;
- *((Transform2D *)&dest) = self->orthonormalized();
- return dest;
-}
-
-godot_transform2d GDAPI godot_transform2d_rotated(const godot_transform2d *p_self, const godot_real p_phi) {
- godot_transform2d dest;
- const Transform2D *self = (const Transform2D *)p_self;
-
- *((Transform2D *)&dest) = self->rotated(p_phi);
- return dest;
-}
-
-godot_transform2d GDAPI godot_transform2d_scaled(const godot_transform2d *p_self, const godot_vector2 *p_scale) {
- godot_transform2d dest;
- const Transform2D *self = (const Transform2D *)p_self;
- const Vector2 *scale = (const Vector2 *)p_scale;
- *((Transform2D *)&dest) = self->scaled(*scale);
- return dest;
-}
-
-godot_transform2d GDAPI godot_transform2d_translated(const godot_transform2d *p_self, const godot_vector2 *p_offset) {
- godot_transform2d dest;
- const Transform2D *self = (const Transform2D *)p_self;
- const Vector2 *offset = (const Vector2 *)p_offset;
- *((Transform2D *)&dest) = self->translated(*offset);
- return dest;
-}
-
-godot_vector2 GDAPI godot_transform2d_xform_vector2(const godot_transform2d *p_self, const godot_vector2 *p_v) {
- godot_vector2 raw_dest;
- Vector2 *dest = (Vector2 *)&raw_dest;
- const Transform2D *self = (const Transform2D *)p_self;
- const Vector2 *v = (const Vector2 *)p_v;
- *dest = self->xform(*v);
- return raw_dest;
-}
-
-godot_vector2 GDAPI godot_transform2d_xform_inv_vector2(const godot_transform2d *p_self, const godot_vector2 *p_v) {
- godot_vector2 raw_dest;
- Vector2 *dest = (Vector2 *)&raw_dest;
- const Transform2D *self = (const Transform2D *)p_self;
- const Vector2 *v = (const Vector2 *)p_v;
- *dest = self->xform_inv(*v);
- return raw_dest;
-}
-
-godot_vector2 GDAPI godot_transform2d_basis_xform_vector2(const godot_transform2d *p_self, const godot_vector2 *p_v) {
- godot_vector2 raw_dest;
- Vector2 *dest = (Vector2 *)&raw_dest;
- const Transform2D *self = (const Transform2D *)p_self;
- const Vector2 *v = (const Vector2 *)p_v;
- *dest = self->basis_xform(*v);
- return raw_dest;
-}
-
-godot_vector2 GDAPI godot_transform2d_basis_xform_inv_vector2(const godot_transform2d *p_self, const godot_vector2 *p_v) {
- godot_vector2 raw_dest;
- Vector2 *dest = (Vector2 *)&raw_dest;
- const Transform2D *self = (const Transform2D *)p_self;
- const Vector2 *v = (const Vector2 *)p_v;
- *dest = self->basis_xform_inv(*v);
- return raw_dest;
-}
-
-godot_transform2d GDAPI godot_transform2d_interpolate_with(const godot_transform2d *p_self, const godot_transform2d *p_m, const godot_real p_c) {
- godot_transform2d dest;
- const Transform2D *self = (const Transform2D *)p_self;
- const Transform2D *m = (const Transform2D *)p_m;
- *((Transform2D *)&dest) = self->interpolate_with(*m, p_c);
- return dest;
-}
-
-godot_bool GDAPI godot_transform2d_operator_equal(const godot_transform2d *p_self, const godot_transform2d *p_b) {
- const Transform2D *self = (const Transform2D *)p_self;
- const Transform2D *b = (const Transform2D *)p_b;
- return *self == *b;
-}
-
-godot_transform2d GDAPI godot_transform2d_operator_multiply(const godot_transform2d *p_self, const godot_transform2d *p_b) {
- godot_transform2d raw_dest;
- Transform2D *dest = (Transform2D *)&raw_dest;
- const Transform2D *self = (const Transform2D *)p_self;
- const Transform2D *b = (const Transform2D *)p_b;
- *dest = *self * *b;
- return raw_dest;
-}
-
-void GDAPI godot_transform2d_new_identity(godot_transform2d *r_dest) {
- Transform2D *dest = (Transform2D *)r_dest;
- *dest = Transform2D();
-}
-
-godot_rect2 GDAPI godot_transform2d_xform_rect2(const godot_transform2d *p_self, const godot_rect2 *p_v) {
- godot_rect2 raw_dest;
- Rect2 *dest = (Rect2 *)&raw_dest;
- const Transform2D *self = (const Transform2D *)p_self;
- const Rect2 *v = (const Rect2 *)p_v;
- *dest = self->xform(*v);
- return raw_dest;
-}
-
-godot_rect2 GDAPI godot_transform2d_xform_inv_rect2(const godot_transform2d *p_self, const godot_rect2 *p_v) {
- godot_rect2 raw_dest;
- Rect2 *dest = (Rect2 *)&raw_dest;
- const Transform2D *self = (const Transform2D *)p_self;
- const Rect2 *v = (const Rect2 *)p_v;
- *dest = self->xform_inv(*v);
- return raw_dest;
+void GDAPI godot_transform2d_new(godot_transform2d *p_self) {
+ memnew_placement(p_self, Transform2D);
}
#ifdef __cplusplus
diff --git a/modules/gdnative/gdnative/variant.cpp b/modules/gdnative/gdnative/variant.cpp
index dac4feb0e5..79f5a536e5 100644
--- a/modules/gdnative/gdnative/variant.cpp
+++ b/modules/gdnative/gdnative/variant.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,8 +30,8 @@
#include "gdnative/variant.h"
-#include "core/reference.h"
-#include "core/variant.h"
+#include "core/object/reference.h"
+#include "core/variant/variant.h"
#ifdef __cplusplus
extern "C" {
@@ -55,16 +55,11 @@ static_assert(sizeof(godot_variant) == sizeof(Variant), "Variant size mismatch")
#pragma GCC pop_options
#endif
-// Constructors
-
-godot_variant_type GDAPI godot_variant_get_type(const godot_variant *p_self) {
- const Variant *self = (const Variant *)p_self;
- return (godot_variant_type)self->get_type();
-}
+// Memory
void GDAPI godot_variant_new_copy(godot_variant *p_dest, const godot_variant *p_src) {
Variant *dest = (Variant *)p_dest;
- Variant *src = (Variant *)p_src;
+ const Variant *src = (const Variant *)p_src;
memnew_placement(dest, Variant(*src));
}
@@ -78,139 +73,134 @@ void GDAPI godot_variant_new_bool(godot_variant *r_dest, const godot_bool p_b) {
memnew_placement_custom(dest, Variant, Variant(p_b));
}
-void GDAPI godot_variant_new_uint(godot_variant *r_dest, const uint64_t p_i) {
+void GDAPI godot_variant_new_int(godot_variant *r_dest, const godot_int p_i) {
Variant *dest = (Variant *)r_dest;
memnew_placement_custom(dest, Variant, Variant(p_i));
}
-void GDAPI godot_variant_new_int(godot_variant *r_dest, const int64_t p_i) {
- Variant *dest = (Variant *)r_dest;
- memnew_placement_custom(dest, Variant, Variant(p_i));
-}
-
-void GDAPI godot_variant_new_real(godot_variant *r_dest, const double p_r) {
+void GDAPI godot_variant_new_float(godot_variant *r_dest, const godot_float p_r) {
Variant *dest = (Variant *)r_dest;
memnew_placement_custom(dest, Variant, Variant(p_r));
}
void GDAPI godot_variant_new_string(godot_variant *r_dest, const godot_string *p_s) {
Variant *dest = (Variant *)r_dest;
- String *s = (String *)p_s;
+ const String *s = (const String *)p_s;
memnew_placement_custom(dest, Variant, Variant(*s));
}
void GDAPI godot_variant_new_string_name(godot_variant *r_dest, const godot_string_name *p_s) {
Variant *dest = (Variant *)r_dest;
- StringName *s = (StringName *)p_s;
+ const StringName *s = (const StringName *)p_s;
memnew_placement_custom(dest, Variant, Variant(*s));
}
void GDAPI godot_variant_new_vector2(godot_variant *r_dest, const godot_vector2 *p_v2) {
Variant *dest = (Variant *)r_dest;
- Vector2 *v2 = (Vector2 *)p_v2;
+ const Vector2 *v2 = (const Vector2 *)p_v2;
memnew_placement_custom(dest, Variant, Variant(*v2));
}
void GDAPI godot_variant_new_vector2i(godot_variant *r_dest, const godot_vector2i *p_v2) {
Variant *dest = (Variant *)r_dest;
- Vector2i *v2 = (Vector2i *)p_v2;
+ const Vector2i *v2 = (const Vector2i *)p_v2;
memnew_placement_custom(dest, Variant, Variant(*v2));
}
void GDAPI godot_variant_new_rect2(godot_variant *r_dest, const godot_rect2 *p_rect2) {
Variant *dest = (Variant *)r_dest;
- Rect2 *rect2 = (Rect2 *)p_rect2;
+ const Rect2 *rect2 = (const Rect2 *)p_rect2;
memnew_placement_custom(dest, Variant, Variant(*rect2));
}
void GDAPI godot_variant_new_rect2i(godot_variant *r_dest, const godot_rect2i *p_rect2) {
Variant *dest = (Variant *)r_dest;
- Rect2i *rect2 = (Rect2i *)p_rect2;
+ const Rect2i *rect2 = (const Rect2i *)p_rect2;
memnew_placement_custom(dest, Variant, Variant(*rect2));
}
void GDAPI godot_variant_new_vector3(godot_variant *r_dest, const godot_vector3 *p_v3) {
Variant *dest = (Variant *)r_dest;
- Vector3 *v3 = (Vector3 *)p_v3;
+ const Vector3 *v3 = (const Vector3 *)p_v3;
memnew_placement_custom(dest, Variant, Variant(*v3));
}
void GDAPI godot_variant_new_vector3i(godot_variant *r_dest, const godot_vector3i *p_v3) {
Variant *dest = (Variant *)r_dest;
- Vector3i *v3 = (Vector3i *)p_v3;
+ const Vector3i *v3 = (const Vector3i *)p_v3;
memnew_placement_custom(dest, Variant, Variant(*v3));
}
void GDAPI godot_variant_new_transform2d(godot_variant *r_dest, const godot_transform2d *p_t2d) {
Variant *dest = (Variant *)r_dest;
- Transform2D *t2d = (Transform2D *)p_t2d;
+ const Transform2D *t2d = (const Transform2D *)p_t2d;
memnew_placement_custom(dest, Variant, Variant(*t2d));
}
void GDAPI godot_variant_new_plane(godot_variant *r_dest, const godot_plane *p_plane) {
Variant *dest = (Variant *)r_dest;
- Plane *plane = (Plane *)p_plane;
+ const Plane *plane = (const Plane *)p_plane;
memnew_placement_custom(dest, Variant, Variant(*plane));
}
void GDAPI godot_variant_new_quat(godot_variant *r_dest, const godot_quat *p_quat) {
Variant *dest = (Variant *)r_dest;
- Quat *quat = (Quat *)p_quat;
+ const Quat *quat = (const Quat *)p_quat;
memnew_placement_custom(dest, Variant, Variant(*quat));
}
void GDAPI godot_variant_new_aabb(godot_variant *r_dest, const godot_aabb *p_aabb) {
Variant *dest = (Variant *)r_dest;
- AABB *aabb = (AABB *)p_aabb;
+ const AABB *aabb = (const AABB *)p_aabb;
memnew_placement_custom(dest, Variant, Variant(*aabb));
}
void GDAPI godot_variant_new_basis(godot_variant *r_dest, const godot_basis *p_basis) {
Variant *dest = (Variant *)r_dest;
- Basis *basis = (Basis *)p_basis;
+ const Basis *basis = (const Basis *)p_basis;
memnew_placement_custom(dest, Variant, Variant(*basis));
}
void GDAPI godot_variant_new_transform(godot_variant *r_dest, const godot_transform *p_trans) {
Variant *dest = (Variant *)r_dest;
- Transform *trans = (Transform *)p_trans;
+ const Transform *trans = (const Transform *)p_trans;
memnew_placement_custom(dest, Variant, Variant(*trans));
}
void GDAPI godot_variant_new_color(godot_variant *r_dest, const godot_color *p_color) {
Variant *dest = (Variant *)r_dest;
- Color *color = (Color *)p_color;
+ const Color *color = (const Color *)p_color;
memnew_placement_custom(dest, Variant, Variant(*color));
}
void GDAPI godot_variant_new_node_path(godot_variant *r_dest, const godot_node_path *p_np) {
Variant *dest = (Variant *)r_dest;
- NodePath *np = (NodePath *)p_np;
+ const NodePath *np = (const NodePath *)p_np;
memnew_placement_custom(dest, Variant, Variant(*np));
}
void GDAPI godot_variant_new_rid(godot_variant *r_dest, const godot_rid *p_rid) {
Variant *dest = (Variant *)r_dest;
- RID *rid = (RID *)p_rid;
+ const RID *rid = (const RID *)p_rid;
memnew_placement_custom(dest, Variant, Variant(*rid));
}
void GDAPI godot_variant_new_callable(godot_variant *r_dest, const godot_callable *p_cb) {
Variant *dest = (Variant *)r_dest;
- Callable *cb = (Callable *)p_cb;
+ const Callable *cb = (const Callable *)p_cb;
memnew_placement_custom(dest, Variant, Variant(*cb));
}
void GDAPI godot_variant_new_signal(godot_variant *r_dest, const godot_signal *p_signal) {
Variant *dest = (Variant *)r_dest;
- Signal *signal = (Signal *)p_signal;
+ const Signal *signal = (const Signal *)p_signal;
memnew_placement_custom(dest, Variant, Variant(*signal));
}
void GDAPI godot_variant_new_object(godot_variant *r_dest, const godot_object *p_obj) {
Variant *dest = (Variant *)r_dest;
- Object *obj = (Object *)p_obj;
- Reference *reference = Object::cast_to<Reference>(obj);
+ const Object *obj = (const Object *)p_obj;
+ const Reference *reference = Object::cast_to<Reference>(obj);
REF ref;
if (reference) {
ref = REF(reference);
@@ -229,67 +219,67 @@ void GDAPI godot_variant_new_object(godot_variant *r_dest, const godot_object *p
void GDAPI godot_variant_new_dictionary(godot_variant *r_dest, const godot_dictionary *p_dict) {
Variant *dest = (Variant *)r_dest;
- Dictionary *dict = (Dictionary *)p_dict;
+ const Dictionary *dict = (const Dictionary *)p_dict;
memnew_placement_custom(dest, Variant, Variant(*dict));
}
void GDAPI godot_variant_new_array(godot_variant *r_dest, const godot_array *p_arr) {
Variant *dest = (Variant *)r_dest;
- Array *arr = (Array *)p_arr;
+ const Array *arr = (const Array *)p_arr;
memnew_placement_custom(dest, Variant, Variant(*arr));
}
void GDAPI godot_variant_new_packed_byte_array(godot_variant *r_dest, const godot_packed_byte_array *p_pba) {
Variant *dest = (Variant *)r_dest;
- PackedByteArray *pba = (PackedByteArray *)p_pba;
+ const PackedByteArray *pba = (const PackedByteArray *)p_pba;
memnew_placement_custom(dest, Variant, Variant(*pba));
}
void GDAPI godot_variant_new_packed_int32_array(godot_variant *r_dest, const godot_packed_int32_array *p_pia) {
Variant *dest = (Variant *)r_dest;
- PackedInt32Array *pia = (PackedInt32Array *)p_pia;
+ const PackedInt32Array *pia = (const PackedInt32Array *)p_pia;
memnew_placement_custom(dest, Variant, Variant(*pia));
}
void GDAPI godot_variant_new_packed_int64_array(godot_variant *r_dest, const godot_packed_int64_array *p_pia) {
Variant *dest = (Variant *)r_dest;
- PackedInt64Array *pia = (PackedInt64Array *)p_pia;
+ const PackedInt64Array *pia = (const PackedInt64Array *)p_pia;
memnew_placement_custom(dest, Variant, Variant(*pia));
}
void GDAPI godot_variant_new_packed_float32_array(godot_variant *r_dest, const godot_packed_float32_array *p_pra) {
Variant *dest = (Variant *)r_dest;
- PackedFloat32Array *pra = (PackedFloat32Array *)p_pra;
+ const PackedFloat32Array *pra = (const PackedFloat32Array *)p_pra;
memnew_placement_custom(dest, Variant, Variant(*pra));
}
void GDAPI godot_variant_new_packed_float64_array(godot_variant *r_dest, const godot_packed_float64_array *p_pra) {
Variant *dest = (Variant *)r_dest;
- PackedFloat64Array *pra = (PackedFloat64Array *)p_pra;
+ const PackedFloat64Array *pra = (const PackedFloat64Array *)p_pra;
memnew_placement_custom(dest, Variant, Variant(*pra));
}
void GDAPI godot_variant_new_packed_string_array(godot_variant *r_dest, const godot_packed_string_array *p_psa) {
Variant *dest = (Variant *)r_dest;
- PackedStringArray *psa = (PackedStringArray *)p_psa;
+ const PackedStringArray *psa = (const PackedStringArray *)p_psa;
memnew_placement_custom(dest, Variant, Variant(*psa));
}
void GDAPI godot_variant_new_packed_vector2_array(godot_variant *r_dest, const godot_packed_vector2_array *p_pv2a) {
Variant *dest = (Variant *)r_dest;
- PackedVector2Array *pv2a = (PackedVector2Array *)p_pv2a;
+ const PackedVector2Array *pv2a = (const PackedVector2Array *)p_pv2a;
memnew_placement_custom(dest, Variant, Variant(*pv2a));
}
void GDAPI godot_variant_new_packed_vector3_array(godot_variant *r_dest, const godot_packed_vector3_array *p_pv3a) {
Variant *dest = (Variant *)r_dest;
- PackedVector3Array *pv3a = (PackedVector3Array *)p_pv3a;
+ const PackedVector3Array *pv3a = (const PackedVector3Array *)p_pv3a;
memnew_placement_custom(dest, Variant, Variant(*pv3a));
}
void GDAPI godot_variant_new_packed_color_array(godot_variant *r_dest, const godot_packed_color_array *p_pca) {
Variant *dest = (Variant *)r_dest;
- PackedColorArray *pca = (PackedColorArray *)p_pca;
+ const PackedColorArray *pca = (const PackedColorArray *)p_pca;
memnew_placement_custom(dest, Variant, Variant(*pca));
}
@@ -298,17 +288,12 @@ godot_bool GDAPI godot_variant_as_bool(const godot_variant *p_self) {
return self->operator bool();
}
-uint64_t GDAPI godot_variant_as_uint(const godot_variant *p_self) {
- const Variant *self = (const Variant *)p_self;
- return self->operator uint64_t();
-}
-
-int64_t GDAPI godot_variant_as_int(const godot_variant *p_self) {
+godot_int GDAPI godot_variant_as_int(const godot_variant *p_self) {
const Variant *self = (const Variant *)p_self;
return self->operator int64_t();
}
-double GDAPI godot_variant_as_real(const godot_variant *p_self) {
+godot_float GDAPI godot_variant_as_float(const godot_variant *p_self) {
const Variant *self = (const Variant *)p_self;
return self->operator double();
}
@@ -569,45 +554,137 @@ godot_packed_color_array GDAPI godot_variant_as_packed_color_array(const godot_v
return raw_dest;
}
-godot_variant GDAPI godot_variant_call(godot_variant *p_self, const godot_string *p_method, const godot_variant **p_args, const godot_int p_argcount, godot_variant_call_error *r_error) {
+void GDAPI godot_variant_destroy(godot_variant *p_self) {
Variant *self = (Variant *)p_self;
- String *method = (String *)p_method;
+ self->~Variant();
+}
+
+// Dynamic interaction.
+
+void GDAPI godot_variant_call(godot_variant *p_self, const godot_string_name *p_method, const godot_variant **p_args, const godot_int p_argcount, godot_variant *r_return, godot_variant_call_error *r_error) {
+ Variant *self = (Variant *)p_self;
+ const StringName *method = (const StringName *)p_method;
const Variant **args = (const Variant **)p_args;
- godot_variant raw_dest;
- Variant *dest = (Variant *)&raw_dest;
+ Variant ret;
Callable::CallError error;
- memnew_placement_custom(dest, Variant, Variant(self->call(*method, args, p_argcount, error)));
+ self->call(*method, args, p_argcount, ret, error);
+ memnew_placement_custom(r_return, Variant, Variant(ret));
+
if (r_error) {
r_error->error = (godot_variant_call_error_error)error.error;
r_error->argument = error.argument;
r_error->expected = (godot_variant_type)error.expected;
}
- return raw_dest;
}
-godot_bool GDAPI godot_variant_has_method(const godot_variant *p_self, const godot_string *p_method) {
+void GDAPI godot_variant_evaluate(godot_variant_operator p_op, const godot_variant *p_a, const godot_variant *p_b, godot_variant *r_return, bool *r_valid) {
+ Variant::Operator op = (Variant::Operator)p_op;
+ const Variant *a = (const Variant *)p_a;
+ const Variant *b = (const Variant *)p_b;
+ Variant *ret = (Variant *)r_return;
+ Variant::evaluate(op, *a, *b, *ret, *r_valid);
+}
+
+void GDAPI godot_variant_set(godot_variant *p_self, const godot_variant *p_key, const godot_variant *p_value, bool *r_valid) {
+ Variant *self = (Variant *)p_self;
+ const Variant *key = (const Variant *)p_key;
+ const Variant *value = (const Variant *)p_value;
+
+ self->set(*key, *value, r_valid);
+}
+
+void GDAPI godot_variant_set_named(godot_variant *p_self, const godot_string_name *p_name, const godot_variant *p_value, bool *r_valid) {
+ Variant *self = (Variant *)p_self;
+ const StringName *name = (const StringName *)p_name;
+ const Variant *value = (const Variant *)p_value;
+
+ self->set_named(*name, *value, *r_valid);
+}
+
+void GDAPI godot_variant_set_keyed(godot_variant *p_self, const godot_variant *p_key, const godot_variant *p_value, bool *r_valid) {
+ Variant *self = (Variant *)p_self;
+ const Variant *key = (const Variant *)p_key;
+ const Variant *value = (const Variant *)p_value;
+
+ self->set_keyed(*key, *value, *r_valid);
+}
+
+void GDAPI godot_variant_set_indexed(godot_variant *p_self, godot_int p_index, const godot_variant *p_value, bool *r_valid, bool *r_oob) {
+ Variant *self = (Variant *)p_self;
+ const Variant *value = (const Variant *)p_value;
+
+ self->set_indexed(p_index, value, *r_valid, *r_oob);
+}
+
+godot_variant GDAPI godot_variant_get(const godot_variant *p_self, const godot_variant *p_key, bool *r_valid) {
const Variant *self = (const Variant *)p_self;
- const String *method = (const String *)p_method;
- return self->has_method(*method);
+ const Variant *key = (const Variant *)p_key;
+ Variant ret;
+
+ ret = self->get(*key, r_valid);
+ godot_variant result;
+ memnew_placement_custom(&result, Variant, Variant(ret));
+ return result;
}
-godot_bool GDAPI godot_variant_operator_equal(const godot_variant *p_self, const godot_variant *p_other) {
+godot_variant GDAPI godot_variant_get_named(const godot_variant *p_self, const godot_string_name *p_key, bool *r_valid) {
const Variant *self = (const Variant *)p_self;
- const Variant *other = (const Variant *)p_other;
- return self->operator==(*other);
+ const StringName *key = (const StringName *)p_key;
+ Variant ret;
+
+ ret = self->get_named(*key, *r_valid);
+ godot_variant result;
+ memnew_placement_custom(&result, Variant, Variant(ret));
+ return result;
}
-godot_bool GDAPI godot_variant_operator_less(const godot_variant *p_self, const godot_variant *p_other) {
+godot_variant GDAPI godot_variant_get_keyed(const godot_variant *p_self, const godot_variant *p_key, bool *r_valid) {
const Variant *self = (const Variant *)p_self;
- const Variant *other = (const Variant *)p_other;
- return self->operator<(*other);
+ const Variant *key = (const Variant *)p_key;
+ Variant ret;
+
+ ret = self->get_keyed(*key, *r_valid);
+ godot_variant result;
+ memnew_placement_custom(&result, Variant, Variant(ret));
+ return result;
}
-uint32_t GDAPI godot_variant_hash(const godot_variant *p_self) {
+godot_variant GDAPI godot_variant_get_indexed(const godot_variant *p_self, godot_int p_index, bool *r_valid, bool *r_oob) {
const Variant *self = (const Variant *)p_self;
- return self->hash();
+ Variant ret;
+
+ ret = self->get_indexed(p_index, *r_valid, *r_oob);
+ godot_variant result;
+ memnew_placement_custom(&result, Variant, Variant(ret));
+ return result;
+}
+
+/// Iteration.
+bool GDAPI godot_variant_iter_init(const godot_variant *p_self, godot_variant *r_iter, bool *r_valid) {
+ const Variant *self = (const Variant *)p_self;
+ Variant *iter = (Variant *)r_iter;
+
+ return self->iter_init(*iter, *r_valid);
+}
+
+bool GDAPI godot_variant_iter_next(const godot_variant *p_self, godot_variant *r_iter, bool *r_valid) {
+ const Variant *self = (const Variant *)p_self;
+ Variant *iter = (Variant *)r_iter;
+
+ return self->iter_next(*iter, *r_valid);
}
+godot_variant GDAPI godot_variant_iter_get(const godot_variant *p_self, godot_variant *r_iter, bool *r_valid) {
+ const Variant *self = (const Variant *)p_self;
+ Variant *iter = (Variant *)r_iter;
+
+ Variant result = self->iter_next(*iter, *r_valid);
+ godot_variant ret;
+ memnew_placement_custom(&ret, Variant, Variant(result));
+ return ret;
+}
+
+/// Variant functions.
godot_bool GDAPI godot_variant_hash_compare(const godot_variant *p_self, const godot_variant *p_other) {
const Variant *self = (const Variant *)p_self;
const Variant *other = (const Variant *)p_other;
@@ -619,27 +696,487 @@ godot_bool GDAPI godot_variant_booleanize(const godot_variant *p_self) {
return self->booleanize();
}
-void GDAPI godot_variant_destroy(godot_variant *p_self) {
- Variant *self = (Variant *)p_self;
- self->~Variant();
+void GDAPI godot_variant_blend(const godot_variant *p_a, const godot_variant *p_b, float p_c, godot_variant *r_dst) {
+ const Variant *a = (const Variant *)p_a;
+ const Variant *b = (const Variant *)p_b;
+ Variant *dst = (Variant *)r_dst;
+ Variant::blend(*a, *b, p_c, *dst);
}
-// GDNative core 1.1
+void GDAPI godot_variant_interpolate(const godot_variant *p_a, const godot_variant *p_b, float p_c, godot_variant *r_dst) {
+ const Variant *a = (const Variant *)p_a;
+ const Variant *b = (const Variant *)p_b;
+ Variant *dst = (Variant *)r_dst;
+ Variant::interpolate(*a, *b, p_c, *dst);
+}
-godot_string GDAPI godot_variant_get_operator_name(godot_variant_operator p_op) {
- Variant::Operator op = (Variant::Operator)p_op;
- godot_string raw_dest;
- String *dest = (String *)&raw_dest;
- memnew_placement(dest, String(Variant::get_operator_name(op))); // operator = is overloaded by String
- return raw_dest;
+godot_variant GDAPI godot_variant_duplicate(const godot_variant *p_self, godot_bool p_deep) {
+ const Variant *self = (const Variant *)p_self;
+ Variant result = self->duplicate(p_deep);
+ godot_variant ret;
+ memnew_placement_custom(&ret, Variant, Variant(result));
+ return ret;
}
-void GDAPI godot_variant_evaluate(godot_variant_operator p_op, const godot_variant *p_a, const godot_variant *p_b, godot_variant *r_ret, godot_bool *r_valid) {
- Variant::Operator op = (Variant::Operator)p_op;
- const Variant *a = (const Variant *)p_a;
- const Variant *b = (const Variant *)p_b;
+godot_string GDAPI godot_variant_stringify(const godot_variant *p_self) {
+ const Variant *self = (const Variant *)p_self;
+ String result = *self;
+ godot_string ret;
+ memnew_placement_custom(&ret, String, String(result));
+ return ret;
+}
+
+// Discovery API
+
+/// Operators
+godot_validated_operator_evaluator GDAPI godot_variant_get_validated_operator_evaluator(godot_variant_operator p_operator, godot_variant_type p_type_a, godot_variant_type p_type_b) {
+ return (godot_validated_operator_evaluator)Variant::get_validated_operator_evaluator((Variant::Operator)p_operator, (Variant::Type)p_type_a, (Variant::Type)p_type_b);
+}
+
+godot_ptr_operator_evaluator GDAPI godot_variant_get_ptr_operator_evaluator(godot_variant_operator p_operator, godot_variant_type p_type_a, godot_variant_type p_type_b) {
+ return (godot_ptr_operator_evaluator)Variant::get_ptr_operator_evaluator((Variant::Operator)p_operator, (Variant::Type)p_type_a, (Variant::Type)p_type_b);
+}
+
+godot_variant_type GDAPI godot_variant_get_operator_return_type(godot_variant_operator p_operator, godot_variant_type p_type_a, godot_variant_type p_type_b) {
+ return (godot_variant_type)Variant::get_operator_return_type((Variant::Operator)p_operator, (Variant::Type)p_type_a, (Variant::Type)p_type_b);
+}
+
+godot_string GDAPI godot_variant_get_operator_name(godot_variant_operator p_operator) {
+ String op_name = Variant::get_operator_name((Variant::Operator)p_operator);
+ godot_string ret;
+ memnew_placement_custom(&ret, String, String(op_name));
+ return ret;
+}
+
+/// Built-in Methods
+
+bool GDAPI godot_variant_has_builtin_method(godot_variant_type p_type, const godot_string_name *p_method) {
+ return Variant::has_builtin_method((Variant::Type)p_type, *((const StringName *)p_method));
+}
+
+bool GDAPI godot_variant_has_builtin_method_with_cstring(godot_variant_type p_type, const char *p_method) {
+ return Variant::has_builtin_method((Variant::Type)p_type, StringName(p_method));
+}
+
+godot_validated_builtin_method GDAPI godot_variant_get_validated_builtin_method(godot_variant_type p_type, const godot_string_name *p_method) {
+ return (godot_validated_builtin_method)Variant::get_validated_builtin_method((Variant::Type)p_type, *((const StringName *)p_method));
+}
+
+godot_validated_builtin_method GDAPI godot_variant_get_validated_builtin_method_with_cstring(godot_variant_type p_type, const char *p_method) {
+ return (godot_validated_builtin_method)Variant::get_validated_builtin_method((Variant::Type)p_type, StringName(p_method));
+}
+
+godot_ptr_builtin_method GDAPI godot_variant_get_ptr_builtin_method(godot_variant_type p_type, const godot_string_name *p_method) {
+ return (godot_ptr_builtin_method)Variant::get_ptr_builtin_method((Variant::Type)p_type, *((const StringName *)p_method));
+}
+
+godot_ptr_builtin_method GDAPI godot_variant_get_ptr_builtin_method_with_cstring(godot_variant_type p_type, const char *p_method) {
+ return (godot_ptr_builtin_method)Variant::get_ptr_builtin_method((Variant::Type)p_type, StringName(p_method));
+}
+
+int GDAPI godot_variant_get_builtin_method_argument_count(godot_variant_type p_type, const godot_string_name *p_method) {
+ return Variant::get_builtin_method_argument_count((Variant::Type)p_type, *((const StringName *)p_method));
+}
+
+int GDAPI godot_variant_get_builtin_method_argument_count_with_cstring(godot_variant_type p_type, const char *p_method) {
+ return Variant::get_builtin_method_argument_count((Variant::Type)p_type, StringName(p_method));
+}
+
+godot_variant_type GDAPI godot_variant_get_builtin_method_argument_type(godot_variant_type p_type, const godot_string_name *p_method, int p_argument) {
+ return (godot_variant_type)Variant::get_builtin_method_argument_type((Variant::Type)p_type, *((const StringName *)p_method), p_argument);
+}
+
+godot_variant_type GDAPI godot_variant_get_builtin_method_argument_type_with_cstring(godot_variant_type p_type, const char *p_method, int p_argument) {
+ return (godot_variant_type)Variant::get_builtin_method_argument_type((Variant::Type)p_type, StringName(p_method), p_argument);
+}
+
+godot_string GDAPI godot_variant_get_builtin_method_argument_name(godot_variant_type p_type, const godot_string_name *p_method, int p_argument) {
+ String name = Variant::get_builtin_method_argument_name((Variant::Type)p_type, *((const StringName *)p_method), p_argument);
+ return *(godot_string *)&name;
+}
+
+godot_string GDAPI godot_variant_get_builtin_method_argument_name_with_cstring(godot_variant_type p_type, const char *p_method, int p_argument) {
+ String name = Variant::get_builtin_method_argument_name((Variant::Type)p_type, StringName(p_method), p_argument);
+ return *(godot_string *)&name;
+}
+
+bool GDAPI godot_variant_has_builtin_method_return_value(godot_variant_type p_type, const godot_string_name *p_method) {
+ return Variant::has_builtin_method_return_value((Variant::Type)p_type, *((const StringName *)p_method));
+}
+
+bool GDAPI godot_variant_has_builtin_method_return_value_with_cstring(godot_variant_type p_type, const char *p_method) {
+ return Variant::has_builtin_method_return_value((Variant::Type)p_type, StringName(p_method));
+}
+
+godot_variant_type GDAPI godot_variant_get_builtin_method_return_type(godot_variant_type p_type, const godot_string_name *p_method) {
+ return (godot_variant_type)Variant::get_builtin_method_return_type((Variant::Type)p_type, *((const StringName *)p_method));
+}
+
+godot_variant_type GDAPI godot_variant_get_builtin_method_return_type_with_cstring(godot_variant_type p_type, const char *p_method) {
+ return (godot_variant_type)Variant::get_builtin_method_return_type((Variant::Type)p_type, StringName(p_method));
+}
+
+bool GDAPI godot_variant_is_builtin_method_const(godot_variant_type p_type, const godot_string_name *p_method) {
+ return Variant::is_builtin_method_const((Variant::Type)p_type, *((const StringName *)p_method));
+}
+
+bool GDAPI godot_variant_is_builtin_method_const_with_cstring(godot_variant_type p_type, const char *p_method) {
+ return Variant::is_builtin_method_const((Variant::Type)p_type, StringName(p_method));
+}
+
+bool GDAPI godot_variant_is_builtin_method_vararg(godot_variant_type p_type, const godot_string_name *p_method) {
+ return Variant::is_builtin_method_vararg((Variant::Type)p_type, *((const StringName *)p_method));
+}
+
+bool GDAPI godot_variant_is_builtin_method_vararg_with_cstring(godot_variant_type p_type, const char *p_method) {
+ return Variant::is_builtin_method_vararg((Variant::Type)p_type, StringName(p_method));
+}
+
+int GDAPI godot_variant_get_builtin_method_count(godot_variant_type p_type) {
+ return Variant::get_builtin_method_count((Variant::Type)p_type);
+}
+
+void GDAPI godot_variant_get_builtin_method_list(godot_variant_type p_type, godot_string_name *r_list) {
+ List<StringName> list;
+ Variant::get_builtin_method_list((Variant::Type)p_type, &list);
+ int i = 0;
+ for (const List<StringName>::Element *E = list.front(); E; E = E->next()) {
+ memnew_placement_custom(&r_list[i], StringName, StringName(E->get()));
+ }
+}
+
+/// Constructors
+
+int GDAPI godot_variant_get_constructor_count(godot_variant_type p_type) {
+ return Variant::get_constructor_count((Variant::Type)p_type);
+}
+
+godot_validated_constructor GDAPI godot_variant_get_validated_constructor(godot_variant_type p_type, int p_constructor) {
+ return (godot_validated_constructor)Variant::get_validated_constructor((Variant::Type)p_type, p_constructor);
+}
+
+godot_ptr_constructor GDAPI godot_variant_get_ptr_constructor(godot_variant_type p_type, int p_constructor) {
+ return (godot_ptr_constructor)Variant::get_ptr_constructor((Variant::Type)p_type, p_constructor);
+}
+
+int GDAPI godot_variant_get_constructor_argument_count(godot_variant_type p_type, int p_constructor) {
+ return Variant::get_constructor_argument_count((Variant::Type)p_type, p_constructor);
+}
+
+godot_variant_type GDAPI godot_variant_get_constructor_argument_type(godot_variant_type p_type, int p_constructor, int p_argument) {
+ return (godot_variant_type)Variant::get_constructor_argument_type((Variant::Type)p_type, p_constructor, p_argument);
+}
+
+godot_string GDAPI godot_variant_get_constructor_argument_name(godot_variant_type p_type, int p_constructor, int p_argument) {
+ String name = Variant::get_constructor_argument_name((Variant::Type)p_type, p_constructor, p_argument);
+ godot_string ret;
+ memnew_placement(&ret, String(name));
+ return ret;
+}
+
+void GDAPI godot_variant_construct(godot_variant_type p_type, godot_variant *p_base, const godot_variant **p_args, int p_argcount, godot_variant_call_error *r_error) {
+ Variant::construct((Variant::Type)p_type, *((Variant *)p_base), (const Variant **)p_args, p_argcount, *((Callable::CallError *)r_error));
+}
+
+/// Properties.
+godot_variant_type GDAPI godot_variant_get_member_type(godot_variant_type p_type, const godot_string_name *p_member) {
+ return (godot_variant_type)Variant::get_member_type((Variant::Type)p_type, *((const StringName *)p_member));
+}
+
+godot_variant_type GDAPI godot_variant_get_member_type_with_cstring(godot_variant_type p_type, const char *p_member) {
+ return (godot_variant_type)Variant::get_member_type((Variant::Type)p_type, StringName(p_member));
+}
+
+int GDAPI godot_variant_get_member_count(godot_variant_type p_type) {
+ return Variant::get_member_count((Variant::Type)p_type);
+}
+
+void GDAPI godot_variant_get_member_list(godot_variant_type p_type, godot_string_name *r_list) {
+ List<StringName> members;
+ Variant::get_member_list((Variant::Type)p_type, &members);
+ int i = 0;
+ for (const List<StringName>::Element *E = members.front(); E; E = E->next()) {
+ memnew_placement_custom(&r_list[i++], StringName, StringName(E->get()));
+ }
+}
+
+godot_validated_setter GDAPI godot_variant_get_validated_setter(godot_variant_type p_type, const godot_string_name *p_member) {
+ return (godot_validated_setter)Variant::get_member_validated_setter((Variant::Type)p_type, *((const StringName *)p_member));
+}
+
+godot_validated_setter GDAPI godot_variant_get_validated_setter_with_cstring(godot_variant_type p_type, const char *p_member) {
+ return (godot_validated_setter)Variant::get_member_validated_setter((Variant::Type)p_type, StringName(p_member));
+}
+
+godot_validated_getter GDAPI godot_variant_get_validated_getter(godot_variant_type p_type, const godot_string_name *p_member) {
+ return (godot_validated_getter)Variant::get_member_validated_getter((Variant::Type)p_type, *((const StringName *)p_member));
+}
+
+godot_validated_getter GDAPI godot_variant_get_validated_getter_with_cstring(godot_variant_type p_type, const char *p_member) {
+ return (godot_validated_getter)Variant::get_member_validated_getter((Variant::Type)p_type, StringName(p_member));
+}
+
+godot_ptr_setter GDAPI godot_variant_get_ptr_setter(godot_variant_type p_type, const godot_string_name *p_member) {
+ return (godot_ptr_setter)Variant::get_member_ptr_setter((Variant::Type)p_type, *((const StringName *)p_member));
+}
+
+godot_ptr_setter GDAPI godot_variant_get_ptr_setter_with_cstring(godot_variant_type p_type, const char *p_member) {
+ return (godot_ptr_setter)Variant::get_member_ptr_setter((Variant::Type)p_type, StringName(p_member));
+}
+
+godot_ptr_getter GDAPI godot_variant_get_ptr_getter(godot_variant_type p_type, const godot_string_name *p_member) {
+ return (godot_ptr_getter)Variant::get_member_ptr_getter((Variant::Type)p_type, *((const StringName *)p_member));
+}
+
+godot_ptr_getter GDAPI godot_variant_get_ptr_getter_with_cstring(godot_variant_type p_type, const char *p_member) {
+ return (godot_ptr_getter)Variant::get_member_ptr_getter((Variant::Type)p_type, StringName(p_member));
+}
+
+/// Indexing.
+bool GDAPI godot_variant_has_indexing(godot_variant_type p_type) {
+ return Variant::has_indexing((Variant::Type)p_type);
+}
+
+godot_variant_type GDAPI godot_variant_get_indexed_element_type(godot_variant_type p_type) {
+ return (godot_variant_type)Variant::get_indexed_element_type((Variant::Type)p_type);
+}
+
+godot_validated_indexed_setter GDAPI godot_variant_get_validated_indexed_setter(godot_variant_type p_type) {
+ return (godot_validated_indexed_setter)Variant::get_member_validated_indexed_setter((Variant::Type)p_type);
+}
+
+godot_validated_indexed_getter GDAPI godot_variant_get_validated_indexed_getter(godot_variant_type p_type) {
+ return (godot_validated_indexed_getter)Variant::get_member_validated_indexed_getter((Variant::Type)p_type);
+}
+
+godot_ptr_indexed_setter GDAPI godot_variant_get_ptr_indexed_setter(godot_variant_type p_type) {
+ return (godot_ptr_indexed_setter)Variant::get_member_ptr_indexed_setter((Variant::Type)p_type);
+}
+
+godot_ptr_indexed_getter GDAPI godot_variant_get_ptr_indexed_getter(godot_variant_type p_type) {
+ return (godot_ptr_indexed_getter)Variant::get_member_ptr_indexed_getter((Variant::Type)p_type);
+}
+
+uint64_t GDAPI godot_variant_get_indexed_size(const godot_variant *p_self) {
+ const Variant *self = (const Variant *)p_self;
+ return self->get_indexed_size();
+}
+
+/// Keying.
+bool GDAPI godot_variant_is_keyed(godot_variant_type p_type) {
+ return Variant::is_keyed((Variant::Type)p_type);
+}
+
+godot_validated_keyed_setter GDAPI godot_variant_get_validated_keyed_setter(godot_variant_type p_type) {
+ return (godot_validated_keyed_setter)Variant::get_member_validated_keyed_setter((Variant::Type)p_type);
+}
+
+godot_validated_keyed_getter GDAPI godot_variant_get_validated_keyed_getter(godot_variant_type p_type) {
+ return (godot_validated_keyed_getter)Variant::get_member_validated_keyed_getter((Variant::Type)p_type);
+}
+
+godot_validated_keyed_checker GDAPI godot_variant_get_validated_keyed_checker(godot_variant_type p_type) {
+ return (godot_validated_keyed_checker)Variant::get_member_validated_keyed_checker((Variant::Type)p_type);
+}
+
+godot_ptr_keyed_setter GDAPI godot_variant_get_ptr_keyed_setter(godot_variant_type p_type) {
+ return (godot_ptr_keyed_setter)Variant::get_member_ptr_keyed_setter((Variant::Type)p_type);
+}
+
+godot_ptr_keyed_getter GDAPI godot_variant_get_ptr_keyed_getter(godot_variant_type p_type) {
+ return (godot_ptr_keyed_getter)Variant::get_member_ptr_keyed_getter((Variant::Type)p_type);
+}
+
+godot_ptr_keyed_checker GDAPI godot_variant_get_ptr_keyed_checker(godot_variant_type p_type) {
+ return (godot_ptr_keyed_checker)Variant::get_member_ptr_keyed_checker((Variant::Type)p_type);
+}
+
+/// Constants.
+int GDAPI godot_variant_get_constants_count(godot_variant_type p_type) {
+ return Variant::get_constants_count_for_type((Variant::Type)p_type);
+}
+
+void GDAPI godot_variant_get_constants_list(godot_variant_type p_type, godot_string_name *r_list) {
+ List<StringName> constants;
+ int i = 0;
+ Variant::get_constants_for_type((Variant::Type)p_type, &constants);
+ for (const List<StringName>::Element *E = constants.front(); E; E = E->next()) {
+ memnew_placement_custom(&r_list[i++], StringName, StringName(E->get()));
+ }
+}
+
+bool GDAPI godot_variant_has_constant(godot_variant_type p_type, const godot_string_name *p_constant) {
+ return Variant::has_constant((Variant::Type)p_type, *((const StringName *)p_constant));
+}
+
+bool GDAPI godot_variant_has_constant_with_cstring(godot_variant_type p_type, const char *p_constant) {
+ return Variant::has_constant((Variant::Type)p_type, StringName(p_constant));
+}
+
+godot_variant GDAPI godot_variant_get_constant_value(godot_variant_type p_type, const godot_string_name *p_constant) {
+ Variant constant = Variant::get_constant_value((Variant::Type)p_type, *((const StringName *)p_constant));
+ godot_variant ret;
+ memnew_placement_custom(&ret, Variant, Variant(constant));
+ return ret;
+}
+
+godot_variant GDAPI godot_variant_get_constant_value_with_cstring(godot_variant_type p_type, const char *p_constant) {
+ Variant constant = Variant::get_constant_value((Variant::Type)p_type, StringName(p_constant));
+ godot_variant ret;
+ memnew_placement_custom(&ret, Variant, Variant(constant));
+ return ret;
+}
+
+/// Utilities.
+bool GDAPI godot_variant_has_utility_function(const godot_string_name *p_function) {
+ return Variant::has_utility_function(*((const StringName *)p_function));
+}
+
+bool GDAPI godot_variant_has_utility_function_with_cstring(const char *p_function) {
+ return Variant::has_utility_function(StringName(p_function));
+}
+
+void GDAPI godot_variant_call_utility_function(const godot_string_name *p_function, godot_variant *r_ret, const godot_variant **p_args, int p_argument_count, godot_variant_call_error *r_error) {
+ const StringName *function = (const StringName *)p_function;
Variant *ret = (Variant *)r_ret;
- Variant::evaluate(op, *a, *b, *ret, *r_valid);
+ const Variant **args = (const Variant **)p_args;
+ Callable::CallError error;
+
+ Variant::call_utility_function(*function, ret, args, p_argument_count, error);
+
+ if (r_error) {
+ r_error->error = (godot_variant_call_error_error)error.error;
+ r_error->argument = error.argument;
+ r_error->expected = (godot_variant_type)error.expected;
+ }
+}
+
+void GDAPI godot_variant_call_utility_function_with_cstring(const char *p_function, godot_variant *r_ret, const godot_variant **p_args, int p_argument_count, godot_variant_call_error *r_error) {
+ Variant *ret = (Variant *)r_ret;
+ const Variant **args = (const Variant **)p_args;
+ Callable::CallError error;
+
+ Variant::call_utility_function(StringName(p_function), ret, args, p_argument_count, error);
+
+ if (r_error) {
+ r_error->error = (godot_variant_call_error_error)error.error;
+ r_error->argument = error.argument;
+ r_error->expected = (godot_variant_type)error.expected;
+ }
+}
+
+godot_variant_utility_function_type GDAPI godot_variant_get_utility_function_type(const godot_string_name *p_function) {
+ return (godot_variant_utility_function_type)Variant::get_utility_function_type(*((const StringName *)p_function));
+}
+
+godot_variant_utility_function_type GDAPI godot_variant_get_utility_function_type_with_cstring(const char *p_function) {
+ return (godot_variant_utility_function_type)Variant::get_utility_function_type(StringName(p_function));
+}
+
+int GDAPI godot_variant_get_utility_function_argument_count(const godot_string_name *p_function) {
+ return Variant::get_utility_function_argument_count(*((const StringName *)p_function));
+}
+
+int GDAPI godot_variant_get_utility_function_argument_count_with_cstring(const char *p_function) {
+ return Variant::get_utility_function_argument_count(StringName(p_function));
+}
+
+godot_variant_type GDAPI godot_variant_get_utility_function_argument_type(const godot_string_name *p_function, int p_argument) {
+ return (godot_variant_type)Variant::get_utility_function_argument_type(*((const StringName *)p_function), p_argument);
+}
+
+godot_variant_type GDAPI godot_variant_get_utility_function_argument_type_with_cstring(const char *p_function, int p_argument) {
+ return (godot_variant_type)Variant::get_utility_function_argument_type(StringName(p_function), p_argument);
+}
+
+godot_string GDAPI godot_variant_get_utility_function_argument_name(const godot_string_name *p_function, int p_argument) {
+ String argument_name = Variant::get_utility_function_argument_name(*((const StringName *)p_function), p_argument);
+ godot_string ret;
+ memnew_placement_custom(&ret, String, String(argument_name));
+ return ret;
+}
+
+godot_string GDAPI godot_variant_get_utility_function_argument_name_with_cstring(const char *p_function, int p_argument) {
+ String argument_name = Variant::get_utility_function_argument_name(StringName(p_function), p_argument);
+ godot_string ret;
+ memnew_placement_custom(&ret, String, String(argument_name));
+ return ret;
+}
+
+bool GDAPI godot_variant_has_utility_function_return_value(const godot_string_name *p_function) {
+ return Variant::has_utility_function_return_value(*((const StringName *)p_function));
+}
+
+bool GDAPI godot_variant_has_utility_function_return_value_with_cstring(const char *p_function) {
+ return Variant::has_utility_function_return_value(StringName(p_function));
+}
+
+godot_variant_type GDAPI godot_variant_get_utility_function_return_type(const godot_string_name *p_function) {
+ return (godot_variant_type)Variant::get_utility_function_return_type(*((const StringName *)p_function));
+}
+
+godot_variant_type GDAPI godot_variant_get_utility_function_return_type_with_cstring(const char *p_function) {
+ return (godot_variant_type)Variant::get_utility_function_return_type(StringName(p_function));
+}
+
+bool GDAPI godot_variant_is_utility_function_vararg(const godot_string_name *p_function) {
+ return Variant::is_utility_function_vararg(*((const StringName *)p_function));
+}
+
+bool GDAPI godot_variant_is_utility_function_vararg_with_cstring(const char *p_function) {
+ return Variant::is_utility_function_vararg(StringName(p_function));
+}
+
+int GDAPI godot_variant_get_utility_function_count() {
+ return Variant::get_utility_function_count();
+}
+
+void GDAPI godot_variant_get_utility_function_list(godot_string_name *r_functions) {
+ List<StringName> functions;
+ godot_string_name *func = r_functions;
+ Variant::get_utility_function_list(&functions);
+
+ for (const List<StringName>::Element *E = functions.front(); E; E = E->next()) {
+ memnew_placement_custom(func++, StringName, StringName(E->get()));
+ }
+}
+
+// Introspection.
+
+godot_variant_type GDAPI godot_variant_get_type(const godot_variant *p_self) {
+ const Variant *self = (const Variant *)p_self;
+ return (godot_variant_type)self->get_type();
+}
+
+bool GDAPI godot_variant_has_method(const godot_variant *p_self, const godot_string_name *p_method) {
+ const Variant *self = (const Variant *)p_self;
+ const StringName *method = (const StringName *)p_method;
+ return self->has_method(*method);
+}
+
+bool GDAPI godot_variant_has_member(godot_variant_type p_type, const godot_string_name *p_member) {
+ return Variant::has_member((Variant::Type)p_type, *((const StringName *)p_member));
+}
+
+bool GDAPI godot_variant_has_key(const godot_variant *p_self, const godot_variant *p_key, bool *r_valid) {
+ const Variant *self = (const Variant *)p_self;
+ const Variant *key = (const Variant *)p_key;
+ return self->has_key(*key, *r_valid);
+}
+
+godot_string GDAPI godot_variant_get_type_name(godot_variant_type p_type) {
+ String name = Variant::get_type_name((Variant::Type)p_type);
+ godot_string ret;
+ memnew_placement_custom(&ret, String, String(name));
+ return ret;
+}
+
+bool GDAPI godot_variant_can_convert(godot_variant_type p_from, godot_variant_type p_to) {
+ return Variant::can_convert((Variant::Type)p_from, (Variant::Type)p_to);
+}
+
+bool GDAPI godot_variant_can_convert_strict(godot_variant_type p_from, godot_variant_type p_to) {
+ return Variant::can_convert_strict((Variant::Type)p_from, (Variant::Type)p_to);
}
#ifdef __cplusplus
diff --git a/modules/gdnative/gdnative/vector2.cpp b/modules/gdnative/gdnative/vector2.cpp
index 1ee716df86..e2f957e4f2 100644
--- a/modules/gdnative/gdnative/vector2.cpp
+++ b/modules/gdnative/gdnative/vector2.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,430 +31,20 @@
#include "gdnative/vector2.h"
#include "core/math/vector2.h"
-#include "core/variant.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
static_assert(sizeof(godot_vector2) == sizeof(Vector2), "Vector2 size mismatch");
static_assert(sizeof(godot_vector2i) == sizeof(Vector2i), "Vector2i size mismatch");
-// Vector2
-
-void GDAPI godot_vector2_new(godot_vector2 *r_dest, const godot_real p_x, const godot_real p_y) {
- Vector2 *dest = (Vector2 *)r_dest;
- *dest = Vector2(p_x, p_y);
-}
-
-godot_string GDAPI godot_vector2_as_string(const godot_vector2 *p_self) {
- godot_string ret;
- const Vector2 *self = (const Vector2 *)p_self;
- memnew_placement(&ret, String(*self));
- return ret;
-}
-
-godot_vector2i GDAPI godot_vector2_as_vector2i(const godot_vector2 *p_self) {
- godot_vector2i dest;
- const Vector2 *self = (const Vector2 *)p_self;
- *((Vector2i *)&dest) = Vector2i(*self);
- return dest;
-}
-
-godot_vector2 GDAPI godot_vector2_normalized(const godot_vector2 *p_self) {
- godot_vector2 dest;
- const Vector2 *self = (const Vector2 *)p_self;
- *((Vector2 *)&dest) = self->normalized();
- return dest;
-}
-
-godot_real GDAPI godot_vector2_length(const godot_vector2 *p_self) {
- const Vector2 *self = (const Vector2 *)p_self;
- return self->length();
-}
-
-godot_real GDAPI godot_vector2_angle(const godot_vector2 *p_self) {
- const Vector2 *self = (const Vector2 *)p_self;
- return self->angle();
-}
-
-godot_real GDAPI godot_vector2_length_squared(const godot_vector2 *p_self) {
- const Vector2 *self = (const Vector2 *)p_self;
- return self->length_squared();
-}
-
-godot_bool GDAPI godot_vector2_is_normalized(const godot_vector2 *p_self) {
- const Vector2 *self = (const Vector2 *)p_self;
- return self->is_normalized();
-}
-
-godot_vector2 GDAPI godot_vector2_direction_to(const godot_vector2 *p_self, const godot_vector2 *p_to) {
- godot_vector2 dest;
- const Vector2 *self = (const Vector2 *)p_self;
- const Vector2 *to = (const Vector2 *)p_to;
- *((Vector2 *)&dest) = self->direction_to(*to);
- return dest;
-}
-
-godot_real GDAPI godot_vector2_distance_to(const godot_vector2 *p_self, const godot_vector2 *p_to) {
- const Vector2 *self = (const Vector2 *)p_self;
- const Vector2 *to = (const Vector2 *)p_to;
- return self->distance_to(*to);
-}
-
-godot_real GDAPI godot_vector2_distance_squared_to(const godot_vector2 *p_self, const godot_vector2 *p_to) {
- const Vector2 *self = (const Vector2 *)p_self;
- const Vector2 *to = (const Vector2 *)p_to;
- return self->distance_squared_to(*to);
-}
-
-godot_real GDAPI godot_vector2_angle_to(const godot_vector2 *p_self, const godot_vector2 *p_to) {
- const Vector2 *self = (const Vector2 *)p_self;
- const Vector2 *to = (const Vector2 *)p_to;
- return self->angle_to(*to);
-}
-
-godot_real GDAPI godot_vector2_angle_to_point(const godot_vector2 *p_self, const godot_vector2 *p_to) {
- const Vector2 *self = (const Vector2 *)p_self;
- const Vector2 *to = (const Vector2 *)p_to;
- return self->angle_to_point(*to);
-}
-
-godot_vector2 GDAPI godot_vector2_lerp(const godot_vector2 *p_self, const godot_vector2 *p_b, const godot_real p_t) {
- godot_vector2 dest;
- const Vector2 *self = (const Vector2 *)p_self;
- const Vector2 *b = (const Vector2 *)p_b;
- *((Vector2 *)&dest) = self->lerp(*b, p_t);
- return dest;
-}
-
-godot_vector2 GDAPI godot_vector2_cubic_interpolate(const godot_vector2 *p_self, const godot_vector2 *p_b, const godot_vector2 *p_pre_a, const godot_vector2 *p_post_b, const godot_real p_t) {
- godot_vector2 dest;
- const Vector2 *self = (const Vector2 *)p_self;
- const Vector2 *b = (const Vector2 *)p_b;
- const Vector2 *pre_a = (const Vector2 *)p_pre_a;
- const Vector2 *post_b = (const Vector2 *)p_post_b;
- *((Vector2 *)&dest) = self->cubic_interpolate(*b, *pre_a, *post_b, p_t);
- return dest;
-}
-
-godot_vector2 GDAPI godot_vector2_move_toward(const godot_vector2 *p_self, const godot_vector2 *p_to, const godot_real p_delta) {
- godot_vector2 dest;
- const Vector2 *self = (const Vector2 *)p_self;
- const Vector2 *to = (const Vector2 *)p_to;
- *((Vector2 *)&dest) = self->move_toward(*to, p_delta);
- return dest;
-}
-
-godot_vector2 GDAPI godot_vector2_rotated(const godot_vector2 *p_self, const godot_real p_phi) {
- godot_vector2 dest;
- const Vector2 *self = (const Vector2 *)p_self;
-
- *((Vector2 *)&dest) = self->rotated(p_phi);
- return dest;
-}
-
-godot_vector2 GDAPI godot_vector2_tangent(const godot_vector2 *p_self) {
- godot_vector2 dest;
- const Vector2 *self = (const Vector2 *)p_self;
- *((Vector2 *)&dest) = self->tangent();
- return dest;
-}
-
-godot_vector2 GDAPI godot_vector2_floor(const godot_vector2 *p_self) {
- godot_vector2 dest;
- const Vector2 *self = (const Vector2 *)p_self;
- *((Vector2 *)&dest) = self->floor();
- return dest;
-}
-
-godot_vector2 GDAPI godot_vector2_sign(const godot_vector2 *p_self) {
- godot_vector2 dest;
- const Vector2 *self = (const Vector2 *)p_self;
- *((Vector2 *)&dest) = self->sign();
- return dest;
-}
-
-godot_vector2 GDAPI godot_vector2_snapped(const godot_vector2 *p_self, const godot_vector2 *p_by) {
- godot_vector2 dest;
- const Vector2 *self = (const Vector2 *)p_self;
- const Vector2 *by = (const Vector2 *)p_by;
- *((Vector2 *)&dest) = self->snapped(*by);
- return dest;
-}
-
-godot_real GDAPI godot_vector2_aspect(const godot_vector2 *p_self) {
- const Vector2 *self = (const Vector2 *)p_self;
- return self->aspect();
-}
-
-godot_real GDAPI godot_vector2_dot(const godot_vector2 *p_self, const godot_vector2 *p_with) {
- const Vector2 *self = (const Vector2 *)p_self;
- const Vector2 *with = (const Vector2 *)p_with;
- return self->dot(*with);
-}
-
-godot_vector2 GDAPI godot_vector2_slide(const godot_vector2 *p_self, const godot_vector2 *p_n) {
- godot_vector2 dest;
- const Vector2 *self = (const Vector2 *)p_self;
- const Vector2 *n = (const Vector2 *)p_n;
- *((Vector2 *)&dest) = self->slide(*n);
- return dest;
-}
-
-godot_vector2 GDAPI godot_vector2_bounce(const godot_vector2 *p_self, const godot_vector2 *p_n) {
- godot_vector2 dest;
- const Vector2 *self = (const Vector2 *)p_self;
- const Vector2 *n = (const Vector2 *)p_n;
- *((Vector2 *)&dest) = self->bounce(*n);
- return dest;
-}
-
-godot_vector2 GDAPI godot_vector2_reflect(const godot_vector2 *p_self, const godot_vector2 *p_n) {
- godot_vector2 dest;
- const Vector2 *self = (const Vector2 *)p_self;
- const Vector2 *n = (const Vector2 *)p_n;
- *((Vector2 *)&dest) = self->reflect(*n);
- return dest;
-}
-
-godot_vector2 GDAPI godot_vector2_abs(const godot_vector2 *p_self) {
- godot_vector2 dest;
- const Vector2 *self = (const Vector2 *)p_self;
- *((Vector2 *)&dest) = self->abs();
- return dest;
-}
-
-godot_vector2 GDAPI godot_vector2_clamped(const godot_vector2 *p_self, const godot_real p_length) {
- godot_vector2 dest;
- const Vector2 *self = (const Vector2 *)p_self;
-
- *((Vector2 *)&dest) = self->clamped(p_length);
- return dest;
-}
-
-godot_vector2 GDAPI godot_vector2_operator_add(const godot_vector2 *p_self, const godot_vector2 *p_b) {
- godot_vector2 raw_dest;
- Vector2 *dest = (Vector2 *)&raw_dest;
- const Vector2 *self = (const Vector2 *)p_self;
- const Vector2 *b = (const Vector2 *)p_b;
- *dest = *self + *b;
- return raw_dest;
-}
-
-godot_vector2 GDAPI godot_vector2_operator_subtract(const godot_vector2 *p_self, const godot_vector2 *p_b) {
- godot_vector2 raw_dest;
- Vector2 *dest = (Vector2 *)&raw_dest;
- const Vector2 *self = (const Vector2 *)p_self;
- const Vector2 *b = (const Vector2 *)p_b;
- *dest = *self - *b;
- return raw_dest;
-}
-
-godot_vector2 GDAPI godot_vector2_operator_multiply_vector(const godot_vector2 *p_self, const godot_vector2 *p_b) {
- godot_vector2 raw_dest;
- Vector2 *dest = (Vector2 *)&raw_dest;
- const Vector2 *self = (const Vector2 *)p_self;
- const Vector2 *b = (const Vector2 *)p_b;
- *dest = *self * *b;
- return raw_dest;
-}
-
-godot_vector2 GDAPI godot_vector2_operator_multiply_scalar(const godot_vector2 *p_self, const godot_real p_b) {
- godot_vector2 raw_dest;
- Vector2 *dest = (Vector2 *)&raw_dest;
- const Vector2 *self = (const Vector2 *)p_self;
- *dest = *self * p_b;
- return raw_dest;
-}
-
-godot_vector2 GDAPI godot_vector2_operator_divide_vector(const godot_vector2 *p_self, const godot_vector2 *p_b) {
- godot_vector2 raw_dest;
- Vector2 *dest = (Vector2 *)&raw_dest;
- const Vector2 *self = (const Vector2 *)p_self;
- const Vector2 *b = (const Vector2 *)p_b;
- *dest = *self / *b;
- return raw_dest;
-}
-
-godot_vector2 GDAPI godot_vector2_operator_divide_scalar(const godot_vector2 *p_self, const godot_real p_b) {
- godot_vector2 raw_dest;
- Vector2 *dest = (Vector2 *)&raw_dest;
- const Vector2 *self = (const Vector2 *)p_self;
- *dest = *self / p_b;
- return raw_dest;
-}
-
-godot_bool GDAPI godot_vector2_operator_equal(const godot_vector2 *p_self, const godot_vector2 *p_b) {
- const Vector2 *self = (const Vector2 *)p_self;
- const Vector2 *b = (const Vector2 *)p_b;
- return *self == *b;
-}
-
-godot_bool GDAPI godot_vector2_operator_less(const godot_vector2 *p_self, const godot_vector2 *p_b) {
- const Vector2 *self = (const Vector2 *)p_self;
- const Vector2 *b = (const Vector2 *)p_b;
- return *self < *b;
-}
-
-godot_vector2 GDAPI godot_vector2_operator_neg(const godot_vector2 *p_self) {
- godot_vector2 raw_dest;
- Vector2 *dest = (Vector2 *)&raw_dest;
- const Vector2 *self = (const Vector2 *)p_self;
- *dest = -(*self);
- return raw_dest;
-}
-
-void GDAPI godot_vector2_set_x(godot_vector2 *p_self, const godot_real p_x) {
- Vector2 *self = (Vector2 *)p_self;
- self->x = p_x;
-}
-
-void GDAPI godot_vector2_set_y(godot_vector2 *p_self, const godot_real p_y) {
- Vector2 *self = (Vector2 *)p_self;
- self->y = p_y;
-}
-
-godot_real GDAPI godot_vector2_get_x(const godot_vector2 *p_self) {
- const Vector2 *self = (const Vector2 *)p_self;
- return self->x;
-}
-
-godot_real GDAPI godot_vector2_get_y(const godot_vector2 *p_self) {
- const Vector2 *self = (const Vector2 *)p_self;
- return self->y;
-}
-
-// Vector2i
-
-void GDAPI godot_vector2i_new(godot_vector2i *r_dest, const godot_int p_x, const godot_int p_y) {
- Vector2i *dest = (Vector2i *)r_dest;
- *dest = Vector2i(p_x, p_y);
-}
-
-godot_string GDAPI godot_vector2i_as_string(const godot_vector2i *p_self) {
- godot_string ret;
- const Vector2i *self = (const Vector2i *)p_self;
- memnew_placement(&ret, String(*self));
- return ret;
-}
-
-godot_vector2 GDAPI godot_vector2i_as_vector2(const godot_vector2i *p_self) {
- godot_vector2 dest;
- const Vector2i *self = (const Vector2i *)p_self;
- *((Vector2 *)&dest) = Vector2(*self);
- return dest;
-}
-
-godot_real GDAPI godot_vector2i_aspect(const godot_vector2i *p_self) {
- const Vector2i *self = (const Vector2i *)p_self;
- return self->aspect();
-}
-
-godot_vector2i GDAPI godot_vector2i_abs(const godot_vector2i *p_self) {
- godot_vector2i dest;
- const Vector2i *self = (const Vector2i *)p_self;
- *((Vector2i *)&dest) = self->abs();
- return dest;
-}
-
-godot_vector2i GDAPI godot_vector2i_sign(const godot_vector2i *p_self) {
- godot_vector2i dest;
- const Vector2i *self = (const Vector2i *)p_self;
- *((Vector2i *)&dest) = self->sign();
- return dest;
-}
-
-godot_vector2i GDAPI godot_vector2i_operator_add(const godot_vector2i *p_self, const godot_vector2i *p_b) {
- godot_vector2i raw_dest;
- Vector2i *dest = (Vector2i *)&raw_dest;
- const Vector2i *self = (const Vector2i *)p_self;
- const Vector2i *b = (const Vector2i *)p_b;
- *dest = *self + *b;
- return raw_dest;
-}
-
-godot_vector2i GDAPI godot_vector2i_operator_subtract(const godot_vector2i *p_self, const godot_vector2i *p_b) {
- godot_vector2i raw_dest;
- Vector2i *dest = (Vector2i *)&raw_dest;
- const Vector2i *self = (const Vector2i *)p_self;
- const Vector2i *b = (const Vector2i *)p_b;
- *dest = *self - *b;
- return raw_dest;
-}
-
-godot_vector2i GDAPI godot_vector2i_operator_multiply_vector(const godot_vector2i *p_self, const godot_vector2i *p_b) {
- godot_vector2i raw_dest;
- Vector2i *dest = (Vector2i *)&raw_dest;
- const Vector2i *self = (const Vector2i *)p_self;
- const Vector2i *b = (const Vector2i *)p_b;
- *dest = *self * *b;
- return raw_dest;
-}
-
-godot_vector2i GDAPI godot_vector2i_operator_multiply_scalar(const godot_vector2i *p_self, const godot_int p_b) {
- godot_vector2i raw_dest;
- Vector2i *dest = (Vector2i *)&raw_dest;
- const Vector2i *self = (const Vector2i *)p_self;
- *dest = *self * p_b;
- return raw_dest;
-}
-
-godot_vector2i GDAPI godot_vector2i_operator_divide_vector(const godot_vector2i *p_self, const godot_vector2i *p_b) {
- godot_vector2i raw_dest;
- Vector2i *dest = (Vector2i *)&raw_dest;
- const Vector2i *self = (const Vector2i *)p_self;
- const Vector2i *b = (const Vector2i *)p_b;
- *dest = *self / *b;
- return raw_dest;
-}
-
-godot_vector2i GDAPI godot_vector2i_operator_divide_scalar(const godot_vector2i *p_self, const godot_int p_b) {
- godot_vector2i raw_dest;
- Vector2i *dest = (Vector2i *)&raw_dest;
- const Vector2i *self = (const Vector2i *)p_self;
- *dest = *self / p_b;
- return raw_dest;
-}
-
-godot_bool GDAPI godot_vector2i_operator_equal(const godot_vector2i *p_self, const godot_vector2i *p_b) {
- const Vector2i *self = (const Vector2i *)p_self;
- const Vector2i *b = (const Vector2i *)p_b;
- return *self == *b;
-}
-
-godot_bool GDAPI godot_vector2i_operator_less(const godot_vector2i *p_self, const godot_vector2i *p_b) {
- const Vector2i *self = (const Vector2i *)p_self;
- const Vector2i *b = (const Vector2i *)p_b;
- return *self < *b;
-}
-
-godot_vector2i GDAPI godot_vector2i_operator_neg(const godot_vector2i *p_self) {
- godot_vector2i raw_dest;
- Vector2i *dest = (Vector2i *)&raw_dest;
- const Vector2i *self = (const Vector2i *)p_self;
- *dest = -(*self);
- return raw_dest;
-}
-
-void GDAPI godot_vector2i_set_x(godot_vector2i *p_self, const godot_int p_x) {
- Vector2i *self = (Vector2i *)p_self;
- self->x = p_x;
-}
-
-void GDAPI godot_vector2i_set_y(godot_vector2i *p_self, const godot_int p_y) {
- Vector2i *self = (Vector2i *)p_self;
- self->y = p_y;
-}
+#ifdef __cplusplus
+extern "C" {
+#endif
-godot_int GDAPI godot_vector2i_get_x(const godot_vector2i *p_self) {
- const Vector2i *self = (const Vector2i *)p_self;
- return self->x;
+void GDAPI godot_vector2_new(godot_vector2 *p_self) {
+ memnew_placement(p_self, Vector2);
}
-godot_int GDAPI godot_vector2i_get_y(const godot_vector2i *p_self) {
- const Vector2i *self = (const Vector2i *)p_self;
- return self->y;
+void GDAPI godot_vector2i_new(godot_vector2i *p_self) {
+ memnew_placement(p_self, Vector2i);
}
#ifdef __cplusplus
diff --git a/modules/gdnative/gdnative/vector3.cpp b/modules/gdnative/gdnative/vector3.cpp
index 32cad30c17..ee365edaec 100644
--- a/modules/gdnative/gdnative/vector3.cpp
+++ b/modules/gdnative/gdnative/vector3.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,433 +30,21 @@
#include "gdnative/vector3.h"
-#include "core/variant.h"
-#include "core/vector.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include "core/math/vector3.h"
static_assert(sizeof(godot_vector3) == sizeof(Vector3), "Vector3 size mismatch");
static_assert(sizeof(godot_vector3i) == sizeof(Vector3i), "Vector3i size mismatch");
-// Vector3
-
-void GDAPI godot_vector3_new(godot_vector3 *r_dest, const godot_real p_x, const godot_real p_y, const godot_real p_z) {
- Vector3 *dest = (Vector3 *)r_dest;
- *dest = Vector3(p_x, p_y, p_z);
-}
-
-godot_string GDAPI godot_vector3_as_string(const godot_vector3 *p_self) {
- godot_string ret;
- const Vector3 *self = (const Vector3 *)p_self;
- memnew_placement(&ret, String(*self));
- return ret;
-}
-
-godot_vector3i GDAPI godot_vector3_as_vector3i(const godot_vector3 *p_self) {
- godot_vector3i dest;
- const Vector3 *self = (const Vector3 *)p_self;
- *((Vector3i *)&dest) = Vector3i(*self);
- return dest;
-}
-
-godot_int GDAPI godot_vector3_min_axis(const godot_vector3 *p_self) {
- const Vector3 *self = (const Vector3 *)p_self;
- return self->min_axis();
-}
-
-godot_int GDAPI godot_vector3_max_axis(const godot_vector3 *p_self) {
- const Vector3 *self = (const Vector3 *)p_self;
- return self->max_axis();
-}
-
-godot_real GDAPI godot_vector3_length(const godot_vector3 *p_self) {
- const Vector3 *self = (const Vector3 *)p_self;
- return self->length();
-}
-
-godot_real GDAPI godot_vector3_length_squared(const godot_vector3 *p_self) {
- const Vector3 *self = (const Vector3 *)p_self;
- return self->length_squared();
-}
-
-godot_bool GDAPI godot_vector3_is_normalized(const godot_vector3 *p_self) {
- const Vector3 *self = (const Vector3 *)p_self;
- return self->is_normalized();
-}
-
-godot_vector3 GDAPI godot_vector3_normalized(const godot_vector3 *p_self) {
- godot_vector3 dest;
- const Vector3 *self = (const Vector3 *)p_self;
- *((Vector3 *)&dest) = self->normalized();
- return dest;
-}
-
-godot_vector3 GDAPI godot_vector3_inverse(const godot_vector3 *p_self) {
- godot_vector3 dest;
- const Vector3 *self = (const Vector3 *)p_self;
- *((Vector3 *)&dest) = self->inverse();
- return dest;
-}
-
-godot_vector3 GDAPI godot_vector3_snapped(const godot_vector3 *p_self, const godot_vector3 *p_by) {
- godot_vector3 dest;
- const Vector3 *self = (const Vector3 *)p_self;
- const Vector3 *snap_axis = (const Vector3 *)p_by;
-
- *((Vector3 *)&dest) = self->snapped(*snap_axis);
- return dest;
-}
-
-godot_vector3 GDAPI godot_vector3_rotated(const godot_vector3 *p_self, const godot_vector3 *p_axis, const godot_real p_phi) {
- godot_vector3 dest;
- const Vector3 *self = (const Vector3 *)p_self;
- const Vector3 *axis = (const Vector3 *)p_axis;
- *((Vector3 *)&dest) = self->rotated(*axis, p_phi);
- return dest;
-}
-
-godot_vector3 GDAPI godot_vector3_lerp(const godot_vector3 *p_self, const godot_vector3 *p_b, const godot_real p_t) {
- godot_vector3 dest;
- const Vector3 *self = (const Vector3 *)p_self;
- const Vector3 *b = (const Vector3 *)p_b;
- *((Vector3 *)&dest) = self->lerp(*b, p_t);
- return dest;
-}
-
-godot_vector3 GDAPI godot_vector3_cubic_interpolate(const godot_vector3 *p_self, const godot_vector3 *p_b, const godot_vector3 *p_pre_a, const godot_vector3 *p_post_b, const godot_real p_t) {
- godot_vector3 dest;
- const Vector3 *self = (const Vector3 *)p_self;
- const Vector3 *b = (const Vector3 *)p_b;
- const Vector3 *pre_a = (const Vector3 *)p_pre_a;
- const Vector3 *post_b = (const Vector3 *)p_post_b;
- *((Vector3 *)&dest) = self->cubic_interpolate(*b, *pre_a, *post_b, p_t);
- return dest;
-}
-
-godot_vector3 GDAPI godot_vector3_move_toward(const godot_vector3 *p_self, const godot_vector3 *p_to, const godot_real p_delta) {
- godot_vector3 dest;
- const Vector3 *self = (const Vector3 *)p_self;
- const Vector3 *to = (const Vector3 *)p_to;
- *((Vector3 *)&dest) = self->move_toward(*to, p_delta);
- return dest;
-}
-
-godot_real GDAPI godot_vector3_dot(const godot_vector3 *p_self, const godot_vector3 *p_b) {
- const Vector3 *self = (const Vector3 *)p_self;
- const Vector3 *b = (const Vector3 *)p_b;
- return self->dot(*b);
-}
-
-godot_vector3 GDAPI godot_vector3_cross(const godot_vector3 *p_self, const godot_vector3 *p_b) {
- godot_vector3 dest;
- const Vector3 *self = (const Vector3 *)p_self;
- const Vector3 *b = (const Vector3 *)p_b;
- *((Vector3 *)&dest) = self->cross(*b);
- return dest;
-}
-
-godot_basis GDAPI godot_vector3_outer(const godot_vector3 *p_self, const godot_vector3 *p_b) {
- godot_basis dest;
- const Vector3 *self = (const Vector3 *)p_self;
- const Vector3 *b = (const Vector3 *)p_b;
- *((Basis *)&dest) = self->outer(*b);
- return dest;
-}
-
-godot_basis GDAPI godot_vector3_to_diagonal_matrix(const godot_vector3 *p_self) {
- godot_basis dest;
- const Vector3 *self = (const Vector3 *)p_self;
- *((Basis *)&dest) = self->to_diagonal_matrix();
- return dest;
-}
-
-godot_vector3 GDAPI godot_vector3_abs(const godot_vector3 *p_self) {
- godot_vector3 dest;
- const Vector3 *self = (const Vector3 *)p_self;
- *((Vector3 *)&dest) = self->abs();
- return dest;
-}
-
-godot_vector3 GDAPI godot_vector3_sign(const godot_vector3 *p_self) {
- godot_vector3 dest;
- const Vector3 *self = (const Vector3 *)p_self;
- *((Vector3 *)&dest) = self->sign();
- return dest;
-}
-
-godot_vector3 GDAPI godot_vector3_floor(const godot_vector3 *p_self) {
- godot_vector3 dest;
- const Vector3 *self = (const Vector3 *)p_self;
- *((Vector3 *)&dest) = self->floor();
- return dest;
-}
-
-godot_vector3 GDAPI godot_vector3_ceil(const godot_vector3 *p_self) {
- godot_vector3 dest;
- const Vector3 *self = (const Vector3 *)p_self;
- *((Vector3 *)&dest) = self->ceil();
- return dest;
-}
-
-godot_vector3 GDAPI godot_vector3_direction_to(const godot_vector3 *p_self, const godot_vector3 *p_to) {
- godot_vector3 dest;
- const Vector3 *self = (const Vector3 *)p_self;
- const Vector3 *to = (const Vector3 *)p_to;
- *((Vector3 *)&dest) = self->direction_to(*to);
- return dest;
-}
-
-godot_real GDAPI godot_vector3_distance_to(const godot_vector3 *p_self, const godot_vector3 *p_b) {
- const Vector3 *self = (const Vector3 *)p_self;
- const Vector3 *b = (const Vector3 *)p_b;
- return self->distance_to(*b);
-}
-
-godot_real GDAPI godot_vector3_distance_squared_to(const godot_vector3 *p_self, const godot_vector3 *p_b) {
- const Vector3 *self = (const Vector3 *)p_self;
- const Vector3 *b = (const Vector3 *)p_b;
- return self->distance_squared_to(*b);
-}
-
-godot_real GDAPI godot_vector3_angle_to(const godot_vector3 *p_self, const godot_vector3 *p_to) {
- const Vector3 *self = (const Vector3 *)p_self;
- const Vector3 *to = (const Vector3 *)p_to;
- return self->angle_to(*to);
-}
-
-godot_vector3 GDAPI godot_vector3_slide(const godot_vector3 *p_self, const godot_vector3 *p_n) {
- godot_vector3 dest;
- const Vector3 *self = (const Vector3 *)p_self;
- const Vector3 *n = (const Vector3 *)p_n;
- *((Vector3 *)&dest) = self->slide(*n);
- return dest;
-}
-
-godot_vector3 GDAPI godot_vector3_bounce(const godot_vector3 *p_self, const godot_vector3 *p_n) {
- godot_vector3 dest;
- const Vector3 *self = (const Vector3 *)p_self;
- const Vector3 *n = (const Vector3 *)p_n;
- *((Vector3 *)&dest) = self->bounce(*n);
- return dest;
-}
-
-godot_vector3 GDAPI godot_vector3_reflect(const godot_vector3 *p_self, const godot_vector3 *p_n) {
- godot_vector3 dest;
- const Vector3 *self = (const Vector3 *)p_self;
- const Vector3 *n = (const Vector3 *)p_n;
- *((Vector3 *)&dest) = self->reflect(*n);
- return dest;
-}
-
-godot_vector3 GDAPI godot_vector3_operator_add(const godot_vector3 *p_self, const godot_vector3 *p_b) {
- godot_vector3 raw_dest;
- Vector3 *dest = (Vector3 *)&raw_dest;
- Vector3 *self = (Vector3 *)p_self;
- const Vector3 *b = (const Vector3 *)p_b;
- *dest = *self + *b;
- return raw_dest;
-}
-
-godot_vector3 GDAPI godot_vector3_operator_subtract(const godot_vector3 *p_self, const godot_vector3 *p_b) {
- godot_vector3 raw_dest;
- Vector3 *dest = (Vector3 *)&raw_dest;
- Vector3 *self = (Vector3 *)p_self;
- const Vector3 *b = (const Vector3 *)p_b;
- *dest = *self - *b;
- return raw_dest;
-}
-
-godot_vector3 GDAPI godot_vector3_operator_multiply_vector(const godot_vector3 *p_self, const godot_vector3 *p_b) {
- godot_vector3 raw_dest;
- Vector3 *dest = (Vector3 *)&raw_dest;
- Vector3 *self = (Vector3 *)p_self;
- const Vector3 *b = (const Vector3 *)p_b;
- *dest = *self * *b;
- return raw_dest;
-}
-
-godot_vector3 GDAPI godot_vector3_operator_multiply_scalar(const godot_vector3 *p_self, const godot_real p_b) {
- godot_vector3 raw_dest;
- Vector3 *dest = (Vector3 *)&raw_dest;
- Vector3 *self = (Vector3 *)p_self;
- *dest = *self * p_b;
- return raw_dest;
-}
-
-godot_vector3 GDAPI godot_vector3_operator_divide_vector(const godot_vector3 *p_self, const godot_vector3 *p_b) {
- godot_vector3 raw_dest;
- Vector3 *dest = (Vector3 *)&raw_dest;
- Vector3 *self = (Vector3 *)p_self;
- const Vector3 *b = (const Vector3 *)p_b;
- *dest = *self / *b;
- return raw_dest;
-}
-
-godot_vector3 GDAPI godot_vector3_operator_divide_scalar(const godot_vector3 *p_self, const godot_real p_b) {
- godot_vector3 raw_dest;
- Vector3 *dest = (Vector3 *)&raw_dest;
- Vector3 *self = (Vector3 *)p_self;
- *dest = *self / p_b;
- return raw_dest;
-}
-
-godot_bool GDAPI godot_vector3_operator_equal(const godot_vector3 *p_self, const godot_vector3 *p_b) {
- Vector3 *self = (Vector3 *)p_self;
- const Vector3 *b = (const Vector3 *)p_b;
- return *self == *b;
-}
-
-godot_bool GDAPI godot_vector3_operator_less(const godot_vector3 *p_self, const godot_vector3 *p_b) {
- Vector3 *self = (Vector3 *)p_self;
- const Vector3 *b = (const Vector3 *)p_b;
- return *self < *b;
-}
-
-godot_vector3 GDAPI godot_vector3_operator_neg(const godot_vector3 *p_self) {
- godot_vector3 raw_dest;
- Vector3 *dest = (Vector3 *)&raw_dest;
- const Vector3 *self = (const Vector3 *)p_self;
- *dest = -(*self);
- return raw_dest;
-}
-
-void GDAPI godot_vector3_set_axis(godot_vector3 *p_self, const godot_vector3_axis p_axis, const godot_real p_val) {
- Vector3 *self = (Vector3 *)p_self;
- self->set_axis(p_axis, p_val);
-}
-
-godot_real GDAPI godot_vector3_get_axis(const godot_vector3 *p_self, const godot_vector3_axis p_axis) {
- const Vector3 *self = (const Vector3 *)p_self;
- return self->get_axis(p_axis);
-}
-
-// Vector3i
-
-void GDAPI godot_vector3i_new(godot_vector3i *r_dest, const godot_int p_x, const godot_int p_y, const godot_int p_z) {
- Vector3i *dest = (Vector3i *)r_dest;
- *dest = Vector3i(p_x, p_y, p_z);
-}
-
-godot_string GDAPI godot_vector3i_as_string(const godot_vector3i *p_self) {
- godot_string ret;
- const Vector3i *self = (const Vector3i *)p_self;
- memnew_placement(&ret, String(*self));
- return ret;
-}
-
-godot_vector3 GDAPI godot_vector3i_as_vector3(const godot_vector3i *p_self) {
- godot_vector3 dest;
- const Vector3i *self = (const Vector3i *)p_self;
- *((Vector3 *)&dest) = Vector3(*self);
- return dest;
-}
-
-godot_int GDAPI godot_vector3i_min_axis(const godot_vector3i *p_self) {
- const Vector3i *self = (const Vector3i *)p_self;
- return self->min_axis();
-}
-
-godot_int GDAPI godot_vector3i_max_axis(const godot_vector3i *p_self) {
- const Vector3i *self = (const Vector3i *)p_self;
- return self->max_axis();
-}
-
-godot_vector3i GDAPI godot_vector3i_abs(const godot_vector3i *p_self) {
- godot_vector3i dest;
- const Vector3i *self = (const Vector3i *)p_self;
- *((Vector3i *)&dest) = self->abs();
- return dest;
-}
-
-godot_vector3i GDAPI godot_vector3i_sign(const godot_vector3i *p_self) {
- godot_vector3i dest;
- const Vector3i *self = (const Vector3i *)p_self;
- *((Vector3i *)&dest) = self->sign();
- return dest;
-}
-
-godot_vector3i GDAPI godot_vector3i_operator_add(const godot_vector3i *p_self, const godot_vector3i *p_b) {
- godot_vector3i raw_dest;
- Vector3i *dest = (Vector3i *)&raw_dest;
- Vector3i *self = (Vector3i *)p_self;
- const Vector3i *b = (const Vector3i *)p_b;
- *dest = *self + *b;
- return raw_dest;
-}
-
-godot_vector3i GDAPI godot_vector3i_operator_subtract(const godot_vector3i *p_self, const godot_vector3i *p_b) {
- godot_vector3i raw_dest;
- Vector3i *dest = (Vector3i *)&raw_dest;
- Vector3i *self = (Vector3i *)p_self;
- const Vector3i *b = (const Vector3i *)p_b;
- *dest = *self - *b;
- return raw_dest;
-}
-
-godot_vector3i GDAPI godot_vector3i_operator_multiply_vector(const godot_vector3i *p_self, const godot_vector3i *p_b) {
- godot_vector3i raw_dest;
- Vector3i *dest = (Vector3i *)&raw_dest;
- Vector3i *self = (Vector3i *)p_self;
- const Vector3i *b = (const Vector3i *)p_b;
- *dest = *self * *b;
- return raw_dest;
-}
-
-godot_vector3i GDAPI godot_vector3i_operator_multiply_scalar(const godot_vector3i *p_self, const godot_int p_b) {
- godot_vector3i raw_dest;
- Vector3i *dest = (Vector3i *)&raw_dest;
- Vector3i *self = (Vector3i *)p_self;
- *dest = *self * p_b;
- return raw_dest;
-}
-
-godot_vector3i GDAPI godot_vector3i_operator_divide_vector(const godot_vector3i *p_self, const godot_vector3i *p_b) {
- godot_vector3i raw_dest;
- Vector3i *dest = (Vector3i *)&raw_dest;
- Vector3i *self = (Vector3i *)p_self;
- const Vector3i *b = (const Vector3i *)p_b;
- *dest = *self / *b;
- return raw_dest;
-}
-
-godot_vector3i GDAPI godot_vector3i_operator_divide_scalar(const godot_vector3i *p_self, const godot_int p_b) {
- godot_vector3i raw_dest;
- Vector3i *dest = (Vector3i *)&raw_dest;
- Vector3i *self = (Vector3i *)p_self;
- *dest = *self / p_b;
- return raw_dest;
-}
-
-godot_bool GDAPI godot_vector3i_operator_equal(const godot_vector3i *p_self, const godot_vector3i *p_b) {
- Vector3i *self = (Vector3i *)p_self;
- const Vector3i *b = (const Vector3i *)p_b;
- return *self == *b;
-}
-
-godot_bool GDAPI godot_vector3i_operator_less(const godot_vector3i *p_self, const godot_vector3i *p_b) {
- Vector3i *self = (Vector3i *)p_self;
- const Vector3i *b = (const Vector3i *)p_b;
- return *self < *b;
-}
-
-godot_vector3i GDAPI godot_vector3i_operator_neg(const godot_vector3i *p_self) {
- godot_vector3i raw_dest;
- Vector3i *dest = (Vector3i *)&raw_dest;
- const Vector3i *self = (const Vector3i *)p_self;
- *dest = -(*self);
- return raw_dest;
-}
+#ifdef __cplusplus
+extern "C" {
+#endif
-void GDAPI godot_vector3i_set_axis(godot_vector3i *p_self, const godot_vector3_axis p_axis, const godot_int p_val) {
- Vector3i *self = (Vector3i *)p_self;
- self->set_axis(p_axis, p_val);
+void GDAPI godot_vector3_new(godot_vector3 *p_self) {
+ memnew_placement(p_self, Vector3);
}
-godot_int GDAPI godot_vector3i_get_axis(const godot_vector3i *p_self, const godot_vector3_axis p_axis) {
- const Vector3i *self = (const Vector3i *)p_self;
- return self->get_axis(p_axis);
+void GDAPI godot_vector3i_new(godot_vector3i *p_self) {
+ memnew_placement(p_self, Vector3i);
}
#ifdef __cplusplus
diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json
index 82bfbd23de..909e91393e 100644
--- a/modules/gdnative/gdnative_api.json
+++ b/modules/gdnative/gdnative_api.json
@@ -1,7627 +1,4535 @@
{
- "core": {
- "type": "CORE",
- "version": {
- "major": 4,
- "minor": 0
- },
- "next": null,
- "api": [
- {
- "name": "godot_aabb_new",
- "return_type": "void",
- "arguments": [
- ["godot_aabb *", "r_dest"],
- ["const godot_vector3 *", "p_pos"],
- ["const godot_vector3 *", "p_size"]
- ]
- },
- {
- "name": "godot_aabb_get_position",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_aabb *", "p_self"]
- ]
- },
- {
- "name": "godot_aabb_set_position",
- "return_type": "void",
- "arguments": [
- ["const godot_aabb *", "p_self"],
- ["const godot_vector3 *", "p_v"]
- ]
- },
- {
- "name": "godot_aabb_get_size",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_aabb *", "p_self"]
- ]
- },
- {
- "name": "godot_aabb_set_size",
- "return_type": "void",
- "arguments": [
- ["const godot_aabb *", "p_self"],
- ["const godot_vector3 *", "p_v"]
- ]
- },
- {
- "name": "godot_aabb_as_string",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_aabb *", "p_self"]
- ]
- },
- {
- "name": "godot_aabb_abs",
- "return_type": "godot_aabb",
- "arguments": [
- ["const godot_aabb *", "p_self"]
- ]
- },
- {
- "name": "godot_aabb_get_area",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_aabb *", "p_self"]
- ]
- },
- {
- "name": "godot_aabb_has_no_area",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_aabb *", "p_self"]
- ]
- },
- {
- "name": "godot_aabb_has_no_surface",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_aabb *", "p_self"]
- ]
- },
- {
- "name": "godot_aabb_intersects",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_aabb *", "p_self"],
- ["const godot_aabb *", "p_with"]
- ]
- },
- {
- "name": "godot_aabb_encloses",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_aabb *", "p_self"],
- ["const godot_aabb *", "p_with"]
- ]
- },
- {
- "name": "godot_aabb_merge",
- "return_type": "godot_aabb",
- "arguments": [
- ["const godot_aabb *", "p_self"],
- ["const godot_aabb *", "p_with"]
- ]
- },
- {
- "name": "godot_aabb_intersection",
- "return_type": "godot_aabb",
- "arguments": [
- ["const godot_aabb *", "p_self"],
- ["const godot_aabb *", "p_with"]
- ]
- },
- {
- "name": "godot_aabb_intersects_plane",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_aabb *", "p_self"],
- ["const godot_plane *", "p_plane"]
- ]
- },
- {
- "name": "godot_aabb_intersects_segment",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_aabb *", "p_self"],
- ["const godot_vector3 *", "p_from"],
- ["const godot_vector3 *", "p_to"]
- ]
- },
- {
- "name": "godot_aabb_has_point",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_aabb *", "p_self"],
- ["const godot_vector3 *", "p_point"]
- ]
- },
- {
- "name": "godot_aabb_get_support",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_aabb *", "p_self"],
- ["const godot_vector3 *", "p_dir"]
- ]
- },
- {
- "name": "godot_aabb_get_longest_axis",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_aabb *", "p_self"]
- ]
- },
- {
- "name": "godot_aabb_get_longest_axis_index",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_aabb *", "p_self"]
- ]
- },
- {
- "name": "godot_aabb_get_longest_axis_size",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_aabb *", "p_self"]
- ]
- },
- {
- "name": "godot_aabb_get_shortest_axis",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_aabb *", "p_self"]
- ]
- },
- {
- "name": "godot_aabb_get_shortest_axis_index",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_aabb *", "p_self"]
- ]
- },
- {
- "name": "godot_aabb_get_shortest_axis_size",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_aabb *", "p_self"]
- ]
- },
- {
- "name": "godot_aabb_expand",
- "return_type": "godot_aabb",
- "arguments": [
- ["const godot_aabb *", "p_self"],
- ["const godot_vector3 *", "p_to_point"]
- ]
- },
- {
- "name": "godot_aabb_grow",
- "return_type": "godot_aabb",
- "arguments": [
- ["const godot_aabb *", "p_self"],
- ["const godot_real", "p_by"]
- ]
- },
- {
- "name": "godot_aabb_get_endpoint",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_aabb *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_aabb_operator_equal",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_aabb *", "p_self"],
- ["const godot_aabb *", "p_b"]
- ]
- },
- {
- "name": "godot_array_new",
- "return_type": "void",
- "arguments": [
- ["godot_array *", "r_dest"]
- ]
- },
- {
- "name": "godot_array_new_copy",
- "return_type": "void",
- "arguments": [
- ["godot_array *", "r_dest"],
- ["const godot_array *", "p_src"]
- ]
- },
- {
- "name": "godot_array_new_packed_color_array",
- "return_type": "void",
- "arguments": [
- ["godot_array *", "r_dest"],
- ["const godot_packed_color_array *", "p_pca"]
- ]
- },
- {
- "name": "godot_array_new_packed_vector3_array",
- "return_type": "void",
- "arguments": [
- ["godot_array *", "r_dest"],
- ["const godot_packed_vector3_array *", "p_pv3a"]
- ]
- },
- {
- "name": "godot_array_new_packed_vector2_array",
- "return_type": "void",
- "arguments": [
- ["godot_array *", "r_dest"],
- ["const godot_packed_vector2_array *", "p_pv2a"]
- ]
- },
- {
- "name": "godot_array_new_packed_string_array",
- "return_type": "void",
- "arguments": [
- ["godot_array *", "r_dest"],
- ["const godot_packed_string_array *", "p_psa"]
- ]
- },
- {
- "name": "godot_array_new_packed_float32_array",
- "return_type": "void",
- "arguments": [
- ["godot_array *", "r_dest"],
- ["const godot_packed_float32_array *", "p_pra"]
- ]
- },
- {
- "name": "godot_array_new_packed_float64_array",
- "return_type": "void",
- "arguments": [
- ["godot_array *", "r_dest"],
- ["const godot_packed_float64_array *", "p_pra"]
- ]
- },
- {
- "name": "godot_array_new_packed_int32_array",
- "return_type": "void",
- "arguments": [
- ["godot_array *", "r_dest"],
- ["const godot_packed_int32_array *", "p_pia"]
- ]
- },
- {
- "name": "godot_array_new_packed_int64_array",
- "return_type": "void",
- "arguments": [
- ["godot_array *", "r_dest"],
- ["const godot_packed_int64_array *", "p_pia"]
- ]
- },
- {
- "name": "godot_array_new_packed_byte_array",
- "return_type": "void",
- "arguments": [
- ["godot_array *", "r_dest"],
- ["const godot_packed_byte_array *", "p_pba"]
- ]
- },
- {
- "name": "godot_array_set",
- "return_type": "void",
- "arguments": [
- ["godot_array *", "p_self"],
- ["const godot_int", "p_idx"],
- ["const godot_variant *", "p_value"]
- ]
- },
- {
- "name": "godot_array_get",
- "return_type": "godot_variant",
- "arguments": [
- ["const godot_array *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_array_operator_index",
- "return_type": "godot_variant *",
- "arguments": [
- ["godot_array *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_array_operator_index_const",
- "return_type": "const godot_variant *",
- "arguments": [
- ["const godot_array *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_array_append",
- "return_type": "void",
- "arguments": [
- ["godot_array *", "p_self"],
- ["const godot_variant *", "p_value"]
- ]
- },
- {
- "name": "godot_array_clear",
- "return_type": "void",
- "arguments": [
- ["godot_array *", "p_self"]
- ]
- },
- {
- "name": "godot_array_count",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_array *", "p_self"],
- ["const godot_variant *", "p_value"]
- ]
- },
- {
- "name": "godot_array_duplicate",
- "return_type": "godot_array",
- "arguments": [
- ["const godot_array *", "p_self"],
- ["const godot_bool", "p_deep"]
- ]
- },
- {
- "name": "godot_array_empty",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_array *", "p_self"]
- ]
- },
- {
- "name": "godot_array_erase",
- "return_type": "void",
- "arguments": [
- ["godot_array *", "p_self"],
- ["const godot_variant *", "p_value"]
- ]
- },
- {
- "name": "godot_array_front",
- "return_type": "godot_variant",
- "arguments": [
- ["const godot_array *", "p_self"]
- ]
- },
- {
- "name": "godot_array_back",
- "return_type": "godot_variant",
- "arguments": [
- ["const godot_array *", "p_self"]
- ]
- },
- {
- "name": "godot_array_find",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_array *", "p_self"],
- ["const godot_variant *", "p_what"],
- ["const godot_int", "p_from"]
- ]
- },
- {
- "name": "godot_array_find_last",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_array *", "p_self"],
- ["const godot_variant *", "p_what"]
- ]
- },
- {
- "name": "godot_array_has",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_array *", "p_self"],
- ["const godot_variant *", "p_value"]
- ]
- },
- {
- "name": "godot_array_hash",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_array *", "p_self"]
- ]
- },
- {
- "name": "godot_array_insert",
- "return_type": "void",
- "arguments": [
- ["godot_array *", "p_self"],
- ["const godot_int", "p_pos"],
- ["const godot_variant *", "p_value"]
- ]
- },
- {
- "name": "godot_array_invert",
- "return_type": "void",
- "arguments": [
- ["godot_array *", "p_self"]
- ]
- },
- {
- "name": "godot_array_max",
- "return_type": "godot_variant",
- "arguments": [
- ["const godot_array *", "p_self"]
- ]
- },
- {
- "name": "godot_array_min",
- "return_type": "godot_variant",
- "arguments": [
- ["const godot_array *", "p_self"]
- ]
- },
- {
- "name": "godot_array_pop_back",
- "return_type": "godot_variant",
- "arguments": [
- ["godot_array *", "p_self"]
- ]
- },
- {
- "name": "godot_array_pop_front",
- "return_type": "godot_variant",
- "arguments": [
- ["godot_array *", "p_self"]
- ]
- },
- {
- "name": "godot_array_push_back",
- "return_type": "void",
- "arguments": [
- ["godot_array *", "p_self"],
- ["const godot_variant *", "p_value"]
- ]
- },
- {
- "name": "godot_array_push_front",
- "return_type": "void",
- "arguments": [
- ["godot_array *", "p_self"],
- ["const godot_variant *", "p_value"]
- ]
- },
- {
- "name": "godot_array_remove",
- "return_type": "void",
- "arguments": [
- ["godot_array *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_array_resize",
- "return_type": "void",
- "arguments": [
- ["godot_array *", "p_self"],
- ["const godot_int", "p_size"]
- ]
- },
- {
- "name": "godot_array_rfind",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_array *", "p_self"],
- ["const godot_variant *", "p_what"],
- ["const godot_int", "p_from"]
- ]
- },
- {
- "name": "godot_array_size",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_array *", "p_self"]
- ]
- },
- {
- "name": "godot_array_shuffle",
- "return_type": "void",
- "arguments": [
- ["godot_array *", "p_self"]
- ]
- },
- {
- "name": "godot_array_slice",
- "return_type": "godot_array",
- "arguments": [
- ["const godot_array *", "p_self"],
- ["const godot_int", "p_begin"],
- ["const godot_int", "p_end"],
- ["const godot_int", "p_step"],
- ["const godot_bool", "p_deep"]
- ]
- },
- {
- "name": "godot_array_sort",
- "return_type": "void",
- "arguments": [
- ["godot_array *", "p_self"]
- ]
- },
- {
- "name": "godot_array_sort_custom",
- "return_type": "void",
- "arguments": [
- ["godot_array *", "p_self"],
- ["godot_object *", "p_obj"],
- ["const godot_string *", "p_func"]
- ]
- },
- {
- "name": "godot_array_bsearch",
- "return_type": "godot_int",
- "arguments": [
- ["godot_array *", "p_self"],
- ["const godot_variant *", "p_value"],
- ["const godot_bool", "p_before"]
- ]
- },
- {
- "name": "godot_array_bsearch_custom",
- "return_type": "godot_int",
- "arguments": [
- ["godot_array *", "p_self"],
- ["const godot_variant *", "p_value"],
- ["godot_object *", "p_obj"],
- ["const godot_string *", "p_func"],
- ["const godot_bool", "p_before"]
- ]
- },
- {
- "name": "godot_array_destroy",
- "return_type": "void",
- "arguments": [
- ["godot_array *", "p_self"]
- ]
- },
- {
- "name": "godot_basis_new_with_rows",
- "return_type": "void",
- "arguments": [
- ["godot_basis *", "r_dest"],
- ["const godot_vector3 *", "p_x_axis"],
- ["const godot_vector3 *", "p_y_axis"],
- ["const godot_vector3 *", "p_z_axis"]
- ]
- },
- {
- "name": "godot_basis_new_with_axis_and_angle",
- "return_type": "void",
- "arguments": [
- ["godot_basis *", "r_dest"],
- ["const godot_vector3 *", "p_axis"],
- ["const godot_real", "p_phi"]
- ]
- },
- {
- "name": "godot_basis_new_with_euler",
- "return_type": "void",
- "arguments": [
- ["godot_basis *", "r_dest"],
- ["const godot_vector3 *", "p_euler"]
- ]
- },
- {
- "name": "godot_basis_as_string",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_basis *", "p_self"]
- ]
- },
- {
- "name": "godot_basis_inverse",
- "return_type": "godot_basis",
- "arguments": [
- ["const godot_basis *", "p_self"]
- ]
- },
- {
- "name": "godot_basis_transposed",
- "return_type": "godot_basis",
- "arguments": [
- ["const godot_basis *", "p_self"]
- ]
- },
- {
- "name": "godot_basis_orthonormalized",
- "return_type": "godot_basis",
- "arguments": [
- ["const godot_basis *", "p_self"]
- ]
- },
- {
- "name": "godot_basis_determinant",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_basis *", "p_self"]
- ]
- },
- {
- "name": "godot_basis_rotated",
- "return_type": "godot_basis",
- "arguments": [
- ["const godot_basis *", "p_self"],
- ["const godot_vector3 *", "p_axis"],
- ["const godot_real", "p_phi"]
- ]
- },
- {
- "name": "godot_basis_scaled",
- "return_type": "godot_basis",
- "arguments": [
- ["const godot_basis *", "p_self"],
- ["const godot_vector3 *", "p_scale"]
- ]
- },
- {
- "name": "godot_basis_get_scale",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_basis *", "p_self"]
- ]
- },
- {
- "name": "godot_basis_get_euler",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_basis *", "p_self"]
- ]
- },
- {
- "name": "godot_basis_tdotx",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_basis *", "p_self"],
- ["const godot_vector3 *", "p_with"]
- ]
- },
- {
- "name": "godot_basis_tdoty",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_basis *", "p_self"],
- ["const godot_vector3 *", "p_with"]
- ]
- },
- {
- "name": "godot_basis_tdotz",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_basis *", "p_self"],
- ["const godot_vector3 *", "p_with"]
- ]
- },
- {
- "name": "godot_basis_xform",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_basis *", "p_self"],
- ["const godot_vector3 *", "p_v"]
- ]
- },
- {
- "name": "godot_basis_xform_inv",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_basis *", "p_self"],
- ["const godot_vector3 *", "p_v"]
- ]
- },
- {
- "name": "godot_basis_get_orthogonal_index",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_basis *", "p_self"]
- ]
- },
- {
- "name": "godot_basis_new",
- "return_type": "void",
- "arguments": [
- ["godot_basis *", "r_dest"]
- ]
- },
- {
- "name": "godot_basis_new_with_euler_quat",
- "return_type": "void",
- "arguments": [
- ["godot_basis *", "r_dest"],
- ["const godot_quat *", "p_euler"]
- ]
- },
- {
- "name": "godot_basis_get_elements",
- "return_type": "void",
- "arguments": [
- ["const godot_basis *", "p_self"],
- ["godot_vector3 *", "p_elements"]
- ]
- },
- {
- "name": "godot_basis_get_axis",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_basis *", "p_self"],
- ["const godot_int", "p_axis"]
- ]
- },
- {
- "name": "godot_basis_set_axis",
- "return_type": "void",
- "arguments": [
- ["godot_basis *", "p_self"],
- ["const godot_int", "p_axis"],
- ["const godot_vector3 *", "p_value"]
- ]
- },
- {
- "name": "godot_basis_get_row",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_basis *", "p_self"],
- ["const godot_int", "p_row"]
- ]
- },
- {
- "name": "godot_basis_set_row",
- "return_type": "void",
- "arguments": [
- ["godot_basis *", "p_self"],
- ["const godot_int", "p_row"],
- ["const godot_vector3 *", "p_value"]
- ]
- },
- {
- "name": "godot_basis_operator_equal",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_basis *", "p_self"],
- ["const godot_basis *", "p_b"]
- ]
- },
- {
- "name": "godot_basis_operator_add",
- "return_type": "godot_basis",
- "arguments": [
- ["const godot_basis *", "p_self"],
- ["const godot_basis *", "p_b"]
- ]
- },
- {
- "name": "godot_basis_operator_subtract",
- "return_type": "godot_basis",
- "arguments": [
- ["const godot_basis *", "p_self"],
- ["const godot_basis *", "p_b"]
- ]
- },
- {
- "name": "godot_basis_operator_multiply_vector",
- "return_type": "godot_basis",
- "arguments": [
- ["const godot_basis *", "p_self"],
- ["const godot_basis *", "p_b"]
- ]
- },
- {
- "name": "godot_basis_operator_multiply_scalar",
- "return_type": "godot_basis",
- "arguments": [
- ["const godot_basis *", "p_self"],
- ["const godot_real", "p_b"]
- ]
- },
- {
- "name": "godot_basis_slerp",
- "return_type": "godot_basis",
- "arguments": [
- ["const godot_basis *", "p_self"],
- ["const godot_basis *", "p_b"],
- ["const godot_real", "p_t"]
- ]
- },
- {
- "name": "godot_basis_get_quat",
- "return_type": "godot_quat",
- "arguments": [
- ["const godot_basis *", "p_self"]
- ]
- },
- {
- "name": "godot_basis_set_quat",
- "return_type": "void",
- "arguments": [
- ["godot_basis *", "p_self"],
- ["const godot_quat *", "p_quat"]
- ]
- },
- {
- "name": "godot_basis_set_axis_angle_scale",
- "return_type": "void",
- "arguments": [
- ["godot_basis *", "p_self"],
- ["const godot_vector3 *", "p_axis"],
- ["godot_real", "p_phi"],
- ["const godot_vector3 *", "p_scale"]
- ]
- },
- {
- "name": "godot_basis_set_euler_scale",
- "return_type": "void",
- "arguments": [
- ["godot_basis *", "p_self"],
- ["const godot_vector3 *", "p_euler"],
- ["const godot_vector3 *", "p_scale"]
- ]
- },
- {
- "name": "godot_basis_set_quat_scale",
- "return_type": "void",
- "arguments": [
- ["godot_basis *", "p_self"],
- ["const godot_quat *", "p_quat"],
- ["const godot_vector3 *", "p_scale"]
- ]
- },
- {
- "name": "godot_callable_new_with_object",
- "return_type": "void",
- "arguments": [
- ["godot_callable *", "r_dest"],
- ["const godot_object *", "p_object"],
- ["const godot_string_name *", "p_method"]
- ]
- },
- {
- "name": "godot_callable_new_with_object_id",
- "return_type": "void",
- "arguments": [
- ["godot_callable *", "r_dest"],
- ["uint64_t", "p_objectid"],
- ["const godot_string_name *", "p_method"]
- ]
- },
- {
- "name": "godot_callable_new_copy",
- "return_type": "void",
- "arguments": [
- ["godot_callable *", "r_dest"],
- ["const godot_callable *", "p_src"]
- ]
- },
- {
- "name": "godot_callable_destroy",
- "return_type": "void",
- "arguments": [
- ["godot_callable *", "p_self"]
- ]
- },
- {
- "name": "godot_callable_call",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_callable *", "p_self"],
- ["const godot_variant **", "p_arguments"],
- ["godot_int", "p_argcount"],
- ["godot_variant *", "r_return_value"]
- ]
- },
- {
- "name": "godot_callable_call_deferred",
- "return_type": "void",
- "arguments": [
- ["const godot_callable *", "p_self"],
- ["const godot_variant **", "p_arguments"],
- ["godot_int", "p_argcount"]
- ]
- },
- {
- "name": "godot_callable_is_null",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_callable *", "p_self"]
- ]
- },
- {
- "name": "godot_callable_is_custom",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_callable *", "p_self"]
- ]
- },
- {
- "name": "godot_callable_is_standard",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_callable *", "p_self"]
- ]
- },
- {
- "name": "godot_callable_get_object",
- "return_type": "godot_object *",
- "arguments": [
- ["const godot_callable *", "p_self"]
- ]
- },
- {
- "name": "godot_callable_get_object_id",
- "return_type": "uint64_t",
- "arguments": [
- ["const godot_callable *", "p_self"]
- ]
- },
- {
- "name": "godot_callable_get_method",
- "return_type": "godot_string_name",
- "arguments": [
- ["const godot_callable *", "p_self"]
- ]
- },
- {
- "name": "godot_callable_hash",
- "return_type": "uint32_t",
- "arguments": [
- ["const godot_callable *", "p_self"]
- ]
- },
- {
- "name": "godot_callable_as_string",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_callable *", "p_self"]
- ]
- },
- {
- "name": "godot_callable_operator_equal",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_callable *", "p_self"],
- ["const godot_callable *", "p_other"]
- ]
- },
- {
- "name": "godot_callable_operator_less",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_callable *", "p_self"],
- ["const godot_callable *", "p_other"]
- ]
- },
- {
- "name": "godot_signal_new_with_object",
- "return_type": "void",
- "arguments": [
- ["godot_signal *", "r_dest"],
- ["const godot_object *", "p_object"],
- ["const godot_string_name *", "p_method"]
- ]
- },
- {
- "name": "godot_signal_new_with_object_id",
- "return_type": "void",
- "arguments": [
- ["godot_signal *", "r_dest"],
- ["uint64_t", "p_objectid"],
- ["const godot_string_name *", "p_method"]
- ]
- },
- {
- "name": "godot_signal_new_copy",
- "return_type": "void",
- "arguments": [
- ["godot_signal *", "r_dest"],
- ["const godot_signal *", "p_src"]
- ]
- },
- {
- "name": "godot_signal_destroy",
- "return_type": "void",
- "arguments": [
- ["godot_signal *", "p_self"]
- ]
- },
- {
- "name": "godot_signal_emit",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_signal *", "p_self"],
- ["const godot_variant **", "p_arguments"],
- ["godot_int", "p_argcount"]
- ]
- },
- {
- "name": "godot_signal_connect",
- "return_type": "godot_int",
- "arguments": [
- ["godot_signal *", "p_self"],
- ["const godot_callable *", "p_callable"],
- ["const godot_array *", "p_binds"],
- ["uint32_t", "p_flags"]
- ]
- },
- {
- "name": "godot_signal_disconnect",
- "return_type": "void",
- "arguments": [
- ["godot_signal *", "p_self"],
- ["const godot_callable *", "p_callable"]
- ]
- },
- {
- "name": "godot_signal_is_null",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_signal *", "p_self"]
- ]
- },
- {
- "name": "godot_signal_is_connected",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_signal *", "p_self"],
- ["const godot_callable *", "p_callable"]
- ]
- },
- {
- "name": "godot_signal_get_connections",
- "return_type": "godot_array",
- "arguments": [
- ["const godot_signal *", "p_self"]
- ]
- },
- {
- "name": "godot_signal_get_object",
- "return_type": "godot_object *",
- "arguments": [
- ["const godot_signal *", "p_self"]
- ]
- },
- {
- "name": "godot_signal_get_object_id",
- "return_type": "uint64_t",
- "arguments": [
- ["const godot_signal *", "p_self"]
- ]
- },
- {
- "name": "godot_signal_get_name",
- "return_type": "godot_string_name",
- "arguments": [
- ["const godot_signal *", "p_self"]
- ]
- },
- {
- "name": "godot_signal_as_string",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_signal *", "p_self"]
- ]
- },
- {
- "name": "godot_signal_operator_equal",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_signal *", "p_self"],
- ["const godot_signal *", "p_other"]
- ]
- },
- {
- "name": "godot_signal_operator_less",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_signal *", "p_self"],
- ["const godot_signal *", "p_other"]
- ]
- },
- {
- "name": "godot_color_new_rgba",
- "return_type": "void",
- "arguments": [
- ["godot_color *", "r_dest"],
- ["const godot_real", "p_r"],
- ["const godot_real", "p_g"],
- ["const godot_real", "p_b"],
- ["const godot_real", "p_a"]
- ]
- },
- {
- "name": "godot_color_new_rgb",
- "return_type": "void",
- "arguments": [
- ["godot_color *", "r_dest"],
- ["const godot_real", "p_r"],
- ["const godot_real", "p_g"],
- ["const godot_real", "p_b"]
- ]
- },
- {
- "name": "godot_color_get_r",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_color *", "p_self"]
- ]
- },
- {
- "name": "godot_color_set_r",
- "return_type": "void",
- "arguments": [
- ["godot_color *", "p_self"],
- ["const godot_real", "r"]
- ]
- },
- {
- "name": "godot_color_get_g",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_color *", "p_self"]
- ]
- },
- {
- "name": "godot_color_set_g",
- "return_type": "void",
- "arguments": [
- ["godot_color *", "p_self"],
- ["const godot_real", "g"]
- ]
- },
- {
- "name": "godot_color_get_b",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_color *", "p_self"]
- ]
- },
- {
- "name": "godot_color_set_b",
- "return_type": "void",
- "arguments": [
- ["godot_color *", "p_self"],
- ["const godot_real", "b"]
- ]
- },
- {
- "name": "godot_color_get_a",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_color *", "p_self"]
- ]
- },
- {
- "name": "godot_color_set_a",
- "return_type": "void",
- "arguments": [
- ["godot_color *", "p_self"],
- ["const godot_real", "a"]
- ]
- },
- {
- "name": "godot_color_get_h",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_color *", "p_self"]
- ]
- },
- {
- "name": "godot_color_get_s",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_color *", "p_self"]
- ]
- },
- {
- "name": "godot_color_get_v",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_color *", "p_self"]
- ]
- },
- {
- "name": "godot_color_as_string",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_color *", "p_self"]
- ]
- },
- {
- "name": "godot_color_to_rgba32",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_color *", "p_self"]
- ]
- },
- {
- "name": "godot_color_to_argb32",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_color *", "p_self"]
- ]
- },
- {
- "name": "godot_color_inverted",
- "return_type": "godot_color",
- "arguments": [
- ["const godot_color *", "p_self"]
- ]
- },
- {
- "name": "godot_color_contrasted",
- "return_type": "godot_color",
- "arguments": [
- ["const godot_color *", "p_self"]
- ]
- },
- {
- "name": "godot_color_lerp",
- "return_type": "godot_color",
- "arguments": [
- ["const godot_color *", "p_self"],
- ["const godot_color *", "p_b"],
- ["const godot_real", "p_t"]
- ]
- },
- {
- "name": "godot_color_blend",
- "return_type": "godot_color",
- "arguments": [
- ["const godot_color *", "p_self"],
- ["const godot_color *", "p_over"]
- ]
- },
- {
- "name": "godot_color_to_html",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_color *", "p_self"],
- ["const godot_bool", "p_with_alpha"]
- ]
- },
- {
- "name": "godot_color_operator_equal",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_color *", "p_self"],
- ["const godot_color *", "p_b"]
- ]
- },
- {
- "name": "godot_color_operator_less",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_color *", "p_self"],
- ["const godot_color *", "p_b"]
- ]
- },
- {
- "name": "godot_color_to_abgr32",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_color *", "p_self"]
- ]
- },
- {
- "name": "godot_color_to_abgr64",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_color *", "p_self"]
- ]
- },
- {
- "name": "godot_color_to_argb64",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_color *", "p_self"]
- ]
- },
- {
- "name": "godot_color_to_rgba64",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_color *", "p_self"]
- ]
- },
- {
- "name": "godot_color_darkened",
- "return_type": "godot_color",
- "arguments": [
- ["const godot_color *", "p_self"],
- ["const godot_real", "p_amount"]
- ]
- },
- {
- "name": "godot_color_from_hsv",
- "return_type": "godot_color",
- "arguments": [
- ["const godot_color *", "p_self"],
- ["const godot_real", "p_h"],
- ["const godot_real", "p_s"],
- ["const godot_real", "p_v"],
- ["const godot_real", "p_a"]
- ]
- },
- {
- "name": "godot_color_lightened",
- "return_type": "godot_color",
- "arguments": [
- ["const godot_color *", "p_self"],
- ["const godot_real", "p_amount"]
- ]
- },
- {
- "name": "godot_dictionary_new",
- "return_type": "void",
- "arguments": [
- ["godot_dictionary *", "r_dest"]
- ]
- },
- {
- "name": "godot_dictionary_new_copy",
- "return_type": "void",
- "arguments": [
- ["godot_dictionary *", "r_dest"],
- ["const godot_dictionary *", "p_src"]
- ]
- },
- {
- "name": "godot_dictionary_destroy",
- "return_type": "void",
- "arguments": [
- ["godot_dictionary *", "p_self"]
- ]
- },
- {
- "name": "godot_dictionary_size",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_dictionary *", "p_self"]
- ]
- },
- {
- "name": "godot_dictionary_empty",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_dictionary *", "p_self"]
- ]
- },
- {
- "name": "godot_dictionary_clear",
- "return_type": "void",
- "arguments": [
- ["godot_dictionary *", "p_self"]
- ]
- },
- {
- "name": "godot_dictionary_has",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_dictionary *", "p_self"],
- ["const godot_variant *", "p_key"]
- ]
- },
- {
- "name": "godot_dictionary_has_all",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_dictionary *", "p_self"],
- ["const godot_array *", "p_keys"]
- ]
- },
- {
- "name": "godot_dictionary_erase",
- "return_type": "void",
- "arguments": [
- ["godot_dictionary *", "p_self"],
- ["const godot_variant *", "p_key"]
- ]
- },
- {
- "name": "godot_dictionary_hash",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_dictionary *", "p_self"]
- ]
- },
- {
- "name": "godot_dictionary_keys",
- "return_type": "godot_array",
- "arguments": [
- ["const godot_dictionary *", "p_self"]
- ]
- },
- {
- "name": "godot_dictionary_values",
- "return_type": "godot_array",
- "arguments": [
- ["const godot_dictionary *", "p_self"]
- ]
- },
- {
- "name": "godot_dictionary_get",
- "return_type": "godot_variant",
- "arguments": [
- ["const godot_dictionary *", "p_self"],
- ["const godot_variant *", "p_key"]
- ]
- },
- {
- "name": "godot_dictionary_set",
- "return_type": "void",
- "arguments": [
- ["godot_dictionary *", "p_self"],
- ["const godot_variant *", "p_key"],
- ["const godot_variant *", "p_value"]
- ]
- },
- {
- "name": "godot_dictionary_operator_index",
- "return_type": "godot_variant *",
- "arguments": [
- ["godot_dictionary *", "p_self"],
- ["const godot_variant *", "p_key"]
- ]
- },
- {
- "name": "godot_dictionary_operator_index_const",
- "return_type": "const godot_variant *",
- "arguments": [
- ["const godot_dictionary *", "p_self"],
- ["const godot_variant *", "p_key"]
- ]
- },
- {
- "name": "godot_dictionary_next",
- "return_type": "godot_variant *",
- "arguments": [
- ["const godot_dictionary *", "p_self"],
- ["const godot_variant *", "p_key"]
- ]
- },
- {
- "name": "godot_dictionary_operator_equal",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_dictionary *", "p_self"],
- ["const godot_dictionary *", "p_b"]
- ]
- },
- {
- "name": "godot_dictionary_to_json",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_dictionary *", "p_self"]
- ]
- },
- {
- "name": "godot_dictionary_duplicate",
- "return_type": "godot_dictionary",
- "arguments": [
- ["const godot_dictionary *", "p_self"],
- ["const godot_bool", "p_deep"]
- ]
- },
- {
- "name": "godot_dictionary_get_with_default",
- "return_type": "godot_variant",
- "arguments": [
- ["const godot_dictionary *", "p_self"],
- ["const godot_variant *", "p_key"],
- ["const godot_variant *", "p_default"]
- ]
- },
- {
- "name": "godot_dictionary_erase_with_return",
- "return_type": "bool",
- "arguments": [
- ["godot_dictionary *", "p_self"],
- ["const godot_variant *", "p_key"]
- ]
- },
- {
- "name": "godot_node_path_new",
- "return_type": "void",
- "arguments": [
- ["godot_node_path *", "r_dest"],
- ["const godot_string *", "p_from"]
- ]
- },
- {
- "name": "godot_node_path_new_copy",
- "return_type": "void",
- "arguments": [
- ["godot_node_path *", "r_dest"],
- ["const godot_node_path *", "p_src"]
- ]
- },
- {
- "name": "godot_node_path_destroy",
- "return_type": "void",
- "arguments": [
- ["godot_node_path *", "p_self"]
- ]
- },
- {
- "name": "godot_node_path_as_string",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_node_path *", "p_self"]
- ]
- },
- {
- "name": "godot_node_path_is_absolute",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_node_path *", "p_self"]
- ]
- },
- {
- "name": "godot_node_path_get_name_count",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_node_path *", "p_self"]
- ]
- },
- {
- "name": "godot_node_path_get_name",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_node_path *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_node_path_get_subname_count",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_node_path *", "p_self"]
- ]
- },
- {
- "name": "godot_node_path_get_subname",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_node_path *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_node_path_get_concatenated_subnames",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_node_path *", "p_self"]
- ]
- },
- {
- "name": "godot_node_path_is_empty",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_node_path *", "p_self"]
- ]
- },
- {
- "name": "godot_node_path_operator_equal",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_node_path *", "p_self"],
- ["const godot_node_path *", "p_b"]
- ]
- },
- {
- "name": "godot_node_path_get_as_property_path",
- "return_type": "godot_node_path",
- "arguments": [
- ["const godot_node_path *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_byte_array_new",
- "return_type": "void",
- "arguments": [
- ["godot_packed_byte_array *", "r_dest"]
- ]
- },
- {
- "name": "godot_packed_byte_array_new_copy",
- "return_type": "void",
- "arguments": [
- ["godot_packed_byte_array *", "r_dest"],
- ["const godot_packed_byte_array *", "p_src"]
- ]
- },
- {
- "name": "godot_packed_byte_array_new_with_array",
- "return_type": "void",
- "arguments": [
- ["godot_packed_byte_array *", "r_dest"],
- ["const godot_array *", "p_a"]
- ]
- },
- {
- "name": "godot_packed_byte_array_empty",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_packed_byte_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_byte_array_append",
- "return_type": "void",
- "arguments": [
- ["godot_packed_byte_array *", "p_self"],
- ["const uint8_t", "p_data"]
- ]
- },
- {
- "name": "godot_packed_byte_array_append_array",
- "return_type": "void",
- "arguments": [
- ["godot_packed_byte_array *", "p_self"],
- ["const godot_packed_byte_array *", "p_array"]
- ]
- },
- {
- "name": "godot_packed_byte_array_insert",
- "return_type": "godot_error",
- "arguments": [
- ["godot_packed_byte_array *", "p_self"],
- ["const godot_int", "p_idx"],
- ["const uint8_t", "p_data"]
- ]
- },
- {
- "name": "godot_packed_byte_array_has",
- "return_type": "godot_bool",
- "arguments": [
- ["godot_packed_byte_array *", "p_self"],
- ["const uint8_t", "p_value"]
- ]
- },
- {
- "name": "godot_packed_byte_array_sort",
- "return_type": "void",
- "arguments": [
- ["godot_packed_byte_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_byte_array_invert",
- "return_type": "void",
- "arguments": [
- ["godot_packed_byte_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_byte_array_push_back",
- "return_type": "void",
- "arguments": [
- ["godot_packed_byte_array *", "p_self"],
- ["const uint8_t", "p_data"]
- ]
- },
- {
- "name": "godot_packed_byte_array_remove",
- "return_type": "void",
- "arguments": [
- ["godot_packed_byte_array *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_packed_byte_array_resize",
- "return_type": "void",
- "arguments": [
- ["godot_packed_byte_array *", "p_self"],
- ["const godot_int", "p_size"]
- ]
- },
- {
- "name": "godot_packed_byte_array_ptr",
- "return_type": "const uint8_t *",
- "arguments": [
- ["const godot_packed_byte_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_byte_array_ptrw",
- "return_type": "uint8_t *",
- "arguments": [
- ["godot_packed_byte_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_byte_array_set",
- "return_type": "void",
- "arguments": [
- ["godot_packed_byte_array *", "p_self"],
- ["const godot_int", "p_idx"],
- ["const uint8_t", "p_data"]
- ]
- },
- {
- "name": "godot_packed_byte_array_get",
- "return_type": "uint8_t",
- "arguments": [
- ["const godot_packed_byte_array *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_packed_byte_array_size",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_packed_byte_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_byte_array_destroy",
- "return_type": "void",
- "arguments": [
- ["godot_packed_byte_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_int32_array_new",
- "return_type": "void",
- "arguments": [
- ["godot_packed_int32_array *", "r_dest"]
- ]
- },
- {
- "name": "godot_packed_int32_array_new_copy",
- "return_type": "void",
- "arguments": [
- ["godot_packed_int32_array *", "r_dest"],
- ["const godot_packed_int32_array *", "p_src"]
- ]
- },
- {
- "name": "godot_packed_int32_array_new_with_array",
- "return_type": "void",
- "arguments": [
- ["godot_packed_int32_array *", "r_dest"],
- ["const godot_array *", "p_a"]
- ]
- },
- {
- "name": "godot_packed_int32_array_empty",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_packed_int32_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_int32_array_append",
- "return_type": "void",
- "arguments": [
- ["godot_packed_int32_array *", "p_self"],
- ["const int32_t", "p_data"]
- ]
- },
- {
- "name": "godot_packed_int32_array_append_array",
- "return_type": "void",
- "arguments": [
- ["godot_packed_int32_array *", "p_self"],
- ["const godot_packed_int32_array *", "p_array"]
- ]
- },
- {
- "name": "godot_packed_int32_array_insert",
- "return_type": "godot_error",
- "arguments": [
- ["godot_packed_int32_array *", "p_self"],
- ["const godot_int", "p_idx"],
- ["const int32_t", "p_data"]
- ]
- },
- {
- "name": "godot_packed_int32_array_has",
- "return_type": "godot_bool",
- "arguments": [
- ["godot_packed_int32_array *", "p_self"],
- ["const int32_t", "p_value"]
- ]
- },
- {
- "name": "godot_packed_int32_array_sort",
- "return_type": "void",
- "arguments": [
- ["godot_packed_int32_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_int32_array_invert",
- "return_type": "void",
- "arguments": [
- ["godot_packed_int32_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_int32_array_push_back",
- "return_type": "void",
- "arguments": [
- ["godot_packed_int32_array *", "p_self"],
- ["const int32_t", "p_data"]
- ]
- },
- {
- "name": "godot_packed_int32_array_remove",
- "return_type": "void",
- "arguments": [
- ["godot_packed_int32_array *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_packed_int32_array_resize",
- "return_type": "void",
- "arguments": [
- ["godot_packed_int32_array *", "p_self"],
- ["const godot_int", "p_size"]
- ]
- },
- {
- "name": "godot_packed_int32_array_ptr",
- "return_type": "const int32_t *",
- "arguments": [
- ["const godot_packed_int32_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_int32_array_ptrw",
- "return_type": "int32_t *",
- "arguments": [
- ["godot_packed_int32_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_int32_array_set",
- "return_type": "void",
- "arguments": [
- ["godot_packed_int32_array *", "p_self"],
- ["const godot_int", "p_idx"],
- ["const int32_t", "p_data"]
- ]
- },
- {
- "name": "godot_packed_int32_array_get",
- "return_type": "int32_t",
- "arguments": [
- ["const godot_packed_int32_array *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_packed_int32_array_size",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_packed_int32_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_int32_array_destroy",
- "return_type": "void",
- "arguments": [
- ["godot_packed_int32_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_int64_array_new",
- "return_type": "void",
- "arguments": [
- ["godot_packed_int64_array *", "r_dest"]
- ]
- },
- {
- "name": "godot_packed_int64_array_new_copy",
- "return_type": "void",
- "arguments": [
- ["godot_packed_int64_array *", "r_dest"],
- ["const godot_packed_int64_array *", "p_src"]
- ]
- },
- {
- "name": "godot_packed_int64_array_new_with_array",
- "return_type": "void",
- "arguments": [
- ["godot_packed_int64_array *", "r_dest"],
- ["const godot_array *", "p_a"]
- ]
- },
- {
- "name": "godot_packed_int64_array_empty",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_packed_int64_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_int64_array_append",
- "return_type": "void",
- "arguments": [
- ["godot_packed_int64_array *", "p_self"],
- ["const int64_t", "p_data"]
- ]
- },
- {
- "name": "godot_packed_int64_array_append_array",
- "return_type": "void",
- "arguments": [
- ["godot_packed_int64_array *", "p_self"],
- ["const godot_packed_int64_array *", "p_array"]
- ]
- },
- {
- "name": "godot_packed_int64_array_insert",
- "return_type": "godot_error",
- "arguments": [
- ["godot_packed_int64_array *", "p_self"],
- ["const godot_int", "p_idx"],
- ["const int64_t", "p_data"]
- ]
- },
- {
- "name": "godot_packed_int64_array_has",
- "return_type": "godot_bool",
- "arguments": [
- ["godot_packed_int64_array *", "p_self"],
- ["const int64_t", "p_value"]
- ]
- },
- {
- "name": "godot_packed_int64_array_sort",
- "return_type": "void",
- "arguments": [
- ["godot_packed_int64_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_int64_array_invert",
- "return_type": "void",
- "arguments": [
- ["godot_packed_int64_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_int64_array_push_back",
- "return_type": "void",
- "arguments": [
- ["godot_packed_int64_array *", "p_self"],
- ["const int64_t", "p_data"]
- ]
- },
- {
- "name": "godot_packed_int64_array_remove",
- "return_type": "void",
- "arguments": [
- ["godot_packed_int64_array *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_packed_int64_array_resize",
- "return_type": "void",
- "arguments": [
- ["godot_packed_int64_array *", "p_self"],
- ["const godot_int", "p_size"]
- ]
- },
- {
- "name": "godot_packed_int64_array_ptr",
- "return_type": "const int64_t *",
- "arguments": [
- ["const godot_packed_int64_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_int64_array_ptrw",
- "return_type": "int64_t *",
- "arguments": [
- ["godot_packed_int64_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_int64_array_set",
- "return_type": "void",
- "arguments": [
- ["godot_packed_int64_array *", "p_self"],
- ["const godot_int", "p_idx"],
- ["const int64_t", "p_data"]
- ]
- },
- {
- "name": "godot_packed_int64_array_get",
- "return_type": "int64_t",
- "arguments": [
- ["const godot_packed_int64_array *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_packed_int64_array_size",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_packed_int64_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_int64_array_destroy",
- "return_type": "void",
- "arguments": [
- ["godot_packed_int64_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_float32_array_new",
- "return_type": "void",
- "arguments": [
- ["godot_packed_float32_array *", "r_dest"]
- ]
- },
- {
- "name": "godot_packed_float32_array_new_copy",
- "return_type": "void",
- "arguments": [
- ["godot_packed_float32_array *", "r_dest"],
- ["const godot_packed_float32_array *", "p_src"]
- ]
- },
- {
- "name": "godot_packed_float32_array_new_with_array",
- "return_type": "void",
- "arguments": [
- ["godot_packed_float32_array *", "r_dest"],
- ["const godot_array *", "p_a"]
- ]
- },
- {
- "name": "godot_packed_float32_array_empty",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_packed_float32_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_float32_array_append",
- "return_type": "void",
- "arguments": [
- ["godot_packed_float32_array *", "p_self"],
- ["const float", "p_data"]
- ]
- },
- {
- "name": "godot_packed_float32_array_append_array",
- "return_type": "void",
- "arguments": [
- ["godot_packed_float32_array *", "p_self"],
- ["const godot_packed_float32_array *", "p_array"]
- ]
- },
- {
- "name": "godot_packed_float32_array_insert",
- "return_type": "godot_error",
- "arguments": [
- ["godot_packed_float32_array *", "p_self"],
- ["const godot_int", "p_idx"],
- ["const float", "p_data"]
- ]
- },
- {
- "name": "godot_packed_float32_array_has",
- "return_type": "godot_bool",
- "arguments": [
- ["godot_packed_float32_array *", "p_self"],
- ["const float", "p_value"]
- ]
- },
- {
- "name": "godot_packed_float32_array_sort",
- "return_type": "void",
- "arguments": [
- ["godot_packed_float32_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_float32_array_invert",
- "return_type": "void",
- "arguments": [
- ["godot_packed_float32_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_float32_array_push_back",
- "return_type": "void",
- "arguments": [
- ["godot_packed_float32_array *", "p_self"],
- ["const float", "p_data"]
- ]
- },
- {
- "name": "godot_packed_float32_array_remove",
- "return_type": "void",
- "arguments": [
- ["godot_packed_float32_array *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_packed_float32_array_resize",
- "return_type": "void",
- "arguments": [
- ["godot_packed_float32_array *", "p_self"],
- ["const godot_int", "p_size"]
- ]
- },
- {
- "name": "godot_packed_float32_array_ptr",
- "return_type": "const float *",
- "arguments": [
- ["const godot_packed_float32_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_float32_array_ptrw",
- "return_type": "float *",
- "arguments": [
- ["godot_packed_float32_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_float32_array_set",
- "return_type": "void",
- "arguments": [
- ["godot_packed_float32_array *", "p_self"],
- ["const godot_int", "p_idx"],
- ["const float", "p_data"]
- ]
- },
- {
- "name": "godot_packed_float32_array_get",
- "return_type": "float",
- "arguments": [
- ["const godot_packed_float32_array *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_packed_float32_array_size",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_packed_float32_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_float32_array_destroy",
- "return_type": "void",
- "arguments": [
- ["godot_packed_float32_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_float64_array_new",
- "return_type": "void",
- "arguments": [
- ["godot_packed_float64_array *", "r_dest"]
- ]
- },
- {
- "name": "godot_packed_float64_array_new_copy",
- "return_type": "void",
- "arguments": [
- ["godot_packed_float64_array *", "r_dest"],
- ["const godot_packed_float64_array *", "p_src"]
- ]
- },
- {
- "name": "godot_packed_float64_array_new_with_array",
- "return_type": "void",
- "arguments": [
- ["godot_packed_float64_array *", "r_dest"],
- ["const godot_array *", "p_a"]
- ]
- },
- {
- "name": "godot_packed_float64_array_empty",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_packed_float64_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_float64_array_append",
- "return_type": "void",
- "arguments": [
- ["godot_packed_float64_array *", "p_self"],
- ["const double", "p_data"]
- ]
- },
- {
- "name": "godot_packed_float64_array_append_array",
- "return_type": "void",
- "arguments": [
- ["godot_packed_float64_array *", "p_self"],
- ["const godot_packed_float64_array *", "p_array"]
- ]
- },
- {
- "name": "godot_packed_float64_array_insert",
- "return_type": "godot_error",
- "arguments": [
- ["godot_packed_float64_array *", "p_self"],
- ["const godot_int", "p_idx"],
- ["const double", "p_data"]
- ]
- },
- {
- "name": "godot_packed_float64_array_has",
- "return_type": "godot_bool",
- "arguments": [
- ["godot_packed_float64_array *", "p_self"],
- ["const double", "p_value"]
- ]
- },
- {
- "name": "godot_packed_float64_array_sort",
- "return_type": "void",
- "arguments": [
- ["godot_packed_float64_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_float64_array_invert",
- "return_type": "void",
- "arguments": [
- ["godot_packed_float64_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_float64_array_push_back",
- "return_type": "void",
- "arguments": [
- ["godot_packed_float64_array *", "p_self"],
- ["const double", "p_data"]
- ]
- },
- {
- "name": "godot_packed_float64_array_remove",
- "return_type": "void",
- "arguments": [
- ["godot_packed_float64_array *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_packed_float64_array_resize",
- "return_type": "void",
- "arguments": [
- ["godot_packed_float64_array *", "p_self"],
- ["const godot_int", "p_size"]
- ]
- },
- {
- "name": "godot_packed_float64_array_ptr",
- "return_type": "const double *",
- "arguments": [
- ["const godot_packed_float64_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_float64_array_ptrw",
- "return_type": "double *",
- "arguments": [
- ["godot_packed_float64_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_float64_array_set",
- "return_type": "void",
- "arguments": [
- ["godot_packed_float64_array *", "p_self"],
- ["const godot_int", "p_idx"],
- ["const double", "p_data"]
- ]
- },
- {
- "name": "godot_packed_float64_array_get",
- "return_type": "double",
- "arguments": [
- ["const godot_packed_float64_array *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_packed_float64_array_size",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_packed_float64_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_float64_array_destroy",
- "return_type": "void",
- "arguments": [
- ["godot_packed_float64_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_string_array_new",
- "return_type": "void",
- "arguments": [
- ["godot_packed_string_array *", "r_dest"]
- ]
- },
- {
- "name": "godot_packed_string_array_new_copy",
- "return_type": "void",
- "arguments": [
- ["godot_packed_string_array *", "r_dest"],
- ["const godot_packed_string_array *", "p_src"]
- ]
- },
- {
- "name": "godot_packed_string_array_new_with_array",
- "return_type": "void",
- "arguments": [
- ["godot_packed_string_array *", "r_dest"],
- ["const godot_array *", "p_a"]
- ]
- },
- {
- "name": "godot_packed_string_array_empty",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_packed_string_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_string_array_append",
- "return_type": "void",
- "arguments": [
- ["godot_packed_string_array *", "p_self"],
- ["const godot_string *", "p_data"]
- ]
- },
- {
- "name": "godot_packed_string_array_append_array",
- "return_type": "void",
- "arguments": [
- ["godot_packed_string_array *", "p_self"],
- ["const godot_packed_string_array *", "p_array"]
- ]
- },
- {
- "name": "godot_packed_string_array_insert",
- "return_type": "godot_error",
- "arguments": [
- ["godot_packed_string_array *", "p_self"],
- ["const godot_int", "p_idx"],
- ["const godot_string *", "p_data"]
- ]
- },
- {
- "name": "godot_packed_string_array_has",
- "return_type": "godot_bool",
- "arguments": [
- ["godot_packed_string_array *", "p_self"],
- ["const godot_string *", "p_value"]
- ]
- },
- {
- "name": "godot_packed_string_array_sort",
- "return_type": "void",
- "arguments": [
- ["godot_packed_string_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_string_array_invert",
- "return_type": "void",
- "arguments": [
- ["godot_packed_string_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_string_array_push_back",
- "return_type": "void",
- "arguments": [
- ["godot_packed_string_array *", "p_self"],
- ["const godot_string *", "p_data"]
- ]
- },
- {
- "name": "godot_packed_string_array_remove",
- "return_type": "void",
- "arguments": [
- ["godot_packed_string_array *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_packed_string_array_resize",
- "return_type": "void",
- "arguments": [
- ["godot_packed_string_array *", "p_self"],
- ["const godot_int", "p_size"]
- ]
- },
- {
- "name": "godot_packed_string_array_ptr",
- "return_type": "const godot_string *",
- "arguments": [
- ["const godot_packed_string_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_string_array_ptrw",
- "return_type": "godot_string *",
- "arguments": [
- ["godot_packed_string_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_string_array_set",
- "return_type": "void",
- "arguments": [
- ["godot_packed_string_array *", "p_self"],
- ["const godot_int", "p_idx"],
- ["const godot_string *", "p_data"]
- ]
- },
- {
- "name": "godot_packed_string_array_get",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_packed_string_array *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_packed_string_array_size",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_packed_string_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_string_array_destroy",
- "return_type": "void",
- "arguments": [
- ["godot_packed_string_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_vector2_array_new",
- "return_type": "void",
- "arguments": [
- ["godot_packed_vector2_array *", "r_dest"]
- ]
- },
- {
- "name": "godot_packed_vector2_array_new_copy",
- "return_type": "void",
- "arguments": [
- ["godot_packed_vector2_array *", "r_dest"],
- ["const godot_packed_vector2_array *", "p_src"]
- ]
- },
- {
- "name": "godot_packed_vector2_array_new_with_array",
- "return_type": "void",
- "arguments": [
- ["godot_packed_vector2_array *", "r_dest"],
- ["const godot_array *", "p_a"]
- ]
- },
- {
- "name": "godot_packed_vector2_array_empty",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_packed_vector2_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_vector2_array_append",
- "return_type": "void",
- "arguments": [
- ["godot_packed_vector2_array *", "p_self"],
- ["const godot_vector2 *", "p_data"]
- ]
- },
- {
- "name": "godot_packed_vector2_array_append_array",
- "return_type": "void",
- "arguments": [
- ["godot_packed_vector2_array *", "p_self"],
- ["const godot_packed_vector2_array *", "p_array"]
- ]
- },
- {
- "name": "godot_packed_vector2_array_insert",
- "return_type": "godot_error",
- "arguments": [
- ["godot_packed_vector2_array *", "p_self"],
- ["const godot_int", "p_idx"],
- ["const godot_vector2 *", "p_data"]
- ]
- },
- {
- "name": "godot_packed_vector2_array_has",
- "return_type": "godot_bool",
- "arguments": [
- ["godot_packed_vector2_array *", "p_self"],
- ["const godot_vector2 *", "p_value"]
- ]
- },
- {
- "name": "godot_packed_vector2_array_sort",
- "return_type": "void",
- "arguments": [
- ["godot_packed_vector2_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_vector2_array_invert",
- "return_type": "void",
- "arguments": [
- ["godot_packed_vector2_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_vector2_array_push_back",
- "return_type": "void",
- "arguments": [
- ["godot_packed_vector2_array *", "p_self"],
- ["const godot_vector2 *", "p_data"]
- ]
- },
- {
- "name": "godot_packed_vector2_array_remove",
- "return_type": "void",
- "arguments": [
- ["godot_packed_vector2_array *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_packed_vector2_array_resize",
- "return_type": "void",
- "arguments": [
- ["godot_packed_vector2_array *", "p_self"],
- ["const godot_int", "p_size"]
- ]
- },
- {
- "name": "godot_packed_vector2_array_ptr",
- "return_type": "const godot_vector2 *",
- "arguments": [
- ["const godot_packed_vector2_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_vector2_array_ptrw",
- "return_type": "godot_vector2 *",
- "arguments": [
- ["godot_packed_vector2_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_vector2_array_set",
- "return_type": "void",
- "arguments": [
- ["godot_packed_vector2_array *", "p_self"],
- ["const godot_int", "p_idx"],
- ["const godot_vector2 *", "p_data"]
- ]
- },
- {
- "name": "godot_packed_vector2_array_get",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_packed_vector2_array *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_packed_vector2_array_size",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_packed_vector2_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_vector2_array_destroy",
- "return_type": "void",
- "arguments": [
- ["godot_packed_vector2_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_vector3_array_new",
- "return_type": "void",
- "arguments": [
- ["godot_packed_vector3_array *", "r_dest"]
- ]
- },
- {
- "name": "godot_packed_vector3_array_new_copy",
- "return_type": "void",
- "arguments": [
- ["godot_packed_vector3_array *", "r_dest"],
- ["const godot_packed_vector3_array *", "p_src"]
- ]
- },
- {
- "name": "godot_packed_vector3_array_new_with_array",
- "return_type": "void",
- "arguments": [
- ["godot_packed_vector3_array *", "r_dest"],
- ["const godot_array *", "p_a"]
- ]
- },
- {
- "name": "godot_packed_vector3_array_empty",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_packed_vector3_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_vector3_array_append",
- "return_type": "void",
- "arguments": [
- ["godot_packed_vector3_array *", "p_self"],
- ["const godot_vector3 *", "p_data"]
- ]
- },
- {
- "name": "godot_packed_vector3_array_append_array",
- "return_type": "void",
- "arguments": [
- ["godot_packed_vector3_array *", "p_self"],
- ["const godot_packed_vector3_array *", "p_array"]
- ]
- },
- {
- "name": "godot_packed_vector3_array_insert",
- "return_type": "godot_error",
- "arguments": [
- ["godot_packed_vector3_array *", "p_self"],
- ["const godot_int", "p_idx"],
- ["const godot_vector3 *", "p_data"]
- ]
- },
- {
- "name": "godot_packed_vector3_array_has",
- "return_type": "godot_bool",
- "arguments": [
- ["godot_packed_vector3_array *", "p_self"],
- ["const godot_vector3 *", "p_value"]
- ]
- },
- {
- "name": "godot_packed_vector3_array_sort",
- "return_type": "void",
- "arguments": [
- ["godot_packed_vector3_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_vector3_array_invert",
- "return_type": "void",
- "arguments": [
- ["godot_packed_vector3_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_vector3_array_push_back",
- "return_type": "void",
- "arguments": [
- ["godot_packed_vector3_array *", "p_self"],
- ["const godot_vector3 *", "p_data"]
- ]
- },
- {
- "name": "godot_packed_vector3_array_remove",
- "return_type": "void",
- "arguments": [
- ["godot_packed_vector3_array *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_packed_vector3_array_resize",
- "return_type": "void",
- "arguments": [
- ["godot_packed_vector3_array *", "p_self"],
- ["const godot_int", "p_size"]
- ]
- },
- {
- "name": "godot_packed_vector3_array_ptr",
- "return_type": "const godot_vector3 *",
- "arguments": [
- ["const godot_packed_vector3_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_vector3_array_ptrw",
- "return_type": "godot_vector3 *",
- "arguments": [
- ["godot_packed_vector3_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_vector3_array_set",
- "return_type": "void",
- "arguments": [
- ["godot_packed_vector3_array *", "p_self"],
- ["const godot_int", "p_idx"],
- ["const godot_vector3 *", "p_data"]
- ]
- },
- {
- "name": "godot_packed_vector3_array_get",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_packed_vector3_array *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_packed_vector3_array_size",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_packed_vector3_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_vector3_array_destroy",
- "return_type": "void",
- "arguments": [
- ["godot_packed_vector3_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_color_array_new",
- "return_type": "void",
- "arguments": [
- ["godot_packed_color_array *", "r_dest"]
- ]
- },
- {
- "name": "godot_packed_color_array_new_copy",
- "return_type": "void",
- "arguments": [
- ["godot_packed_color_array *", "r_dest"],
- ["const godot_packed_color_array *", "p_src"]
- ]
- },
- {
- "name": "godot_packed_color_array_new_with_array",
- "return_type": "void",
- "arguments": [
- ["godot_packed_color_array *", "r_dest"],
- ["const godot_array *", "p_a"]
- ]
- },
- {
- "name": "godot_packed_color_array_empty",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_packed_color_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_color_array_append",
- "return_type": "void",
- "arguments": [
- ["godot_packed_color_array *", "p_self"],
- ["const godot_color *", "p_data"]
- ]
- },
- {
- "name": "godot_packed_color_array_append_array",
- "return_type": "void",
- "arguments": [
- ["godot_packed_color_array *", "p_self"],
- ["const godot_packed_color_array *", "p_array"]
- ]
- },
- {
- "name": "godot_packed_color_array_insert",
- "return_type": "godot_error",
- "arguments": [
- ["godot_packed_color_array *", "p_self"],
- ["const godot_int", "p_idx"],
- ["const godot_color *", "p_data"]
- ]
- },
- {
- "name": "godot_packed_color_array_has",
- "return_type": "godot_bool",
- "arguments": [
- ["godot_packed_color_array *", "p_self"],
- ["const godot_color *", "p_value"]
- ]
- },
- {
- "name": "godot_packed_color_array_sort",
- "return_type": "void",
- "arguments": [
- ["godot_packed_color_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_color_array_invert",
- "return_type": "void",
- "arguments": [
- ["godot_packed_color_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_color_array_push_back",
- "return_type": "void",
- "arguments": [
- ["godot_packed_color_array *", "p_self"],
- ["const godot_color *", "p_data"]
- ]
- },
- {
- "name": "godot_packed_color_array_remove",
- "return_type": "void",
- "arguments": [
- ["godot_packed_color_array *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_packed_color_array_resize",
- "return_type": "void",
- "arguments": [
- ["godot_packed_color_array *", "p_self"],
- ["const godot_int", "p_size"]
- ]
- },
- {
- "name": "godot_packed_color_array_ptr",
- "return_type": "const godot_color *",
- "arguments": [
- ["const godot_packed_color_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_color_array_ptrw",
- "return_type": "godot_color *",
- "arguments": [
- ["godot_packed_color_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_color_array_set",
- "return_type": "void",
- "arguments": [
- ["godot_packed_color_array *", "p_self"],
- ["const godot_int", "p_idx"],
- ["const godot_color *", "p_data"]
- ]
- },
- {
- "name": "godot_packed_color_array_get",
- "return_type": "godot_color",
- "arguments": [
- ["const godot_packed_color_array *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_packed_color_array_size",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_packed_color_array *", "p_self"]
- ]
- },
- {
- "name": "godot_packed_color_array_destroy",
- "return_type": "void",
- "arguments": [
- ["godot_packed_color_array *", "p_self"]
- ]
- },
- {
- "name": "godot_plane_new_with_reals",
- "return_type": "void",
- "arguments": [
- ["godot_plane *", "r_dest"],
- ["const godot_real", "p_a"],
- ["const godot_real", "p_b"],
- ["const godot_real", "p_c"],
- ["const godot_real", "p_d"]
- ]
- },
- {
- "name": "godot_plane_new_with_vectors",
- "return_type": "void",
- "arguments": [
- ["godot_plane *", "r_dest"],
- ["const godot_vector3 *", "p_v1"],
- ["const godot_vector3 *", "p_v2"],
- ["const godot_vector3 *", "p_v3"]
- ]
- },
- {
- "name": "godot_plane_new_with_normal",
- "return_type": "void",
- "arguments": [
- ["godot_plane *", "r_dest"],
- ["const godot_vector3 *", "p_normal"],
- ["const godot_real", "p_d"]
- ]
- },
- {
- "name": "godot_plane_as_string",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_plane *", "p_self"]
- ]
- },
- {
- "name": "godot_plane_normalized",
- "return_type": "godot_plane",
- "arguments": [
- ["const godot_plane *", "p_self"]
- ]
- },
- {
- "name": "godot_plane_center",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_plane *", "p_self"]
- ]
- },
- {
- "name": "godot_plane_is_point_over",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_plane *", "p_self"],
- ["const godot_vector3 *", "p_point"]
- ]
- },
- {
- "name": "godot_plane_distance_to",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_plane *", "p_self"],
- ["const godot_vector3 *", "p_point"]
- ]
- },
- {
- "name": "godot_plane_has_point",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_plane *", "p_self"],
- ["const godot_vector3 *", "p_point"],
- ["const godot_real", "p_epsilon"]
- ]
- },
- {
- "name": "godot_plane_project",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_plane *", "p_self"],
- ["const godot_vector3 *", "p_point"]
- ]
- },
- {
- "name": "godot_plane_intersect_3",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_plane *", "p_self"],
- ["godot_vector3 *", "r_dest"],
- ["const godot_plane *", "p_b"],
- ["const godot_plane *", "p_c"]
- ]
- },
- {
- "name": "godot_plane_intersects_ray",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_plane *", "p_self"],
- ["godot_vector3 *", "r_dest"],
- ["const godot_vector3 *", "p_from"],
- ["const godot_vector3 *", "p_dir"]
- ]
- },
- {
- "name": "godot_plane_intersects_segment",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_plane *", "p_self"],
- ["godot_vector3 *", "r_dest"],
- ["const godot_vector3 *", "p_begin"],
- ["const godot_vector3 *", "p_end"]
- ]
- },
- {
- "name": "godot_plane_operator_neg",
- "return_type": "godot_plane",
- "arguments": [
- ["const godot_plane *", "p_self"]
- ]
- },
- {
- "name": "godot_plane_operator_equal",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_plane *", "p_self"],
- ["const godot_plane *", "p_b"]
- ]
- },
- {
- "name": "godot_plane_set_normal",
- "return_type": "void",
- "arguments": [
- ["godot_plane *", "p_self"],
- ["const godot_vector3 *", "p_normal"]
- ]
- },
- {
- "name": "godot_plane_get_normal",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_plane *", "p_self"]
- ]
- },
- {
- "name": "godot_plane_get_d",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_plane *", "p_self"]
- ]
- },
- {
- "name": "godot_plane_set_d",
- "return_type": "void",
- "arguments": [
- ["godot_plane *", "p_self"],
- ["const godot_real", "p_d"]
- ]
- },
- {
- "name": "godot_quat_new",
- "return_type": "void",
- "arguments": [
- ["godot_quat *", "r_dest"],
- ["const godot_real", "p_x"],
- ["const godot_real", "p_y"],
- ["const godot_real", "p_z"],
- ["const godot_real", "p_w"]
- ]
- },
- {
- "name": "godot_quat_new_with_axis_angle",
- "return_type": "void",
- "arguments": [
- ["godot_quat *", "r_dest"],
- ["const godot_vector3 *", "p_axis"],
- ["const godot_real", "p_angle"]
- ]
- },
- {
- "name": "godot_quat_new_with_basis",
- "return_type": "void",
- "arguments": [
- ["godot_quat *", "r_dest"],
- ["const godot_basis *", "p_basis"]
- ]
- },
- {
- "name": "godot_quat_new_with_euler",
- "return_type": "void",
- "arguments": [
- ["godot_quat *", "r_dest"],
- ["const godot_vector3 *", "p_euler"]
- ]
- },
- {
- "name": "godot_quat_get_x",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_quat *", "p_self"]
- ]
- },
- {
- "name": "godot_quat_set_x",
- "return_type": "void",
- "arguments": [
- ["godot_quat *", "p_self"],
- ["const godot_real", "val"]
- ]
- },
- {
- "name": "godot_quat_get_y",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_quat *", "p_self"]
- ]
- },
- {
- "name": "godot_quat_set_y",
- "return_type": "void",
- "arguments": [
- ["godot_quat *", "p_self"],
- ["const godot_real", "val"]
- ]
- },
- {
- "name": "godot_quat_get_z",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_quat *", "p_self"]
- ]
- },
- {
- "name": "godot_quat_set_z",
- "return_type": "void",
- "arguments": [
- ["godot_quat *", "p_self"],
- ["const godot_real", "val"]
- ]
- },
- {
- "name": "godot_quat_get_w",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_quat *", "p_self"]
- ]
- },
- {
- "name": "godot_quat_set_w",
- "return_type": "void",
- "arguments": [
- ["godot_quat *", "p_self"],
- ["const godot_real", "val"]
- ]
- },
- {
- "name": "godot_quat_set_axis_angle",
- "return_type": "void",
- "arguments": [
- ["godot_quat *", "p_self"],
- ["const godot_vector3 *", "p_axis"],
- ["const godot_real", "p_angle"]
- ]
- },
- {
- "name": "godot_quat_as_string",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_quat *", "p_self"]
- ]
- },
- {
- "name": "godot_quat_length",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_quat *", "p_self"]
- ]
- },
- {
- "name": "godot_quat_length_squared",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_quat *", "p_self"]
- ]
- },
- {
- "name": "godot_quat_normalized",
- "return_type": "godot_quat",
- "arguments": [
- ["const godot_quat *", "p_self"]
- ]
- },
- {
- "name": "godot_quat_is_normalized",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_quat *", "p_self"]
- ]
- },
- {
- "name": "godot_quat_inverse",
- "return_type": "godot_quat",
- "arguments": [
- ["const godot_quat *", "p_self"]
- ]
- },
- {
- "name": "godot_quat_dot",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_quat *", "p_self"],
- ["const godot_quat *", "p_b"]
- ]
- },
- {
- "name": "godot_quat_xform",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_quat *", "p_self"],
- ["const godot_vector3 *", "p_v"]
- ]
- },
- {
- "name": "godot_quat_slerp",
- "return_type": "godot_quat",
- "arguments": [
- ["const godot_quat *", "p_self"],
- ["const godot_quat *", "p_b"],
- ["const godot_real", "p_t"]
- ]
- },
- {
- "name": "godot_quat_slerpni",
- "return_type": "godot_quat",
- "arguments": [
- ["const godot_quat *", "p_self"],
- ["const godot_quat *", "p_b"],
- ["const godot_real", "p_t"]
- ]
- },
- {
- "name": "godot_quat_cubic_slerp",
- "return_type": "godot_quat",
- "arguments": [
- ["const godot_quat *", "p_self"],
- ["const godot_quat *", "p_b"],
- ["const godot_quat *", "p_pre_a"],
- ["const godot_quat *", "p_post_b"],
- ["const godot_real", "p_t"]
- ]
- },
- {
- "name": "godot_quat_operator_multiply",
- "return_type": "godot_quat",
- "arguments": [
- ["const godot_quat *", "p_self"],
- ["const godot_real", "p_b"]
- ]
- },
- {
- "name": "godot_quat_operator_add",
- "return_type": "godot_quat",
- "arguments": [
- ["const godot_quat *", "p_self"],
- ["const godot_quat *", "p_b"]
- ]
- },
- {
- "name": "godot_quat_operator_subtract",
- "return_type": "godot_quat",
- "arguments": [
- ["const godot_quat *", "p_self"],
- ["const godot_quat *", "p_b"]
- ]
- },
- {
- "name": "godot_quat_operator_divide",
- "return_type": "godot_quat",
- "arguments": [
- ["const godot_quat *", "p_self"],
- ["const godot_real", "p_b"]
- ]
- },
- {
- "name": "godot_quat_operator_equal",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_quat *", "p_self"],
- ["const godot_quat *", "p_b"]
- ]
- },
- {
- "name": "godot_quat_operator_neg",
- "return_type": "godot_quat",
- "arguments": [
- ["const godot_quat *", "p_self"]
- ]
- },
- {
- "name": "godot_rect2_new_with_position_and_size",
- "return_type": "void",
- "arguments": [
- ["godot_rect2 *", "r_dest"],
- ["const godot_vector2 *", "p_pos"],
- ["const godot_vector2 *", "p_size"]
- ]
- },
- {
- "name": "godot_rect2_new",
- "return_type": "void",
- "arguments": [
- ["godot_rect2 *", "r_dest"],
- ["const godot_real", "p_x"],
- ["const godot_real", "p_y"],
- ["const godot_real", "p_width"],
- ["const godot_real", "p_height"]
- ]
- },
- {
- "name": "godot_rect2_as_rect2i",
- "return_type": "godot_rect2i",
- "arguments": [
- ["const godot_rect2 *", "p_self"]
- ]
- },
- {
- "name": "godot_rect2_as_string",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_rect2 *", "p_self"]
- ]
- },
- {
- "name": "godot_rect2_get_area",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_rect2 *", "p_self"]
- ]
- },
- {
- "name": "godot_rect2_grow_individual",
- "return_type": "godot_rect2",
- "arguments": [
- ["const godot_rect2 *", "p_self"],
- ["const godot_real", "p_left"],
- ["const godot_real", "p_top"],
- ["const godot_real", "p_right"],
- ["const godot_real", "p_bottom"]
- ]
- },
- {
- "name": "godot_rect2_grow_margin",
- "return_type": "godot_rect2",
- "arguments": [
- ["const godot_rect2 *", "p_self"],
- ["const godot_int", "p_margin"],
- ["const godot_real", "p_by"]
- ]
- },
- {
- "name": "godot_rect2_abs",
- "return_type": "godot_rect2",
- "arguments": [
- ["const godot_rect2 *", "p_self"]
- ]
- },
- {
- "name": "godot_rect2_intersects",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_rect2 *", "p_self"],
- ["const godot_rect2 *", "p_b"]
- ]
- },
- {
- "name": "godot_rect2_encloses",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_rect2 *", "p_self"],
- ["const godot_rect2 *", "p_b"]
- ]
- },
- {
- "name": "godot_rect2_has_no_area",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_rect2 *", "p_self"]
- ]
- },
- {
- "name": "godot_rect2_clip",
- "return_type": "godot_rect2",
- "arguments": [
- ["const godot_rect2 *", "p_self"],
- ["const godot_rect2 *", "p_b"]
- ]
- },
- {
- "name": "godot_rect2_merge",
- "return_type": "godot_rect2",
- "arguments": [
- ["const godot_rect2 *", "p_self"],
- ["const godot_rect2 *", "p_b"]
- ]
- },
- {
- "name": "godot_rect2_has_point",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_rect2 *", "p_self"],
- ["const godot_vector2 *", "p_point"]
- ]
- },
- {
- "name": "godot_rect2_grow",
- "return_type": "godot_rect2",
- "arguments": [
- ["const godot_rect2 *", "p_self"],
- ["const godot_real", "p_by"]
- ]
- },
- {
- "name": "godot_rect2_expand",
- "return_type": "godot_rect2",
- "arguments": [
- ["const godot_rect2 *", "p_self"],
- ["const godot_vector2 *", "p_to"]
- ]
- },
- {
- "name": "godot_rect2_operator_equal",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_rect2 *", "p_self"],
- ["const godot_rect2 *", "p_b"]
- ]
- },
- {
- "name": "godot_rect2_get_position",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_rect2 *", "p_self"]
- ]
- },
- {
- "name": "godot_rect2_get_size",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_rect2 *", "p_self"]
- ]
- },
- {
- "name": "godot_rect2_set_position",
- "return_type": "void",
- "arguments": [
- ["godot_rect2 *", "p_self"],
- ["const godot_vector2 *", "p_pos"]
- ]
- },
- {
- "name": "godot_rect2_set_size",
- "return_type": "void",
- "arguments": [
- ["godot_rect2 *", "p_self"],
- ["const godot_vector2 *", "p_size"]
- ]
- },
- {
- "name": "godot_rect2i_new_with_position_and_size",
- "return_type": "void",
- "arguments": [
- ["godot_rect2i *", "r_dest"],
- ["const godot_vector2i *", "p_pos"],
- ["const godot_vector2i *", "p_size"]
- ]
- },
- {
- "name": "godot_rect2i_new",
- "return_type": "void",
- "arguments": [
- ["godot_rect2i *", "r_dest"],
- ["const godot_int", "p_x"],
- ["const godot_int", "p_y"],
- ["const godot_int", "p_width"],
- ["const godot_int", "p_height"]
- ]
- },
- {
- "name": "godot_rect2i_as_string",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_rect2i *", "p_self"]
- ]
- },
- {
- "name": "godot_rect2i_as_rect2",
- "return_type": "godot_rect2",
- "arguments": [
- ["const godot_rect2i *", "p_self"]
- ]
- },
- {
- "name": "godot_rect2i_get_area",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_rect2i *", "p_self"]
- ]
- },
- {
- "name": "godot_rect2i_intersects",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_rect2i *", "p_self"],
- ["const godot_rect2i *", "p_b"]
- ]
- },
- {
- "name": "godot_rect2i_encloses",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_rect2i *", "p_self"],
- ["const godot_rect2i *", "p_b"]
- ]
- },
- {
- "name": "godot_rect2i_has_no_area",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_rect2i *", "p_self"]
- ]
- },
- {
- "name": "godot_rect2i_clip",
- "return_type": "godot_rect2i",
- "arguments": [
- ["const godot_rect2i *", "p_self"],
- ["const godot_rect2i *", "p_b"]
- ]
- },
- {
- "name": "godot_rect2i_merge",
- "return_type": "godot_rect2i",
- "arguments": [
- ["const godot_rect2i *", "p_self"],
- ["const godot_rect2i *", "p_b"]
- ]
- },
- {
- "name": "godot_rect2i_has_point",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_rect2i *", "p_self"],
- ["const godot_vector2i *", "p_point"]
- ]
- },
- {
- "name": "godot_rect2i_grow",
- "return_type": "godot_rect2i",
- "arguments": [
- ["const godot_rect2i *", "p_self"],
- ["const godot_int", "p_by"]
- ]
- },
- {
- "name": "godot_rect2i_grow_individual",
- "return_type": "godot_rect2i",
- "arguments": [
- ["const godot_rect2i *", "p_self"],
- ["const godot_int", "p_left"],
- ["const godot_int", "p_top"],
- ["const godot_int", "p_right"],
- ["const godot_int", "p_bottom"]
- ]
- },
- {
- "name": "godot_rect2i_grow_margin",
- "return_type": "godot_rect2i",
- "arguments": [
- ["const godot_rect2i *", "p_self"],
- ["const godot_int", "p_margin"],
- ["const godot_int", "p_by"]
- ]
- },
- {
- "name": "godot_rect2i_abs",
- "return_type": "godot_rect2i",
- "arguments": [
- ["const godot_rect2i *", "p_self"]
- ]
- },
- {
- "name": "godot_rect2i_expand",
- "return_type": "godot_rect2i",
- "arguments": [
- ["const godot_rect2i *", "p_self"],
- ["const godot_vector2i *", "p_to"]
- ]
- },
- {
- "name": "godot_rect2i_operator_equal",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_rect2i *", "p_self"],
- ["const godot_rect2i *", "p_b"]
- ]
- },
- {
- "name": "godot_rect2i_get_position",
- "return_type": "godot_vector2i",
- "arguments": [
- ["const godot_rect2i *", "p_self"]
- ]
- },
- {
- "name": "godot_rect2i_get_size",
- "return_type": "godot_vector2i",
- "arguments": [
- ["const godot_rect2i *", "p_self"]
- ]
- },
- {
- "name": "godot_rect2i_set_position",
- "return_type": "void",
- "arguments": [
- ["godot_rect2i *", "p_self"],
- ["const godot_vector2i *", "p_pos"]
- ]
- },
- {
- "name": "godot_rect2i_set_size",
- "return_type": "void",
- "arguments": [
- ["godot_rect2i *", "p_self"],
- ["const godot_vector2i *", "p_size"]
- ]
- },
- {
- "name": "godot_rid_new",
- "return_type": "void",
- "arguments": [
- ["godot_rid *", "r_dest"]
- ]
- },
- {
- "name": "godot_rid_get_id",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_rid *", "p_self"]
- ]
- },
- {
- "name": "godot_rid_new_with_resource",
- "return_type": "void",
- "arguments": [
- ["godot_rid *", "r_dest"],
- ["const godot_object *", "p_from"]
- ]
- },
- {
- "name": "godot_rid_operator_equal",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_rid *", "p_self"],
- ["const godot_rid *", "p_b"]
- ]
- },
- {
- "name": "godot_rid_operator_less",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_rid *", "p_self"],
- ["const godot_rid *", "p_b"]
- ]
- },
- {
- "name": "godot_char_string_length",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_char_string *", "p_cs"]
- ]
- },
- {
- "name": "godot_char_string_get_data",
- "return_type": "const char *",
- "arguments": [
- ["const godot_char_string *", "p_cs"]
- ]
- },
- {
- "name": "godot_char_string_destroy",
- "return_type": "void",
- "arguments": [
- ["godot_char_string *", "p_cs"]
- ]
- },
- {
- "name": "godot_char16_string_length",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_char16_string *", "p_cs"]
- ]
- },
- {
- "name": "godot_char16_string_get_data",
- "return_type": "const char16_t *",
- "arguments": [
- ["const godot_char16_string *", "p_cs"]
- ]
- },
- {
- "name": "godot_char16_string_destroy",
- "return_type": "void",
- "arguments": [
- ["godot_char16_string *", "p_cs"]
- ]
- },
- {
- "name": "godot_string_new",
- "return_type": "void",
- "arguments": [
- ["godot_string *", "r_dest"]
- ]
- },
- {
- "name": "godot_string_new_copy",
- "return_type": "void",
- "arguments": [
- ["godot_string *", "r_dest"],
- ["const godot_string *", "p_src"]
- ]
- },
- {
- "name": "godot_string_new_with_latin1_chars",
- "return_type": "void",
- "arguments": [
- ["godot_string *", "r_dest"],
- ["const char *", "p_contents"]
- ]
- },
- {
- "name": "godot_string_new_with_utf8_chars",
- "return_type": "void",
- "arguments": [
- ["godot_string *", "r_dest"],
- ["const char *", "p_contents"]
- ]
- },
- {
- "name": "godot_string_new_with_utf16_chars",
- "return_type": "void",
- "arguments": [
- ["godot_string *", "r_dest"],
- ["const char16_t *", "p_contents"]
- ]
- },
- {
- "name": "godot_string_new_with_utf32_chars",
- "return_type": "void",
- "arguments": [
- ["godot_string *", "r_dest"],
- ["const char32_t *", "p_contents"]
- ]
- },
- {
- "name": "godot_string_new_with_wide_chars",
- "return_type": "void",
- "arguments": [
- ["godot_string *", "r_dest"],
- ["const wchar_t *", "p_contents"]
- ]
- },
- {
- "name": "godot_string_new_with_latin1_chars_and_len",
- "return_type": "void",
- "arguments": [
- ["godot_string *", "r_dest"],
- ["const char *", "p_contents"],
- ["const int", "p_size"]
- ]
- },
- {
- "name": "godot_string_new_with_utf8_chars_and_len",
- "return_type": "void",
- "arguments": [
- ["godot_string *", "r_dest"],
- ["const char *", "p_contents"],
- ["const int", "p_size"]
- ]
- },
- {
- "name": "godot_string_new_with_utf16_chars_and_len",
- "return_type": "void",
- "arguments": [
- ["godot_string *", "r_dest"],
- ["const char16_t *", "p_contents"],
- ["const int", "p_size"]
- ]
- },
- {
- "name": "godot_string_new_with_utf32_chars_and_len",
- "return_type": "void",
- "arguments": [
- ["godot_string *", "r_dest"],
- ["const char32_t *", "p_contents"],
- ["const int", "p_size"]
- ]
- },
- {
- "name": "godot_string_new_with_wide_chars_and_len",
- "return_type": "void",
- "arguments": [
- ["godot_string *", "r_dest"],
- ["const wchar_t *", "p_contents"],
- ["const int", "p_size"]
- ]
- },
- {
- "name": "godot_string_operator_index",
- "return_type": "const godot_char_type *",
- "arguments": [
- ["godot_string *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_string_operator_index_const",
- "return_type": "godot_char_type",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_string_get_data",
- "return_type": "const godot_char_type *",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_operator_equal",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_b"]
- ]
- },
- {
- "name": "godot_string_operator_less",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_b"]
- ]
- },
- {
- "name": "godot_string_operator_plus",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_b"]
- ]
- },
- {
- "name": "godot_string_count",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_what"],
- ["godot_int", "p_from"],
- ["godot_int", "p_to"]
- ]
- },
- {
- "name": "godot_string_countn",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_what"],
- ["godot_int", "p_from"],
- ["godot_int", "p_to"]
- ]
- },
- {
- "name": "godot_string_dedent",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_length",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_casecmp_to",
- "return_type": "signed char",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_str"]
- ]
- },
- {
- "name": "godot_string_nocasecmp_to",
- "return_type": "signed char",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_str"]
- ]
- },
- {
- "name": "godot_string_naturalnocasecmp_to",
- "return_type": "signed char",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_str"]
- ]
- },
- {
- "name": "godot_string_begins_with",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_string"]
- ]
- },
- {
- "name": "godot_string_begins_with_char_array",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const char *", "p_char_array"]
- ]
- },
- {
- "name": "godot_string_bigrams",
- "return_type": "godot_packed_string_array",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_chr",
- "return_type": "godot_string",
- "arguments": [
- ["godot_char_type", "p_character"]
- ]
- },
- {
- "name": "godot_string_ends_with",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_string"]
- ]
- },
- {
- "name": "godot_string_ends_with_char_array",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const char *", "p_char_array"]
- ]
- },
- {
- "name": "godot_string_find",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_what"]
- ]
- },
- {
- "name": "godot_string_find_from",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_what"],
- ["godot_int", "p_from"]
- ]
- },
- {
- "name": "godot_string_findmk",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_packed_string_array *", "p_keys"]
- ]
- },
- {
- "name": "godot_string_findmk_from",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_packed_string_array *", "p_keys"],
- ["godot_int", "p_from"]
- ]
- },
- {
- "name": "godot_string_findmk_from_in_place",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_packed_string_array *", "p_keys"],
- ["godot_int", "p_from"],
- ["godot_int *", "r_key"]
- ]
- },
- {
- "name": "godot_string_findn",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_what"]
- ]
- },
- {
- "name": "godot_string_findn_from",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_what"],
- ["godot_int", "p_from"]
- ]
- },
- {
- "name": "godot_string_format",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_variant *", "p_values"]
- ]
- },
- {
- "name": "godot_string_format_with_custom_placeholder",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_variant *", "p_values"],
- ["const char *", "p_placeholder"]
- ]
- },
- {
- "name": "godot_string_hex_encode_buffer",
- "return_type": "godot_string",
- "arguments": [
- ["const uint8_t *", "p_buffer"],
- ["godot_int", "p_len"]
- ]
- },
- {
- "name": "godot_string_insert",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["godot_int", "p_at_pos"],
- ["const godot_string *", "p_string"]
- ]
- },
- {
- "name": "godot_string_is_numeric",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_is_subsequence_of",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_string"]
- ]
- },
- {
- "name": "godot_string_is_subsequence_ofi",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_string"]
- ]
- },
- {
- "name": "godot_string_lpad",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["godot_int", "p_min_length"]
- ]
- },
- {
- "name": "godot_string_lpad_with_custom_character",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["godot_int", "p_min_length"],
- ["const godot_string *", "p_character"]
- ]
- },
- {
- "name": "godot_string_match",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_wildcard"]
- ]
- },
- {
- "name": "godot_string_matchn",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_wildcard"]
- ]
- },
- {
- "name": "godot_string_md5",
- "return_type": "godot_string",
- "arguments": [
- ["const uint8_t *", "p_md5"]
- ]
- },
- {
- "name": "godot_string_num",
- "return_type": "godot_string",
- "arguments": [
- ["double", "p_num"]
- ]
- },
- {
- "name": "godot_string_num_int64",
- "return_type": "godot_string",
- "arguments": [
- ["int64_t", "p_num"],
- ["godot_int", "p_base"]
- ]
- },
- {
- "name": "godot_string_num_int64_capitalized",
- "return_type": "godot_string",
- "arguments": [
- ["int64_t", "p_num"],
- ["godot_int", "p_base"],
- ["godot_bool", "p_capitalize_hex"]
- ]
- },
- {
- "name": "godot_string_num_real",
- "return_type": "godot_string",
- "arguments": [
- ["double", "p_num"]
- ]
- },
- {
- "name": "godot_string_num_scientific",
- "return_type": "godot_string",
- "arguments": [
- ["double", "p_num"]
- ]
- },
- {
- "name": "godot_string_num_with_decimals",
- "return_type": "godot_string",
- "arguments": [
- ["double", "p_num"],
- ["godot_int", "p_decimals"]
- ]
- },
- {
- "name": "godot_string_pad_decimals",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["godot_int", "p_digits"]
- ]
- },
- {
- "name": "godot_string_pad_zeros",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["godot_int", "p_digits"]
- ]
- },
- {
- "name": "godot_string_replace_first",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_key"],
- ["const godot_string *", "p_with"]
- ]
- },
- {
- "name": "godot_string_replace",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_key"],
- ["const godot_string *", "p_with"]
- ]
- },
- {
- "name": "godot_string_replacen",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_key"],
- ["const godot_string *", "p_with"]
- ]
- },
- {
- "name": "godot_string_rfind",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_what"]
- ]
- },
- {
- "name": "godot_string_rfindn",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_what"]
- ]
- },
- {
- "name": "godot_string_rfind_from",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_what"],
- ["godot_int", "p_from"]
- ]
- },
- {
- "name": "godot_string_rfindn_from",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_what"],
- ["godot_int", "p_from"]
- ]
- },
- {
- "name": "godot_string_rpad",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["godot_int", "p_min_length"]
- ]
- },
- {
- "name": "godot_string_rpad_with_custom_character",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["godot_int", "p_min_length"],
- ["const godot_string *", "p_character"]
- ]
- },
- {
- "name": "godot_string_similarity",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_string"]
- ]
- },
- {
- "name": "godot_string_sprintf",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_array *", "p_values"],
- ["godot_bool *", "p_error"]
- ]
- },
- {
- "name": "godot_string_substr",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["godot_int", "p_from"],
- ["godot_int", "p_chars"]
- ]
- },
- {
- "name": "godot_string_to_int",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_to_float",
- "return_type": "double",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_camelcase_to_underscore",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_camelcase_to_underscore_lowercased",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_capitalize",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_char_to_float",
- "return_type": "double",
- "arguments": [
- ["const char *", "p_what"]
- ]
- },
- {
- "name": "godot_string_wchar_to_float",
- "return_type": "double",
- "arguments": [
- ["const wchar_t *", "p_str"],
- ["const wchar_t **", "r_end"]
- ]
- },
- {
- "name": "godot_string_char_to_int",
- "return_type": "godot_int",
- "arguments": [
- ["const char *", "p_what"]
- ]
- },
- {
- "name": "godot_string_wchar_to_int",
- "return_type": "godot_int",
- "arguments": [
- ["const wchar_t *", "p_str"]
- ]
- },
- {
- "name": "godot_string_char_to_int_with_len",
- "return_type": "godot_int",
- "arguments": [
- ["const char *", "p_what"],
- ["godot_int", "p_len"]
- ]
- },
- {
- "name": "godot_string_wchar_to_int_with_len",
- "return_type": "godot_int",
- "arguments": [
- ["const wchar_t *", "p_str"],
- ["int", "p_len"]
- ]
- },
- {
- "name": "godot_string_hex_to_int",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_hex_to_int_with_prefix",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_get_slice_count",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_splitter"]
- ]
- },
- {
- "name": "godot_string_get_slice",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_splitter"],
- ["godot_int", "p_slice"]
- ]
- },
- {
- "name": "godot_string_get_slicec",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["godot_char_type", "p_splitter"],
- ["godot_int", "p_slice"]
- ]
- },
- {
- "name": "godot_string_split",
- "return_type": "godot_packed_string_array",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_splitter"]
- ]
- },
- {
- "name": "godot_string_split_allow_empty",
- "return_type": "godot_packed_string_array",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_splitter"]
- ]
- },
- {
- "name": "godot_string_split_with_maxsplit",
- "return_type": "godot_packed_string_array",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_splitter"],
- ["const godot_bool", "p_allow_empty"],
- ["const godot_int", "p_maxsplit"]
- ]
- },
- {
- "name": "godot_string_rsplit",
- "return_type": "godot_packed_string_array",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_splitter"]
- ]
- },
- {
- "name": "godot_string_rsplit_allow_empty",
- "return_type": "godot_packed_string_array",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_splitter"]
- ]
- },
- {
- "name": "godot_string_rsplit_with_maxsplit",
- "return_type": "godot_packed_string_array",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_splitter"],
- ["const godot_bool", "p_allow_empty"],
- ["const godot_int", "p_maxsplit"]
- ]
- },
- {
- "name": "godot_string_split_floats",
- "return_type": "godot_packed_float32_array",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_splitter"]
- ]
- },
- {
- "name": "godot_string_split_floats_allow_empty",
- "return_type": "godot_packed_float32_array",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_splitter"]
- ]
- },
- {
- "name": "godot_string_split_floats_mk",
- "return_type": "godot_packed_float32_array",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_packed_string_array *", "p_splitters"]
- ]
- },
- {
- "name": "godot_string_split_floats_mk_allow_empty",
- "return_type": "godot_packed_float32_array",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_packed_string_array *", "p_splitters"]
- ]
- },
- {
- "name": "godot_string_split_ints",
- "return_type": "godot_packed_int32_array",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_splitter"]
- ]
- },
- {
- "name": "godot_string_split_ints_allow_empty",
- "return_type": "godot_packed_int32_array",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_splitter"]
- ]
- },
- {
- "name": "godot_string_split_ints_mk",
- "return_type": "godot_packed_int32_array",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_packed_string_array *", "p_splitters"]
- ]
- },
- {
- "name": "godot_string_split_ints_mk_allow_empty",
- "return_type": "godot_packed_int32_array",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_packed_string_array *", "p_splitters"]
- ]
- },
- {
- "name": "godot_string_split_spaces",
- "return_type": "godot_packed_string_array",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_lstrip",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_chars"]
- ]
- },
- {
- "name": "godot_string_rstrip",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_chars"]
- ]
- },
- {
- "name": "godot_string_trim_prefix",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_prefix"]
- ]
- },
- {
- "name": "godot_string_trim_suffix",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_suffix"]
- ]
- },
- {
- "name": "godot_string_char_lowercase",
- "return_type": "godot_char_type",
- "arguments": [
- ["godot_char_type", "p_char"]
- ]
- },
- {
- "name": "godot_string_char_uppercase",
- "return_type": "godot_char_type",
- "arguments": [
- ["godot_char_type", "p_char"]
- ]
- },
- {
- "name": "godot_string_to_lower",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_to_upper",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_get_basename",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_get_extension",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_left",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["godot_int", "p_pos"]
- ]
- },
- {
- "name": "godot_string_ord_at",
- "return_type": "godot_char_type",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["godot_int", "p_idx"]
- ]
- },
- {
- "name": "godot_string_plus_file",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_file"]
- ]
- },
- {
- "name": "godot_string_right",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["godot_int", "p_pos"]
- ]
- },
- {
- "name": "godot_string_repeat",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["godot_int", "p_count"]
- ]
- },
- {
- "name": "godot_string_strip_edges",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["godot_bool", "p_left"],
- ["godot_bool", "p_right"]
- ]
- },
- {
- "name": "godot_string_strip_escapes",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_erase",
- "return_type": "void",
- "arguments": [
- ["godot_string *", "p_self"],
- ["godot_int", "p_pos"],
- ["godot_int", "p_chars"]
- ]
- },
- {
- "name": "godot_string_ascii",
- "return_type": "godot_char_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_latin1",
- "return_type": "godot_char_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_utf8",
- "return_type": "godot_char_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_parse_utf8",
- "return_type": "godot_bool",
- "arguments": [
- ["godot_string *", "p_self"],
- ["const char *", "p_utf8"]
- ]
- },
- {
- "name": "godot_string_parse_utf8_with_len",
- "return_type": "godot_bool",
- "arguments": [
- ["godot_string *", "p_self"],
- ["const char *", "p_utf8"],
- ["godot_int", "p_len"]
- ]
- },
- {
- "name": "godot_string_utf16",
- "return_type": "godot_char16_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_parse_utf16",
- "return_type": "godot_bool",
- "arguments": [
- ["godot_string *", "p_self"],
- ["const char16_t *", "p_utf16"]
- ]
- },
- {
- "name": "godot_string_parse_utf16_with_len",
- "return_type": "godot_bool",
- "arguments": [
- ["godot_string *", "p_self"],
- ["const char16_t *", "p_utf16"],
- ["godot_int", "p_len"]
- ]
- },
- {
- "name": "godot_string_hash",
- "return_type": "uint32_t",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_hash64",
- "return_type": "uint64_t",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_hash_chars",
- "return_type": "uint32_t",
- "arguments": [
- ["const char *", "p_cstr"]
- ]
- },
- {
- "name": "godot_string_hash_chars_with_len",
- "return_type": "uint32_t",
- "arguments": [
- ["const char *", "p_cstr"],
- ["godot_int", "p_len"]
- ]
- },
- {
- "name": "godot_string_hash_wide_chars",
- "return_type": "uint32_t",
- "arguments": [
- ["const wchar_t *", "p_str"]
- ]
- },
- {
- "name": "godot_string_hash_wide_chars_with_len",
- "return_type": "uint32_t",
- "arguments": [
- ["const wchar_t *", "p_str"],
- ["godot_int", "p_len"]
- ]
- },
- {
- "name": "godot_string_md5_buffer",
- "return_type": "godot_packed_byte_array",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_md5_text",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_sha1_buffer",
- "return_type": "godot_packed_byte_array",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_sha1_text",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_sha256_buffer",
- "return_type": "godot_packed_byte_array",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_sha256_text",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_empty",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_get_base_dir",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_get_file",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_humanize_size",
- "return_type": "godot_string",
- "arguments": [
- ["size_t", "p_size"]
- ]
- },
- {
- "name": "godot_string_is_abs_path",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_is_rel_path",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_is_resource_file",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_path_to",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_path"]
- ]
- },
- {
- "name": "godot_string_path_to_file",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_string *", "p_path"]
- ]
- },
- {
- "name": "godot_string_simplify_path",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_c_escape",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_c_escape_multiline",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_c_unescape",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_http_escape",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_http_unescape",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_json_escape",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_xml_escape",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_xml_escape_with_quotes",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_xml_unescape",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_percent_decode",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_percent_encode",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_join",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["const godot_packed_string_array *", "p_parts"]
- ]
- },
- {
- "name": "godot_string_is_valid_filename",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_is_valid_float",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_is_valid_hex_number",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["godot_bool", "p_with_prefix"]
- ]
- },
- {
- "name": "godot_string_is_valid_html_color",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_is_valid_identifier",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_is_valid_integer",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_is_valid_ip_address",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_destroy",
- "return_type": "void",
- "arguments": [
- ["godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_name_new",
- "return_type": "void",
- "arguments": [
- ["godot_string_name *", "r_dest"],
- ["const godot_string *", "p_name"]
- ]
- },
- {
- "name": "godot_string_name_new_data",
- "return_type": "void",
- "arguments": [
- ["godot_string_name *", "r_dest"],
- ["const char *", "p_name"]
- ]
- },
- {
- "name": "godot_string_name_get_name",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string_name *", "p_self"]
- ]
- },
- {
- "name": "godot_string_name_get_hash",
- "return_type": "uint32_t",
- "arguments": [
- ["const godot_string_name *", "p_self"]
- ]
- },
- {
- "name": "godot_string_name_get_data_unique_pointer",
- "return_type": "const void *",
- "arguments": [
- ["const godot_string_name *", "p_self"]
- ]
- },
- {
- "name": "godot_string_name_operator_equal",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_string_name *", "p_self"],
- ["const godot_string_name *", "p_other"]
- ]
- },
- {
- "name": "godot_string_name_operator_less",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_string_name *", "p_self"],
- ["const godot_string_name *", "p_other"]
- ]
- },
- {
- "name": "godot_string_name_destroy",
- "return_type": "void",
- "arguments": [
- ["godot_string_name *", "p_self"]
- ]
- },
- {
- "name": "godot_transform_new_with_axis_origin",
- "return_type": "void",
- "arguments": [
- ["godot_transform *", "r_dest"],
- ["const godot_vector3 *", "p_x_axis"],
- ["const godot_vector3 *", "p_y_axis"],
- ["const godot_vector3 *", "p_z_axis"],
- ["const godot_vector3 *", "p_origin"]
- ]
- },
- {
- "name": "godot_transform_new_with_quat",
- "return_type": "void",
- "arguments": [
- ["godot_transform *", "r_dest"],
- ["const godot_quat *", "p_quat"]
- ]
- },
- {
- "name": "godot_transform_new",
- "return_type": "void",
- "arguments": [
- ["godot_transform *", "r_dest"],
- ["const godot_basis *", "p_basis"],
- ["const godot_vector3 *", "p_origin"]
- ]
- },
- {
- "name": "godot_transform_get_basis",
- "return_type": "godot_basis",
- "arguments": [
- ["const godot_transform *", "p_self"]
- ]
- },
- {
- "name": "godot_transform_set_basis",
- "return_type": "void",
- "arguments": [
- ["godot_transform *", "p_self"],
- ["const godot_basis *", "p_v"]
- ]
- },
- {
- "name": "godot_transform_get_origin",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_transform *", "p_self"]
- ]
- },
- {
- "name": "godot_transform_set_origin",
- "return_type": "void",
- "arguments": [
- ["godot_transform *", "p_self"],
- ["const godot_vector3 *", "p_v"]
- ]
- },
- {
- "name": "godot_transform_as_string",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_transform *", "p_self"]
- ]
- },
- {
- "name": "godot_transform_inverse",
- "return_type": "godot_transform",
- "arguments": [
- ["const godot_transform *", "p_self"]
- ]
- },
- {
- "name": "godot_transform_affine_inverse",
- "return_type": "godot_transform",
- "arguments": [
- ["const godot_transform *", "p_self"]
- ]
- },
- {
- "name": "godot_transform_orthonormalized",
- "return_type": "godot_transform",
- "arguments": [
- ["const godot_transform *", "p_self"]
- ]
- },
- {
- "name": "godot_transform_rotated",
- "return_type": "godot_transform",
- "arguments": [
- ["const godot_transform *", "p_self"],
- ["const godot_vector3 *", "p_axis"],
- ["const godot_real", "p_phi"]
- ]
- },
- {
- "name": "godot_transform_scaled",
- "return_type": "godot_transform",
- "arguments": [
- ["const godot_transform *", "p_self"],
- ["const godot_vector3 *", "p_scale"]
- ]
- },
- {
- "name": "godot_transform_translated",
- "return_type": "godot_transform",
- "arguments": [
- ["const godot_transform *", "p_self"],
- ["const godot_vector3 *", "p_ofs"]
- ]
- },
- {
- "name": "godot_transform_looking_at",
- "return_type": "godot_transform",
- "arguments": [
- ["const godot_transform *", "p_self"],
- ["const godot_vector3 *", "p_target"],
- ["const godot_vector3 *", "p_up"]
- ]
- },
- {
- "name": "godot_transform_xform_plane",
- "return_type": "godot_plane",
- "arguments": [
- ["const godot_transform *", "p_self"],
- ["const godot_plane *", "p_v"]
- ]
- },
- {
- "name": "godot_transform_xform_inv_plane",
- "return_type": "godot_plane",
- "arguments": [
- ["const godot_transform *", "p_self"],
- ["const godot_plane *", "p_v"]
- ]
- },
- {
- "name": "godot_transform_new_identity",
- "return_type": "void",
- "arguments": [
- ["godot_transform *", "r_dest"]
- ]
- },
- {
- "name": "godot_transform_operator_equal",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_transform *", "p_self"],
- ["const godot_transform *", "p_b"]
- ]
- },
- {
- "name": "godot_transform_operator_multiply",
- "return_type": "godot_transform",
- "arguments": [
- ["const godot_transform *", "p_self"],
- ["const godot_transform *", "p_b"]
- ]
- },
- {
- "name": "godot_transform_xform_vector3",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_transform *", "p_self"],
- ["const godot_vector3 *", "p_v"]
- ]
- },
- {
- "name": "godot_transform_xform_inv_vector3",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_transform *", "p_self"],
- ["const godot_vector3 *", "p_v"]
- ]
- },
- {
- "name": "godot_transform_xform_aabb",
- "return_type": "godot_aabb",
- "arguments": [
- ["const godot_transform *", "p_self"],
- ["const godot_aabb *", "p_v"]
- ]
- },
- {
- "name": "godot_transform_xform_inv_aabb",
- "return_type": "godot_aabb",
- "arguments": [
- ["const godot_transform *", "p_self"],
- ["const godot_aabb *", "p_v"]
- ]
- },
- {
- "name": "godot_transform2d_new",
- "return_type": "void",
- "arguments": [
- ["godot_transform2d *", "r_dest"],
- ["const godot_real", "p_rot"],
- ["const godot_vector2 *", "p_pos"]
- ]
- },
- {
- "name": "godot_transform2d_new_axis_origin",
- "return_type": "void",
- "arguments": [
- ["godot_transform2d *", "r_dest"],
- ["const godot_vector2 *", "p_x_axis"],
- ["const godot_vector2 *", "p_y_axis"],
- ["const godot_vector2 *", "p_origin"]
- ]
- },
- {
- "name": "godot_transform2d_as_string",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_transform2d *", "p_self"]
- ]
- },
- {
- "name": "godot_transform2d_inverse",
- "return_type": "godot_transform2d",
- "arguments": [
- ["const godot_transform2d *", "p_self"]
- ]
- },
- {
- "name": "godot_transform2d_affine_inverse",
- "return_type": "godot_transform2d",
- "arguments": [
- ["const godot_transform2d *", "p_self"]
- ]
- },
- {
- "name": "godot_transform2d_get_rotation",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_transform2d *", "p_self"]
- ]
- },
- {
- "name": "godot_transform2d_get_origin",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_transform2d *", "p_self"]
- ]
- },
- {
- "name": "godot_transform2d_get_scale",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_transform2d *", "p_self"]
- ]
- },
- {
- "name": "godot_transform2d_orthonormalized",
- "return_type": "godot_transform2d",
- "arguments": [
- ["const godot_transform2d *", "p_self"]
- ]
- },
- {
- "name": "godot_transform2d_rotated",
- "return_type": "godot_transform2d",
- "arguments": [
- ["const godot_transform2d *", "p_self"],
- ["const godot_real", "p_phi"]
- ]
- },
- {
- "name": "godot_transform2d_scaled",
- "return_type": "godot_transform2d",
- "arguments": [
- ["const godot_transform2d *", "p_self"],
- ["const godot_vector2 *", "p_scale"]
- ]
- },
- {
- "name": "godot_transform2d_translated",
- "return_type": "godot_transform2d",
- "arguments": [
- ["const godot_transform2d *", "p_self"],
- ["const godot_vector2 *", "p_offset"]
- ]
- },
- {
- "name": "godot_transform2d_xform_vector2",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_transform2d *", "p_self"],
- ["const godot_vector2 *", "p_v"]
- ]
- },
- {
- "name": "godot_transform2d_xform_inv_vector2",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_transform2d *", "p_self"],
- ["const godot_vector2 *", "p_v"]
- ]
- },
- {
- "name": "godot_transform2d_basis_xform_vector2",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_transform2d *", "p_self"],
- ["const godot_vector2 *", "p_v"]
- ]
- },
- {
- "name": "godot_transform2d_basis_xform_inv_vector2",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_transform2d *", "p_self"],
- ["const godot_vector2 *", "p_v"]
- ]
- },
- {
- "name": "godot_transform2d_interpolate_with",
- "return_type": "godot_transform2d",
- "arguments": [
- ["const godot_transform2d *", "p_self"],
- ["const godot_transform2d *", "p_m"],
- ["const godot_real", "p_c"]
- ]
- },
- {
- "name": "godot_transform2d_operator_equal",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_transform2d *", "p_self"],
- ["const godot_transform2d *", "p_b"]
- ]
- },
- {
- "name": "godot_transform2d_operator_multiply",
- "return_type": "godot_transform2d",
- "arguments": [
- ["const godot_transform2d *", "p_self"],
- ["const godot_transform2d *", "p_b"]
- ]
- },
- {
- "name": "godot_transform2d_new_identity",
- "return_type": "void",
- "arguments": [
- ["godot_transform2d *", "r_dest"]
- ]
- },
- {
- "name": "godot_transform2d_xform_rect2",
- "return_type": "godot_rect2",
- "arguments": [
- ["const godot_transform2d *", "p_self"],
- ["const godot_rect2 *", "p_v"]
- ]
- },
- {
- "name": "godot_transform2d_xform_inv_rect2",
- "return_type": "godot_rect2",
- "arguments": [
- ["const godot_transform2d *", "p_self"],
- ["const godot_rect2 *", "p_v"]
- ]
- },
- {
- "name": "godot_variant_get_type",
- "return_type": "godot_variant_type",
- "arguments": [
- ["const godot_variant *", "p_v"]
- ]
- },
- {
- "name": "godot_variant_new_copy",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_variant *", "p_src"]
- ]
- },
- {
- "name": "godot_variant_new_nil",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"]
- ]
- },
- {
- "name": "godot_variant_new_bool",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_bool", "p_b"]
- ]
- },
- {
- "name": "godot_variant_new_uint",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const uint64_t", "p_i"]
- ]
- },
- {
- "name": "godot_variant_new_int",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const int64_t", "p_i"]
- ]
- },
- {
- "name": "godot_variant_new_real",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const double", "p_r"]
- ]
- },
- {
- "name": "godot_variant_new_string",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_string *", "p_s"]
- ]
- },
- {
- "name": "godot_variant_new_string_name",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_string_name *", "p_s"]
- ]
- },
- {
- "name": "godot_variant_new_vector2",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_vector2 *", "p_v2"]
- ]
- },
- {
- "name": "godot_variant_new_vector2i",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_vector2i *", "p_v2"]
- ]
- },
- {
- "name": "godot_variant_new_rect2",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_rect2 *", "p_rect2"]
- ]
- },
- {
- "name": "godot_variant_new_rect2i",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_rect2i *", "p_rect2"]
- ]
- },
- {
- "name": "godot_variant_new_vector3",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_vector3 *", "p_v3"]
- ]
- },
- {
- "name": "godot_variant_new_vector3i",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_vector3i *", "p_v3"]
- ]
- },
- {
- "name": "godot_variant_new_transform2d",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_transform2d *", "p_t2d"]
- ]
- },
- {
- "name": "godot_variant_new_plane",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_plane *", "p_plane"]
- ]
- },
- {
- "name": "godot_variant_new_quat",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_quat *", "p_quat"]
- ]
- },
- {
- "name": "godot_variant_new_aabb",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_aabb *", "p_aabb"]
- ]
- },
- {
- "name": "godot_variant_new_basis",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_basis *", "p_basis"]
- ]
- },
- {
- "name": "godot_variant_new_transform",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_transform *", "p_trans"]
- ]
- },
- {
- "name": "godot_variant_new_color",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_color *", "p_color"]
- ]
- },
- {
- "name": "godot_variant_new_node_path",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_node_path *", "p_np"]
- ]
- },
- {
- "name": "godot_variant_new_rid",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_rid *", "p_rid"]
- ]
- },
- {
- "name": "godot_variant_new_object",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_object *", "p_obj"]
- ]
- },
- {
- "name": "godot_variant_new_callable",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_callable *", "p_cb"]
- ]
- },
- {
- "name": "godot_variant_new_signal",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_signal *", "p_signal"]
- ]
- },
- {
- "name": "godot_variant_new_dictionary",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_dictionary *", "p_dict"]
- ]
- },
- {
- "name": "godot_variant_new_array",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_array *", "p_arr"]
- ]
- },
- {
- "name": "godot_variant_new_packed_byte_array",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_packed_byte_array *", "p_pba"]
- ]
- },
- {
- "name": "godot_variant_new_packed_int32_array",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_packed_int32_array *", "p_pia"]
- ]
- },
- {
- "name": "godot_variant_new_packed_int64_array",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_packed_int64_array *", "p_pia"]
- ]
- },
- {
- "name": "godot_variant_new_packed_float32_array",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_packed_float32_array *", "p_pra"]
- ]
- },
- {
- "name": "godot_variant_new_packed_float64_array",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_packed_float64_array *", "p_pra"]
- ]
- },
- {
- "name": "godot_variant_new_packed_string_array",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_packed_string_array *", "p_psa"]
- ]
- },
- {
- "name": "godot_variant_new_packed_vector2_array",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_packed_vector2_array *", "p_pv2a"]
- ]
- },
- {
- "name": "godot_variant_new_packed_vector3_array",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_packed_vector3_array *", "p_pv3a"]
- ]
- },
- {
- "name": "godot_variant_new_packed_color_array",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "r_dest"],
- ["const godot_packed_color_array *", "p_pca"]
- ]
- },
- {
- "name": "godot_variant_as_bool",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_uint",
- "return_type": "uint64_t",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_int",
- "return_type": "int64_t",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_real",
- "return_type": "double",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_string",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_string_name",
- "return_type": "godot_string_name",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_vector2",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_vector2i",
- "return_type": "godot_vector2i",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_rect2",
- "return_type": "godot_rect2",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_rect2i",
- "return_type": "godot_rect2i",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_vector3",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_vector3i",
- "return_type": "godot_vector3i",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_transform2d",
- "return_type": "godot_transform2d",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_plane",
- "return_type": "godot_plane",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_quat",
- "return_type": "godot_quat",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_aabb",
- "return_type": "godot_aabb",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_basis",
- "return_type": "godot_basis",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_transform",
- "return_type": "godot_transform",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_color",
- "return_type": "godot_color",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_node_path",
- "return_type": "godot_node_path",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_rid",
- "return_type": "godot_rid",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_object",
- "return_type": "godot_object *",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_callable",
- "return_type": "godot_callable",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_signal",
- "return_type": "godot_signal",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_dictionary",
- "return_type": "godot_dictionary",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_array",
- "return_type": "godot_array",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_packed_byte_array",
- "return_type": "godot_packed_byte_array",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_packed_int32_array",
- "return_type": "godot_packed_int32_array",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_packed_int64_array",
- "return_type": "godot_packed_int64_array",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_packed_float32_array",
- "return_type": "godot_packed_float32_array",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_packed_float64_array",
- "return_type": "godot_packed_float64_array",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_packed_string_array",
- "return_type": "godot_packed_string_array",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_packed_vector2_array",
- "return_type": "godot_packed_vector2_array",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_packed_vector3_array",
- "return_type": "godot_packed_vector3_array",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_as_packed_color_array",
- "return_type": "godot_packed_color_array",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_call",
- "return_type": "godot_variant",
- "arguments": [
- ["godot_variant *", "p_self"],
- ["const godot_string *", "p_method"],
- ["const godot_variant **", "p_args"],
- ["const godot_int", "p_argcount"],
- ["godot_variant_call_error *", "r_error"]
- ]
- },
- {
- "name": "godot_variant_has_method",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_variant *", "p_self"],
- ["const godot_string *", "p_method"]
- ]
- },
- {
- "name": "godot_variant_hash",
- "return_type": "uint32_t",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_operator_equal",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_variant *", "p_self"],
- ["const godot_variant *", "p_other"]
- ]
- },
- {
- "name": "godot_variant_operator_less",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_variant *", "p_self"],
- ["const godot_variant *", "p_other"]
- ]
- },
- {
- "name": "godot_variant_get_operator_name",
- "return_type": "godot_string",
- "arguments": [
- ["godot_variant_operator", "p_op"]
- ]
- },
- {
- "name": "godot_variant_evaluate",
- "return_type": "void",
- "arguments": [
- ["godot_variant_operator", "p_op"],
- ["const godot_variant *", "p_a"],
- ["const godot_variant *", "p_b"],
- ["godot_variant *", "r_ret"],
- ["godot_bool *", "r_valid"]
- ]
- },
- {
- "name": "godot_variant_hash_compare",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_variant *", "p_self"],
- ["const godot_variant *", "p_other"]
- ]
- },
- {
- "name": "godot_variant_booleanize",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_variant_destroy",
- "return_type": "void",
- "arguments": [
- ["godot_variant *", "p_self"]
- ]
- },
- {
- "name": "godot_vector2_as_vector2i",
- "return_type": "godot_vector2i",
- "arguments": [
- ["const godot_vector2 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector2_sign",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_vector2 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector2_move_toward",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_vector2 *", "p_self"],
- ["const godot_vector2 *", "p_to"],
- ["const godot_real", "p_delta"]
- ]
- },
- {
- "name": "godot_vector2_direction_to",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_vector2 *", "p_self"],
- ["const godot_vector2 *", "p_to"]
- ]
- },
- {
- "name": "godot_vector2_new",
- "return_type": "void",
- "arguments": [
- ["godot_vector2 *", "r_dest"],
- ["const godot_real", "p_x"],
- ["const godot_real", "p_y"]
- ]
- },
- {
- "name": "godot_vector2_as_string",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_vector2 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector2_normalized",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_vector2 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector2_length",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_vector2 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector2_angle",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_vector2 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector2_length_squared",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_vector2 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector2_is_normalized",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_vector2 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector2_distance_to",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_vector2 *", "p_self"],
- ["const godot_vector2 *", "p_to"]
- ]
- },
- {
- "name": "godot_vector2_distance_squared_to",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_vector2 *", "p_self"],
- ["const godot_vector2 *", "p_to"]
- ]
- },
- {
- "name": "godot_vector2_angle_to",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_vector2 *", "p_self"],
- ["const godot_vector2 *", "p_to"]
- ]
- },
- {
- "name": "godot_vector2_angle_to_point",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_vector2 *", "p_self"],
- ["const godot_vector2 *", "p_to"]
- ]
- },
- {
- "name": "godot_vector2_lerp",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_vector2 *", "p_self"],
- ["const godot_vector2 *", "p_b"],
- ["const godot_real", "p_t"]
- ]
- },
- {
- "name": "godot_vector2_cubic_interpolate",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_vector2 *", "p_self"],
- ["const godot_vector2 *", "p_b"],
- ["const godot_vector2 *", "p_pre_a"],
- ["const godot_vector2 *", "p_post_b"],
- ["const godot_real", "p_t"]
- ]
- },
- {
- "name": "godot_vector2_rotated",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_vector2 *", "p_self"],
- ["const godot_real", "p_phi"]
- ]
- },
- {
- "name": "godot_vector2_tangent",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_vector2 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector2_floor",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_vector2 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector2_snapped",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_vector2 *", "p_self"],
- ["const godot_vector2 *", "p_by"]
- ]
- },
- {
- "name": "godot_vector2_aspect",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_vector2 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector2_dot",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_vector2 *", "p_self"],
- ["const godot_vector2 *", "p_with"]
- ]
- },
- {
- "name": "godot_vector2_slide",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_vector2 *", "p_self"],
- ["const godot_vector2 *", "p_n"]
- ]
- },
- {
- "name": "godot_vector2_bounce",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_vector2 *", "p_self"],
- ["const godot_vector2 *", "p_n"]
- ]
- },
- {
- "name": "godot_vector2_reflect",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_vector2 *", "p_self"],
- ["const godot_vector2 *", "p_n"]
- ]
- },
- {
- "name": "godot_vector2_abs",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_vector2 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector2_clamped",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_vector2 *", "p_self"],
- ["const godot_real", "p_length"]
- ]
- },
- {
- "name": "godot_vector2_operator_add",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_vector2 *", "p_self"],
- ["const godot_vector2 *", "p_b"]
- ]
- },
- {
- "name": "godot_vector2_operator_subtract",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_vector2 *", "p_self"],
- ["const godot_vector2 *", "p_b"]
- ]
- },
- {
- "name": "godot_vector2_operator_multiply_vector",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_vector2 *", "p_self"],
- ["const godot_vector2 *", "p_b"]
- ]
- },
- {
- "name": "godot_vector2_operator_multiply_scalar",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_vector2 *", "p_self"],
- ["const godot_real", "p_b"]
- ]
- },
- {
- "name": "godot_vector2_operator_divide_vector",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_vector2 *", "p_self"],
- ["const godot_vector2 *", "p_b"]
- ]
- },
- {
- "name": "godot_vector2_operator_divide_scalar",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_vector2 *", "p_self"],
- ["const godot_real", "p_b"]
- ]
- },
- {
- "name": "godot_vector2_operator_equal",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_vector2 *", "p_self"],
- ["const godot_vector2 *", "p_b"]
- ]
- },
- {
- "name": "godot_vector2_operator_less",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_vector2 *", "p_self"],
- ["const godot_vector2 *", "p_b"]
- ]
- },
- {
- "name": "godot_vector2_operator_neg",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_vector2 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector2_set_x",
- "return_type": "void",
- "arguments": [
- ["godot_vector2 *", "p_self"],
- ["const godot_real", "p_x"]
- ]
- },
- {
- "name": "godot_vector2_set_y",
- "return_type": "void",
- "arguments": [
- ["godot_vector2 *", "p_self"],
- ["const godot_real", "p_y"]
- ]
- },
- {
- "name": "godot_vector2_get_x",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_vector2 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector2_get_y",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_vector2 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector2i_new",
- "return_type": "void",
- "arguments": [
- ["godot_vector2i *", "r_dest"],
- ["const godot_int", "p_x"],
- ["const godot_int", "p_y"]
- ]
- },
- {
- "name": "godot_vector2i_as_string",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_vector2i *", "p_self"]
- ]
- },
- {
- "name": "godot_vector2i_as_vector2",
- "return_type": "godot_vector2",
- "arguments": [
- ["const godot_vector2i *", "p_self"]
- ]
- },
- {
- "name": "godot_vector2i_aspect",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_vector2i *", "p_self"]
- ]
- },
- {
- "name": "godot_vector2i_abs",
- "return_type": "godot_vector2i",
- "arguments": [
- ["const godot_vector2i *", "p_self"]
- ]
- },
- {
- "name": "godot_vector2i_sign",
- "return_type": "godot_vector2i",
- "arguments": [
- ["const godot_vector2i *", "p_self"]
- ]
- },
- {
- "name": "godot_vector2i_operator_add",
- "return_type": "godot_vector2i",
- "arguments": [
- ["const godot_vector2i *", "p_self"],
- ["const godot_vector2i *", "p_b"]
- ]
- },
- {
- "name": "godot_vector2i_operator_subtract",
- "return_type": "godot_vector2i",
- "arguments": [
- ["const godot_vector2i *", "p_self"],
- ["const godot_vector2i *", "p_b"]
- ]
- },
- {
- "name": "godot_vector2i_operator_multiply_vector",
- "return_type": "godot_vector2i",
- "arguments": [
- ["const godot_vector2i *", "p_self"],
- ["const godot_vector2i *", "p_b"]
- ]
- },
- {
- "name": "godot_vector2i_operator_multiply_scalar",
- "return_type": "godot_vector2i",
- "arguments": [
- ["const godot_vector2i *", "p_self"],
- ["const godot_int", "p_b"]
- ]
- },
- {
- "name": "godot_vector2i_operator_divide_vector",
- "return_type": "godot_vector2i",
- "arguments": [
- ["const godot_vector2i *", "p_self"],
- ["const godot_vector2i *", "p_b"]
- ]
- },
- {
- "name": "godot_vector2i_operator_divide_scalar",
- "return_type": "godot_vector2i",
- "arguments": [
- ["const godot_vector2i *", "p_self"],
- ["const godot_int", "p_b"]
- ]
- },
- {
- "name": "godot_vector2i_operator_equal",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_vector2i *", "p_self"],
- ["const godot_vector2i *", "p_b"]
- ]
- },
- {
- "name": "godot_vector2i_operator_less",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_vector2i *", "p_self"],
- ["const godot_vector2i *", "p_b"]
- ]
- },
- {
- "name": "godot_vector2i_operator_neg",
- "return_type": "godot_vector2i",
- "arguments": [
- ["const godot_vector2i *", "p_self"]
- ]
- },
- {
- "name": "godot_vector2i_set_x",
- "return_type": "void",
- "arguments": [
- ["godot_vector2i *", "p_self"],
- ["const godot_int", "p_x"]
- ]
- },
- {
- "name": "godot_vector2i_set_y",
- "return_type": "void",
- "arguments": [
- ["godot_vector2i *", "p_self"],
- ["const godot_int", "p_y"]
- ]
- },
- {
- "name": "godot_vector2i_get_x",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_vector2i *", "p_self"]
- ]
- },
- {
- "name": "godot_vector2i_get_y",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_vector2i *", "p_self"]
- ]
- },
- {
- "name": "godot_vector3_as_vector3i",
- "return_type": "godot_vector3i",
- "arguments": [
- ["const godot_vector3 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector3_sign",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_vector3 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector3_move_toward",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_vector3 *", "p_self"],
- ["const godot_vector3 *", "p_to"],
- ["const godot_real", "p_delta"]
- ]
- },
- {
- "name": "godot_vector3_direction_to",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_vector3 *", "p_self"],
- ["const godot_vector3 *", "p_to"]
- ]
- },
- {
- "name": "godot_vector3_new",
- "return_type": "void",
- "arguments": [
- ["godot_vector3 *", "r_dest"],
- ["const godot_real", "p_x"],
- ["const godot_real", "p_y"],
- ["const godot_real", "p_z"]
- ]
- },
- {
- "name": "godot_vector3_as_string",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_vector3 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector3_min_axis",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_vector3 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector3_max_axis",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_vector3 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector3_length",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_vector3 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector3_length_squared",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_vector3 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector3_is_normalized",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_vector3 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector3_normalized",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_vector3 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector3_inverse",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_vector3 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector3_snapped",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_vector3 *", "p_self"],
- ["const godot_vector3 *", "p_by"]
- ]
- },
- {
- "name": "godot_vector3_rotated",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_vector3 *", "p_self"],
- ["const godot_vector3 *", "p_axis"],
- ["const godot_real", "p_phi"]
- ]
- },
- {
- "name": "godot_vector3_lerp",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_vector3 *", "p_self"],
- ["const godot_vector3 *", "p_b"],
- ["const godot_real", "p_t"]
- ]
- },
- {
- "name": "godot_vector3_cubic_interpolate",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_vector3 *", "p_self"],
- ["const godot_vector3 *", "p_b"],
- ["const godot_vector3 *", "p_pre_a"],
- ["const godot_vector3 *", "p_post_b"],
- ["const godot_real", "p_t"]
- ]
- },
- {
- "name": "godot_vector3_dot",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_vector3 *", "p_self"],
- ["const godot_vector3 *", "p_b"]
- ]
- },
- {
- "name": "godot_vector3_cross",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_vector3 *", "p_self"],
- ["const godot_vector3 *", "p_b"]
- ]
- },
- {
- "name": "godot_vector3_outer",
- "return_type": "godot_basis",
- "arguments": [
- ["const godot_vector3 *", "p_self"],
- ["const godot_vector3 *", "p_b"]
- ]
- },
- {
- "name": "godot_vector3_to_diagonal_matrix",
- "return_type": "godot_basis",
- "arguments": [
- ["const godot_vector3 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector3_abs",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_vector3 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector3_floor",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_vector3 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector3_ceil",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_vector3 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector3_distance_to",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_vector3 *", "p_self"],
- ["const godot_vector3 *", "p_b"]
- ]
- },
- {
- "name": "godot_vector3_distance_squared_to",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_vector3 *", "p_self"],
- ["const godot_vector3 *", "p_b"]
- ]
- },
- {
- "name": "godot_vector3_angle_to",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_vector3 *", "p_self"],
- ["const godot_vector3 *", "p_to"]
- ]
- },
- {
- "name": "godot_vector3_slide",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_vector3 *", "p_self"],
- ["const godot_vector3 *", "p_n"]
- ]
- },
- {
- "name": "godot_vector3_bounce",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_vector3 *", "p_self"],
- ["const godot_vector3 *", "p_n"]
- ]
- },
- {
- "name": "godot_vector3_reflect",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_vector3 *", "p_self"],
- ["const godot_vector3 *", "p_n"]
- ]
- },
- {
- "name": "godot_vector3_operator_add",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_vector3 *", "p_self"],
- ["const godot_vector3 *", "p_b"]
- ]
- },
- {
- "name": "godot_vector3_operator_subtract",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_vector3 *", "p_self"],
- ["const godot_vector3 *", "p_b"]
- ]
- },
- {
- "name": "godot_vector3_operator_multiply_vector",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_vector3 *", "p_self"],
- ["const godot_vector3 *", "p_b"]
- ]
- },
- {
- "name": "godot_vector3_operator_multiply_scalar",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_vector3 *", "p_self"],
- ["const godot_real", "p_b"]
- ]
- },
- {
- "name": "godot_vector3_operator_divide_vector",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_vector3 *", "p_self"],
- ["const godot_vector3 *", "p_b"]
- ]
- },
- {
- "name": "godot_vector3_operator_divide_scalar",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_vector3 *", "p_self"],
- ["const godot_real", "p_b"]
- ]
- },
- {
- "name": "godot_vector3_operator_equal",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_vector3 *", "p_self"],
- ["const godot_vector3 *", "p_b"]
- ]
- },
- {
- "name": "godot_vector3_operator_less",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_vector3 *", "p_self"],
- ["const godot_vector3 *", "p_b"]
- ]
- },
- {
- "name": "godot_vector3_operator_neg",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_vector3 *", "p_self"]
- ]
- },
- {
- "name": "godot_vector3_set_axis",
- "return_type": "void",
- "arguments": [
- ["godot_vector3 *", "p_self"],
- ["const godot_vector3_axis", "p_axis"],
- ["const godot_real", "p_val"]
- ]
- },
- {
- "name": "godot_vector3_get_axis",
- "return_type": "godot_real",
- "arguments": [
- ["const godot_vector3 *", "p_self"],
- ["const godot_vector3_axis", "p_axis"]
- ]
- },
- {
- "name": "godot_vector3i_new",
- "return_type": "void",
- "arguments": [
- ["godot_vector3i *", "r_dest"],
- ["const godot_int", "p_x"],
- ["const godot_int", "p_y"],
- ["const godot_int", "p_z"]
- ]
- },
- {
- "name": "godot_vector3i_as_string",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_vector3i *", "p_self"]
- ]
- },
- {
- "name": "godot_vector3i_as_vector3",
- "return_type": "godot_vector3",
- "arguments": [
- ["const godot_vector3i *", "p_self"]
- ]
- },
- {
- "name": "godot_vector3i_min_axis",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_vector3i *", "p_self"]
- ]
- },
- {
- "name": "godot_vector3i_max_axis",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_vector3i *", "p_self"]
- ]
- },
- {
- "name": "godot_vector3i_abs",
- "return_type": "godot_vector3i",
- "arguments": [
- ["const godot_vector3i *", "p_self"]
- ]
- },
- {
- "name": "godot_vector3i_sign",
- "return_type": "godot_vector3i",
- "arguments": [
- ["const godot_vector3i *", "p_self"]
- ]
- },
- {
- "name": "godot_vector3i_operator_add",
- "return_type": "godot_vector3i",
- "arguments": [
- ["const godot_vector3i *", "p_self"],
- ["const godot_vector3i *", "p_b"]
- ]
- },
- {
- "name": "godot_vector3i_operator_subtract",
- "return_type": "godot_vector3i",
- "arguments": [
- ["const godot_vector3i *", "p_self"],
- ["const godot_vector3i *", "p_b"]
- ]
- },
- {
- "name": "godot_vector3i_operator_multiply_vector",
- "return_type": "godot_vector3i",
- "arguments": [
- ["const godot_vector3i *", "p_self"],
- ["const godot_vector3i *", "p_b"]
- ]
- },
- {
- "name": "godot_vector3i_operator_multiply_scalar",
- "return_type": "godot_vector3i",
- "arguments": [
- ["const godot_vector3i *", "p_self"],
- ["const godot_int", "p_b"]
- ]
- },
- {
- "name": "godot_vector3i_operator_divide_vector",
- "return_type": "godot_vector3i",
- "arguments": [
- ["const godot_vector3i *", "p_self"],
- ["const godot_vector3i *", "p_b"]
- ]
- },
- {
- "name": "godot_vector3i_operator_divide_scalar",
- "return_type": "godot_vector3i",
- "arguments": [
- ["const godot_vector3i *", "p_self"],
- ["const godot_int", "p_b"]
- ]
- },
- {
- "name": "godot_vector3i_operator_equal",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_vector3i *", "p_self"],
- ["const godot_vector3i *", "p_b"]
- ]
- },
- {
- "name": "godot_vector3i_operator_less",
- "return_type": "godot_bool",
- "arguments": [
- ["const godot_vector3i *", "p_self"],
- ["const godot_vector3i *", "p_b"]
- ]
- },
- {
- "name": "godot_vector3i_operator_neg",
- "return_type": "godot_vector3i",
- "arguments": [
- ["const godot_vector3i *", "p_self"]
- ]
- },
- {
- "name": "godot_vector3i_set_axis",
- "return_type": "void",
- "arguments": [
- ["godot_vector3i *", "p_self"],
- ["const godot_vector3_axis", "p_axis"],
- ["const godot_int", "p_val"]
- ]
- },
- {
- "name": "godot_vector3i_get_axis",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_vector3i *", "p_self"],
- ["const godot_vector3_axis", "p_axis"]
- ]
- },
- {
- "name": "godot_global_get_singleton",
- "return_type": "godot_object *",
- "arguments": [
- ["char *", "p_name"]
- ]
- },
- {
- "name": "godot_get_class_tag",
- "return_type": "void *",
- "arguments": [
- ["const godot_string_name *", "p_class"]
- ]
- },
- {
- "name": "godot_object_cast_to",
- "return_type": "godot_object *",
- "arguments": [
- ["const godot_object *", "p_object"],
- ["void *", "p_class_tag"]
- ]
- },
- {
- "name": "godot_object_get_instance_id",
- "return_type": "uint64_t",
- "arguments": [
- ["const godot_object *", "p_object"]
- ]
- },
- {
- "name": "godot_instance_from_id",
- "return_type": "godot_object *",
- "arguments": [
- ["uint64_t", "p_instance_id"]
- ]
- },
- {
- "name": "godot_object_destroy",
- "return_type": "void",
- "arguments": [
- ["godot_object *", "p_o"]
- ]
- },
- {
- "name": "godot_method_bind_get_method",
- "return_type": "godot_method_bind *",
- "arguments": [
- ["const char *", "p_classname"],
- ["const char *", "p_methodname"]
- ]
- },
- {
- "name": "godot_method_bind_ptrcall",
- "return_type": "void",
- "arguments": [
- ["godot_method_bind *", "p_method_bind"],
- ["godot_object *", "p_instance"],
- ["const void **", "p_args"],
- ["void *", "p_ret"]
- ]
- },
- {
- "name": "godot_method_bind_call",
- "return_type": "godot_variant",
- "arguments": [
- ["godot_method_bind *", "p_method_bind"],
- ["godot_object *", "p_instance"],
- ["const godot_variant **", "p_args"],
- ["const int", "p_arg_count"],
- ["godot_variant_call_error *", "p_call_error"]
- ]
- },
- {
- "name": "godot_get_class_constructor",
- "return_type": "godot_class_constructor",
- "arguments": [
- ["const char *", "p_classname"]
- ]
- },
- {
- "name": "godot_get_global_constants",
- "return_type": "godot_dictionary",
- "arguments": [
- ]
- },
- {
- "name": "godot_register_native_call_type",
- "return_type": "void",
- "arguments": [
- ["const char *", "call_type"],
- ["native_call_cb", "p_callback"]
- ]
- },
- {
- "name": "godot_alloc",
- "return_type": "void *",
- "arguments": [
- ["int", "p_bytes"]
- ]
- },
- {
- "name": "godot_realloc",
- "return_type": "void *",
- "arguments": [
- ["void *", "p_ptr"],
- ["int", "p_bytes"]
- ]
- },
- {
- "name": "godot_free",
- "return_type": "void",
- "arguments": [
- ["void *", "p_ptr"]
- ]
- },
- {
- "name": "godot_print_error",
- "return_type": "void",
- "arguments": [
- ["const char *", "p_description"],
- ["const char *", "p_function"],
- ["const char *", "p_file"],
- ["int", "p_line"]
- ]
- },
- {
- "name": "godot_print_warning",
- "return_type": "void",
- "arguments": [
- ["const char *", "p_description"],
- ["const char *", "p_function"],
- ["const char *", "p_file"],
- ["int", "p_line"]
- ]
- },
- {
- "name": "godot_print",
- "return_type": "void",
- "arguments": [
- ["const godot_string *", "p_message"]
- ]
- }
- ]
- },
- "extensions": [
- {
- "name": "nativescript",
- "type": "NATIVESCRIPT",
- "version": {
- "major": 4,
- "minor": 0
- },
- "next": null,
- "api": [
- {
- "name": "godot_nativescript_register_class",
- "return_type": "void",
- "arguments": [
- ["void *", "p_gdnative_handle"],
- ["const char *", "p_name"],
- ["const char *", "p_base"],
- ["godot_nativescript_instance_create_func", "p_create_func"],
- ["godot_nativescript_instance_destroy_func", "p_destroy_func"]
- ]
- },
- {
- "name": "godot_nativescript_register_tool_class",
- "return_type": "void",
- "arguments": [
- ["void *", "p_gdnative_handle"],
- ["const char *", "p_name"],
- ["const char *", "p_base"],
- ["godot_nativescript_instance_create_func", "p_create_func"],
- ["godot_nativescript_instance_destroy_func", "p_destroy_func"]
- ]
- },
- {
- "name": "godot_nativescript_register_method",
- "return_type": "void",
- "arguments": [
- ["void *", "p_gdnative_handle"],
- ["const char *", "p_name"],
- ["const char *", "p_function_name"],
- ["godot_nativescript_method_attributes", "p_attr"],
- ["godot_nativescript_instance_method", "p_method"]
- ]
- },
- {
- "name": "godot_nativescript_set_method_argument_information",
- "return_type": "void",
- "arguments": [
- ["void *", "p_gdnative_handle"],
- ["const char *", "p_name"],
- ["const char *", "p_function_name"],
- ["int", "p_num_args"],
- ["const godot_nativescript_method_argument *", "p_args"]
- ]
- },
- {
- "name": "godot_nativescript_register_property",
- "return_type": "void",
- "arguments": [
- ["void *", "p_gdnative_handle"],
- ["const char *", "p_name"],
- ["const char *", "p_path"],
- ["godot_nativescript_property_attributes *", "p_attr"],
- ["godot_nativescript_property_set_func", "p_set_func"],
- ["godot_nativescript_property_get_func", "p_get_func"]
- ]
- },
- {
- "name": "godot_nativescript_register_signal",
- "return_type": "void",
- "arguments": [
- ["void *", "p_gdnative_handle"],
- ["const char *", "p_name"],
- ["const godot_nativescript_signal *", "p_signal"]
- ]
- },
- {
- "name": "godot_nativescript_get_userdata",
- "return_type": "void *",
- "arguments": [
- ["godot_object *", "p_instance"]
- ]
- },
- {
- "name": "godot_nativescript_set_class_documentation",
- "return_type": "void",
- "arguments": [
- ["void *", "p_gdnative_handle"],
- ["const char *", "p_name"],
- ["godot_string", "p_documentation"]
- ]
- },
- {
- "name": "godot_nativescript_set_method_documentation",
- "return_type": "void",
- "arguments": [
- ["void *", "p_gdnative_handle"],
- ["const char *", "p_name"],
- ["const char *", "p_function_name"],
- ["godot_string", "p_documentation"]
- ]
- },
- {
- "name": "godot_nativescript_set_property_documentation",
- "return_type": "void",
- "arguments": [
- ["void *", "p_gdnative_handle"],
- ["const char *", "p_name"],
- ["const char *", "p_path"],
- ["godot_string", "p_documentation"]
- ]
- },
- {
- "name": "godot_nativescript_set_signal_documentation",
- "return_type": "void",
- "arguments": [
- ["void *", "p_gdnative_handle"],
- ["const char *", "p_name"],
- ["const char *", "p_signal_name"],
- ["godot_string", "p_documentation"]
- ]
- },
- {
- "name": "godot_nativescript_set_global_type_tag",
- "return_type": "void",
- "arguments": [
- ["int", "p_idx"],
- ["const char *", "p_name"],
- ["const void *", "p_type_tag"]
- ]
- },
- {
- "name": "godot_nativescript_get_global_type_tag",
- "return_type": "const void *",
- "arguments": [
- ["int", "p_idx"],
- ["const char *", "p_name"]
- ]
- },
- {
- "name": "godot_nativescript_set_type_tag",
- "return_type": "void",
- "arguments": [
- ["void *", "p_gdnative_handle"],
- ["const char *", "p_name"],
- ["const void *", "p_type_tag"]
- ]
- },
- {
- "name": "godot_nativescript_get_type_tag",
- "return_type": "const void *",
- "arguments": [
- ["const godot_object *", "p_object"]
- ]
- },
- {
- "name": "godot_nativescript_register_instance_binding_data_functions",
- "return_type": "int",
- "arguments": [
- ["godot_nativescript_instance_binding_functions", "p_binding_functions"]
- ]
- },
- {
- "name": "godot_nativescript_unregister_instance_binding_data_functions",
- "return_type": "void",
- "arguments": [
- ["int", "p_idx"]
- ]
- },
- {
- "name": "godot_nativescript_get_instance_binding_data",
- "return_type": "void *",
- "arguments": [
- ["int", "p_idx"],
- ["godot_object *", "p_object"]
- ]
- },
- {
- "name": "godot_nativescript_profiling_add_data",
- "return_type": "void",
- "arguments": [
- ["const char *", "p_signature"],
- ["uint64_t", "p_line"]
- ]
- }
- ]
- },
- {
- "name": "pluginscript",
- "type": "PLUGINSCRIPT",
- "version": {
- "major": 1,
- "minor": 0
- },
- "next": null,
- "api": [
- {
- "name": "godot_pluginscript_register_language",
- "return_type": "void",
- "arguments": [
- ["const godot_pluginscript_language_desc *", "language_desc"]
- ]
- }
- ]
- },
- {
- "name": "android",
- "type": "ANDROID",
- "version": {
- "major": 1,
- "minor": 1
- },
- "next": null,
- "api": [
- {
- "name": "godot_android_get_env",
- "return_type": "JNIEnv*",
- "arguments": [
- ]
- },
- {
- "name": "godot_android_get_activity",
- "return_type": "jobject",
- "arguments": [
- ]
- },
- {
- "name": "godot_android_get_surface",
- "return_type": "jobject",
- "arguments": [
- ]
- },
- {
- "name": "godot_android_is_activity_resumed",
- "return_type": "bool",
- "arguments": [
- ]
- }
- ]
- },
- {
- "name": "xr",
- "type": "XR",
- "version": {
- "major": 1,
- "minor": 1
- },
- "next": null,
- "api": [
- {
- "name": "godot_xr_register_interface",
- "return_type": "void",
- "arguments": [
- ["const godot_xr_interface_gdnative *", "p_interface"]
- ]
- },
- {
- "name": "godot_xr_get_worldscale",
- "return_type": "godot_real",
- "arguments": []
- },
- {
- "name": "godot_xr_get_reference_frame",
- "return_type": "godot_transform",
- "arguments": []
- },
- {
- "name": "godot_xr_blit",
- "return_type": "void",
- "arguments": [
- ["godot_int", "p_eye"],
- ["godot_rid *", "p_render_target"],
- ["godot_rect2 *", "p_screen_rect"]
- ]
- },
- {
- "name": "godot_xr_get_texid",
- "return_type": "godot_int",
- "arguments": [
- ["godot_rid *", "p_render_target"]
- ]
- },
- {
- "name": "godot_xr_add_controller",
- "return_type": "godot_int",
- "arguments": [
- ["char *", "p_device_name"],
- ["godot_int", "p_hand"],
- ["godot_bool", "p_tracks_orientation"],
- ["godot_bool", "p_tracks_position"]
- ]
- },
- {
- "name": "godot_xr_remove_controller",
- "return_type": "void",
- "arguments": [
- ["godot_int", "p_controller_id"]
- ]
- },
- {
- "name": "godot_xr_set_controller_transform",
- "return_type": "void",
- "arguments": [
- ["godot_int", "p_controller_id"],
- ["godot_transform *", "p_transform"],
- ["godot_bool", "p_tracks_orientation"],
- ["godot_bool", "p_tracks_position"]
- ]
- },
- {
- "name": "godot_xr_set_controller_button",
- "return_type": "void",
- "arguments": [
- ["godot_int", "p_controller_id"],
- ["godot_int", "p_button"],
- ["godot_bool", "p_is_pressed"]
- ]
- },
- {
- "name": "godot_xr_set_controller_axis",
- "return_type": "void",
- "arguments": [
- ["godot_int", "p_controller_id"],
- ["godot_int", "p_exis"],
- ["godot_real", "p_value"],
- ["godot_bool", "p_can_be_negative"]
- ]
- },
- {
- "name": "godot_xr_get_controller_rumble",
- "return_type": "godot_real",
- "arguments": [
- ["godot_int", "p_controller_id"]
- ]
- }
- ]
- },
- {
- "name": "videodecoder",
- "type": "VIDEODECODER",
- "version": {
- "major": 0,
- "minor": 1
- },
- "next": null,
- "api": [
- {
- "name": "godot_videodecoder_file_read",
- "return_type": "godot_int",
- "arguments": [
- ["void *", "file_ptr"],
- ["uint8_t *", "buf"],
- ["int", "buf_size"]
- ]
- },
- {
- "name": "godot_videodecoder_file_seek",
- "return_type": "int64_t",
- "arguments": [
- [ "void *", "file_ptr"],
- ["int64_t", "pos"],
- ["int", "whence"]
- ]
- },
- {
- "name": "godot_videodecoder_register_decoder",
- "return_type": "void",
- "arguments": [
- ["const godot_videodecoder_interface_gdnative *", "p_interface"]
- ]
- }
- ]
- },
- {
- "name": "net",
- "type": "NET",
- "version": {
- "major": 4,
- "minor": 0
- },
- "next": null,
- "api": [
- {
- "name": "godot_net_bind_stream_peer",
- "return_type": "void",
- "arguments": [
- ["godot_object *", "p_obj"],
- ["const godot_net_stream_peer *", "p_interface"]
- ]
- },
- {
- "name": "godot_net_bind_packet_peer",
- "return_type": "void",
- "arguments": [
- ["godot_object *", "p_obj"],
- ["const godot_net_packet_peer *", "p_interface"]
- ]
- },
- {
- "name": "godot_net_bind_multiplayer_peer",
- "return_type": "void",
- "arguments": [
- ["godot_object *", "p_obj"],
- ["const godot_net_multiplayer_peer *", "p_interface"]
- ]
- },
- {
- "name": "godot_net_set_webrtc_library",
- "return_type": "godot_error",
- "arguments": [
- ["const godot_net_webrtc_library *", "p_library"]
- ]
- },
- {
- "name": "godot_net_bind_webrtc_peer_connection",
- "return_type": "void",
- "arguments": [
- ["godot_object *", "p_obj"],
- ["const godot_net_webrtc_peer_connection *", "p_interface"]
- ]
- },
- {
- "name": "godot_net_bind_webrtc_data_channel",
- "return_type": "void",
- "arguments": [
- ["godot_object *", "p_obj"],
- ["const godot_net_webrtc_data_channel *", "p_interface"]
- ]
- }
- ]
- }
- ]
+ "core": {
+ "type": "CORE",
+ "version": {
+ "major": 4,
+ "minor": 0
+ },
+ "next": null,
+ "api": [
+ {
+ "name": "godot_object_destroy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_object *",
+ "p_o"
+ ]
+ ]
+ },
+ {
+ "name": "godot_global_get_singleton",
+ "return_type": "godot_object *",
+ "arguments": [
+ [
+ "char *",
+ "p_name"
+ ]
+ ]
+ },
+ {
+ "name": "godot_method_bind_get_method",
+ "return_type": "godot_method_bind *",
+ "arguments": [
+ [
+ "const char *",
+ "p_classname"
+ ],
+ [
+ "const char *",
+ "p_methodname"
+ ]
+ ]
+ },
+ {
+ "name": "godot_method_bind_ptrcall",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_method_bind *",
+ "p_method_bind"
+ ],
+ [
+ "godot_object *",
+ "p_instance"
+ ],
+ [
+ "const void **",
+ "p_args"
+ ],
+ [
+ "void *",
+ "p_ret"
+ ]
+ ]
+ },
+ {
+ "name": "godot_method_bind_call",
+ "return_type": "godot_variant",
+ "arguments": [
+ [
+ "godot_method_bind *",
+ "p_method_bind"
+ ],
+ [
+ "godot_object *",
+ "p_instance"
+ ],
+ [
+ "const godot_variant **",
+ "p_args"
+ ],
+ [
+ "const int",
+ "p_arg_count"
+ ],
+ [
+ "godot_variant_call_error *",
+ "p_call_error"
+ ]
+ ]
+ },
+ {
+ "name": "godot_get_class_constructor",
+ "return_type": "godot_class_constructor",
+ "arguments": [
+ [
+ "const char *",
+ "p_classname"
+ ]
+ ]
+ },
+ {
+ "name": "godot_get_global_constants",
+ "return_type": "godot_dictionary",
+ "arguments": []
+ },
+ {
+ "name": "godot_register_native_call_type",
+ "return_type": "void",
+ "arguments": [
+ [
+ "const char *",
+ "call_type"
+ ],
+ [
+ "native_call_cb",
+ "p_callback"
+ ]
+ ]
+ },
+ {
+ "name": "godot_alloc",
+ "return_type": "void *",
+ "arguments": [
+ [
+ "int",
+ "p_bytes"
+ ]
+ ]
+ },
+ {
+ "name": "godot_realloc",
+ "return_type": "void *",
+ "arguments": [
+ [
+ "void *",
+ "p_ptr"
+ ],
+ [
+ "int",
+ "p_bytes"
+ ]
+ ]
+ },
+ {
+ "name": "godot_free",
+ "return_type": "void",
+ "arguments": [
+ [
+ "void *",
+ "p_ptr"
+ ]
+ ]
+ },
+ {
+ "name": "godot_get_class_tag",
+ "return_type": "void *",
+ "arguments": [
+ [
+ "const godot_string_name *",
+ "p_class"
+ ]
+ ]
+ },
+ {
+ "name": "godot_object_cast_to",
+ "return_type": "godot_object *",
+ "arguments": [
+ [
+ "const godot_object *",
+ "p_object"
+ ],
+ [
+ "void *",
+ "p_class_tag"
+ ]
+ ]
+ },
+ {
+ "name": "godot_instance_from_id",
+ "return_type": "godot_object *",
+ "arguments": [
+ [
+ "uint64_t",
+ "p_instance_id"
+ ]
+ ]
+ },
+ {
+ "name": "godot_object_get_instance_id",
+ "return_type": "uint64_t",
+ "arguments": [
+ [
+ "const godot_object *",
+ "p_object"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_variant *",
+ "p_src"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_nil",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_bool",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_bool",
+ "p_b"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_int",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const int64_t",
+ "p_i"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_float",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const double",
+ "p_f"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_string",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_string *",
+ "p_s"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_string_name",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_string_name *",
+ "p_s"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_vector2",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_vector2 *",
+ "p_v2"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_vector2i",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_vector2i *",
+ "p_v2"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_rect2",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_rect2 *",
+ "p_rect2"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_rect2i",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_rect2i *",
+ "p_rect2"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_vector3",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_vector3 *",
+ "p_v3"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_vector3i",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_vector3i *",
+ "p_v3"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_transform2d",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_transform2d *",
+ "p_t2d"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_plane",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_plane *",
+ "p_plane"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_quat",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_quat *",
+ "p_quat"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_aabb",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_aabb *",
+ "p_aabb"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_basis",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_basis *",
+ "p_basis"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_transform",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_transform *",
+ "p_trans"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_color",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_color *",
+ "p_color"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_node_path",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_node_path *",
+ "p_np"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_rid",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_rid *",
+ "p_rid"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_object",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_object *",
+ "p_obj"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_callable",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_callable *",
+ "p_cb"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_signal",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_signal *",
+ "p_signal"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_dictionary",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_dictionary *",
+ "p_dict"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_array",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_array *",
+ "p_arr"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_packed_byte_array",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_byte_array *",
+ "p_pba"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_packed_int32_array",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_int32_array *",
+ "p_pia"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_packed_int64_array",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_int64_array *",
+ "p_pia"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_packed_float32_array",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_float32_array *",
+ "p_pra"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_packed_float64_array",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_float64_array *",
+ "p_pra"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_packed_string_array",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_string_array *",
+ "p_psa"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_packed_vector2_array",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_vector2_array *",
+ "p_pv2a"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_packed_vector3_array",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_vector3_array *",
+ "p_pv3a"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_new_packed_color_array",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_color_array *",
+ "p_pca"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_bool",
+ "return_type": "godot_bool",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_int",
+ "return_type": "int64_t",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_float",
+ "return_type": "double",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_string",
+ "return_type": "godot_string",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_string_name",
+ "return_type": "godot_string_name",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_vector2",
+ "return_type": "godot_vector2",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_vector2i",
+ "return_type": "godot_vector2i",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_rect2",
+ "return_type": "godot_rect2",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_rect2i",
+ "return_type": "godot_rect2i",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_vector3",
+ "return_type": "godot_vector3",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_vector3i",
+ "return_type": "godot_vector3i",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_transform2d",
+ "return_type": "godot_transform2d",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_plane",
+ "return_type": "godot_plane",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_quat",
+ "return_type": "godot_quat",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_aabb",
+ "return_type": "godot_aabb",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_basis",
+ "return_type": "godot_basis",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_transform",
+ "return_type": "godot_transform",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_color",
+ "return_type": "godot_color",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_node_path",
+ "return_type": "godot_node_path",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_rid",
+ "return_type": "godot_rid",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_object",
+ "return_type": "godot_object *",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_callable",
+ "return_type": "godot_callable",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_signal",
+ "return_type": "godot_signal",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_dictionary",
+ "return_type": "godot_dictionary",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_array",
+ "return_type": "godot_array",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_packed_byte_array",
+ "return_type": "godot_packed_byte_array",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_packed_int32_array",
+ "return_type": "godot_packed_int32_array",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_packed_int64_array",
+ "return_type": "godot_packed_int64_array",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_packed_float32_array",
+ "return_type": "godot_packed_float32_array",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_packed_float64_array",
+ "return_type": "godot_packed_float64_array",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_packed_string_array",
+ "return_type": "godot_packed_string_array",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_packed_vector2_array",
+ "return_type": "godot_packed_vector2_array",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_packed_vector3_array",
+ "return_type": "godot_packed_vector3_array",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_as_packed_color_array",
+ "return_type": "godot_packed_color_array",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_destroy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_call",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "p_self"
+ ],
+ [
+ "const godot_string_name *",
+ "p_method"
+ ],
+ [
+ "const godot_variant **",
+ "p_args"
+ ],
+ [
+ "const godot_int",
+ "p_argument_count"
+ ],
+ [
+ "godot_variant *",
+ "r_return"
+ ],
+ [
+ "godot_variant_call_error *",
+ "r_error"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_evaluate",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant_operator",
+ "p_op"
+ ],
+ [
+ "const godot_variant *",
+ "p_a"
+ ],
+ [
+ "const godot_variant *",
+ "p_b"
+ ],
+ [
+ "godot_variant *",
+ "r_return"
+ ],
+ [
+ "bool *",
+ "r_valid"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_set",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "p_self"
+ ],
+ [
+ "const godot_variant *",
+ "p_key"
+ ],
+ [
+ "const godot_variant *",
+ "p_value"
+ ],
+ [
+ "bool *",
+ "r_valid"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_set_named",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "p_self"
+ ],
+ [
+ "const godot_string_name *",
+ "p_name"
+ ],
+ [
+ "const godot_variant *",
+ "p_value"
+ ],
+ [
+ "bool *",
+ "r_valid"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_set_keyed",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "p_self"
+ ],
+ [
+ "const godot_variant *",
+ "p_key"
+ ],
+ [
+ "const godot_variant *",
+ "p_value"
+ ],
+ [
+ "bool *",
+ "r_valid"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_set_indexed",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ],
+ [
+ "const godot_variant *",
+ "p_value"
+ ],
+ [
+ "bool *",
+ "r_valid"
+ ],
+ [
+ "bool *",
+ "r_oob"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get",
+ "return_type": "godot_variant",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ],
+ [
+ "const godot_variant *",
+ "p_key"
+ ],
+ [
+ "bool *",
+ "r_valid"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_named",
+ "return_type": "godot_variant",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ],
+ [
+ "const godot_string_name *",
+ "p_key"
+ ],
+ [
+ "bool *",
+ "r_valid"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_keyed",
+ "return_type": "godot_variant",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ],
+ [
+ "const godot_variant *",
+ "p_key"
+ ],
+ [
+ "bool *",
+ "r_valid"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_indexed",
+ "return_type": "godot_variant",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ],
+ [
+ "bool *",
+ "r_valid"
+ ],
+ [
+ "bool *",
+ "r_oob"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_iter_init",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ],
+ [
+ "godot_variant *",
+ "r_iter"
+ ],
+ [
+ "bool *",
+ "r_valid"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_iter_next",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ],
+ [
+ "godot_variant *",
+ "r_iter"
+ ],
+ [
+ "bool *",
+ "r_valid"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_iter_get",
+ "return_type": "godot_variant",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ],
+ [
+ "godot_variant *",
+ "r_iter"
+ ],
+ [
+ "bool *",
+ "r_valid"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_hash_compare",
+ "return_type": "godot_bool",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ],
+ [
+ "const godot_variant *",
+ "p_other"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_booleanize",
+ "return_type": "godot_bool",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_blend",
+ "return_type": "void",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_a"
+ ],
+ [
+ "const godot_variant *",
+ "p_b"
+ ],
+ [
+ "float",
+ "p_c"
+ ],
+ [
+ "godot_variant *",
+ "r_dst"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_interpolate",
+ "return_type": "void",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_a"
+ ],
+ [
+ "const godot_variant *",
+ "p_b"
+ ],
+ [
+ "float",
+ "p_c"
+ ],
+ [
+ "godot_variant *",
+ "r_dst"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_duplicate",
+ "return_type": "godot_variant",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ],
+ [
+ "godot_bool",
+ "p_deep"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_stringify",
+ "return_type": "godot_string",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_validated_operator_evaluator",
+ "return_type": "godot_validated_operator_evaluator",
+ "arguments": [
+ [
+ "godot_variant_operator",
+ "p_operator"
+ ],
+ [
+ "godot_variant_type",
+ "p_type_a"
+ ],
+ [
+ "godot_variant_type",
+ "p_type_b"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_ptr_operator_evaluator",
+ "return_type": "godot_ptr_operator_evaluator",
+ "arguments": [
+ [
+ "godot_variant_operator",
+ "p_operator"
+ ],
+ [
+ "godot_variant_type",
+ "p_type_a"
+ ],
+ [
+ "godot_variant_type",
+ "p_type_b"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_operator_return_type",
+ "return_type": "godot_variant_type",
+ "arguments": [
+ [
+ "godot_variant_operator",
+ "p_operator"
+ ],
+ [
+ "godot_variant_type",
+ "p_type_a"
+ ],
+ [
+ "godot_variant_type",
+ "p_type_b"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_operator_name",
+ "return_type": "godot_string",
+ "arguments": [
+ [
+ "godot_variant_operator",
+ "p_operator"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_has_builtin_method",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const godot_string_name *",
+ "p_method"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_has_builtin_method_with_cstring",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const char *",
+ "p_method"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_validated_builtin_method",
+ "return_type": "godot_validated_builtin_method",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const godot_string_name *",
+ "p_method"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_validated_builtin_method_with_cstring",
+ "return_type": "godot_validated_builtin_method",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const char *",
+ "p_method"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_ptr_builtin_method",
+ "return_type": "godot_ptr_builtin_method",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const godot_string_name *",
+ "p_method"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_ptr_builtin_method_with_cstring",
+ "return_type": "godot_ptr_builtin_method",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const char *",
+ "p_method"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_builtin_method_argument_count",
+ "return_type": "int",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const godot_string_name *",
+ "p_method"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_builtin_method_argument_count_with_cstring",
+ "return_type": "int",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const char *",
+ "p_method"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_builtin_method_argument_type",
+ "return_type": "godot_variant_type",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const godot_string_name *",
+ "p_method"
+ ],
+ [
+ "int",
+ "p_argument"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_builtin_method_argument_type_with_cstring",
+ "return_type": "godot_variant_type",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const char *",
+ "p_method"
+ ],
+ [
+ "int",
+ "p_argument"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_builtin_method_argument_name",
+ "return_type": "godot_string",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const godot_string_name *",
+ "p_method"
+ ],
+ [
+ "int",
+ "p_argument"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_builtin_method_argument_name_with_cstring",
+ "return_type": "godot_string",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const char *",
+ "p_method"
+ ],
+ [
+ "int",
+ "p_argument"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_has_builtin_method_return_value",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const godot_string_name *",
+ "p_method"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_has_builtin_method_return_value_with_cstring",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const char *",
+ "p_method"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_builtin_method_return_type",
+ "return_type": "godot_variant_type",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const godot_string_name *",
+ "p_method"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_builtin_method_return_type_with_cstring",
+ "return_type": "godot_variant_type",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const char *",
+ "p_method"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_is_builtin_method_const",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const godot_string_name *",
+ "p_method"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_is_builtin_method_const_with_cstring",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const char *",
+ "p_method"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_is_builtin_method_vararg",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const godot_string_name *",
+ "p_method"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_is_builtin_method_vararg_with_cstring",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const char *",
+ "p_method"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_builtin_method_count",
+ "return_type": "int",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_builtin_method_list",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "godot_string_name *",
+ "r_list"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_constructor_count",
+ "return_type": "int",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_validated_constructor",
+ "return_type": "godot_validated_constructor",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "int",
+ "p_constructor"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_ptr_constructor",
+ "return_type": "godot_ptr_constructor",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "int",
+ "p_constructor"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_constructor_argument_count",
+ "return_type": "int",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "int",
+ "p_constructor"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_constructor_argument_type",
+ "return_type": "godot_variant_type",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "int",
+ "p_constructor"
+ ],
+ [
+ "int",
+ "p_argument"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_constructor_argument_name",
+ "return_type": "godot_string",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "int",
+ "p_constructor"
+ ],
+ [
+ "int",
+ "p_argument"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_construct",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "godot_variant *",
+ "p_base"
+ ],
+ [
+ "const godot_variant **",
+ "p_args"
+ ],
+ [
+ "int",
+ "p_argument_count"
+ ],
+ [
+ "godot_variant_call_error *",
+ "r_error"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_member_type",
+ "return_type": "godot_variant_type",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const godot_string_name *",
+ "p_member"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_member_type_with_cstring",
+ "return_type": "godot_variant_type",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const char *",
+ "p_member"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_member_count",
+ "return_type": "int",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_member_list",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "godot_string_name *",
+ "r_list"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_validated_setter",
+ "return_type": "godot_validated_setter",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const godot_string_name *",
+ "p_member"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_validated_setter_with_cstring",
+ "return_type": "godot_validated_setter",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const char *",
+ "p_member"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_validated_getter",
+ "return_type": "godot_validated_getter",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const godot_string_name *",
+ "p_member"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_validated_getter_with_cstring",
+ "return_type": "godot_validated_getter",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const char *",
+ "p_member"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_ptr_setter",
+ "return_type": "godot_ptr_setter",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const godot_string_name *",
+ "p_member"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_ptr_setter_with_cstring",
+ "return_type": "godot_ptr_setter",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const char *",
+ "p_member"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_ptr_getter",
+ "return_type": "godot_ptr_getter",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const godot_string_name *",
+ "p_member"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_ptr_getter_with_cstring",
+ "return_type": "godot_ptr_getter",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const char *",
+ "p_member"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_has_indexing",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_indexed_element_type",
+ "return_type": "godot_variant_type",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_validated_indexed_setter",
+ "return_type": "godot_validated_indexed_setter",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_validated_indexed_getter",
+ "return_type": "godot_validated_indexed_getter",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_ptr_indexed_setter",
+ "return_type": "godot_ptr_indexed_setter",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_ptr_indexed_getter",
+ "return_type": "godot_ptr_indexed_getter",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_indexed_size",
+ "return_type": "uint64_t",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_is_keyed",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_validated_keyed_setter",
+ "return_type": "godot_validated_keyed_setter",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_validated_keyed_getter",
+ "return_type": "godot_validated_keyed_getter",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_validated_keyed_checker",
+ "return_type": "godot_validated_keyed_checker",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_ptr_keyed_setter",
+ "return_type": "godot_ptr_keyed_setter",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_ptr_keyed_getter",
+ "return_type": "godot_ptr_keyed_getter",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_ptr_keyed_checker",
+ "return_type": "godot_ptr_keyed_checker",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_constants_count",
+ "return_type": "int",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_constants_list",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "godot_string_name *",
+ "r_list"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_has_constant",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const godot_string_name *",
+ "p_constant"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_has_constant_with_cstring",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const char *",
+ "p_constant"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_constant_value",
+ "return_type": "godot_variant",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const godot_string_name *",
+ "p_constant"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_constant_value_with_cstring",
+ "return_type": "godot_variant",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const char *",
+ "p_constant"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_has_utility_function",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "const godot_string_name *",
+ "p_function"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_has_utility_function_with_cstring",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "const char *",
+ "p_function"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_call_utility_function",
+ "return_type": "void",
+ "arguments": [
+ [
+ "const godot_string_name *",
+ "p_function"
+ ],
+ [
+ "godot_variant *",
+ "r_ret"
+ ],
+ [
+ "const godot_variant **",
+ "p_args"
+ ],
+ [
+ "int",
+ "p_argument_count"
+ ],
+ [
+ "godot_variant_call_error *",
+ "r_error"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_call_utility_function_with_cstring",
+ "return_type": "void",
+ "arguments": [
+ [
+ "const char *",
+ "p_function"
+ ],
+ [
+ "godot_variant *",
+ "r_ret"
+ ],
+ [
+ "const godot_variant **",
+ "p_args"
+ ],
+ [
+ "int",
+ "p_argument_count"
+ ],
+ [
+ "godot_variant_call_error *",
+ "r_error"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_utility_function_type",
+ "return_type": "godot_variant_utility_function_type",
+ "arguments": [
+ [
+ "const godot_string_name *",
+ "p_function"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_utility_function_type_with_cstring",
+ "return_type": "godot_variant_utility_function_type",
+ "arguments": [
+ [
+ "const char *",
+ "p_function"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_utility_function_argument_count",
+ "return_type": "int",
+ "arguments": [
+ [
+ "const godot_string_name *",
+ "p_function"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_utility_function_argument_count_with_cstring",
+ "return_type": "int",
+ "arguments": [
+ [
+ "const char *",
+ "p_function"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_utility_function_argument_type",
+ "return_type": "godot_variant_type",
+ "arguments": [
+ [
+ "const godot_string_name *",
+ "p_function"
+ ],
+ [
+ "int",
+ "p_argument"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_utility_function_argument_type_with_cstring",
+ "return_type": "godot_variant_type",
+ "arguments": [
+ [
+ "const char *",
+ "p_function"
+ ],
+ [
+ "int",
+ "p_argument"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_utility_function_argument_name",
+ "return_type": "godot_string",
+ "arguments": [
+ [
+ "const godot_string_name *",
+ "p_function"
+ ],
+ [
+ "int",
+ "p_argument"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_utility_function_argument_name_with_cstring",
+ "return_type": "godot_string",
+ "arguments": [
+ [
+ "const char *",
+ "p_function"
+ ],
+ [
+ "int",
+ "p_argument"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_has_utility_function_return_value",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "const godot_string_name *",
+ "p_function"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_has_utility_function_return_value_with_cstring",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "const char *",
+ "p_function"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_utility_function_return_type",
+ "return_type": "godot_variant_type",
+ "arguments": [
+ [
+ "const godot_string_name *",
+ "p_function"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_utility_function_return_type_with_cstring",
+ "return_type": "godot_variant_type",
+ "arguments": [
+ [
+ "const char *",
+ "p_function"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_is_utility_function_vararg",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "const godot_string_name *",
+ "p_function"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_is_utility_function_vararg_with_cstring",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "const char *",
+ "p_function"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_utility_function_count",
+ "return_type": "int",
+ "arguments": []
+ },
+ {
+ "name": "godot_variant_get_utility_function_list",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_string_name *",
+ "r_functions"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_type",
+ "return_type": "godot_variant_type",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_has_method",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ],
+ [
+ "const godot_string_name *",
+ "p_method"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_has_member",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const godot_string_name *",
+ "p_member"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_has_key",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ],
+ [
+ "const godot_variant *",
+ "p_key"
+ ],
+ [
+ "bool *",
+ "r_valid"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_type_name",
+ "return_type": "godot_string",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_can_convert",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_from"
+ ],
+ [
+ "godot_variant_type",
+ "p_to"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_can_convert_strict",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_from"
+ ],
+ [
+ "godot_variant_type",
+ "p_to"
+ ]
+ ]
+ },
+ {
+ "name": "godot_aabb_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_aabb *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_array_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_array_destroy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_basis_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_basis *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_callable_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_callable *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_callable_destroy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_callable *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_color_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_color *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_dictionary_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_dictionary *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_dictionary_destroy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_dictionary *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_node_path_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_node_path *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_node_path_destroy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_node_path *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_byte_array_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_byte_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_byte_array_destroy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_byte_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_int32_array_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_int32_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_int32_array_destroy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_int32_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_int64_array_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_int64_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_int64_array_destroy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_int64_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_float32_array_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_float32_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_float32_array_destroy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_float32_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_float64_array_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_float64_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_float64_array_destroy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_float64_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_string_array_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_string_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_string_array_destroy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_string_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_vector2_array_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_vector2_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_vector2_array_destroy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_vector2_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_vector2i_array_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_vector2i_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_vector2i_array_destroy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_vector2i_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_vector3_array_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_vector3_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_vector3_array_destroy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_vector3_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_color_array_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_color_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_color_array_destroy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_color_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_plane_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_plane *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_quat_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_quat *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_rect2_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_rect2 *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_rect2i_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_rect2i *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_rid_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_rid *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_signal_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_signal *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_signal_destroy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_signal *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_string *",
+ "r_dest"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_string *",
+ "r_dest"
+ ],
+ [
+ "const godot_string *",
+ "p_src"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_destroy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_string *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_new_with_latin1_chars",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_string *",
+ "r_dest"
+ ],
+ [
+ "const char *",
+ "p_contents"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_new_with_utf8_chars",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_string *",
+ "r_dest"
+ ],
+ [
+ "const char *",
+ "p_contents"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_new_with_utf16_chars",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_string *",
+ "r_dest"
+ ],
+ [
+ "const char16_t *",
+ "p_contents"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_new_with_utf32_chars",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_string *",
+ "r_dest"
+ ],
+ [
+ "const char32_t *",
+ "p_contents"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_new_with_wide_chars",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_string *",
+ "r_dest"
+ ],
+ [
+ "const wchar_t *",
+ "p_contents"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_new_with_latin1_chars_and_len",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_string *",
+ "r_dest"
+ ],
+ [
+ "const char *",
+ "p_contents"
+ ],
+ [
+ "const int",
+ "p_size"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_new_with_utf8_chars_and_len",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_string *",
+ "r_dest"
+ ],
+ [
+ "const char *",
+ "p_contents"
+ ],
+ [
+ "const int",
+ "p_size"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_new_with_utf16_chars_and_len",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_string *",
+ "r_dest"
+ ],
+ [
+ "const char16_t *",
+ "p_contents"
+ ],
+ [
+ "const int",
+ "p_size"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_new_with_utf32_chars_and_len",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_string *",
+ "r_dest"
+ ],
+ [
+ "const char32_t *",
+ "p_contents"
+ ],
+ [
+ "const int",
+ "p_size"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_new_with_wide_chars_and_len",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_string *",
+ "r_dest"
+ ],
+ [
+ "const wchar_t *",
+ "p_contents"
+ ],
+ [
+ "const int",
+ "p_size"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_name_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_string_name *",
+ "r_dest"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_name_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_string_name *",
+ "r_dest"
+ ],
+ [
+ "const godot_string_name *",
+ "p_src"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_name_destroy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_string_name *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_name_new_with_latin1_chars",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_string_name *",
+ "r_dest"
+ ],
+ [
+ "const char *",
+ "p_contents"
+ ]
+ ]
+ },
+ {
+ "name": "godot_transform_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_transform *",
+ "r_dest"
+ ]
+ ]
+ },
+ {
+ "name": "godot_transform2d_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_transform2d *",
+ "r_dest"
+ ]
+ ]
+ },
+ {
+ "name": "godot_vector2_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_vector2 *",
+ "r_dest"
+ ]
+ ]
+ },
+ {
+ "name": "godot_vector2i_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_vector2i *",
+ "r_dest"
+ ]
+ ]
+ },
+ {
+ "name": "godot_vector3_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_vector3 *",
+ "r_dest"
+ ]
+ ]
+ },
+ {
+ "name": "godot_vector3i_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_vector3i *",
+ "r_dest"
+ ]
+ ]
+ }
+ ]
+ },
+ "extensions": [
+ {
+ "name": "nativescript",
+ "type": "NATIVESCRIPT",
+ "version": {
+ "major": 4,
+ "minor": 0
+ },
+ "next": null,
+ "api": [
+ {
+ "name": "godot_nativescript_register_class",
+ "return_type": "void",
+ "arguments": [
+ [
+ "void *",
+ "p_gdnative_handle"
+ ],
+ [
+ "const char *",
+ "p_name"
+ ],
+ [
+ "const char *",
+ "p_base"
+ ],
+ [
+ "godot_nativescript_instance_create_func",
+ "p_create_func"
+ ],
+ [
+ "godot_nativescript_instance_destroy_func",
+ "p_destroy_func"
+ ]
+ ]
+ },
+ {
+ "name": "godot_nativescript_register_tool_class",
+ "return_type": "void",
+ "arguments": [
+ [
+ "void *",
+ "p_gdnative_handle"
+ ],
+ [
+ "const char *",
+ "p_name"
+ ],
+ [
+ "const char *",
+ "p_base"
+ ],
+ [
+ "godot_nativescript_instance_create_func",
+ "p_create_func"
+ ],
+ [
+ "godot_nativescript_instance_destroy_func",
+ "p_destroy_func"
+ ]
+ ]
+ },
+ {
+ "name": "godot_nativescript_register_method",
+ "return_type": "void",
+ "arguments": [
+ [
+ "void *",
+ "p_gdnative_handle"
+ ],
+ [
+ "const char *",
+ "p_name"
+ ],
+ [
+ "const char *",
+ "p_function_name"
+ ],
+ [
+ "godot_nativescript_method_attributes",
+ "p_attr"
+ ],
+ [
+ "godot_nativescript_instance_method",
+ "p_method"
+ ]
+ ]
+ },
+ {
+ "name": "godot_nativescript_set_method_argument_information",
+ "return_type": "void",
+ "arguments": [
+ [
+ "void *",
+ "p_gdnative_handle"
+ ],
+ [
+ "const char *",
+ "p_name"
+ ],
+ [
+ "const char *",
+ "p_function_name"
+ ],
+ [
+ "int",
+ "p_num_args"
+ ],
+ [
+ "const godot_nativescript_method_argument *",
+ "p_args"
+ ]
+ ]
+ },
+ {
+ "name": "godot_nativescript_register_property",
+ "return_type": "void",
+ "arguments": [
+ [
+ "void *",
+ "p_gdnative_handle"
+ ],
+ [
+ "const char *",
+ "p_name"
+ ],
+ [
+ "const char *",
+ "p_path"
+ ],
+ [
+ "godot_nativescript_property_attributes *",
+ "p_attr"
+ ],
+ [
+ "godot_nativescript_property_set_func",
+ "p_set_func"
+ ],
+ [
+ "godot_nativescript_property_get_func",
+ "p_get_func"
+ ]
+ ]
+ },
+ {
+ "name": "godot_nativescript_register_signal",
+ "return_type": "void",
+ "arguments": [
+ [
+ "void *",
+ "p_gdnative_handle"
+ ],
+ [
+ "const char *",
+ "p_name"
+ ],
+ [
+ "const godot_nativescript_signal *",
+ "p_signal"
+ ]
+ ]
+ },
+ {
+ "name": "godot_nativescript_get_userdata",
+ "return_type": "void *",
+ "arguments": [
+ [
+ "godot_object *",
+ "p_instance"
+ ]
+ ]
+ },
+ {
+ "name": "godot_nativescript_set_class_documentation",
+ "return_type": "void",
+ "arguments": [
+ [
+ "void *",
+ "p_gdnative_handle"
+ ],
+ [
+ "const char *",
+ "p_name"
+ ],
+ [
+ "godot_string",
+ "p_documentation"
+ ]
+ ]
+ },
+ {
+ "name": "godot_nativescript_set_method_documentation",
+ "return_type": "void",
+ "arguments": [
+ [
+ "void *",
+ "p_gdnative_handle"
+ ],
+ [
+ "const char *",
+ "p_name"
+ ],
+ [
+ "const char *",
+ "p_function_name"
+ ],
+ [
+ "godot_string",
+ "p_documentation"
+ ]
+ ]
+ },
+ {
+ "name": "godot_nativescript_set_property_documentation",
+ "return_type": "void",
+ "arguments": [
+ [
+ "void *",
+ "p_gdnative_handle"
+ ],
+ [
+ "const char *",
+ "p_name"
+ ],
+ [
+ "const char *",
+ "p_path"
+ ],
+ [
+ "godot_string",
+ "p_documentation"
+ ]
+ ]
+ },
+ {
+ "name": "godot_nativescript_set_signal_documentation",
+ "return_type": "void",
+ "arguments": [
+ [
+ "void *",
+ "p_gdnative_handle"
+ ],
+ [
+ "const char *",
+ "p_name"
+ ],
+ [
+ "const char *",
+ "p_signal_name"
+ ],
+ [
+ "godot_string",
+ "p_documentation"
+ ]
+ ]
+ },
+ {
+ "name": "godot_nativescript_set_global_type_tag",
+ "return_type": "void",
+ "arguments": [
+ [
+ "int",
+ "p_idx"
+ ],
+ [
+ "const char *",
+ "p_name"
+ ],
+ [
+ "const void *",
+ "p_type_tag"
+ ]
+ ]
+ },
+ {
+ "name": "godot_nativescript_get_global_type_tag",
+ "return_type": "const void *",
+ "arguments": [
+ [
+ "int",
+ "p_idx"
+ ],
+ [
+ "const char *",
+ "p_name"
+ ]
+ ]
+ },
+ {
+ "name": "godot_nativescript_set_type_tag",
+ "return_type": "void",
+ "arguments": [
+ [
+ "void *",
+ "p_gdnative_handle"
+ ],
+ [
+ "const char *",
+ "p_name"
+ ],
+ [
+ "const void *",
+ "p_type_tag"
+ ]
+ ]
+ },
+ {
+ "name": "godot_nativescript_get_type_tag",
+ "return_type": "const void *",
+ "arguments": [
+ [
+ "const godot_object *",
+ "p_object"
+ ]
+ ]
+ },
+ {
+ "name": "godot_nativescript_register_instance_binding_data_functions",
+ "return_type": "int",
+ "arguments": [
+ [
+ "godot_nativescript_instance_binding_functions",
+ "p_binding_functions"
+ ]
+ ]
+ },
+ {
+ "name": "godot_nativescript_unregister_instance_binding_data_functions",
+ "return_type": "void",
+ "arguments": [
+ [
+ "int",
+ "p_idx"
+ ]
+ ]
+ },
+ {
+ "name": "godot_nativescript_get_instance_binding_data",
+ "return_type": "void *",
+ "arguments": [
+ [
+ "int",
+ "p_idx"
+ ],
+ [
+ "godot_object *",
+ "p_object"
+ ]
+ ]
+ },
+ {
+ "name": "godot_nativescript_profiling_add_data",
+ "return_type": "void",
+ "arguments": [
+ [
+ "const char *",
+ "p_signature"
+ ],
+ [
+ "uint64_t",
+ "p_line"
+ ]
+ ]
+ }
+ ]
+ },
+ {
+ "name": "pluginscript",
+ "type": "PLUGINSCRIPT",
+ "version": {
+ "major": 1,
+ "minor": 0
+ },
+ "next": null,
+ "api": [
+ {
+ "name": "godot_pluginscript_register_language",
+ "return_type": "void",
+ "arguments": [
+ [
+ "const godot_pluginscript_language_desc *",
+ "language_desc"
+ ]
+ ]
+ }
+ ]
+ },
+ {
+ "name": "android",
+ "type": "ANDROID",
+ "version": {
+ "major": 1,
+ "minor": 1
+ },
+ "next": null,
+ "api": [
+ {
+ "name": "godot_android_get_env",
+ "return_type": "JNIEnv*",
+ "arguments": []
+ },
+ {
+ "name": "godot_android_get_activity",
+ "return_type": "jobject",
+ "arguments": []
+ },
+ {
+ "name": "godot_android_get_surface",
+ "return_type": "jobject",
+ "arguments": []
+ },
+ {
+ "name": "godot_android_is_activity_resumed",
+ "return_type": "bool",
+ "arguments": []
+ }
+ ]
+ },
+ {
+ "name": "xr",
+ "type": "XR",
+ "version": {
+ "major": 1,
+ "minor": 1
+ },
+ "next": null,
+ "api": [
+ {
+ "name": "godot_xr_register_interface",
+ "return_type": "void",
+ "arguments": [
+ [
+ "const godot_xr_interface_gdnative *",
+ "p_interface"
+ ]
+ ]
+ },
+ {
+ "name": "godot_xr_get_worldscale",
+ "return_type": "godot_float",
+ "arguments": []
+ },
+ {
+ "name": "godot_xr_get_reference_frame",
+ "return_type": "godot_transform",
+ "arguments": []
+ },
+ {
+ "name": "godot_xr_blit",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_int",
+ "p_eye"
+ ],
+ [
+ "godot_rid *",
+ "p_render_target"
+ ],
+ [
+ "godot_rect2 *",
+ "p_screen_rect"
+ ]
+ ]
+ },
+ {
+ "name": "godot_xr_get_texid",
+ "return_type": "godot_int",
+ "arguments": [
+ [
+ "godot_rid *",
+ "p_render_target"
+ ]
+ ]
+ },
+ {
+ "name": "godot_xr_add_controller",
+ "return_type": "godot_int",
+ "arguments": [
+ [
+ "char *",
+ "p_device_name"
+ ],
+ [
+ "godot_int",
+ "p_hand"
+ ],
+ [
+ "godot_bool",
+ "p_tracks_orientation"
+ ],
+ [
+ "godot_bool",
+ "p_tracks_position"
+ ]
+ ]
+ },
+ {
+ "name": "godot_xr_remove_controller",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_int",
+ "p_controller_id"
+ ]
+ ]
+ },
+ {
+ "name": "godot_xr_set_controller_transform",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_int",
+ "p_controller_id"
+ ],
+ [
+ "godot_transform *",
+ "p_transform"
+ ],
+ [
+ "godot_bool",
+ "p_tracks_orientation"
+ ],
+ [
+ "godot_bool",
+ "p_tracks_position"
+ ]
+ ]
+ },
+ {
+ "name": "godot_xr_set_controller_button",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_int",
+ "p_controller_id"
+ ],
+ [
+ "godot_int",
+ "p_button"
+ ],
+ [
+ "godot_bool",
+ "p_is_pressed"
+ ]
+ ]
+ },
+ {
+ "name": "godot_xr_set_controller_axis",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_int",
+ "p_controller_id"
+ ],
+ [
+ "godot_int",
+ "p_exis"
+ ],
+ [
+ "godot_float",
+ "p_value"
+ ],
+ [
+ "godot_bool",
+ "p_can_be_negative"
+ ]
+ ]
+ },
+ {
+ "name": "godot_xr_get_controller_rumble",
+ "return_type": "godot_float",
+ "arguments": [
+ [
+ "godot_int",
+ "p_controller_id"
+ ]
+ ]
+ }
+ ]
+ },
+ {
+ "name": "videodecoder",
+ "type": "VIDEODECODER",
+ "version": {
+ "major": 0,
+ "minor": 1
+ },
+ "next": null,
+ "api": [
+ {
+ "name": "godot_videodecoder_file_read",
+ "return_type": "godot_int",
+ "arguments": [
+ [
+ "void *",
+ "file_ptr"
+ ],
+ [
+ "uint8_t *",
+ "buf"
+ ],
+ [
+ "int",
+ "buf_size"
+ ]
+ ]
+ },
+ {
+ "name": "godot_videodecoder_file_seek",
+ "return_type": "int64_t",
+ "arguments": [
+ [
+ "void *",
+ "file_ptr"
+ ],
+ [
+ "int64_t",
+ "pos"
+ ],
+ [
+ "int",
+ "whence"
+ ]
+ ]
+ },
+ {
+ "name": "godot_videodecoder_register_decoder",
+ "return_type": "void",
+ "arguments": [
+ [
+ "const godot_videodecoder_interface_gdnative *",
+ "p_interface"
+ ]
+ ]
+ }
+ ]
+ },
+ {
+ "name": "net",
+ "type": "NET",
+ "version": {
+ "major": 4,
+ "minor": 0
+ },
+ "next": null,
+ "api": [
+ {
+ "name": "godot_net_bind_stream_peer",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_object *",
+ "p_obj"
+ ],
+ [
+ "const godot_net_stream_peer *",
+ "p_interface"
+ ]
+ ]
+ },
+ {
+ "name": "godot_net_bind_packet_peer",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_object *",
+ "p_obj"
+ ],
+ [
+ "const godot_net_packet_peer *",
+ "p_interface"
+ ]
+ ]
+ },
+ {
+ "name": "godot_net_bind_multiplayer_peer",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_object *",
+ "p_obj"
+ ],
+ [
+ "const godot_net_multiplayer_peer *",
+ "p_interface"
+ ]
+ ]
+ },
+ {
+ "name": "godot_net_set_webrtc_library",
+ "return_type": "godot_error",
+ "arguments": [
+ [
+ "const godot_net_webrtc_library *",
+ "p_library"
+ ]
+ ]
+ },
+ {
+ "name": "godot_net_bind_webrtc_peer_connection",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_object *",
+ "p_obj"
+ ],
+ [
+ "const godot_net_webrtc_peer_connection *",
+ "p_interface"
+ ]
+ ]
+ },
+ {
+ "name": "godot_net_bind_webrtc_data_channel",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_object *",
+ "p_obj"
+ ],
+ [
+ "const godot_net_webrtc_data_channel *",
+ "p_interface"
+ ]
+ ]
+ }
+ ]
+ },
+ {
+ "name": "text",
+ "type": "TEXT",
+ "version": {
+ "major": 1,
+ "minor": 0
+ },
+ "next": null,
+ "api": [
+ {
+ "name": "godot_text_register_interface",
+ "return_type": "void",
+ "arguments": [
+ [
+ "const godot_text_interface_gdnative *",
+ "p_interface"
+ ],
+ [
+ "const godot_string *",
+ "p_name"
+ ],
+ [
+ "uint32_t",
+ "p_features"
+ ]
+ ]
+ },
+ {
+ "name": "godot_glyph_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_glyph *",
+ "r_dest"
+ ]
+ ]
+ },
+ {
+ "name": "godot_glyph_get_range",
+ "return_type": "godot_vector2i",
+ "arguments": [
+ [
+ "const godot_glyph *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_glyph_set_range",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_glyph *",
+ "p_self"
+ ],
+ [
+ "const godot_vector2i *",
+ "p_range"
+ ]
+ ]
+ },
+ {
+ "name": "godot_glyph_get_count",
+ "return_type": "godot_int",
+ "arguments": [
+ [
+ "const godot_glyph *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_glyph_set_count",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_glyph *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_count"
+ ]
+ ]
+ },
+ {
+ "name": "godot_glyph_get_repeat",
+ "return_type": "godot_int",
+ "arguments": [
+ [
+ "const godot_glyph *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_glyph_set_repeat",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_glyph *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_repeat"
+ ]
+ ]
+ },
+ {
+ "name": "godot_glyph_get_flags",
+ "return_type": "godot_int",
+ "arguments": [
+ [
+ "const godot_glyph *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_glyph_set_flags",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_glyph *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_flags"
+ ]
+ ]
+ },
+ {
+ "name": "godot_glyph_get_offset",
+ "return_type": "godot_vector2",
+ "arguments": [
+ [
+ "const godot_glyph *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_glyph_set_offset",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_glyph *",
+ "p_self"
+ ],
+ [
+ "const godot_vector2 *",
+ "p_offset"
+ ]
+ ]
+ },
+ {
+ "name": "godot_glyph_get_advance",
+ "return_type": "godot_float",
+ "arguments": [
+ [
+ "const godot_glyph *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_glyph_set_advance",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_glyph *",
+ "p_self"
+ ],
+ [
+ "godot_float",
+ "p_advance"
+ ]
+ ]
+ },
+ {
+ "name": "godot_glyph_get_font",
+ "return_type": "godot_rid",
+ "arguments": [
+ [
+ "const godot_glyph *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_glyph_set_font",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_glyph *",
+ "p_self"
+ ],
+ [
+ "godot_rid *",
+ "p_font"
+ ]
+ ]
+ },
+ {
+ "name": "godot_glyph_get_font_size",
+ "return_type": "godot_int",
+ "arguments": [
+ [
+ "const godot_glyph *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_glyph_set_font_size",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_glyph *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_size"
+ ]
+ ]
+ },
+ {
+ "name": "godot_glyph_get_index",
+ "return_type": "godot_int",
+ "arguments": [
+ [
+ "const godot_glyph *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_glyph_set_index",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_glyph *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_glyph_array_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_glyph_array *",
+ "r_dest"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_glyph_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_glyph_array *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_glyph_array *",
+ "p_src"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_glyph_array_is_empty",
+ "return_type": "godot_bool",
+ "arguments": [
+ [
+ "const godot_packed_glyph_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_glyph_array_append",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_glyph_array *",
+ "p_self"
+ ],
+ [
+ "const godot_glyph *",
+ "p_data"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_glyph_array_append_array",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_glyph_array *",
+ "p_self"
+ ],
+ [
+ "const godot_packed_glyph_array *",
+ "p_array"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_glyph_array_insert",
+ "return_type": "godot_error",
+ "arguments": [
+ [
+ "godot_packed_glyph_array *",
+ "p_self"
+ ],
+ [
+ "const godot_int",
+ "p_idx"
+ ],
+ [
+ "const godot_glyph *",
+ "p_data"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_glyph_array_has",
+ "return_type": "godot_bool",
+ "arguments": [
+ [
+ "godot_packed_glyph_array *",
+ "p_self"
+ ],
+ [
+ "const godot_glyph *",
+ "p_value"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_glyph_array_sort",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_glyph_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_glyph_array_invert",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_glyph_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_glyph_array_push_back",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_glyph_array *",
+ "p_self"
+ ],
+ [
+ "const godot_glyph *",
+ "p_data"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_glyph_array_remove",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_glyph_array *",
+ "p_self"
+ ],
+ [
+ "const godot_int",
+ "p_idx"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_glyph_array_resize",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_glyph_array *",
+ "p_self"
+ ],
+ [
+ "const godot_int",
+ "p_size"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_glyph_array_ptr",
+ "return_type": "const godot_glyph *",
+ "arguments": [
+ [
+ "const godot_packed_glyph_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_glyph_array_ptrw",
+ "return_type": "godot_glyph *",
+ "arguments": [
+ [
+ "godot_packed_glyph_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_glyph_array_set",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_glyph_array *",
+ "p_self"
+ ],
+ [
+ "const godot_int",
+ "p_idx"
+ ],
+ [
+ "const godot_glyph *",
+ "p_data"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_glyph_array_get",
+ "return_type": "godot_glyph",
+ "arguments": [
+ [
+ "const godot_packed_glyph_array *",
+ "p_self"
+ ],
+ [
+ "const godot_int",
+ "p_idx"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_glyph_array_size",
+ "return_type": "godot_int",
+ "arguments": [
+ [
+ "const godot_packed_glyph_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_glyph_array_destroy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_glyph_array *",
+ "p_self"
+ ]
+ ]
+ }
+ ]
+ }
+ ]
}
diff --git a/modules/gdnative/gdnative_builders.py b/modules/gdnative/gdnative_builders.py
index 28e4957b2f..d03298d7a9 100644
--- a/modules/gdnative/gdnative_builders.py
+++ b/modules/gdnative/gdnative_builders.py
@@ -24,6 +24,7 @@ def _build_gdnative_api_struct_header(api):
"#include <net/godot_net.h>",
"#include <pluginscript/godot_pluginscript.h>",
"#include <videodecoder/godot_videodecoder.h>",
+ "#include <text/godot_text.h>",
"",
"#ifdef __cplusplus",
'extern "C" {',
diff --git a/modules/gdnative/gdnative_library_editor_plugin.cpp b/modules/gdnative/gdnative_library_editor_plugin.cpp
index f0f095ddf5..d3cca5b1be 100644
--- a/modules/gdnative/gdnative_library_editor_plugin.cpp
+++ b/modules/gdnative/gdnative_library_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -65,7 +65,7 @@ void GDNativeLibraryEditor::_update_tree() {
continue;
}
Map<String, NativePlatformConfig>::Element *E = platforms.find(filter_list->get_item_metadata(i));
- if (!text.empty()) {
+ if (!text.is_empty()) {
text += ", ";
}
text += E->get().name;
@@ -91,7 +91,7 @@ void GDNativeLibraryEditor::_update_tree() {
bit->add_button(1, get_theme_icon("Folder", "EditorIcons"), BUTTON_SELECT_LIBRARY, false, TTR("Select the dynamic library for this entry"));
String file = entry_configs[target].library;
- if (!file.empty()) {
+ if (!file.is_empty()) {
bit->add_button(1, get_theme_icon("Clear", "EditorIcons"), BUTTON_CLEAR_LIBRARY, false, TTR("Clear"));
}
bit->set_text(1, file);
@@ -195,7 +195,7 @@ void GDNativeLibraryEditor::_on_item_activated() {
void GDNativeLibraryEditor::_on_create_new_entry() {
String platform = new_architecture_dialog->get_meta("platform");
String entry = new_architecture_input->get_text().strip_edges();
- if (!entry.empty()) {
+ if (!entry.is_empty()) {
platforms[platform].entries.push_back(entry);
_update_tree();
}
@@ -248,7 +248,7 @@ void GDNativeLibraryEditor::_translate_to_config_file() {
for (Map<String, NativePlatformConfig>::Element *E = platforms.front(); E; E = E->next()) {
for (List<String>::Element *it = E->value().entries.front(); it; it = it->next()) {
String target = E->key() + "." + it->get();
- if (entry_configs[target].library.empty() && entry_configs[target].dependencies.empty()) {
+ if (entry_configs[target].library.is_empty() && entry_configs[target].dependencies.is_empty()) {
continue;
}
@@ -308,11 +308,11 @@ GDNativeLibraryEditor::GDNativeLibraryEditor() {
platform_android.library_extension = "*.so";
platforms["Android"] = platform_android;
- // TODO: Javascript platform is not supported yet
- // NativePlatformConfig platform_html5;
- // platform_html5.name = "HTML5";
- // platform_html5.library_extension = "*.wasm";
- // platforms["Javascript"] = platform_html5;
+ NativePlatformConfig platform_html5;
+ platform_html5.name = "HTML5";
+ platform_html5.entries.push_back("wasm32");
+ platform_html5.library_extension = "*.wasm";
+ platforms["HTML5"] = platform_html5;
NativePlatformConfig platform_ios;
platform_ios.name = "iOS";
@@ -327,7 +327,7 @@ GDNativeLibraryEditor::GDNativeLibraryEditor() {
VBoxContainer *container = memnew(VBoxContainer);
add_child(container);
- container->set_anchors_and_margins_preset(PRESET_WIDE);
+ container->set_anchors_and_offsets_preset(PRESET_WIDE);
HBoxContainer *hbox = memnew(HBoxContainer);
container->add_child(hbox);
@@ -381,8 +381,8 @@ GDNativeLibraryEditor::GDNativeLibraryEditor() {
new_architecture_input = memnew(LineEdit);
new_architecture_dialog->add_child(new_architecture_input);
// new_architecture_dialog->set_custom_minimum_size(Vector2(300, 80) * EDSCALE);
- new_architecture_input->set_anchors_and_margins_preset(PRESET_HCENTER_WIDE, PRESET_MODE_MINSIZE, 5 * EDSCALE);
- new_architecture_dialog->get_ok()->connect("pressed", callable_mp(this, &GDNativeLibraryEditor::_on_create_new_entry));
+ new_architecture_input->set_anchors_and_offsets_preset(PRESET_HCENTER_WIDE, PRESET_MODE_MINSIZE, 5 * EDSCALE);
+ new_architecture_dialog->get_ok_button()->connect("pressed", callable_mp(this, &GDNativeLibraryEditor::_on_create_new_entry));
}
void GDNativeLibraryEditorPlugin::edit(Object *p_node) {
diff --git a/modules/gdnative/gdnative_library_editor_plugin.h b/modules/gdnative/gdnative_library_editor_plugin.h
index 180ab7707c..184db3d817 100644
--- a/modules/gdnative/gdnative_library_editor_plugin.h
+++ b/modules/gdnative/gdnative_library_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnative/gdnative_library_singleton_editor.cpp b/modules/gdnative/gdnative_library_singleton_editor.cpp
index 409b6cbffe..f1b4a9a81b 100644
--- a/modules/gdnative/gdnative_library_singleton_editor.cpp
+++ b/modules/gdnative/gdnative_library_singleton_editor.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnative/gdnative_library_singleton_editor.h b/modules/gdnative/gdnative_library_singleton_editor.h
index 1a213d8094..5bb823d920 100644
--- a/modules/gdnative/gdnative_library_singleton_editor.h
+++ b/modules/gdnative/gdnative_library_singleton_editor.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnative/icons/GDNativeLibrary.svg b/modules/gdnative/icons/GDNativeLibrary.svg
index b494c7af6e..0ddfd4e6f2 100644
--- a/modules/gdnative/icons/GDNativeLibrary.svg
+++ b/modules/gdnative/icons/GDNativeLibrary.svg
@@ -1,5 +1 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1036.4)">
-<path transform="translate(0 1036.4)" d="m7 1l-0.56445 2.2578a5 5 0 0 0 -0.68945 0.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941a5 5 0 0 0 -0.28516 0.68555l-2.2539 0.5625v2l2.2578 0.56445a5 5 0 0 0 0.2793 0.6875l-1.1934 1.9902 1.4141 1.4141 1.9941-1.1953a5 5 0 0 0 0.68555 0.28516l0.5625 2.2539v-5.2695a2 2 0 0 1 -1 -1.7305 2 2 0 0 1 1 -1.7285v-0.27148h1 4.5762a5 5 0 0 0 -0.11328 -0.25195l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953a5 5 0 0 0 -0.68555 -0.28516l-0.5625-2.2539h-2zm2 7v1 5 1h5c0.55228 0 1-0.4477 1-1v-5c0-0.5523-0.44772-1-1-1v4l-1-1-1 1v-4h-3z" fill="#e0e0e0"/>
-</g>
-</svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1-.56445 2.2578a5 5 0 0 0 -.68945.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941a5 5 0 0 0 -.28516.68555l-2.2539.5625v2l2.2578.56445a5 5 0 0 0 .2793.6875l-1.1934 1.9902 1.4141 1.4141 1.9941-1.1953a5 5 0 0 0 .68555.28516l.5625 2.2539v-5.2695a2 2 0 0 1 -1-1.7305 2 2 0 0 1 1-1.7285v-.27148h1 4.5762a5 5 0 0 0 -.11328-.25195l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953a5 5 0 0 0 -.68555-.28516l-.5625-2.2539h-2zm2 7v1 5 1h5c.55228 0 1-.4477 1-1v-5c0-.5523-.44772-1-1-1v4l-1-1-1 1v-4z" fill="#e0e0e0"/></svg>
diff --git a/modules/gdnative/icons/NativeScript.svg b/modules/gdnative/icons/NativeScript.svg
index fb9e135627..2224b36b29 100644
--- a/modules/gdnative/icons/NativeScript.svg
+++ b/modules/gdnative/icons/NativeScript.svg
@@ -1,5 +1 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1036.4)">
-<path transform="translate(0 1036.4)" d="m7 1l-0.56445 2.2578a5 5 0 0 0 -0.68945 0.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941a5 5 0 0 0 -0.28516 0.68555l-2.2539 0.5625h3v1 1h2v-0.95117a2 2 0 0 1 0 -0.048828 2 2 0 0 1 2 -2 2 2 0 0 1 2 2v1h5v-2l-2.2578-0.56445a5 5 0 0 0 -0.2793 -0.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953a5 5 0 0 0 -0.68555 -0.28516l-0.5625-2.2539h-2zm-6 7v4 4h2a3 3 0 0 0 3 -3 3 3 0 0 0 -3 -3v-2h-2zm6 0v2h2v-2h-2zm3 2v6h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3 -3h-2zm-7 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1v-2zm4 0v4h2v-4h-2z" fill="#e0e0e0"/>
-</g>
-</svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1-.56445 2.2578a5 5 0 0 0 -.68945.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941a5 5 0 0 0 -.28516.68555l-2.2539.5625h3v1 1h2v-.95117a2 2 0 0 1 0-.048828 2 2 0 0 1 2-2 2 2 0 0 1 2 2v1h5v-2l-2.2578-.56445a5 5 0 0 0 -.2793-.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953a5 5 0 0 0 -.68555-.28516l-.5625-2.2539h-2zm-6 7v4 4h2a3 3 0 0 0 3-3 3 3 0 0 0 -3-3v-2zm6 0v2h2v-2zm3 2v6h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3-3zm-7 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1zm4 0v4h2v-4z" fill="#e0e0e0"/></svg>
diff --git a/modules/gdnative/include/android/godot_android.h b/modules/gdnative/include/android/godot_android.h
index 45d4eaff37..867ef9e03a 100644
--- a/modules/gdnative/include/android/godot_android.h
+++ b/modules/gdnative/include/android/godot_android.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnative/include/gdnative/aabb.h b/modules/gdnative/include/gdnative/aabb.h
index c776297944..be0235221f 100644
--- a/modules/gdnative/include/gdnative/aabb.h
+++ b/modules/gdnative/include/gdnative/aabb.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,9 +35,9 @@
extern "C" {
#endif
-#include <stdint.h>
+#include <gdnative/math_defs.h>
-#define GODOT_AABB_SIZE 24
+#define GODOT_AABB_SIZE (sizeof(godot_real_t) * 6)
#ifndef GODOT_CORE_API_GODOT_AABB_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_AABB_TYPE_DEFINED
@@ -46,72 +46,9 @@ typedef struct {
} godot_aabb;
#endif
-// reduce extern "C" nesting for VS2013
-#ifdef __cplusplus
-}
-#endif
-
#include <gdnative/gdnative.h>
-#include <gdnative/plane.h>
-#include <gdnative/vector3.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void GDAPI godot_aabb_new(godot_aabb *r_dest, const godot_vector3 *p_pos, const godot_vector3 *p_size);
-
-godot_vector3 GDAPI godot_aabb_get_position(const godot_aabb *p_self);
-void GDAPI godot_aabb_set_position(const godot_aabb *p_self, const godot_vector3 *p_v);
-
-godot_vector3 GDAPI godot_aabb_get_size(const godot_aabb *p_self);
-void GDAPI godot_aabb_set_size(const godot_aabb *p_self, const godot_vector3 *p_v);
-
-godot_string GDAPI godot_aabb_as_string(const godot_aabb *p_self);
-
-godot_aabb GDAPI godot_aabb_abs(const godot_aabb *p_self);
-
-godot_real GDAPI godot_aabb_get_area(const godot_aabb *p_self);
-
-godot_bool GDAPI godot_aabb_has_no_area(const godot_aabb *p_self);
-
-godot_bool GDAPI godot_aabb_has_no_surface(const godot_aabb *p_self);
-
-godot_bool GDAPI godot_aabb_intersects(const godot_aabb *p_self, const godot_aabb *p_with);
-
-godot_bool GDAPI godot_aabb_encloses(const godot_aabb *p_self, const godot_aabb *p_with);
-
-godot_aabb GDAPI godot_aabb_merge(const godot_aabb *p_self, const godot_aabb *p_with);
-
-godot_aabb GDAPI godot_aabb_intersection(const godot_aabb *p_self, const godot_aabb *p_with);
-
-godot_bool GDAPI godot_aabb_intersects_plane(const godot_aabb *p_self, const godot_plane *p_plane);
-
-godot_bool GDAPI godot_aabb_intersects_segment(const godot_aabb *p_self, const godot_vector3 *p_from, const godot_vector3 *p_to);
-
-godot_bool GDAPI godot_aabb_has_point(const godot_aabb *p_self, const godot_vector3 *p_point);
-
-godot_vector3 GDAPI godot_aabb_get_support(const godot_aabb *p_self, const godot_vector3 *p_dir);
-
-godot_vector3 GDAPI godot_aabb_get_longest_axis(const godot_aabb *p_self);
-
-godot_int GDAPI godot_aabb_get_longest_axis_index(const godot_aabb *p_self);
-
-godot_real GDAPI godot_aabb_get_longest_axis_size(const godot_aabb *p_self);
-
-godot_vector3 GDAPI godot_aabb_get_shortest_axis(const godot_aabb *p_self);
-
-godot_int GDAPI godot_aabb_get_shortest_axis_index(const godot_aabb *p_self);
-
-godot_real GDAPI godot_aabb_get_shortest_axis_size(const godot_aabb *p_self);
-
-godot_aabb GDAPI godot_aabb_expand(const godot_aabb *p_self, const godot_vector3 *p_to_point);
-
-godot_aabb GDAPI godot_aabb_grow(const godot_aabb *p_self, const godot_real p_by);
-
-godot_vector3 GDAPI godot_aabb_get_endpoint(const godot_aabb *p_self, const godot_int p_idx);
-godot_bool GDAPI godot_aabb_operator_equal(const godot_aabb *p_self, const godot_aabb *p_b);
+void GDAPI godot_aabb_new(godot_aabb *p_self);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/array.h b/modules/gdnative/include/gdnative/array.h
index 4db685873f..d734d49232 100644
--- a/modules/gdnative/include/gdnative/array.h
+++ b/modules/gdnative/include/gdnative/array.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -46,102 +46,11 @@ typedef struct {
} godot_array;
#endif
-// reduce extern "C" nesting for VS2013
-#ifdef __cplusplus
-}
-#endif
-
-#include <gdnative/packed_arrays.h>
-#include <gdnative/variant.h>
-
#include <gdnative/gdnative.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void GDAPI godot_array_new(godot_array *r_dest);
-void GDAPI godot_array_new_copy(godot_array *r_dest, const godot_array *p_src);
-void GDAPI godot_array_new_packed_color_array(godot_array *r_dest, const godot_packed_color_array *p_pca);
-void GDAPI godot_array_new_packed_vector3_array(godot_array *r_dest, const godot_packed_vector3_array *p_pv3a);
-void GDAPI godot_array_new_packed_vector2_array(godot_array *r_dest, const godot_packed_vector2_array *p_pv2a);
-void GDAPI godot_array_new_packed_string_array(godot_array *r_dest, const godot_packed_string_array *p_psa);
-void GDAPI godot_array_new_packed_float32_array(godot_array *r_dest, const godot_packed_float32_array *p_pra);
-void GDAPI godot_array_new_packed_float64_array(godot_array *r_dest, const godot_packed_float64_array *p_pra);
-void GDAPI godot_array_new_packed_int32_array(godot_array *r_dest, const godot_packed_int32_array *p_pia);
-void GDAPI godot_array_new_packed_int64_array(godot_array *r_dest, const godot_packed_int64_array *p_pia);
-void GDAPI godot_array_new_packed_byte_array(godot_array *r_dest, const godot_packed_byte_array *p_pba);
-
-void GDAPI godot_array_set(godot_array *p_self, const godot_int p_idx, const godot_variant *p_value);
-
-godot_variant GDAPI godot_array_get(const godot_array *p_self, const godot_int p_idx);
-
-godot_variant GDAPI *godot_array_operator_index(godot_array *p_self, const godot_int p_idx);
-
-const godot_variant GDAPI *godot_array_operator_index_const(const godot_array *p_self, const godot_int p_idx);
-
-void GDAPI godot_array_append(godot_array *p_self, const godot_variant *p_value);
-
-void GDAPI godot_array_clear(godot_array *p_self);
-
-godot_int GDAPI godot_array_count(const godot_array *p_self, const godot_variant *p_value);
-
-godot_bool GDAPI godot_array_empty(const godot_array *p_self);
-
-void GDAPI godot_array_erase(godot_array *p_self, const godot_variant *p_value);
-
-godot_variant GDAPI godot_array_front(const godot_array *p_self);
-
-godot_variant GDAPI godot_array_back(const godot_array *p_self);
-
-godot_int GDAPI godot_array_find(const godot_array *p_self, const godot_variant *p_what, const godot_int p_from);
-
-godot_int GDAPI godot_array_find_last(const godot_array *p_self, const godot_variant *p_what);
-
-godot_bool GDAPI godot_array_has(const godot_array *p_self, const godot_variant *p_value);
-
-godot_int GDAPI godot_array_hash(const godot_array *p_self);
-
-void GDAPI godot_array_insert(godot_array *p_self, const godot_int p_pos, const godot_variant *p_value);
-
-void GDAPI godot_array_invert(godot_array *p_self);
-
-godot_variant GDAPI godot_array_pop_back(godot_array *p_self);
-
-godot_variant GDAPI godot_array_pop_front(godot_array *p_self);
-
-void GDAPI godot_array_push_back(godot_array *p_self, const godot_variant *p_value);
-
-void GDAPI godot_array_push_front(godot_array *p_self, const godot_variant *p_value);
-
-void GDAPI godot_array_remove(godot_array *p_self, const godot_int p_idx);
-
-void GDAPI godot_array_resize(godot_array *p_self, const godot_int p_size);
-
-godot_int GDAPI godot_array_rfind(const godot_array *p_self, const godot_variant *p_what, const godot_int p_from);
-
-godot_int GDAPI godot_array_size(const godot_array *p_self);
-
-void GDAPI godot_array_sort(godot_array *p_self);
-
-void GDAPI godot_array_sort_custom(godot_array *p_self, godot_object *p_obj, const godot_string *p_func);
-
-godot_int GDAPI godot_array_bsearch(godot_array *p_self, const godot_variant *p_value, const godot_bool p_before);
-
-godot_int GDAPI godot_array_bsearch_custom(godot_array *p_self, const godot_variant *p_value, godot_object *p_obj, const godot_string *p_func, const godot_bool p_before);
-
+void GDAPI godot_array_new(godot_array *p_self);
void GDAPI godot_array_destroy(godot_array *p_self);
-godot_array GDAPI godot_array_duplicate(const godot_array *p_self, const godot_bool p_deep);
-
-godot_array GDAPI godot_array_slice(const godot_array *p_self, const godot_int p_begin, const godot_int p_end, const godot_int p_step, const godot_bool p_deep);
-
-godot_variant GDAPI godot_array_max(const godot_array *p_self);
-
-godot_variant GDAPI godot_array_min(const godot_array *p_self);
-
-void GDAPI godot_array_shuffle(godot_array *p_self);
-
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/include/gdnative/basis.h b/modules/gdnative/include/gdnative/basis.h
index c7425ebbfa..d40ca3d6a5 100644
--- a/modules/gdnative/include/gdnative/basis.h
+++ b/modules/gdnative/include/gdnative/basis.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,9 +35,9 @@
extern "C" {
#endif
-#include <stdint.h>
+#include <gdnative/math_defs.h>
-#define GODOT_BASIS_SIZE 36
+#define GODOT_BASIS_SIZE (sizeof(godot_real_t) * 9)
#ifndef GODOT_CORE_API_GODOT_BASIS_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_BASIS_TYPE_DEFINED
@@ -46,88 +46,9 @@ typedef struct {
} godot_basis;
#endif
-// reduce extern "C" nesting for VS2013
-#ifdef __cplusplus
-}
-#endif
-
#include <gdnative/gdnative.h>
-#include <gdnative/quat.h>
-#include <gdnative/vector3.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void GDAPI godot_basis_new_with_rows(godot_basis *r_dest, const godot_vector3 *p_x_axis, const godot_vector3 *p_y_axis, const godot_vector3 *p_z_axis);
-void GDAPI godot_basis_new_with_axis_and_angle(godot_basis *r_dest, const godot_vector3 *p_axis, const godot_real p_phi);
-void GDAPI godot_basis_new_with_euler(godot_basis *r_dest, const godot_vector3 *p_euler);
-void GDAPI godot_basis_new_with_euler_quat(godot_basis *r_dest, const godot_quat *p_euler);
-
-godot_string GDAPI godot_basis_as_string(const godot_basis *p_self);
-
-godot_basis GDAPI godot_basis_inverse(const godot_basis *p_self);
-
-godot_basis GDAPI godot_basis_transposed(const godot_basis *p_self);
-
-godot_basis GDAPI godot_basis_orthonormalized(const godot_basis *p_self);
-
-godot_real GDAPI godot_basis_determinant(const godot_basis *p_self);
-
-godot_basis GDAPI godot_basis_rotated(const godot_basis *p_self, const godot_vector3 *p_axis, const godot_real p_phi);
-
-godot_basis GDAPI godot_basis_scaled(const godot_basis *p_self, const godot_vector3 *p_scale);
-
-godot_vector3 GDAPI godot_basis_get_scale(const godot_basis *p_self);
-
-godot_vector3 GDAPI godot_basis_get_euler(const godot_basis *p_self);
-
-godot_quat GDAPI godot_basis_get_quat(const godot_basis *p_self);
-
-void GDAPI godot_basis_set_quat(godot_basis *p_self, const godot_quat *p_quat);
-
-void GDAPI godot_basis_set_axis_angle_scale(godot_basis *p_self, const godot_vector3 *p_axis, godot_real p_phi, const godot_vector3 *p_scale);
-
-void GDAPI godot_basis_set_euler_scale(godot_basis *p_self, const godot_vector3 *p_euler, const godot_vector3 *p_scale);
-
-void GDAPI godot_basis_set_quat_scale(godot_basis *p_self, const godot_quat *p_quat, const godot_vector3 *p_scale);
-
-godot_real GDAPI godot_basis_tdotx(const godot_basis *p_self, const godot_vector3 *p_with);
-
-godot_real GDAPI godot_basis_tdoty(const godot_basis *p_self, const godot_vector3 *p_with);
-
-godot_real GDAPI godot_basis_tdotz(const godot_basis *p_self, const godot_vector3 *p_with);
-
-godot_vector3 GDAPI godot_basis_xform(const godot_basis *p_self, const godot_vector3 *p_v);
-
-godot_vector3 GDAPI godot_basis_xform_inv(const godot_basis *p_self, const godot_vector3 *p_v);
-
-godot_int GDAPI godot_basis_get_orthogonal_index(const godot_basis *p_self);
-
-void GDAPI godot_basis_new(godot_basis *r_dest);
-
-// p_elements is a pointer to an array of 3 (!!) vector3
-void GDAPI godot_basis_get_elements(const godot_basis *p_self, godot_vector3 *p_elements);
-
-godot_vector3 GDAPI godot_basis_get_axis(const godot_basis *p_self, const godot_int p_axis);
-
-void GDAPI godot_basis_set_axis(godot_basis *p_self, const godot_int p_axis, const godot_vector3 *p_value);
-
-godot_vector3 GDAPI godot_basis_get_row(const godot_basis *p_self, const godot_int p_row);
-
-void GDAPI godot_basis_set_row(godot_basis *p_self, const godot_int p_row, const godot_vector3 *p_value);
-
-godot_bool GDAPI godot_basis_operator_equal(const godot_basis *p_self, const godot_basis *p_b);
-
-godot_basis GDAPI godot_basis_operator_add(const godot_basis *p_self, const godot_basis *p_b);
-
-godot_basis GDAPI godot_basis_operator_subtract(const godot_basis *p_self, const godot_basis *p_b);
-
-godot_basis GDAPI godot_basis_operator_multiply_vector(const godot_basis *p_self, const godot_basis *p_b);
-
-godot_basis GDAPI godot_basis_operator_multiply_scalar(const godot_basis *p_self, const godot_real p_b);
-godot_basis GDAPI godot_basis_slerp(const godot_basis *p_self, const godot_basis *p_b, const godot_real p_t);
+void GDAPI godot_basis_new(godot_basis *p_self);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/callable.h b/modules/gdnative/include/gdnative/callable.h
index dbb5d02590..6f359ada5e 100644
--- a/modules/gdnative/include/gdnative/callable.h
+++ b/modules/gdnative/include/gdnative/callable.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -46,79 +46,11 @@ typedef struct {
} godot_callable;
#endif
-#define GODOT_SIGNAL_SIZE (16)
-
-#ifndef GODOT_CORE_API_GODOT_SIGNAL_TYPE_DEFINED
-#define GODOT_CORE_API_GODOT_SIGNAL_TYPE_DEFINED
-typedef struct {
- uint8_t _dont_touch_that[GODOT_SIGNAL_SIZE];
-} godot_signal;
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
#include <gdnative/gdnative.h>
-#include <gdnative/string_name.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Callable
-
-void GDAPI godot_callable_new_with_object(godot_callable *r_dest, const godot_object *p_object, const godot_string_name *p_method);
-void GDAPI godot_callable_new_with_object_id(godot_callable *r_dest, uint64_t p_objectid, const godot_string_name *p_method);
-void GDAPI godot_callable_new_copy(godot_callable *r_dest, const godot_callable *p_src);
+void GDAPI godot_callable_new(godot_callable *p_self);
void GDAPI godot_callable_destroy(godot_callable *p_self);
-godot_int GDAPI godot_callable_call(const godot_callable *p_self, const godot_variant **p_arguments, godot_int p_argcount, godot_variant *r_return_value);
-void GDAPI godot_callable_call_deferred(const godot_callable *p_self, const godot_variant **p_arguments, godot_int p_argcount);
-
-godot_bool GDAPI godot_callable_is_null(const godot_callable *p_self);
-godot_bool GDAPI godot_callable_is_custom(const godot_callable *p_self);
-godot_bool GDAPI godot_callable_is_standard(const godot_callable *p_self);
-
-godot_object GDAPI *godot_callable_get_object(const godot_callable *p_self);
-uint64_t GDAPI godot_callable_get_object_id(const godot_callable *p_self);
-godot_string_name GDAPI godot_callable_get_method(const godot_callable *p_self);
-
-uint32_t GDAPI godot_callable_hash(const godot_callable *p_self);
-
-godot_string GDAPI godot_callable_as_string(const godot_callable *p_self);
-
-godot_bool GDAPI godot_callable_operator_equal(const godot_callable *p_self, const godot_callable *p_other);
-godot_bool GDAPI godot_callable_operator_less(const godot_callable *p_self, const godot_callable *p_other);
-
-// Signal
-
-void GDAPI godot_signal_new_with_object(godot_signal *r_dest, const godot_object *p_object, const godot_string_name *p_name);
-void GDAPI godot_signal_new_with_object_id(godot_signal *r_dest, uint64_t p_objectid, const godot_string_name *p_name);
-void GDAPI godot_signal_new_copy(godot_signal *r_dest, const godot_signal *p_src);
-
-void GDAPI godot_signal_destroy(godot_signal *p_self);
-
-godot_int GDAPI godot_signal_emit(const godot_signal *p_self, const godot_variant **p_arguments, godot_int p_argcount);
-
-godot_int GDAPI godot_signal_connect(godot_signal *p_self, const godot_callable *p_callable, const godot_array *p_binds, uint32_t p_flags);
-void GDAPI godot_signal_disconnect(godot_signal *p_self, const godot_callable *p_callable);
-
-godot_bool GDAPI godot_signal_is_null(const godot_signal *p_self);
-godot_bool GDAPI godot_signal_is_connected(const godot_signal *p_self, const godot_callable *p_callable);
-
-godot_array GDAPI godot_signal_get_connections(const godot_signal *p_self);
-
-godot_object GDAPI *godot_signal_get_object(const godot_signal *p_self);
-uint64_t GDAPI godot_signal_get_object_id(const godot_signal *p_self);
-godot_string_name GDAPI godot_signal_get_name(const godot_signal *p_self);
-
-godot_string GDAPI godot_signal_as_string(const godot_signal *p_self);
-
-godot_bool GDAPI godot_signal_operator_equal(const godot_signal *p_self, const godot_signal *p_other);
-godot_bool GDAPI godot_signal_operator_less(const godot_signal *p_self, const godot_signal *p_other);
-
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/include/gdnative/color.h b/modules/gdnative/include/gdnative/color.h
index e7737bf8e1..12c4a829bd 100644
--- a/modules/gdnative/include/gdnative/color.h
+++ b/modules/gdnative/include/gdnative/color.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,9 +35,10 @@
extern "C" {
#endif
-#include <stdint.h>
+#include <gdnative/math_defs.h>
-#define GODOT_COLOR_SIZE 16
+// Colors should always use 32-bit floats, so don't use real_t here.
+#define GODOT_COLOR_SIZE (sizeof(float) * 4)
#ifndef GODOT_CORE_API_GODOT_COLOR_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_COLOR_TYPE_DEFINED
@@ -46,70 +47,9 @@ typedef struct {
} godot_color;
#endif
-// reduce extern "C" nesting for VS2013
-#ifdef __cplusplus
-}
-#endif
-
#include <gdnative/gdnative.h>
-#include <gdnative/string.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void GDAPI godot_color_new_rgba(godot_color *r_dest, const godot_real p_r, const godot_real p_g, const godot_real p_b, const godot_real p_a);
-void GDAPI godot_color_new_rgb(godot_color *r_dest, const godot_real p_r, const godot_real p_g, const godot_real p_b);
-
-godot_real godot_color_get_r(const godot_color *p_self);
-void godot_color_set_r(godot_color *p_self, const godot_real r);
-
-godot_real godot_color_get_g(const godot_color *p_self);
-void godot_color_set_g(godot_color *p_self, const godot_real g);
-
-godot_real godot_color_get_b(const godot_color *p_self);
-void godot_color_set_b(godot_color *p_self, const godot_real b);
-
-godot_real godot_color_get_a(const godot_color *p_self);
-void godot_color_set_a(godot_color *p_self, const godot_real a);
-
-godot_real godot_color_get_h(const godot_color *p_self);
-godot_real godot_color_get_s(const godot_color *p_self);
-godot_real godot_color_get_v(const godot_color *p_self);
-
-godot_string GDAPI godot_color_as_string(const godot_color *p_self);
-
-godot_int GDAPI godot_color_to_rgba32(const godot_color *p_self);
-
-godot_int GDAPI godot_color_to_abgr32(const godot_color *p_self);
-
-godot_int GDAPI godot_color_to_abgr64(const godot_color *p_self);
-
-godot_int GDAPI godot_color_to_argb64(const godot_color *p_self);
-
-godot_int GDAPI godot_color_to_rgba64(const godot_color *p_self);
-
-godot_int GDAPI godot_color_to_argb32(const godot_color *p_self);
-
-godot_color GDAPI godot_color_inverted(const godot_color *p_self);
-
-godot_color GDAPI godot_color_contrasted(const godot_color *p_self);
-
-godot_color GDAPI godot_color_lerp(const godot_color *p_self, const godot_color *p_b, const godot_real p_t);
-
-godot_color GDAPI godot_color_blend(const godot_color *p_self, const godot_color *p_over);
-
-godot_color GDAPI godot_color_darkened(const godot_color *p_self, const godot_real p_amount);
-
-godot_color GDAPI godot_color_from_hsv(const godot_color *p_self, const godot_real p_h, const godot_real p_s, const godot_real p_v, const godot_real p_a);
-
-godot_color GDAPI godot_color_lightened(const godot_color *p_self, const godot_real p_amount);
-
-godot_string GDAPI godot_color_to_html(const godot_color *p_self, const godot_bool p_with_alpha);
-
-godot_bool GDAPI godot_color_operator_equal(const godot_color *p_self, const godot_color *p_b);
-godot_bool GDAPI godot_color_operator_less(const godot_color *p_self, const godot_color *p_b);
+void GDAPI godot_color_new(godot_color *p_self);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/dictionary.h b/modules/gdnative/include/gdnative/dictionary.h
index 873efaa9bf..231d2ef578 100644
--- a/modules/gdnative/include/gdnative/dictionary.h
+++ b/modules/gdnative/include/gdnative/dictionary.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -46,62 +46,11 @@ typedef struct {
} godot_dictionary;
#endif
-// reduce extern "C" nesting for VS2013
-#ifdef __cplusplus
-}
-#endif
-
-#include <gdnative/array.h>
#include <gdnative/gdnative.h>
-#include <gdnative/variant.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-void GDAPI godot_dictionary_new(godot_dictionary *r_dest);
-void GDAPI godot_dictionary_new_copy(godot_dictionary *r_dest, const godot_dictionary *p_src);
+void GDAPI godot_dictionary_new(godot_dictionary *p_self);
void GDAPI godot_dictionary_destroy(godot_dictionary *p_self);
-godot_dictionary GDAPI godot_dictionary_duplicate(const godot_dictionary *p_self, const godot_bool p_deep);
-
-godot_int GDAPI godot_dictionary_size(const godot_dictionary *p_self);
-
-godot_bool GDAPI godot_dictionary_empty(const godot_dictionary *p_self);
-
-void GDAPI godot_dictionary_clear(godot_dictionary *p_self);
-
-godot_bool GDAPI godot_dictionary_has(const godot_dictionary *p_self, const godot_variant *p_key);
-
-godot_bool GDAPI godot_dictionary_has_all(const godot_dictionary *p_self, const godot_array *p_keys);
-
-void GDAPI godot_dictionary_erase(godot_dictionary *p_self, const godot_variant *p_key);
-
-godot_int GDAPI godot_dictionary_hash(const godot_dictionary *p_self);
-
-godot_array GDAPI godot_dictionary_keys(const godot_dictionary *p_self);
-
-godot_array GDAPI godot_dictionary_values(const godot_dictionary *p_self);
-
-godot_variant GDAPI godot_dictionary_get(const godot_dictionary *p_self, const godot_variant *p_key);
-void GDAPI godot_dictionary_set(godot_dictionary *p_self, const godot_variant *p_key, const godot_variant *p_value);
-
-godot_variant GDAPI *godot_dictionary_operator_index(godot_dictionary *p_self, const godot_variant *p_key);
-
-const godot_variant GDAPI *godot_dictionary_operator_index_const(const godot_dictionary *p_self, const godot_variant *p_key);
-
-godot_variant GDAPI *godot_dictionary_next(const godot_dictionary *p_self, const godot_variant *p_key);
-
-godot_bool GDAPI godot_dictionary_operator_equal(const godot_dictionary *p_self, const godot_dictionary *p_b);
-
-godot_string GDAPI godot_dictionary_to_json(const godot_dictionary *p_self);
-
-// GDNative core 1.1
-
-godot_bool GDAPI godot_dictionary_erase_with_return(godot_dictionary *p_self, const godot_variant *p_key);
-
-godot_variant GDAPI godot_dictionary_get_with_default(const godot_dictionary *p_self, const godot_variant *p_key, const godot_variant *p_default);
-
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/include/gdnative/gdnative.h b/modules/gdnative/include/gdnative/gdnative.h
index 6a0a375da8..630966b035 100644
--- a/modules/gdnative/include/gdnative/gdnative.h
+++ b/modules/gdnative/include/gdnative/gdnative.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -118,21 +118,6 @@ typedef enum {
GODOT_ERR_PRINTER_ON_FIRE, /// the parallel port printer is engulfed in flames
} godot_error;
-////// bool
-
-typedef bool godot_bool;
-
-#define GODOT_TRUE 1
-#define GODOT_FALSE 0
-
-/////// int
-
-typedef int64_t godot_int;
-
-/////// real
-
-typedef float godot_real;
-
/////// Object (forward declared)
typedef void godot_object;
@@ -215,7 +200,7 @@ void GDAPI godot_object_destroy(godot_object *p_o);
////// Singleton API
-godot_object GDAPI *godot_global_get_singleton(char *p_name); // result shouldn't be freed
+godot_object GDAPI *godot_global_get_singleton(char *p_name); // Result shouldn't be freed.
////// MethodBind API
@@ -281,13 +266,6 @@ void GDAPI *godot_alloc(int p_bytes);
void GDAPI *godot_realloc(void *p_ptr, int p_bytes);
void GDAPI godot_free(void *p_ptr);
-//print using Godot's error handler list
-void GDAPI godot_print_error(const char *p_description, const char *p_function, const char *p_file, int p_line);
-void GDAPI godot_print_warning(const char *p_description, const char *p_function, const char *p_file, int p_line);
-void GDAPI godot_print(const godot_string *p_message);
-
-// GDNATIVE CORE 1.0.2?
-
//tags used for safe dynamic casting
void GDAPI *godot_get_class_tag(const godot_string_name *p_class);
godot_object GDAPI *godot_object_cast_to(const godot_object *p_object, void *p_class_tag);
@@ -301,4 +279,4 @@ uint64_t GDAPI godot_object_get_instance_id(const godot_object *p_object);
}
#endif
-#endif // GODOT_C_H
+#endif // GODOT_GDNATIVE_H
diff --git a/modules/gdnative/include/gdnative/math_defs.h b/modules/gdnative/include/gdnative/math_defs.h
new file mode 100644
index 0000000000..b5cf389506
--- /dev/null
+++ b/modules/gdnative/include/gdnative/math_defs.h
@@ -0,0 +1,66 @@
+/*************************************************************************/
+/* math_defs.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GODOT_GDNATIVE_MATH_DEFS_H
+#define GODOT_GDNATIVE_MATH_DEFS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include <stdint.h>
+
+////// bool
+
+typedef bool godot_bool;
+
+#define GODOT_TRUE 1
+#define GODOT_FALSE 0
+
+/////// int
+
+typedef int64_t godot_int;
+
+/////// float
+
+typedef double godot_float;
+
+#ifdef REAL_T_IS_DOUBLE
+typedef double godot_real_t;
+#else
+typedef float godot_real_t;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // GODOT_C_H
diff --git a/modules/gdnative/include/gdnative/node_path.h b/modules/gdnative/include/gdnative/node_path.h
index 0cd0c3cb9c..3c31b9a98f 100644
--- a/modules/gdnative/include/gdnative/node_path.h
+++ b/modules/gdnative/include/gdnative/node_path.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -46,42 +46,11 @@ typedef struct {
} godot_node_path;
#endif
-// reduce extern "C" nesting for VS2013
-#ifdef __cplusplus
-}
-#endif
-
#include <gdnative/gdnative.h>
-#include <gdnative/string.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void GDAPI godot_node_path_new(godot_node_path *r_dest, const godot_string *p_from);
-void GDAPI godot_node_path_new_copy(godot_node_path *r_dest, const godot_node_path *p_src);
+void GDAPI godot_node_path_new(godot_node_path *p_self);
void GDAPI godot_node_path_destroy(godot_node_path *p_self);
-godot_string GDAPI godot_node_path_as_string(const godot_node_path *p_self);
-
-godot_bool GDAPI godot_node_path_is_absolute(const godot_node_path *p_self);
-
-godot_int GDAPI godot_node_path_get_name_count(const godot_node_path *p_self);
-
-godot_string GDAPI godot_node_path_get_name(const godot_node_path *p_self, const godot_int p_idx);
-
-godot_int GDAPI godot_node_path_get_subname_count(const godot_node_path *p_self);
-
-godot_string GDAPI godot_node_path_get_subname(const godot_node_path *p_self, const godot_int p_idx);
-
-godot_string GDAPI godot_node_path_get_concatenated_subnames(const godot_node_path *p_self);
-
-godot_bool GDAPI godot_node_path_is_empty(const godot_node_path *p_self);
-
-godot_bool GDAPI godot_node_path_operator_equal(const godot_node_path *p_self, const godot_node_path *p_b);
-
-godot_node_path godot_node_path_get_as_property_path(const godot_node_path *p_self);
-
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/include/gdnative/packed_arrays.h b/modules/gdnative/include/gdnative/packed_arrays.h
index 6a1727d76f..1a26d8ed6d 100644
--- a/modules/gdnative/include/gdnative/packed_arrays.h
+++ b/modules/gdnative/include/gdnative/packed_arrays.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -114,6 +114,17 @@ typedef struct {
} godot_packed_vector2_array;
#endif
+/////// PackedVector2iArray
+
+#define GODOT_PACKED_VECTOR2I_ARRAY_SIZE (2 * sizeof(void *))
+
+#ifndef GODOT_CORE_API_GODOT_PACKED_VECTOR2I_ARRAY_TYPE_DEFINED
+#define GODOT_CORE_API_GODOT_PACKED_VECTOR2I_ARRAY_TYPE_DEFINED
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_PACKED_VECTOR2I_ARRAY_SIZE];
+} godot_packed_vector2i_array;
+#endif
+
/////// PackedVector3Array
#define GODOT_PACKED_VECTOR3_ARRAY_SIZE (2 * sizeof(void *))
@@ -125,6 +136,17 @@ typedef struct {
} godot_packed_vector3_array;
#endif
+/////// PackedVector3iArray
+
+#define GODOT_PACKED_VECTOR3I_ARRAY_SIZE (2 * sizeof(void *))
+
+#ifndef GODOT_CORE_API_GODOT_PACKED_VECTOR3I_ARRAY_TYPE_DEFINED
+#define GODOT_CORE_API_GODOT_PACKED_VECTOR3I_ARRAY_TYPE_DEFINED
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_PACKED_VECTOR3I_ARRAY_SIZE];
+} godot_packed_vector3i_array;
+#endif
+
/////// PackedColorArray
#define GODOT_PACKED_COLOR_ARRAY_SIZE (2 * sizeof(void *))
@@ -136,344 +158,56 @@ typedef struct {
} godot_packed_color_array;
#endif
-// reduce extern "C" nesting for VS2013
-#ifdef __cplusplus
-}
-#endif
-
-#include <gdnative/array.h>
-#include <gdnative/color.h>
-#include <gdnative/vector2.h>
-#include <gdnative/vector3.h>
-
#include <gdnative/gdnative.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// byte
-
-void GDAPI godot_packed_byte_array_new(godot_packed_byte_array *r_dest);
-void GDAPI godot_packed_byte_array_new_copy(godot_packed_byte_array *r_dest, const godot_packed_byte_array *p_src);
-void GDAPI godot_packed_byte_array_new_with_array(godot_packed_byte_array *r_dest, const godot_array *p_a);
-
-const uint8_t GDAPI *godot_packed_byte_array_ptr(const godot_packed_byte_array *p_self);
-uint8_t GDAPI *godot_packed_byte_array_ptrw(godot_packed_byte_array *p_self);
-
-void GDAPI godot_packed_byte_array_append(godot_packed_byte_array *p_self, const uint8_t p_data);
-
-void GDAPI godot_packed_byte_array_append_array(godot_packed_byte_array *p_self, const godot_packed_byte_array *p_array);
-
-godot_error GDAPI godot_packed_byte_array_insert(godot_packed_byte_array *p_self, const godot_int p_idx, const uint8_t p_data);
-
-godot_bool GDAPI godot_packed_byte_array_has(godot_packed_byte_array *p_self, const uint8_t p_value);
-
-void GDAPI godot_packed_byte_array_sort(godot_packed_byte_array *p_self);
-
-void GDAPI godot_packed_byte_array_invert(godot_packed_byte_array *p_self);
-
-void GDAPI godot_packed_byte_array_push_back(godot_packed_byte_array *p_self, const uint8_t p_data);
-
-void GDAPI godot_packed_byte_array_remove(godot_packed_byte_array *p_self, const godot_int p_idx);
-
-void GDAPI godot_packed_byte_array_resize(godot_packed_byte_array *p_self, const godot_int p_size);
-
-void GDAPI godot_packed_byte_array_set(godot_packed_byte_array *p_self, const godot_int p_idx, const uint8_t p_data);
-uint8_t GDAPI godot_packed_byte_array_get(const godot_packed_byte_array *p_self, const godot_int p_idx);
-
-godot_int GDAPI godot_packed_byte_array_size(const godot_packed_byte_array *p_self);
-
-godot_bool GDAPI godot_packed_byte_array_empty(const godot_packed_byte_array *p_self);
+// Byte.
+void GDAPI godot_packed_byte_array_new(godot_packed_byte_array *p_self);
void GDAPI godot_packed_byte_array_destroy(godot_packed_byte_array *p_self);
-// int32
-
-void GDAPI godot_packed_int32_array_new(godot_packed_int32_array *r_dest);
-void GDAPI godot_packed_int32_array_new_copy(godot_packed_int32_array *r_dest, const godot_packed_int32_array *p_src);
-void GDAPI godot_packed_int32_array_new_with_array(godot_packed_int32_array *r_dest, const godot_array *p_a);
-
-const int32_t GDAPI *godot_packed_int32_array_ptr(const godot_packed_int32_array *p_self);
-int32_t GDAPI *godot_packed_int32_array_ptrw(godot_packed_int32_array *p_self);
-
-void GDAPI godot_packed_int32_array_append(godot_packed_int32_array *p_self, const int32_t p_data);
-
-void GDAPI godot_packed_int32_array_append_array(godot_packed_int32_array *p_self, const godot_packed_int32_array *p_array);
-
-godot_error GDAPI godot_packed_int32_array_insert(godot_packed_int32_array *p_self, const godot_int p_idx, const int32_t p_data);
-
-godot_bool GDAPI godot_packed_int32_array_has(godot_packed_int32_array *p_self, const int32_t p_value);
-
-void GDAPI godot_packed_int32_array_sort(godot_packed_int32_array *p_self);
-
-void GDAPI godot_packed_int32_array_invert(godot_packed_int32_array *p_self);
-
-void GDAPI godot_packed_int32_array_push_back(godot_packed_int32_array *p_self, const int32_t p_data);
-
-void GDAPI godot_packed_int32_array_remove(godot_packed_int32_array *p_self, const godot_int p_idx);
-
-void GDAPI godot_packed_int32_array_resize(godot_packed_int32_array *p_self, const godot_int p_size);
-
-void GDAPI godot_packed_int32_array_set(godot_packed_int32_array *p_self, const godot_int p_idx, const int32_t p_data);
-int32_t GDAPI godot_packed_int32_array_get(const godot_packed_int32_array *p_self, const godot_int p_idx);
-
-godot_int GDAPI godot_packed_int32_array_size(const godot_packed_int32_array *p_self);
-
-godot_bool GDAPI godot_packed_int32_array_empty(const godot_packed_int32_array *p_self);
+// Int32.
+void GDAPI godot_packed_int32_array_new(godot_packed_int32_array *p_self);
void GDAPI godot_packed_int32_array_destroy(godot_packed_int32_array *p_self);
-// int64
-
-void GDAPI godot_packed_int64_array_new(godot_packed_int64_array *r_dest);
-void GDAPI godot_packed_int64_array_new_copy(godot_packed_int64_array *r_dest, const godot_packed_int64_array *p_src);
-void GDAPI godot_packed_int64_array_new_with_array(godot_packed_int64_array *r_dest, const godot_array *p_a);
-
-const int64_t GDAPI *godot_packed_int64_array_ptr(const godot_packed_int64_array *p_self);
-int64_t GDAPI *godot_packed_int64_array_ptrw(godot_packed_int64_array *p_self);
-
-void GDAPI godot_packed_int64_array_append(godot_packed_int64_array *p_self, const int64_t p_data);
-
-void GDAPI godot_packed_int64_array_append_array(godot_packed_int64_array *p_self, const godot_packed_int64_array *p_array);
-
-godot_error GDAPI godot_packed_int64_array_insert(godot_packed_int64_array *p_self, const godot_int p_idx, const int64_t p_data);
-
-godot_bool GDAPI godot_packed_int64_array_has(godot_packed_int64_array *p_self, const int64_t p_value);
-
-void GDAPI godot_packed_int64_array_sort(godot_packed_int64_array *p_self);
-
-void GDAPI godot_packed_int64_array_invert(godot_packed_int64_array *p_self);
-
-void GDAPI godot_packed_int64_array_push_back(godot_packed_int64_array *p_self, const int64_t p_data);
-
-void GDAPI godot_packed_int64_array_remove(godot_packed_int64_array *p_self, const godot_int p_idx);
-
-void GDAPI godot_packed_int64_array_resize(godot_packed_int64_array *p_self, const godot_int p_size);
-
-void GDAPI godot_packed_int64_array_set(godot_packed_int64_array *p_self, const godot_int p_idx, const int64_t p_data);
-int64_t GDAPI godot_packed_int64_array_get(const godot_packed_int64_array *p_self, const godot_int p_idx);
-
-godot_int GDAPI godot_packed_int64_array_size(const godot_packed_int64_array *p_self);
-
-godot_bool GDAPI godot_packed_int64_array_empty(const godot_packed_int64_array *p_self);
+// Int64.
+void GDAPI godot_packed_int64_array_new(godot_packed_int64_array *p_self);
void GDAPI godot_packed_int64_array_destroy(godot_packed_int64_array *p_self);
-// float32
-
-void GDAPI godot_packed_float32_array_new(godot_packed_float32_array *r_dest);
-void GDAPI godot_packed_float32_array_new_copy(godot_packed_float32_array *r_dest, const godot_packed_float32_array *p_src);
-void GDAPI godot_packed_float32_array_new_with_array(godot_packed_float32_array *r_dest, const godot_array *p_a);
-
-const float GDAPI *godot_packed_float32_array_ptr(const godot_packed_float32_array *p_self);
-float GDAPI *godot_packed_float32_array_ptrw(godot_packed_float32_array *p_self);
-
-void GDAPI godot_packed_float32_array_append(godot_packed_float32_array *p_self, const float p_data);
-
-void GDAPI godot_packed_float32_array_append_array(godot_packed_float32_array *p_self, const godot_packed_float32_array *p_array);
-
-godot_error GDAPI godot_packed_float32_array_insert(godot_packed_float32_array *p_self, const godot_int p_idx, const float p_data);
-
-godot_bool GDAPI godot_packed_float32_array_has(godot_packed_float32_array *p_self, const float p_value);
-
-void GDAPI godot_packed_float32_array_sort(godot_packed_float32_array *p_self);
-
-void GDAPI godot_packed_float32_array_invert(godot_packed_float32_array *p_self);
-
-void GDAPI godot_packed_float32_array_push_back(godot_packed_float32_array *p_self, const float p_data);
-
-void GDAPI godot_packed_float32_array_remove(godot_packed_float32_array *p_self, const godot_int p_idx);
-
-void GDAPI godot_packed_float32_array_resize(godot_packed_float32_array *p_self, const godot_int p_size);
-
-void GDAPI godot_packed_float32_array_set(godot_packed_float32_array *p_self, const godot_int p_idx, const float p_data);
-float GDAPI godot_packed_float32_array_get(const godot_packed_float32_array *p_self, const godot_int p_idx);
-
-godot_int GDAPI godot_packed_float32_array_size(const godot_packed_float32_array *p_self);
-
-godot_bool GDAPI godot_packed_float32_array_empty(const godot_packed_float32_array *p_self);
+// Float32.
+void GDAPI godot_packed_float32_array_new(godot_packed_float32_array *p_self);
void GDAPI godot_packed_float32_array_destroy(godot_packed_float32_array *p_self);
-// float64
-
-void GDAPI godot_packed_float64_array_new(godot_packed_float64_array *r_dest);
-void GDAPI godot_packed_float64_array_new_copy(godot_packed_float64_array *r_dest, const godot_packed_float64_array *p_src);
-void GDAPI godot_packed_float64_array_new_with_array(godot_packed_float64_array *r_dest, const godot_array *p_a);
-
-const double GDAPI *godot_packed_float64_array_ptr(const godot_packed_float64_array *p_self);
-double GDAPI *godot_packed_float64_array_ptrw(godot_packed_float64_array *p_self);
-
-void GDAPI godot_packed_float64_array_append(godot_packed_float64_array *p_self, const double p_data);
-
-void GDAPI godot_packed_float64_array_append_array(godot_packed_float64_array *p_self, const godot_packed_float64_array *p_array);
-
-godot_error GDAPI godot_packed_float64_array_insert(godot_packed_float64_array *p_self, const godot_int p_idx, const double p_data);
-
-godot_bool GDAPI godot_packed_float64_array_has(godot_packed_float64_array *p_self, const double p_value);
-
-void GDAPI godot_packed_float64_array_sort(godot_packed_float64_array *p_self);
-
-void GDAPI godot_packed_float64_array_invert(godot_packed_float64_array *p_self);
-
-void GDAPI godot_packed_float64_array_push_back(godot_packed_float64_array *p_self, const double p_data);
-
-void GDAPI godot_packed_float64_array_remove(godot_packed_float64_array *p_self, const godot_int p_idx);
-
-void GDAPI godot_packed_float64_array_resize(godot_packed_float64_array *p_self, const godot_int p_size);
-
-void GDAPI godot_packed_float64_array_set(godot_packed_float64_array *p_self, const godot_int p_idx, const double p_data);
-double GDAPI godot_packed_float64_array_get(const godot_packed_float64_array *p_self, const godot_int p_idx);
-
-godot_int GDAPI godot_packed_float64_array_size(const godot_packed_float64_array *p_self);
-
-godot_bool GDAPI godot_packed_float64_array_empty(const godot_packed_float64_array *p_self);
+// Float64.
+void GDAPI godot_packed_float64_array_new(godot_packed_float64_array *p_self);
void GDAPI godot_packed_float64_array_destroy(godot_packed_float64_array *p_self);
-// string
-
-void GDAPI godot_packed_string_array_new(godot_packed_string_array *r_dest);
-void GDAPI godot_packed_string_array_new_copy(godot_packed_string_array *r_dest, const godot_packed_string_array *p_src);
-void GDAPI godot_packed_string_array_new_with_array(godot_packed_string_array *r_dest, const godot_array *p_a);
-
-const godot_string GDAPI *godot_packed_string_array_ptr(const godot_packed_string_array *p_self);
-godot_string GDAPI *godot_packed_string_array_ptrw(godot_packed_string_array *p_self);
-
-void GDAPI godot_packed_string_array_append(godot_packed_string_array *p_self, const godot_string *p_data);
-
-void GDAPI godot_packed_string_array_append_array(godot_packed_string_array *p_self, const godot_packed_string_array *p_array);
-
-godot_error GDAPI godot_packed_string_array_insert(godot_packed_string_array *p_self, const godot_int p_idx, const godot_string *p_data);
-
-godot_bool GDAPI godot_packed_string_array_has(godot_packed_string_array *p_self, const godot_string *p_value);
-
-void GDAPI godot_packed_string_array_sort(godot_packed_string_array *p_self);
-
-void GDAPI godot_packed_string_array_invert(godot_packed_string_array *p_self);
-
-void GDAPI godot_packed_string_array_push_back(godot_packed_string_array *p_self, const godot_string *p_data);
-
-void GDAPI godot_packed_string_array_remove(godot_packed_string_array *p_self, const godot_int p_idx);
-
-void GDAPI godot_packed_string_array_resize(godot_packed_string_array *p_self, const godot_int p_size);
-
-void GDAPI godot_packed_string_array_set(godot_packed_string_array *p_self, const godot_int p_idx, const godot_string *p_data);
-godot_string GDAPI godot_packed_string_array_get(const godot_packed_string_array *p_self, const godot_int p_idx);
-
-godot_int GDAPI godot_packed_string_array_size(const godot_packed_string_array *p_self);
-
-godot_bool GDAPI godot_packed_string_array_empty(const godot_packed_string_array *p_self);
+// String.
+void GDAPI godot_packed_string_array_new(godot_packed_string_array *p_self);
void GDAPI godot_packed_string_array_destroy(godot_packed_string_array *p_self);
-// vector2
-
-void GDAPI godot_packed_vector2_array_new(godot_packed_vector2_array *r_dest);
-void GDAPI godot_packed_vector2_array_new_copy(godot_packed_vector2_array *r_dest, const godot_packed_vector2_array *p_src);
-void GDAPI godot_packed_vector2_array_new_with_array(godot_packed_vector2_array *r_dest, const godot_array *p_a);
-
-const godot_vector2 GDAPI *godot_packed_vector2_array_ptr(const godot_packed_vector2_array *p_self);
-godot_vector2 GDAPI *godot_packed_vector2_array_ptrw(godot_packed_vector2_array *p_self);
-
-void GDAPI godot_packed_vector2_array_append(godot_packed_vector2_array *p_self, const godot_vector2 *p_data);
-
-void GDAPI godot_packed_vector2_array_append_array(godot_packed_vector2_array *p_self, const godot_packed_vector2_array *p_array);
-
-godot_error GDAPI godot_packed_vector2_array_insert(godot_packed_vector2_array *p_self, const godot_int p_idx, const godot_vector2 *p_data);
-
-godot_bool GDAPI godot_packed_vector2_array_has(godot_packed_vector2_array *p_self, const godot_vector2 *p_value);
-
-void GDAPI godot_packed_vector2_array_sort(godot_packed_vector2_array *p_self);
-
-void GDAPI godot_packed_vector2_array_invert(godot_packed_vector2_array *p_self);
-
-void GDAPI godot_packed_vector2_array_push_back(godot_packed_vector2_array *p_self, const godot_vector2 *p_data);
-
-void GDAPI godot_packed_vector2_array_remove(godot_packed_vector2_array *p_self, const godot_int p_idx);
-
-void GDAPI godot_packed_vector2_array_resize(godot_packed_vector2_array *p_self, const godot_int p_size);
-
-void GDAPI godot_packed_vector2_array_set(godot_packed_vector2_array *p_self, const godot_int p_idx, const godot_vector2 *p_data);
-godot_vector2 GDAPI godot_packed_vector2_array_get(const godot_packed_vector2_array *p_self, const godot_int p_idx);
-
-godot_int GDAPI godot_packed_vector2_array_size(const godot_packed_vector2_array *p_self);
-
-godot_bool GDAPI godot_packed_vector2_array_empty(const godot_packed_vector2_array *p_self);
+// Vector2.
+void GDAPI godot_packed_vector2_array_new(godot_packed_vector2_array *p_self);
void GDAPI godot_packed_vector2_array_destroy(godot_packed_vector2_array *p_self);
-// vector3
-
-void GDAPI godot_packed_vector3_array_new(godot_packed_vector3_array *r_dest);
-void GDAPI godot_packed_vector3_array_new_copy(godot_packed_vector3_array *r_dest, const godot_packed_vector3_array *p_src);
-void GDAPI godot_packed_vector3_array_new_with_array(godot_packed_vector3_array *r_dest, const godot_array *p_a);
-
-const godot_vector3 GDAPI *godot_packed_vector3_array_ptr(const godot_packed_vector3_array *p_self);
-godot_vector3 GDAPI *godot_packed_vector3_array_ptrw(godot_packed_vector3_array *p_self);
-
-void GDAPI godot_packed_vector3_array_append(godot_packed_vector3_array *p_self, const godot_vector3 *p_data);
-
-void GDAPI godot_packed_vector3_array_append_array(godot_packed_vector3_array *p_self, const godot_packed_vector3_array *p_array);
-
-godot_error GDAPI godot_packed_vector3_array_insert(godot_packed_vector3_array *p_self, const godot_int p_idx, const godot_vector3 *p_data);
-
-godot_bool GDAPI godot_packed_vector3_array_has(godot_packed_vector3_array *p_self, const godot_vector3 *p_value);
-
-void GDAPI godot_packed_vector3_array_sort(godot_packed_vector3_array *p_self);
-
-void GDAPI godot_packed_vector3_array_invert(godot_packed_vector3_array *p_self);
-
-void GDAPI godot_packed_vector3_array_push_back(godot_packed_vector3_array *p_self, const godot_vector3 *p_data);
+// Vector2i.
-void GDAPI godot_packed_vector3_array_remove(godot_packed_vector3_array *p_self, const godot_int p_idx);
+void GDAPI godot_packed_vector2i_array_new(godot_packed_vector2i_array *p_self);
+void GDAPI godot_packed_vector2i_array_destroy(godot_packed_vector2i_array *p_self);
-void GDAPI godot_packed_vector3_array_resize(godot_packed_vector3_array *p_self, const godot_int p_size);
-
-void GDAPI godot_packed_vector3_array_set(godot_packed_vector3_array *p_self, const godot_int p_idx, const godot_vector3 *p_data);
-godot_vector3 GDAPI godot_packed_vector3_array_get(const godot_packed_vector3_array *p_self, const godot_int p_idx);
-
-godot_int GDAPI godot_packed_vector3_array_size(const godot_packed_vector3_array *p_self);
-
-godot_bool GDAPI godot_packed_vector3_array_empty(const godot_packed_vector3_array *p_self);
+// Vector3.
+void GDAPI godot_packed_vector3_array_new(godot_packed_vector3_array *p_self);
void GDAPI godot_packed_vector3_array_destroy(godot_packed_vector3_array *p_self);
-// color
-
-void GDAPI godot_packed_color_array_new(godot_packed_color_array *r_dest);
-void GDAPI godot_packed_color_array_new_copy(godot_packed_color_array *r_dest, const godot_packed_color_array *p_src);
-void GDAPI godot_packed_color_array_new_with_array(godot_packed_color_array *r_dest, const godot_array *p_a);
-
-const godot_color GDAPI *godot_packed_color_array_ptr(const godot_packed_color_array *p_self);
-godot_color GDAPI *godot_packed_color_array_ptrw(godot_packed_color_array *p_self);
-
-void GDAPI godot_packed_color_array_append(godot_packed_color_array *p_self, const godot_color *p_data);
-
-void GDAPI godot_packed_color_array_append_array(godot_packed_color_array *p_self, const godot_packed_color_array *p_array);
-
-godot_error GDAPI godot_packed_color_array_insert(godot_packed_color_array *p_self, const godot_int p_idx, const godot_color *p_data);
-
-godot_bool GDAPI godot_packed_color_array_has(godot_packed_color_array *p_self, const godot_color *p_value);
-
-void GDAPI godot_packed_color_array_sort(godot_packed_color_array *p_self);
-
-void GDAPI godot_packed_color_array_invert(godot_packed_color_array *p_self);
-
-void GDAPI godot_packed_color_array_push_back(godot_packed_color_array *p_self, const godot_color *p_data);
-
-void GDAPI godot_packed_color_array_remove(godot_packed_color_array *p_self, const godot_int p_idx);
-
-void GDAPI godot_packed_color_array_resize(godot_packed_color_array *p_self, const godot_int p_size);
-
-void GDAPI godot_packed_color_array_set(godot_packed_color_array *p_self, const godot_int p_idx, const godot_color *p_data);
-godot_color GDAPI godot_packed_color_array_get(const godot_packed_color_array *p_self, const godot_int p_idx);
-
-godot_int GDAPI godot_packed_color_array_size(const godot_packed_color_array *p_self);
-
-godot_bool GDAPI godot_packed_color_array_empty(const godot_packed_color_array *p_self);
+// Color.
+void GDAPI godot_packed_color_array_new(godot_packed_color_array *p_self);
void GDAPI godot_packed_color_array_destroy(godot_packed_color_array *p_self);
#ifdef __cplusplus
diff --git a/modules/gdnative/include/gdnative/plane.h b/modules/gdnative/include/gdnative/plane.h
index 9843056489..ed10955e5f 100644
--- a/modules/gdnative/include/gdnative/plane.h
+++ b/modules/gdnative/include/gdnative/plane.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,9 +35,9 @@
extern "C" {
#endif
-#include <stdint.h>
+#include <gdnative/math_defs.h>
-#define GODOT_PLANE_SIZE 16
+#define GODOT_PLANE_SIZE (sizeof(godot_real_t) * 4)
#ifndef GODOT_CORE_API_GODOT_PLANE_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_PLANE_TYPE_DEFINED
@@ -46,53 +46,9 @@ typedef struct {
} godot_plane;
#endif
-// reduce extern "C" nesting for VS2013
-#ifdef __cplusplus
-}
-#endif
-
#include <gdnative/gdnative.h>
-#include <gdnative/vector3.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void GDAPI godot_plane_new_with_reals(godot_plane *r_dest, const godot_real p_a, const godot_real p_b, const godot_real p_c, const godot_real p_d);
-void GDAPI godot_plane_new_with_vectors(godot_plane *r_dest, const godot_vector3 *p_v1, const godot_vector3 *p_v2, const godot_vector3 *p_v3);
-void GDAPI godot_plane_new_with_normal(godot_plane *r_dest, const godot_vector3 *p_normal, const godot_real p_d);
-
-godot_string GDAPI godot_plane_as_string(const godot_plane *p_self);
-
-godot_plane GDAPI godot_plane_normalized(const godot_plane *p_self);
-
-godot_vector3 GDAPI godot_plane_center(const godot_plane *p_self);
-
-godot_bool GDAPI godot_plane_is_point_over(const godot_plane *p_self, const godot_vector3 *p_point);
-
-godot_real GDAPI godot_plane_distance_to(const godot_plane *p_self, const godot_vector3 *p_point);
-
-godot_bool GDAPI godot_plane_has_point(const godot_plane *p_self, const godot_vector3 *p_point, const godot_real p_epsilon);
-
-godot_vector3 GDAPI godot_plane_project(const godot_plane *p_self, const godot_vector3 *p_point);
-
-godot_bool GDAPI godot_plane_intersect_3(const godot_plane *p_self, godot_vector3 *r_dest, const godot_plane *p_b, const godot_plane *p_c);
-
-godot_bool GDAPI godot_plane_intersects_ray(const godot_plane *p_self, godot_vector3 *r_dest, const godot_vector3 *p_from, const godot_vector3 *p_dir);
-
-godot_bool GDAPI godot_plane_intersects_segment(const godot_plane *p_self, godot_vector3 *r_dest, const godot_vector3 *p_begin, const godot_vector3 *p_end);
-
-godot_plane GDAPI godot_plane_operator_neg(const godot_plane *p_self);
-
-godot_bool GDAPI godot_plane_operator_equal(const godot_plane *p_self, const godot_plane *p_b);
-
-void GDAPI godot_plane_set_normal(godot_plane *p_self, const godot_vector3 *p_normal);
-
-godot_vector3 GDAPI godot_plane_get_normal(const godot_plane *p_self);
-
-godot_real GDAPI godot_plane_get_d(const godot_plane *p_self);
-void GDAPI godot_plane_set_d(godot_plane *p_self, const godot_real p_d);
+void GDAPI godot_plane_new(godot_plane *p_self);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/quat.h b/modules/gdnative/include/gdnative/quat.h
index d315b2d754..a87d0bdbe5 100644
--- a/modules/gdnative/include/gdnative/quat.h
+++ b/modules/gdnative/include/gdnative/quat.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,9 +35,9 @@
extern "C" {
#endif
-#include <stdint.h>
+#include <gdnative/math_defs.h>
-#define GODOT_QUAT_SIZE 16
+#define GODOT_QUAT_SIZE (sizeof(godot_real_t) * 4)
#ifndef GODOT_CORE_API_GODOT_QUAT_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_QUAT_TYPE_DEFINED
@@ -46,70 +46,9 @@ typedef struct {
} godot_quat;
#endif
-// reduce extern "C" nesting for VS2013
-#ifdef __cplusplus
-}
-#endif
-
#include <gdnative/gdnative.h>
-#include <gdnative/vector3.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void GDAPI godot_quat_new(godot_quat *r_dest, const godot_real p_x, const godot_real p_y, const godot_real p_z, const godot_real p_w);
-void GDAPI godot_quat_new_with_axis_angle(godot_quat *r_dest, const godot_vector3 *p_axis, const godot_real p_angle);
-void GDAPI godot_quat_new_with_basis(godot_quat *r_dest, const godot_basis *p_basis);
-void GDAPI godot_quat_new_with_euler(godot_quat *r_dest, const godot_vector3 *p_euler);
-
-godot_real GDAPI godot_quat_get_x(const godot_quat *p_self);
-void GDAPI godot_quat_set_x(godot_quat *p_self, const godot_real val);
-
-godot_real GDAPI godot_quat_get_y(const godot_quat *p_self);
-void GDAPI godot_quat_set_y(godot_quat *p_self, const godot_real val);
-
-godot_real GDAPI godot_quat_get_z(const godot_quat *p_self);
-void GDAPI godot_quat_set_z(godot_quat *p_self, const godot_real val);
-
-godot_real GDAPI godot_quat_get_w(const godot_quat *p_self);
-void GDAPI godot_quat_set_w(godot_quat *p_self, const godot_real val);
-
-godot_string GDAPI godot_quat_as_string(const godot_quat *p_self);
-
-godot_real GDAPI godot_quat_length(const godot_quat *p_self);
-
-godot_real GDAPI godot_quat_length_squared(const godot_quat *p_self);
-
-godot_quat GDAPI godot_quat_normalized(const godot_quat *p_self);
-
-godot_bool GDAPI godot_quat_is_normalized(const godot_quat *p_self);
-
-godot_quat GDAPI godot_quat_inverse(const godot_quat *p_self);
-
-godot_real GDAPI godot_quat_dot(const godot_quat *p_self, const godot_quat *p_b);
-
-godot_vector3 GDAPI godot_quat_xform(const godot_quat *p_self, const godot_vector3 *p_v);
-
-godot_quat GDAPI godot_quat_slerp(const godot_quat *p_self, const godot_quat *p_b, const godot_real p_t);
-
-godot_quat GDAPI godot_quat_slerpni(const godot_quat *p_self, const godot_quat *p_b, const godot_real p_t);
-
-godot_quat GDAPI godot_quat_cubic_slerp(const godot_quat *p_self, const godot_quat *p_b, const godot_quat *p_pre_a, const godot_quat *p_post_b, const godot_real p_t);
-
-godot_quat GDAPI godot_quat_operator_multiply(const godot_quat *p_self, const godot_real p_b);
-
-godot_quat GDAPI godot_quat_operator_add(const godot_quat *p_self, const godot_quat *p_b);
-
-godot_quat GDAPI godot_quat_operator_subtract(const godot_quat *p_self, const godot_quat *p_b);
-
-godot_quat GDAPI godot_quat_operator_divide(const godot_quat *p_self, const godot_real p_b);
-
-godot_bool GDAPI godot_quat_operator_equal(const godot_quat *p_self, const godot_quat *p_b);
-
-godot_quat GDAPI godot_quat_operator_neg(const godot_quat *p_self);
-void GDAPI godot_quat_set_axis_angle(godot_quat *p_self, const godot_vector3 *p_axis, const godot_real p_angle);
+void GDAPI godot_quat_new(godot_quat *p_self);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/rect2.h b/modules/gdnative/include/gdnative/rect2.h
index f317afc9da..9e51254cfe 100644
--- a/modules/gdnative/include/gdnative/rect2.h
+++ b/modules/gdnative/include/gdnative/rect2.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,119 +35,30 @@
extern "C" {
#endif
-#include <stdint.h>
+#include <gdnative/math_defs.h>
+
+#define GODOT_RECT2_SIZE (sizeof(godot_real_t) * 4)
#ifndef GODOT_CORE_API_GODOT_RECT2_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_RECT2_TYPE_DEFINED
typedef struct godot_rect2 {
- uint8_t _dont_touch_that[16];
+ uint8_t _dont_touch_that[GODOT_RECT2_SIZE];
} godot_rect2;
#endif
+#define GODOT_RECT2I_SIZE (sizeof(int32_t) * 4)
+
#ifndef GODOT_CORE_API_GODOT_RECT2I_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_RECT2I_TYPE_DEFINED
typedef struct godot_rect2i {
- uint8_t _dont_touch_that[16];
+ uint8_t _dont_touch_that[GODOT_RECT2I_SIZE];
} godot_rect2i;
#endif
-// reduce extern "C" nesting for VS2013
-#ifdef __cplusplus
-}
-#endif
-
#include <gdnative/gdnative.h>
-#include <gdnative/vector2.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Rect2
-
-void GDAPI godot_rect2_new_with_position_and_size(godot_rect2 *r_dest, const godot_vector2 *p_pos, const godot_vector2 *p_size);
-void GDAPI godot_rect2_new(godot_rect2 *r_dest, const godot_real p_x, const godot_real p_y, const godot_real p_width, const godot_real p_height);
-
-godot_string GDAPI godot_rect2_as_string(const godot_rect2 *p_self);
-
-godot_rect2i GDAPI godot_rect2_as_rect2i(const godot_rect2 *p_self);
-
-godot_real GDAPI godot_rect2_get_area(const godot_rect2 *p_self);
-
-godot_bool GDAPI godot_rect2_intersects(const godot_rect2 *p_self, const godot_rect2 *p_b);
-
-godot_bool GDAPI godot_rect2_encloses(const godot_rect2 *p_self, const godot_rect2 *p_b);
-
-godot_bool GDAPI godot_rect2_has_no_area(const godot_rect2 *p_self);
-
-godot_rect2 GDAPI godot_rect2_clip(const godot_rect2 *p_self, const godot_rect2 *p_b);
-
-godot_rect2 GDAPI godot_rect2_merge(const godot_rect2 *p_self, const godot_rect2 *p_b);
-
-godot_bool GDAPI godot_rect2_has_point(const godot_rect2 *p_self, const godot_vector2 *p_point);
-
-godot_rect2 GDAPI godot_rect2_grow(const godot_rect2 *p_self, const godot_real p_by);
-
-godot_rect2 GDAPI godot_rect2_grow_individual(const godot_rect2 *p_self, const godot_real p_left, const godot_real p_top, const godot_real p_right, const godot_real p_bottom);
-
-godot_rect2 GDAPI godot_rect2_grow_margin(const godot_rect2 *p_self, const godot_int p_margin, const godot_real p_by);
-
-godot_rect2 GDAPI godot_rect2_abs(const godot_rect2 *p_self);
-
-godot_rect2 GDAPI godot_rect2_expand(const godot_rect2 *p_self, const godot_vector2 *p_to);
-
-godot_bool GDAPI godot_rect2_operator_equal(const godot_rect2 *p_self, const godot_rect2 *p_b);
-
-godot_vector2 GDAPI godot_rect2_get_position(const godot_rect2 *p_self);
-
-godot_vector2 GDAPI godot_rect2_get_size(const godot_rect2 *p_self);
-
-void GDAPI godot_rect2_set_position(godot_rect2 *p_self, const godot_vector2 *p_pos);
-
-void GDAPI godot_rect2_set_size(godot_rect2 *p_self, const godot_vector2 *p_size);
-
-// Rect2I
-
-void GDAPI godot_rect2i_new_with_position_and_size(godot_rect2i *r_dest, const godot_vector2i *p_pos, const godot_vector2i *p_size);
-void GDAPI godot_rect2i_new(godot_rect2i *r_dest, const godot_int p_x, const godot_int p_y, const godot_int p_width, const godot_int p_height);
-
-godot_string GDAPI godot_rect2i_as_string(const godot_rect2i *p_self);
-
-godot_rect2 GDAPI godot_rect2i_as_rect2(const godot_rect2i *p_self);
-
-godot_int GDAPI godot_rect2i_get_area(const godot_rect2i *p_self);
-
-godot_bool GDAPI godot_rect2i_intersects(const godot_rect2i *p_self, const godot_rect2i *p_b);
-
-godot_bool GDAPI godot_rect2i_encloses(const godot_rect2i *p_self, const godot_rect2i *p_b);
-
-godot_bool GDAPI godot_rect2i_has_no_area(const godot_rect2i *p_self);
-
-godot_rect2i GDAPI godot_rect2i_clip(const godot_rect2i *p_self, const godot_rect2i *p_b);
-
-godot_rect2i GDAPI godot_rect2i_merge(const godot_rect2i *p_self, const godot_rect2i *p_b);
-
-godot_bool GDAPI godot_rect2i_has_point(const godot_rect2i *p_self, const godot_vector2i *p_point);
-
-godot_rect2i GDAPI godot_rect2i_grow(const godot_rect2i *p_self, const godot_int p_by);
-
-godot_rect2i GDAPI godot_rect2i_grow_individual(const godot_rect2i *p_self, const godot_int p_left, const godot_int p_top, const godot_int p_right, const godot_int p_bottom);
-
-godot_rect2i GDAPI godot_rect2i_grow_margin(const godot_rect2i *p_self, const godot_int p_margin, const godot_int p_by);
-
-godot_rect2i GDAPI godot_rect2i_abs(const godot_rect2i *p_self);
-
-godot_rect2i GDAPI godot_rect2i_expand(const godot_rect2i *p_self, const godot_vector2i *p_to);
-
-godot_bool GDAPI godot_rect2i_operator_equal(const godot_rect2i *p_self, const godot_rect2i *p_b);
-
-godot_vector2i GDAPI godot_rect2i_get_position(const godot_rect2i *p_self);
-
-godot_vector2i GDAPI godot_rect2i_get_size(const godot_rect2i *p_self);
-
-void GDAPI godot_rect2i_set_position(godot_rect2i *p_self, const godot_vector2i *p_pos);
-void GDAPI godot_rect2i_set_size(godot_rect2i *p_self, const godot_vector2i *p_size);
+void GDAPI godot_rect2_new(godot_rect2 *p_self);
+void GDAPI godot_rect2i_new(godot_rect2i *p_self);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/rid.h b/modules/gdnative/include/gdnative/rid.h
index 73b601dc04..7ea8cfd174 100644
--- a/modules/gdnative/include/gdnative/rid.h
+++ b/modules/gdnative/include/gdnative/rid.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -46,26 +46,9 @@ typedef struct {
} godot_rid;
#endif
-// reduce extern "C" nesting for VS2013
-#ifdef __cplusplus
-}
-#endif
-
#include <gdnative/gdnative.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void GDAPI godot_rid_new(godot_rid *r_dest);
-
-godot_int GDAPI godot_rid_get_id(const godot_rid *p_self);
-
-void GDAPI godot_rid_new_with_resource(godot_rid *r_dest, const godot_object *p_from);
-
-godot_bool GDAPI godot_rid_operator_equal(const godot_rid *p_self, const godot_rid *p_b);
-
-godot_bool GDAPI godot_rid_operator_less(const godot_rid *p_self, const godot_rid *p_b);
+void GDAPI godot_rid_new(godot_rid *p_self);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/signal.h b/modules/gdnative/include/gdnative/signal.h
new file mode 100644
index 0000000000..ad84542677
--- /dev/null
+++ b/modules/gdnative/include/gdnative/signal.h
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* signal.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GODOT_SIGNAL_H
+#define GODOT_SIGNAL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#define GODOT_SIGNAL_SIZE (16)
+
+#ifndef GODOT_CORE_API_GODOT_SIGNAL_TYPE_DEFINED
+#define GODOT_CORE_API_GODOT_SIGNAL_TYPE_DEFINED
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_SIGNAL_SIZE];
+} godot_signal;
+#endif
+
+#include <gdnative/gdnative.h>
+
+void GDAPI godot_signal_new(godot_signal *p_self);
+void GDAPI godot_signal_destroy(godot_signal *p_self);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/modules/gdnative/include/gdnative/string.h b/modules/gdnative/include/gdnative/string.h
index 0582d95f63..10fbb2c078 100644
--- a/modules/gdnative/include/gdnative/string.h
+++ b/modules/gdnative/include/gdnative/string.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,60 +35,30 @@
extern "C" {
#endif
+#include <stddef.h>
#include <stdint.h>
-#include <wchar.h>
+
+#ifndef __cplusplus
+typedef uint16_t char16_t;
+typedef uint32_t char32_t;
+#endif
typedef char32_t godot_char_type;
#define GODOT_STRING_SIZE sizeof(void *)
-#define GODOT_CHAR_STRING_SIZE sizeof(void *)
-#define GODOT_CHAR16_STRING_SIZE sizeof(void *)
#ifndef GODOT_CORE_API_GODOT_STRING_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_STRING_TYPE_DEFINED
typedef struct {
uint8_t _dont_touch_that[GODOT_STRING_SIZE];
} godot_string;
-
-#endif
-
-#ifndef GODOT_CORE_API_GODOT_CHAR_STRING_TYPE_DEFINED
-#define GODOT_CORE_API_GODOT_CHAR_STRING_TYPE_DEFINED
-typedef struct {
- uint8_t _dont_touch_that[GODOT_CHAR_STRING_SIZE];
-} godot_char_string;
-#endif
-
-#ifndef GODOT_CORE_API_GODOT_CHAR16_STRING_TYPE_DEFINED
-#define GODOT_CORE_API_GODOT_CHAR16_STRING_TYPE_DEFINED
-typedef struct {
- uint8_t _dont_touch_that[GODOT_CHAR16_STRING_SIZE];
-} godot_char16_string;
#endif
-// reduce extern "C" nesting for VS2013
-#ifdef __cplusplus
-}
-#endif
-
-#include <gdnative/array.h>
#include <gdnative/gdnative.h>
-#include <gdnative/variant.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-godot_int GDAPI godot_char_string_length(const godot_char_string *p_cs);
-const char GDAPI *godot_char_string_get_data(const godot_char_string *p_cs);
-void GDAPI godot_char_string_destroy(godot_char_string *p_cs);
-
-godot_int GDAPI godot_char16_string_length(const godot_char16_string *p_cs);
-const char16_t GDAPI *godot_char16_string_get_data(const godot_char16_string *p_cs);
-void GDAPI godot_char16_string_destroy(godot_char16_string *p_cs);
void GDAPI godot_string_new(godot_string *r_dest);
void GDAPI godot_string_new_copy(godot_string *r_dest, const godot_string *p_src);
+void GDAPI godot_string_destroy(godot_string *p_self);
void GDAPI godot_string_new_with_latin1_chars(godot_string *r_dest, const char *p_contents);
void GDAPI godot_string_new_with_utf8_chars(godot_string *r_dest, const char *p_contents);
@@ -102,198 +72,6 @@ void GDAPI godot_string_new_with_utf16_chars_and_len(godot_string *r_dest, const
void GDAPI godot_string_new_with_utf32_chars_and_len(godot_string *r_dest, const char32_t *p_contents, const int p_size);
void GDAPI godot_string_new_with_wide_chars_and_len(godot_string *r_dest, const wchar_t *p_contents, const int p_size);
-const godot_char_type GDAPI *godot_string_operator_index(godot_string *p_self, const godot_int p_idx);
-godot_char_type GDAPI godot_string_operator_index_const(const godot_string *p_self, const godot_int p_idx);
-const godot_char_type GDAPI *godot_string_get_data(const godot_string *p_self);
-
-godot_bool GDAPI godot_string_operator_equal(const godot_string *p_self, const godot_string *p_b);
-godot_bool GDAPI godot_string_operator_less(const godot_string *p_self, const godot_string *p_b);
-godot_string GDAPI godot_string_operator_plus(const godot_string *p_self, const godot_string *p_b);
-
-/* Standard size stuff */
-
-/*+++*/ godot_int GDAPI godot_string_length(const godot_string *p_self);
-
-/* Helpers */
-
-signed char GDAPI godot_string_casecmp_to(const godot_string *p_self, const godot_string *p_str);
-signed char GDAPI godot_string_nocasecmp_to(const godot_string *p_self, const godot_string *p_str);
-signed char GDAPI godot_string_naturalnocasecmp_to(const godot_string *p_self, const godot_string *p_str);
-
-godot_bool GDAPI godot_string_begins_with(const godot_string *p_self, const godot_string *p_string);
-godot_bool GDAPI godot_string_begins_with_char_array(const godot_string *p_self, const char *p_char_array);
-godot_packed_string_array GDAPI godot_string_bigrams(const godot_string *p_self);
-godot_string GDAPI godot_string_chr(godot_char_type p_character);
-godot_bool GDAPI godot_string_ends_with(const godot_string *p_self, const godot_string *p_string);
-godot_bool GDAPI godot_string_ends_with_char_array(const godot_string *p_self, const char *p_char_array);
-godot_int GDAPI godot_string_count(const godot_string *p_self, const godot_string *p_what, godot_int p_from, godot_int p_to);
-godot_int GDAPI godot_string_countn(const godot_string *p_self, const godot_string *p_what, godot_int p_from, godot_int p_to);
-godot_int GDAPI godot_string_find(const godot_string *p_self, const godot_string *p_what);
-godot_int GDAPI godot_string_find_from(const godot_string *p_self, const godot_string *p_what, godot_int p_from);
-godot_int GDAPI godot_string_findmk(const godot_string *p_self, const godot_packed_string_array *p_keys);
-godot_int GDAPI godot_string_findmk_from(const godot_string *p_self, const godot_packed_string_array *p_keys, godot_int p_from);
-godot_int GDAPI godot_string_findmk_from_in_place(const godot_string *p_self, const godot_packed_string_array *p_keys, godot_int p_from, godot_int *r_key);
-godot_int GDAPI godot_string_findn(const godot_string *p_self, const godot_string *p_what);
-godot_int GDAPI godot_string_findn_from(const godot_string *p_self, const godot_string *p_what, godot_int p_from);
-godot_string GDAPI godot_string_format(const godot_string *p_self, const godot_variant *p_values);
-godot_string GDAPI godot_string_format_with_custom_placeholder(const godot_string *p_self, const godot_variant *p_values, const char *p_placeholder);
-godot_string GDAPI godot_string_hex_encode_buffer(const uint8_t *p_buffer, godot_int p_len);
-godot_int GDAPI godot_string_hex_to_int(const godot_string *p_self);
-godot_int GDAPI godot_string_hex_to_int_with_prefix(const godot_string *p_self);
-godot_string GDAPI godot_string_insert(const godot_string *p_self, godot_int p_at_pos, const godot_string *p_string);
-godot_bool GDAPI godot_string_is_numeric(const godot_string *p_self);
-godot_bool GDAPI godot_string_is_subsequence_of(const godot_string *p_self, const godot_string *p_string);
-godot_bool GDAPI godot_string_is_subsequence_ofi(const godot_string *p_self, const godot_string *p_string);
-godot_string GDAPI godot_string_lpad(const godot_string *p_self, godot_int p_min_length);
-godot_string GDAPI godot_string_lpad_with_custom_character(const godot_string *p_self, godot_int p_min_length, const godot_string *p_character);
-godot_bool GDAPI godot_string_match(const godot_string *p_self, const godot_string *p_wildcard);
-godot_bool GDAPI godot_string_matchn(const godot_string *p_self, const godot_string *p_wildcard);
-godot_string GDAPI godot_string_md5(const uint8_t *p_md5);
-godot_string GDAPI godot_string_num(double p_num);
-godot_string GDAPI godot_string_num_int64(int64_t p_num, godot_int p_base);
-godot_string GDAPI godot_string_num_int64_capitalized(int64_t p_num, godot_int p_base, godot_bool p_capitalize_hex);
-godot_string GDAPI godot_string_num_real(double p_num);
-godot_string GDAPI godot_string_num_scientific(double p_num);
-godot_string GDAPI godot_string_num_with_decimals(double p_num, godot_int p_decimals);
-godot_string GDAPI godot_string_pad_decimals(const godot_string *p_self, godot_int p_digits);
-godot_string GDAPI godot_string_pad_zeros(const godot_string *p_self, godot_int p_digits);
-godot_string GDAPI godot_string_replace_first(const godot_string *p_self, const godot_string *p_key, const godot_string *p_with);
-godot_string GDAPI godot_string_replace(const godot_string *p_self, const godot_string *p_key, const godot_string *p_with);
-godot_string GDAPI godot_string_replacen(const godot_string *p_self, const godot_string *p_key, const godot_string *p_with);
-godot_int GDAPI godot_string_rfind(const godot_string *p_self, const godot_string *p_what);
-godot_int GDAPI godot_string_rfindn(const godot_string *p_self, const godot_string *p_what);
-godot_int GDAPI godot_string_rfind_from(const godot_string *p_self, const godot_string *p_what, godot_int p_from);
-godot_int GDAPI godot_string_rfindn_from(const godot_string *p_self, const godot_string *p_what, godot_int p_from);
-godot_string GDAPI godot_string_rpad(const godot_string *p_self, godot_int p_min_length);
-godot_string GDAPI godot_string_rpad_with_custom_character(const godot_string *p_self, godot_int p_min_length, const godot_string *p_character);
-godot_real GDAPI godot_string_similarity(const godot_string *p_self, const godot_string *p_string);
-godot_string GDAPI godot_string_sprintf(const godot_string *p_self, const godot_array *p_values, godot_bool *p_error);
-godot_string GDAPI godot_string_substr(const godot_string *p_self, godot_int p_from, godot_int p_chars);
-double GDAPI godot_string_to_float(const godot_string *p_self);
-godot_int GDAPI godot_string_to_int(const godot_string *p_self);
-
-godot_string GDAPI godot_string_camelcase_to_underscore(const godot_string *p_self);
-godot_string GDAPI godot_string_camelcase_to_underscore_lowercased(const godot_string *p_self);
-godot_string GDAPI godot_string_capitalize(const godot_string *p_self);
-
-double GDAPI godot_string_char_to_float(const char *p_what);
-double GDAPI godot_string_wchar_to_float(const wchar_t *p_str, const wchar_t **r_end);
-
-godot_int GDAPI godot_string_char_to_int(const char *p_what);
-godot_int GDAPI godot_string_wchar_to_int(const wchar_t *p_str);
-
-godot_int GDAPI godot_string_char_to_int_with_len(const char *p_what, godot_int p_len);
-godot_int GDAPI godot_string_wchar_to_int_with_len(const wchar_t *p_str, int p_len);
-
-godot_int GDAPI godot_string_get_slice_count(const godot_string *p_self, const godot_string *p_splitter);
-godot_string GDAPI godot_string_get_slice(const godot_string *p_self, const godot_string *p_splitter, godot_int p_slice);
-godot_string GDAPI godot_string_get_slicec(const godot_string *p_self, godot_char_type p_splitter, godot_int p_slice);
-
-godot_packed_string_array GDAPI godot_string_split(const godot_string *p_self, const godot_string *p_splitter);
-godot_packed_string_array GDAPI godot_string_split_allow_empty(const godot_string *p_self, const godot_string *p_splitter);
-godot_packed_string_array GDAPI godot_string_split_with_maxsplit(const godot_string *p_self, const godot_string *p_splitter, const godot_bool p_allow_empty, const godot_int p_maxsplit);
-
-godot_packed_string_array GDAPI godot_string_rsplit(const godot_string *p_self, const godot_string *p_splitter);
-godot_packed_string_array GDAPI godot_string_rsplit_allow_empty(const godot_string *p_self, const godot_string *p_splitter);
-godot_packed_string_array GDAPI godot_string_rsplit_with_maxsplit(const godot_string *p_self, const godot_string *p_splitter, const godot_bool p_allow_empty, const godot_int p_maxsplit);
-
-godot_packed_float32_array GDAPI godot_string_split_floats(const godot_string *p_self, const godot_string *p_splitter);
-godot_packed_float32_array GDAPI godot_string_split_floats_allow_empty(const godot_string *p_self, const godot_string *p_splitter);
-godot_packed_float32_array GDAPI godot_string_split_floats_mk(const godot_string *p_self, const godot_packed_string_array *p_splitters);
-godot_packed_float32_array GDAPI godot_string_split_floats_mk_allow_empty(const godot_string *p_self, const godot_packed_string_array *p_splitters);
-godot_packed_int32_array GDAPI godot_string_split_ints(const godot_string *p_self, const godot_string *p_splitter);
-godot_packed_int32_array GDAPI godot_string_split_ints_allow_empty(const godot_string *p_self, const godot_string *p_splitter);
-godot_packed_int32_array GDAPI godot_string_split_ints_mk(const godot_string *p_self, const godot_packed_string_array *p_splitters);
-godot_packed_int32_array GDAPI godot_string_split_ints_mk_allow_empty(const godot_string *p_self, const godot_packed_string_array *p_splitters);
-
-godot_packed_string_array GDAPI godot_string_split_spaces(const godot_string *p_self);
-
-godot_char_type GDAPI godot_string_char_lowercase(godot_char_type p_char);
-godot_char_type GDAPI godot_string_char_uppercase(godot_char_type p_char);
-godot_string GDAPI godot_string_to_lower(const godot_string *p_self);
-godot_string GDAPI godot_string_to_upper(const godot_string *p_self);
-
-godot_string GDAPI godot_string_get_basename(const godot_string *p_self);
-godot_string GDAPI godot_string_get_extension(const godot_string *p_self);
-godot_string GDAPI godot_string_left(const godot_string *p_self, godot_int p_pos);
-godot_char_type GDAPI godot_string_ord_at(const godot_string *p_self, godot_int p_idx);
-godot_string GDAPI godot_string_plus_file(const godot_string *p_self, const godot_string *p_file);
-godot_string GDAPI godot_string_right(const godot_string *p_self, godot_int p_pos);
-godot_string GDAPI godot_string_repeat(const godot_string *p_self, godot_int p_count);
-godot_string GDAPI godot_string_strip_edges(const godot_string *p_self, godot_bool p_left, godot_bool p_right);
-godot_string GDAPI godot_string_strip_escapes(const godot_string *p_self);
-
-void GDAPI godot_string_erase(godot_string *p_self, godot_int p_pos, godot_int p_chars);
-
-godot_char_string GDAPI godot_string_ascii(const godot_string *p_self);
-godot_char_string GDAPI godot_string_latin1(const godot_string *p_self);
-
-godot_char_string GDAPI godot_string_utf8(const godot_string *p_self);
-godot_bool GDAPI godot_string_parse_utf8(godot_string *p_self, const char *p_utf8);
-godot_bool GDAPI godot_string_parse_utf8_with_len(godot_string *p_self, const char *p_utf8, godot_int p_len);
-
-godot_char16_string GDAPI godot_string_utf16(const godot_string *p_self);
-godot_bool GDAPI godot_string_parse_utf16(godot_string *p_self, const char16_t *p_utf16);
-godot_bool GDAPI godot_string_parse_utf16_with_len(godot_string *p_self, const char16_t *p_utf16, godot_int p_len);
-
-uint32_t GDAPI godot_string_hash(const godot_string *p_self);
-uint64_t GDAPI godot_string_hash64(const godot_string *p_self);
-
-uint32_t GDAPI godot_string_hash_chars(const char *p_cstr);
-uint32_t GDAPI godot_string_hash_chars_with_len(const char *p_cstr, godot_int p_len);
-uint32_t GDAPI godot_string_hash_wide_chars(const wchar_t *p_str);
-uint32_t GDAPI godot_string_hash_wide_chars_with_len(const wchar_t *p_str, godot_int p_len);
-
-godot_packed_byte_array GDAPI godot_string_md5_buffer(const godot_string *p_self);
-godot_string GDAPI godot_string_md5_text(const godot_string *p_self);
-godot_packed_byte_array GDAPI godot_string_sha1_buffer(const godot_string *p_self);
-godot_string GDAPI godot_string_sha1_text(const godot_string *p_self);
-godot_packed_byte_array GDAPI godot_string_sha256_buffer(const godot_string *p_self);
-godot_string GDAPI godot_string_sha256_text(const godot_string *p_self);
-
-godot_bool godot_string_empty(const godot_string *p_self);
-
-// path functions
-godot_string GDAPI godot_string_get_base_dir(const godot_string *p_self);
-godot_string GDAPI godot_string_get_file(const godot_string *p_self);
-godot_string GDAPI godot_string_humanize_size(size_t p_size);
-godot_bool GDAPI godot_string_is_abs_path(const godot_string *p_self);
-godot_bool GDAPI godot_string_is_rel_path(const godot_string *p_self);
-godot_bool GDAPI godot_string_is_resource_file(const godot_string *p_self);
-godot_string GDAPI godot_string_path_to(const godot_string *p_self, const godot_string *p_path);
-godot_string GDAPI godot_string_path_to_file(const godot_string *p_self, const godot_string *p_path);
-godot_string GDAPI godot_string_simplify_path(const godot_string *p_self);
-
-godot_string GDAPI godot_string_c_escape(const godot_string *p_self);
-godot_string GDAPI godot_string_c_escape_multiline(const godot_string *p_self);
-godot_string GDAPI godot_string_c_unescape(const godot_string *p_self);
-godot_string GDAPI godot_string_http_escape(const godot_string *p_self);
-godot_string GDAPI godot_string_http_unescape(const godot_string *p_self);
-godot_string GDAPI godot_string_json_escape(const godot_string *p_self);
-godot_string GDAPI godot_string_xml_escape(const godot_string *p_self);
-godot_string GDAPI godot_string_xml_escape_with_quotes(const godot_string *p_self);
-godot_string GDAPI godot_string_xml_unescape(const godot_string *p_self);
-
-godot_string GDAPI godot_string_percent_decode(const godot_string *p_self);
-godot_string GDAPI godot_string_percent_encode(const godot_string *p_self);
-godot_string GDAPI godot_string_join(const godot_string *p_self, const godot_packed_string_array *p_parts);
-
-godot_bool GDAPI godot_string_is_valid_filename(const godot_string *p_self);
-godot_bool GDAPI godot_string_is_valid_float(const godot_string *p_self);
-godot_bool GDAPI godot_string_is_valid_hex_number(const godot_string *p_self, godot_bool p_with_prefix);
-godot_bool GDAPI godot_string_is_valid_html_color(const godot_string *p_self);
-godot_bool GDAPI godot_string_is_valid_identifier(const godot_string *p_self);
-godot_bool GDAPI godot_string_is_valid_integer(const godot_string *p_self);
-godot_bool GDAPI godot_string_is_valid_ip_address(const godot_string *p_self);
-
-godot_string GDAPI godot_string_dedent(const godot_string *p_self);
-godot_string GDAPI godot_string_trim_prefix(const godot_string *p_self, const godot_string *p_prefix);
-godot_string GDAPI godot_string_trim_suffix(const godot_string *p_self, const godot_string *p_suffix);
-godot_string GDAPI godot_string_lstrip(const godot_string *p_self, const godot_string *p_chars);
-godot_string GDAPI godot_string_rstrip(const godot_string *p_self, const godot_string *p_chars);
-
-void GDAPI godot_string_destroy(godot_string *p_self);
-
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/include/gdnative/string_name.h b/modules/gdnative/include/gdnative/string_name.h
index f2555ab98f..346f626e81 100644
--- a/modules/gdnative/include/gdnative/string_name.h
+++ b/modules/gdnative/include/gdnative/string_name.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -47,30 +47,14 @@ typedef struct {
} godot_string_name;
#endif
-// reduce extern "C" nesting for VS2013
-#ifdef __cplusplus
-}
-#endif
-
#include <gdnative/gdnative.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void GDAPI godot_string_name_new(godot_string_name *r_dest, const godot_string *p_name);
-void GDAPI godot_string_name_new_data(godot_string_name *r_dest, const char *p_name);
-
-godot_string GDAPI godot_string_name_get_name(const godot_string_name *p_self);
-
-uint32_t GDAPI godot_string_name_get_hash(const godot_string_name *p_self);
-const void GDAPI *godot_string_name_get_data_unique_pointer(const godot_string_name *p_self);
-
-godot_bool GDAPI godot_string_name_operator_equal(const godot_string_name *p_self, const godot_string_name *p_other);
-godot_bool GDAPI godot_string_name_operator_less(const godot_string_name *p_self, const godot_string_name *p_other);
-
+void GDAPI godot_string_name_new(godot_string_name *r_dest);
+void GDAPI godot_string_name_new_copy(godot_string_name *r_dest, const godot_string_name *p_src);
void GDAPI godot_string_name_destroy(godot_string_name *p_self);
+void GDAPI godot_string_name_new_with_latin1_chars(godot_string_name *r_dest, const char *p_contents);
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/include/gdnative/transform.h b/modules/gdnative/include/gdnative/transform.h
index bc51438b17..e67862d140 100644
--- a/modules/gdnative/include/gdnative/transform.h
+++ b/modules/gdnative/include/gdnative/transform.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,9 +35,9 @@
extern "C" {
#endif
-#include <stdint.h>
+#include <gdnative/math_defs.h>
-#define GODOT_TRANSFORM_SIZE 48
+#define GODOT_TRANSFORM_SIZE (sizeof(godot_real_t) * 12)
#ifndef GODOT_CORE_API_GODOT_TRANSFORM_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_TRANSFORM_TYPE_DEFINED
@@ -46,63 +46,9 @@ typedef struct {
} godot_transform;
#endif
-// reduce extern "C" nesting for VS2013
-#ifdef __cplusplus
-}
-#endif
-
-#include <gdnative/basis.h>
#include <gdnative/gdnative.h>
-#include <gdnative/variant.h>
-#include <gdnative/vector3.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void GDAPI godot_transform_new_with_axis_origin(godot_transform *r_dest, const godot_vector3 *p_x_axis, const godot_vector3 *p_y_axis, const godot_vector3 *p_z_axis, const godot_vector3 *p_origin);
-void GDAPI godot_transform_new(godot_transform *r_dest, const godot_basis *p_basis, const godot_vector3 *p_origin);
-void GDAPI godot_transform_new_with_quat(godot_transform *r_dest, const godot_quat *p_quat);
-
-godot_basis GDAPI godot_transform_get_basis(const godot_transform *p_self);
-void GDAPI godot_transform_set_basis(godot_transform *p_self, const godot_basis *p_v);
-
-godot_vector3 GDAPI godot_transform_get_origin(const godot_transform *p_self);
-void GDAPI godot_transform_set_origin(godot_transform *p_self, const godot_vector3 *p_v);
-
-godot_string GDAPI godot_transform_as_string(const godot_transform *p_self);
-
-godot_transform GDAPI godot_transform_inverse(const godot_transform *p_self);
-
-godot_transform GDAPI godot_transform_affine_inverse(const godot_transform *p_self);
-
-godot_transform GDAPI godot_transform_orthonormalized(const godot_transform *p_self);
-
-godot_transform GDAPI godot_transform_rotated(const godot_transform *p_self, const godot_vector3 *p_axis, const godot_real p_phi);
-
-godot_transform GDAPI godot_transform_scaled(const godot_transform *p_self, const godot_vector3 *p_scale);
-
-godot_transform GDAPI godot_transform_translated(const godot_transform *p_self, const godot_vector3 *p_ofs);
-
-godot_transform GDAPI godot_transform_looking_at(const godot_transform *p_self, const godot_vector3 *p_target, const godot_vector3 *p_up);
-
-godot_plane GDAPI godot_transform_xform_plane(const godot_transform *p_self, const godot_plane *p_v);
-
-godot_plane GDAPI godot_transform_xform_inv_plane(const godot_transform *p_self, const godot_plane *p_v);
-
-void GDAPI godot_transform_new_identity(godot_transform *r_dest);
-
-godot_bool GDAPI godot_transform_operator_equal(const godot_transform *p_self, const godot_transform *p_b);
-
-godot_transform GDAPI godot_transform_operator_multiply(const godot_transform *p_self, const godot_transform *p_b);
-
-godot_vector3 GDAPI godot_transform_xform_vector3(const godot_transform *p_self, const godot_vector3 *p_v);
-
-godot_vector3 GDAPI godot_transform_xform_inv_vector3(const godot_transform *p_self, const godot_vector3 *p_v);
-
-godot_aabb GDAPI godot_transform_xform_aabb(const godot_transform *p_self, const godot_aabb *p_v);
-godot_aabb GDAPI godot_transform_xform_inv_aabb(const godot_transform *p_self, const godot_aabb *p_v);
+void GDAPI godot_transform_new(godot_transform *p_self);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/transform2d.h b/modules/gdnative/include/gdnative/transform2d.h
index 6b414ca7b2..85e3a86972 100644
--- a/modules/gdnative/include/gdnative/transform2d.h
+++ b/modules/gdnative/include/gdnative/transform2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,9 +35,9 @@
extern "C" {
#endif
-#include <stdint.h>
+#include <gdnative/math_defs.h>
-#define GODOT_TRANSFORM2D_SIZE 24
+#define GODOT_TRANSFORM2D_SIZE (sizeof(godot_real_t) * 6)
#ifndef GODOT_CORE_API_GODOT_TRANSFORM2D_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_TRANSFORM2D_TYPE_DEFINED
@@ -46,61 +46,9 @@ typedef struct {
} godot_transform2d;
#endif
-// reduce extern "C" nesting for VS2013
-#ifdef __cplusplus
-}
-#endif
-
#include <gdnative/gdnative.h>
-#include <gdnative/variant.h>
-#include <gdnative/vector2.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void GDAPI godot_transform2d_new(godot_transform2d *r_dest, const godot_real p_rot, const godot_vector2 *p_pos);
-void GDAPI godot_transform2d_new_axis_origin(godot_transform2d *r_dest, const godot_vector2 *p_x_axis, const godot_vector2 *p_y_axis, const godot_vector2 *p_origin);
-
-godot_string GDAPI godot_transform2d_as_string(const godot_transform2d *p_self);
-
-godot_transform2d GDAPI godot_transform2d_inverse(const godot_transform2d *p_self);
-
-godot_transform2d GDAPI godot_transform2d_affine_inverse(const godot_transform2d *p_self);
-
-godot_real GDAPI godot_transform2d_get_rotation(const godot_transform2d *p_self);
-
-godot_vector2 GDAPI godot_transform2d_get_origin(const godot_transform2d *p_self);
-
-godot_vector2 GDAPI godot_transform2d_get_scale(const godot_transform2d *p_self);
-
-godot_transform2d GDAPI godot_transform2d_orthonormalized(const godot_transform2d *p_self);
-
-godot_transform2d GDAPI godot_transform2d_rotated(const godot_transform2d *p_self, const godot_real p_phi);
-
-godot_transform2d GDAPI godot_transform2d_scaled(const godot_transform2d *p_self, const godot_vector2 *p_scale);
-
-godot_transform2d GDAPI godot_transform2d_translated(const godot_transform2d *p_self, const godot_vector2 *p_offset);
-
-godot_vector2 GDAPI godot_transform2d_xform_vector2(const godot_transform2d *p_self, const godot_vector2 *p_v);
-
-godot_vector2 GDAPI godot_transform2d_xform_inv_vector2(const godot_transform2d *p_self, const godot_vector2 *p_v);
-
-godot_vector2 GDAPI godot_transform2d_basis_xform_vector2(const godot_transform2d *p_self, const godot_vector2 *p_v);
-
-godot_vector2 GDAPI godot_transform2d_basis_xform_inv_vector2(const godot_transform2d *p_self, const godot_vector2 *p_v);
-
-godot_transform2d GDAPI godot_transform2d_interpolate_with(const godot_transform2d *p_self, const godot_transform2d *p_m, const godot_real p_c);
-
-godot_bool GDAPI godot_transform2d_operator_equal(const godot_transform2d *p_self, const godot_transform2d *p_b);
-
-godot_transform2d GDAPI godot_transform2d_operator_multiply(const godot_transform2d *p_self, const godot_transform2d *p_b);
-
-void GDAPI godot_transform2d_new_identity(godot_transform2d *r_dest);
-
-godot_rect2 GDAPI godot_transform2d_xform_rect2(const godot_transform2d *p_self, const godot_rect2 *p_v);
-godot_rect2 GDAPI godot_transform2d_xform_inv_rect2(const godot_transform2d *p_self, const godot_rect2 *p_v);
+void GDAPI godot_transform2d_new(godot_transform2d *p_self);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/variant.h b/modules/gdnative/include/gdnative/variant.h
index 0a611b76e9..82bd030170 100644
--- a/modules/gdnative/include/gdnative/variant.h
+++ b/modules/gdnative/include/gdnative/variant.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,9 +35,9 @@
extern "C" {
#endif
-#include <stdint.h>
+#include <gdnative/math_defs.h>
-#define GODOT_VARIANT_SIZE (16 + sizeof(int64_t))
+#define GODOT_VARIANT_SIZE (sizeof(godot_real_t) * 4 + sizeof(int64_t))
#ifndef GODOT_CORE_API_GODOT_VARIANT_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_VARIANT_TYPE_DEFINED
@@ -52,7 +52,7 @@ typedef enum godot_variant_type {
// atomic types
GODOT_VARIANT_TYPE_BOOL,
GODOT_VARIANT_TYPE_INT,
- GODOT_VARIANT_TYPE_REAL,
+ GODOT_VARIANT_TYPE_FLOAT,
GODOT_VARIANT_TYPE_STRING,
// math types
@@ -146,10 +146,35 @@ typedef enum godot_variant_operator {
GODOT_VARIANT_OP_MAX,
} godot_variant_operator;
-// reduce extern "C" nesting for VS2013
-#ifdef __cplusplus
-}
-#endif
+typedef enum godot_variant_utility_function_type {
+ GODOT_UTILITY_FUNC_TYPE_MATH,
+ GODOT_UTILITY_FUNC_TYPE_RANDOM,
+ GODOT_UTILITY_FUNC_TYPE_GENERAL,
+} godot_variant_utility_function_type;
+
+// Types for function pointers.
+typedef void (*godot_validated_operator_evaluator)(const godot_variant *p_left, const godot_variant *p_right, godot_variant *r_result);
+typedef void (*godot_ptr_operator_evaluator)(const void *p_left, const void *p_right, void *r_result);
+typedef void (*godot_validated_builtin_method)(godot_variant *p_base, const godot_variant **p_args, int p_argument_count, godot_variant *r_return);
+typedef void (*godot_ptr_builtin_method)(void *p_base, const void **p_args, void *r_return, int p_argument_count);
+typedef void (*godot_validated_constructor)(godot_variant *p_base, const godot_variant **p_args);
+typedef void (*godot_ptr_constructor)(void *p_base, const void **p_args);
+typedef void (*godot_validated_setter)(godot_variant *p_base, const godot_variant *p_value);
+typedef void (*godot_validated_getter)(const godot_variant *p_base, godot_variant *r_value);
+typedef void (*godot_ptr_setter)(void *p_base, const void *p_value);
+typedef void (*godot_ptr_getter)(const void *p_base, void *r_value);
+typedef void (*godot_validated_indexed_setter)(godot_variant *p_base, godot_int p_index, const godot_variant *p_value, bool *r_oob);
+typedef void (*godot_validated_indexed_getter)(const godot_variant *p_base, godot_int p_index, godot_variant *r_value, bool *r_oob);
+typedef void (*godot_ptr_indexed_setter)(void *p_base, godot_int p_index, const void *p_value);
+typedef void (*godot_ptr_indexed_getter)(const void *p_base, godot_int p_index, void *r_value);
+typedef void (*godot_validated_keyed_setter)(godot_variant *p_base, const godot_variant *p_key, const godot_variant *p_value, bool *r_valid);
+typedef void (*godot_validated_keyed_getter)(const godot_variant *p_base, const godot_variant *p_key, godot_variant *r_value, bool *r_valid);
+typedef bool (*godot_validated_keyed_checker)(const godot_variant *p_base, const godot_variant *p_key, bool *r_valid);
+typedef void (*godot_ptr_keyed_setter)(void *p_base, const void *p_key, const void *p_value);
+typedef void (*godot_ptr_keyed_getter)(const void *p_base, const void *p_key, void *r_value);
+typedef bool (*godot_ptr_keyed_checker)(const godot_variant *p_base, const godot_variant *p_key);
+typedef void (*godot_validated_utility_function)(godot_variant *r_return, const godot_variant **p_arguments, int p_argument_count);
+typedef void (*godot_ptr_utility_function)(void *r_return, const void **p_arguments, int p_argument_count);
#include <gdnative/aabb.h>
#include <gdnative/array.h>
@@ -163,6 +188,7 @@ typedef enum godot_variant_operator {
#include <gdnative/quat.h>
#include <gdnative/rect2.h>
#include <gdnative/rid.h>
+#include <gdnative/signal.h>
#include <gdnative/string.h>
#include <gdnative/string_name.h>
#include <gdnative/transform.h>
@@ -173,22 +199,15 @@ typedef enum godot_variant_operator {
#include <gdnative/gdnative.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-godot_variant_type GDAPI godot_variant_get_type(const godot_variant *p_v);
+// Memory.
void GDAPI godot_variant_new_copy(godot_variant *r_dest, const godot_variant *p_src);
void GDAPI godot_variant_new_nil(godot_variant *r_dest);
-
void GDAPI godot_variant_new_bool(godot_variant *r_dest, const godot_bool p_b);
-void GDAPI godot_variant_new_uint(godot_variant *r_dest, const uint64_t p_i);
-void GDAPI godot_variant_new_int(godot_variant *r_dest, const int64_t p_i);
-void GDAPI godot_variant_new_real(godot_variant *r_dest, const double p_r);
+void GDAPI godot_variant_new_int(godot_variant *r_dest, const godot_int p_i);
+void GDAPI godot_variant_new_float(godot_variant *r_dest, const godot_float p_f);
void GDAPI godot_variant_new_string(godot_variant *r_dest, const godot_string *p_s);
-void GDAPI godot_variant_new_string_name(godot_variant *r_dest, const godot_string_name *p_s);
void GDAPI godot_variant_new_vector2(godot_variant *r_dest, const godot_vector2 *p_v2);
void GDAPI godot_variant_new_vector2i(godot_variant *r_dest, const godot_vector2i *p_v2);
void GDAPI godot_variant_new_rect2(godot_variant *r_dest, const godot_rect2 *p_rect2);
@@ -202,11 +221,12 @@ void GDAPI godot_variant_new_aabb(godot_variant *r_dest, const godot_aabb *p_aab
void GDAPI godot_variant_new_basis(godot_variant *r_dest, const godot_basis *p_basis);
void GDAPI godot_variant_new_transform(godot_variant *r_dest, const godot_transform *p_trans);
void GDAPI godot_variant_new_color(godot_variant *r_dest, const godot_color *p_color);
+void GDAPI godot_variant_new_string_name(godot_variant *r_dest, const godot_string_name *p_s);
void GDAPI godot_variant_new_node_path(godot_variant *r_dest, const godot_node_path *p_np);
void GDAPI godot_variant_new_rid(godot_variant *r_dest, const godot_rid *p_rid);
+void GDAPI godot_variant_new_object(godot_variant *r_dest, const godot_object *p_obj);
void GDAPI godot_variant_new_callable(godot_variant *r_dest, const godot_callable *p_callable);
void GDAPI godot_variant_new_signal(godot_variant *r_dest, const godot_signal *p_signal);
-void GDAPI godot_variant_new_object(godot_variant *r_dest, const godot_object *p_obj);
void GDAPI godot_variant_new_dictionary(godot_variant *r_dest, const godot_dictionary *p_dict);
void GDAPI godot_variant_new_array(godot_variant *r_dest, const godot_array *p_arr);
void GDAPI godot_variant_new_packed_byte_array(godot_variant *r_dest, const godot_packed_byte_array *p_pba);
@@ -220,11 +240,9 @@ void GDAPI godot_variant_new_packed_vector3_array(godot_variant *r_dest, const g
void GDAPI godot_variant_new_packed_color_array(godot_variant *r_dest, const godot_packed_color_array *p_pca);
godot_bool GDAPI godot_variant_as_bool(const godot_variant *p_self);
-uint64_t GDAPI godot_variant_as_uint(const godot_variant *p_self);
-int64_t GDAPI godot_variant_as_int(const godot_variant *p_self);
-double GDAPI godot_variant_as_real(const godot_variant *p_self);
+godot_int GDAPI godot_variant_as_int(const godot_variant *p_self);
+godot_float GDAPI godot_variant_as_float(const godot_variant *p_self);
godot_string GDAPI godot_variant_as_string(const godot_variant *p_self);
-godot_string_name GDAPI godot_variant_as_string_name(const godot_variant *p_self);
godot_vector2 GDAPI godot_variant_as_vector2(const godot_variant *p_self);
godot_vector2i GDAPI godot_variant_as_vector2i(const godot_variant *p_self);
godot_rect2 GDAPI godot_variant_as_rect2(const godot_variant *p_self);
@@ -238,11 +256,12 @@ godot_aabb GDAPI godot_variant_as_aabb(const godot_variant *p_self);
godot_basis GDAPI godot_variant_as_basis(const godot_variant *p_self);
godot_transform GDAPI godot_variant_as_transform(const godot_variant *p_self);
godot_color GDAPI godot_variant_as_color(const godot_variant *p_self);
+godot_string_name GDAPI godot_variant_as_string_name(const godot_variant *p_self);
godot_node_path GDAPI godot_variant_as_node_path(const godot_variant *p_self);
godot_rid GDAPI godot_variant_as_rid(const godot_variant *p_self);
+godot_object GDAPI *godot_variant_as_object(const godot_variant *p_self);
godot_callable GDAPI godot_variant_as_callable(const godot_variant *p_self);
godot_signal GDAPI godot_variant_as_signal(const godot_variant *p_self);
-godot_object GDAPI *godot_variant_as_object(const godot_variant *p_self);
godot_dictionary GDAPI godot_variant_as_dictionary(const godot_variant *p_self);
godot_array GDAPI godot_variant_as_array(const godot_variant *p_self);
godot_packed_byte_array GDAPI godot_variant_as_packed_byte_array(const godot_variant *p_self);
@@ -255,24 +274,149 @@ godot_packed_vector2_array GDAPI godot_variant_as_packed_vector2_array(const god
godot_packed_vector3_array GDAPI godot_variant_as_packed_vector3_array(const godot_variant *p_self);
godot_packed_color_array GDAPI godot_variant_as_packed_color_array(const godot_variant *p_self);
-godot_variant GDAPI godot_variant_call(godot_variant *p_self, const godot_string *p_method, const godot_variant **p_args, const godot_int p_argcount, godot_variant_call_error *r_error);
-
-godot_bool GDAPI godot_variant_has_method(const godot_variant *p_self, const godot_string *p_method);
-
-godot_bool GDAPI godot_variant_operator_equal(const godot_variant *p_self, const godot_variant *p_other);
-godot_bool GDAPI godot_variant_operator_less(const godot_variant *p_self, const godot_variant *p_other);
+void GDAPI godot_variant_destroy(godot_variant *p_self);
-uint32_t GDAPI godot_variant_hash(const godot_variant *p_self);
+// Dynamic interaction.
+
+void GDAPI godot_variant_call(godot_variant *p_self, const godot_string_name *p_method, const godot_variant **p_args, const godot_int p_argument_count, godot_variant *r_return, godot_variant_call_error *r_error);
+void GDAPI godot_variant_call_with_cstring(godot_variant *p_self, const char *p_method, const godot_variant **p_args, const godot_int p_argument_count, godot_variant *r_return, godot_variant_call_error *r_error);
+void GDAPI godot_variant_evaluate(godot_variant_operator p_op, const godot_variant *p_a, const godot_variant *p_b, godot_variant *r_return, bool *r_valid);
+void GDAPI godot_variant_set(godot_variant *p_self, const godot_variant *p_key, const godot_variant *p_value, bool *r_valid);
+void GDAPI godot_variant_set_named(godot_variant *p_self, const godot_string_name *p_name, const godot_variant *p_value, bool *r_valid);
+void GDAPI godot_variant_set_named_with_cstring(godot_variant *p_self, const char *p_name, const godot_variant *p_value, bool *r_valid);
+void GDAPI godot_variant_set_keyed(godot_variant *p_self, const godot_variant *p_key, const godot_variant *p_value, bool *r_valid);
+void GDAPI godot_variant_set_indexed(godot_variant *p_self, godot_int p_index, const godot_variant *p_value, bool *r_valid, bool *r_oob);
+godot_variant GDAPI godot_variant_get(const godot_variant *p_self, const godot_variant *p_key, bool *r_valid);
+godot_variant GDAPI godot_variant_get_named(const godot_variant *p_self, const godot_string_name *p_key, bool *r_valid);
+godot_variant GDAPI godot_variant_get_named_with_cstring(const godot_variant *p_self, const char *p_key, bool *r_valid);
+godot_variant GDAPI godot_variant_get_keyed(const godot_variant *p_self, const godot_variant *p_key, bool *r_valid);
+godot_variant GDAPI godot_variant_get_indexed(const godot_variant *p_self, godot_int p_index, bool *r_valid, bool *r_oob);
+/// Iteration.
+bool GDAPI godot_variant_iter_init(const godot_variant *p_self, godot_variant *r_iter, bool *r_valid);
+bool GDAPI godot_variant_iter_next(const godot_variant *p_self, godot_variant *r_iter, bool *r_valid);
+godot_variant GDAPI godot_variant_iter_get(const godot_variant *p_self, godot_variant *r_iter, bool *r_valid);
+
+/// Variant functions.
godot_bool GDAPI godot_variant_hash_compare(const godot_variant *p_self, const godot_variant *p_other);
-
godot_bool GDAPI godot_variant_booleanize(const godot_variant *p_self);
-
-void GDAPI godot_variant_destroy(godot_variant *p_self);
-
-// GDNative core 1.1
-
-godot_string GDAPI godot_variant_get_operator_name(godot_variant_operator p_op);
-void GDAPI godot_variant_evaluate(godot_variant_operator p_op, const godot_variant *p_a, const godot_variant *p_b, godot_variant *r_ret, godot_bool *r_valid);
+void GDAPI godot_variant_blend(const godot_variant *p_a, const godot_variant *p_b, float p_c, godot_variant *r_dst);
+void GDAPI godot_variant_interpolate(const godot_variant *p_a, const godot_variant *p_b, float p_c, godot_variant *r_dst);
+godot_variant GDAPI godot_variant_duplicate(const godot_variant *p_self, godot_bool p_deep);
+godot_string GDAPI godot_variant_stringify(const godot_variant *p_self);
+
+// Discovery API.
+
+/// Operators.
+godot_validated_operator_evaluator GDAPI godot_variant_get_validated_operator_evaluator(godot_variant_operator p_operator, godot_variant_type p_type_a, godot_variant_type p_type_b);
+godot_ptr_operator_evaluator GDAPI godot_variant_get_ptr_operator_evaluator(godot_variant_operator p_operator, godot_variant_type p_type_a, godot_variant_type p_type_b);
+godot_variant_type GDAPI godot_variant_get_operator_return_type(godot_variant_operator p_operator, godot_variant_type p_type_a, godot_variant_type p_type_b);
+godot_string GDAPI godot_variant_get_operator_name(godot_variant_operator p_operator);
+
+/// Built-in methods.
+bool GDAPI godot_variant_has_builtin_method(godot_variant_type p_type, const godot_string_name *p_method);
+bool GDAPI godot_variant_has_builtin_method_with_cstring(godot_variant_type p_type, const char *p_method);
+godot_validated_builtin_method GDAPI godot_variant_get_validated_builtin_method(godot_variant_type p_type, const godot_string_name *p_method);
+godot_validated_builtin_method GDAPI godot_variant_get_validated_builtin_method_with_cstring(godot_variant_type p_type, const char *p_method);
+godot_ptr_builtin_method GDAPI godot_variant_get_ptr_builtin_method(godot_variant_type p_type, const godot_string_name *p_method);
+godot_ptr_builtin_method GDAPI godot_variant_get_ptr_builtin_method_with_cstring(godot_variant_type p_type, const char *p_method);
+int GDAPI godot_variant_get_builtin_method_argument_count(godot_variant_type p_type, const godot_string_name *p_method);
+int GDAPI godot_variant_get_builtin_method_argument_count_with_cstring(godot_variant_type p_type, const char *p_method);
+godot_variant_type GDAPI godot_variant_get_builtin_method_argument_type(godot_variant_type p_type, const godot_string_name *p_method, int p_argument);
+godot_variant_type GDAPI godot_variant_get_builtin_method_argument_type_with_cstring(godot_variant_type p_type, const char *p_method, int p_argument);
+godot_string GDAPI godot_variant_get_builtin_method_argument_name(godot_variant_type p_type, const godot_string_name *p_method, int p_argument);
+godot_string GDAPI godot_variant_get_builtin_method_argument_name_with_cstring(godot_variant_type p_type, const char *p_method, int p_argument);
+bool GDAPI godot_variant_has_builtin_method_return_value(godot_variant_type p_type, const godot_string_name *p_method);
+bool GDAPI godot_variant_has_builtin_method_return_value_with_cstring(godot_variant_type p_type, const char *p_method);
+godot_variant_type GDAPI godot_variant_get_builtin_method_return_type(godot_variant_type p_type, const godot_string_name *p_method);
+godot_variant_type GDAPI godot_variant_get_builtin_method_return_type_with_cstring(godot_variant_type p_type, const char *p_method);
+bool GDAPI godot_variant_is_builtin_method_const(godot_variant_type p_type, const godot_string_name *p_method);
+bool GDAPI godot_variant_is_builtin_method_const_with_cstring(godot_variant_type p_type, const char *p_method);
+bool GDAPI godot_variant_is_builtin_method_vararg(godot_variant_type p_type, const godot_string_name *p_method);
+bool GDAPI godot_variant_is_builtin_method_vararg_with_cstring(godot_variant_type p_type, const char *p_method);
+int GDAPI godot_variant_get_builtin_method_count(godot_variant_type p_type);
+void GDAPI godot_variant_get_builtin_method_list(godot_variant_type p_type, godot_string_name *r_list);
+
+/// Constructors.
+int GDAPI godot_variant_get_constructor_count(godot_variant_type p_type);
+godot_validated_constructor GDAPI godot_variant_get_validated_constructor(godot_variant_type p_type, int p_constructor);
+godot_ptr_constructor GDAPI godot_variant_get_ptr_constructor(godot_variant_type p_type, int p_constructor);
+int GDAPI godot_variant_get_constructor_argument_count(godot_variant_type p_type, int p_constructor);
+godot_variant_type GDAPI godot_variant_get_constructor_argument_type(godot_variant_type p_type, int p_constructor, int p_argument);
+godot_string GDAPI godot_variant_get_constructor_argument_name(godot_variant_type p_type, int p_constructor, int p_argument);
+void GDAPI godot_variant_construct(godot_variant_type p_type, godot_variant *p_base, const godot_variant **p_args, int p_argument_count, godot_variant_call_error *r_error);
+
+/// Properties.
+godot_variant_type GDAPI godot_variant_get_member_type(godot_variant_type p_type, const godot_string_name *p_member);
+godot_variant_type GDAPI godot_variant_get_member_type_with_cstring(godot_variant_type p_type, const char *p_member);
+int GDAPI godot_variant_get_member_count(godot_variant_type p_type);
+void GDAPI godot_variant_get_member_list(godot_variant_type p_type, godot_string_name *r_list);
+godot_validated_setter GDAPI godot_variant_get_validated_setter(godot_variant_type p_type, const godot_string_name *p_member);
+godot_validated_setter GDAPI godot_variant_get_validated_setter_with_cstring(godot_variant_type p_type, const char *p_member);
+godot_validated_getter GDAPI godot_variant_get_validated_getter(godot_variant_type p_type, const godot_string_name *p_member);
+godot_validated_getter GDAPI godot_variant_get_validated_getter_with_cstring(godot_variant_type p_type, const char *p_member);
+godot_ptr_setter GDAPI godot_variant_get_ptr_setter(godot_variant_type p_type, const godot_string_name *p_member);
+godot_ptr_setter GDAPI godot_variant_get_ptr_setter_with_cstring(godot_variant_type p_type, const char *p_member);
+godot_ptr_getter GDAPI godot_variant_get_ptr_getter(godot_variant_type p_type, const godot_string_name *p_member);
+godot_ptr_getter GDAPI godot_variant_get_ptr_getter_with_cstring(godot_variant_type p_type, const char *p_member);
+
+/// Indexing.
+bool GDAPI godot_variant_has_indexing(godot_variant_type p_type);
+godot_variant_type GDAPI godot_variant_get_indexed_element_type(godot_variant_type p_type);
+godot_validated_indexed_setter GDAPI godot_variant_get_validated_indexed_setter(godot_variant_type p_type);
+godot_validated_indexed_getter GDAPI godot_variant_get_validated_indexed_getter(godot_variant_type p_type);
+godot_ptr_indexed_setter GDAPI godot_variant_get_ptr_indexed_setter(godot_variant_type p_type);
+godot_ptr_indexed_getter GDAPI godot_variant_get_ptr_indexed_getter(godot_variant_type p_type);
+uint64_t GDAPI godot_variant_get_indexed_size(const godot_variant *p_self);
+
+/// Keying.
+bool GDAPI godot_variant_is_keyed(godot_variant_type p_type);
+godot_validated_keyed_setter GDAPI godot_variant_get_validated_keyed_setter(godot_variant_type p_type);
+godot_validated_keyed_getter GDAPI godot_variant_get_validated_keyed_getter(godot_variant_type p_type);
+godot_validated_keyed_checker GDAPI godot_variant_get_validated_keyed_checker(godot_variant_type p_type);
+godot_ptr_keyed_setter GDAPI godot_variant_get_ptr_keyed_setter(godot_variant_type p_type);
+godot_ptr_keyed_getter GDAPI godot_variant_get_ptr_keyed_getter(godot_variant_type p_type);
+godot_ptr_keyed_checker GDAPI godot_variant_get_ptr_keyed_checker(godot_variant_type p_type);
+
+/// Constants.
+int GDAPI godot_variant_get_constants_count(godot_variant_type p_type);
+void GDAPI godot_variant_get_constants_list(godot_variant_type p_type, godot_string_name *r_list);
+bool GDAPI godot_variant_has_constant(godot_variant_type p_type, const godot_string_name *p_constant);
+bool GDAPI godot_variant_has_constant_with_cstring(godot_variant_type p_type, const char *p_constant);
+godot_variant GDAPI godot_variant_get_constant_value(godot_variant_type p_type, const godot_string_name *p_constant);
+godot_variant GDAPI godot_variant_get_constant_value_with_cstring(godot_variant_type p_type, const char *p_constant);
+
+/// Utilities.
+bool GDAPI godot_variant_has_utility_function(const godot_string_name *p_function);
+bool GDAPI godot_variant_has_utility_function_with_cstring(const char *p_function);
+void GDAPI godot_variant_call_utility_function(const godot_string_name *p_function, godot_variant *r_ret, const godot_variant **p_args, int p_argument_count, godot_variant_call_error *r_error);
+void GDAPI godot_variant_call_utility_function_with_cstring(const char *p_function, godot_variant *r_ret, const godot_variant **p_args, int p_argument_count, godot_variant_call_error *r_error);
+godot_variant_utility_function_type GDAPI godot_variant_get_utility_function_type(const godot_string_name *p_function);
+godot_variant_utility_function_type GDAPI godot_variant_get_utility_function_type_with_cstring(const char *p_function);
+int GDAPI godot_variant_get_utility_function_argument_count(const godot_string_name *p_function);
+int GDAPI godot_variant_get_utility_function_argument_count_with_cstring(const char *p_function);
+godot_variant_type GDAPI godot_variant_get_utility_function_argument_type(const godot_string_name *p_function, int p_argument);
+godot_variant_type GDAPI godot_variant_get_utility_function_argument_type_with_cstring(const char *p_function, int p_argument);
+godot_string GDAPI godot_variant_get_utility_function_argument_name(const godot_string_name *p_function, int p_argument);
+godot_string GDAPI godot_variant_get_utility_function_argument_name_with_cstring(const char *p_function, int p_argument);
+bool GDAPI godot_variant_has_utility_function_return_value(const godot_string_name *p_function);
+bool GDAPI godot_variant_has_utility_function_return_value_with_cstring(const char *p_function);
+godot_variant_type GDAPI godot_variant_get_utility_function_return_type(const godot_string_name *p_function);
+godot_variant_type GDAPI godot_variant_get_utility_function_return_type_with_cstring(const char *p_function);
+bool GDAPI godot_variant_is_utility_function_vararg(const godot_string_name *p_function);
+bool GDAPI godot_variant_is_utility_function_vararg_with_cstring(const char *p_function);
+int GDAPI godot_variant_get_utility_function_count();
+void GDAPI godot_variant_get_utility_function_list(godot_string_name *r_functions);
+
+// Introspection.
+
+godot_variant_type GDAPI godot_variant_get_type(const godot_variant *p_self);
+bool GDAPI godot_variant_has_method(const godot_variant *p_self, const godot_string_name *p_method);
+bool GDAPI godot_variant_has_member(godot_variant_type p_type, const godot_string_name *p_member);
+bool GDAPI godot_variant_has_key(const godot_variant *p_self, const godot_variant *p_key, bool *r_valid);
+
+godot_string GDAPI godot_variant_get_type_name(godot_variant_type p_type);
+bool GDAPI godot_variant_can_convert(godot_variant_type p_from, godot_variant_type p_to);
+bool GDAPI godot_variant_can_convert_strict(godot_variant_type p_from, godot_variant_type p_to);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/vector2.h b/modules/gdnative/include/gdnative/vector2.h
index 35b02c5a75..a21ab304d0 100644
--- a/modules/gdnative/include/gdnative/vector2.h
+++ b/modules/gdnative/include/gdnative/vector2.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,9 +35,9 @@
extern "C" {
#endif
-#include <stdint.h>
+#include <gdnative/math_defs.h>
-#define GODOT_VECTOR2_SIZE 8
+#define GODOT_VECTOR2_SIZE (sizeof(godot_real_t) * 2)
#ifndef GODOT_CORE_API_GODOT_VECTOR2_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_VECTOR2_TYPE_DEFINED
@@ -46,7 +46,7 @@ typedef struct {
} godot_vector2;
#endif
-#define GODOT_VECTOR2I_SIZE 8
+#define GODOT_VECTOR2I_SIZE (sizeof(int32_t) * 2)
#ifndef GODOT_CORE_API_GODOT_VECTOR2I_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_VECTOR2I_TYPE_DEFINED
@@ -55,140 +55,10 @@ typedef struct {
} godot_vector2i;
#endif
-// reduce extern "C" nesting for VS2013
-#ifdef __cplusplus
-}
-#endif
-
#include <gdnative/gdnative.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Vector2
-
-void GDAPI godot_vector2_new(godot_vector2 *r_dest, const godot_real p_x, const godot_real p_y);
-
-godot_string GDAPI godot_vector2_as_string(const godot_vector2 *p_self);
-
-godot_vector2i GDAPI godot_vector2_as_vector2i(const godot_vector2 *p_self);
-
-godot_vector2 GDAPI godot_vector2_normalized(const godot_vector2 *p_self);
-
-godot_real GDAPI godot_vector2_length(const godot_vector2 *p_self);
-
-godot_real GDAPI godot_vector2_angle(const godot_vector2 *p_self);
-
-godot_real GDAPI godot_vector2_length_squared(const godot_vector2 *p_self);
-
-godot_bool GDAPI godot_vector2_is_normalized(const godot_vector2 *p_self);
-
-godot_vector2 GDAPI godot_vector2_direction_to(const godot_vector2 *p_self, const godot_vector2 *p_b);
-
-godot_real GDAPI godot_vector2_distance_to(const godot_vector2 *p_self, const godot_vector2 *p_to);
-
-godot_real GDAPI godot_vector2_distance_squared_to(const godot_vector2 *p_self, const godot_vector2 *p_to);
-
-godot_real GDAPI godot_vector2_angle_to(const godot_vector2 *p_self, const godot_vector2 *p_to);
-
-godot_real GDAPI godot_vector2_angle_to_point(const godot_vector2 *p_self, const godot_vector2 *p_to);
-
-godot_vector2 GDAPI godot_vector2_lerp(const godot_vector2 *p_self, const godot_vector2 *p_b, const godot_real p_t);
-
-godot_vector2 GDAPI godot_vector2_cubic_interpolate(const godot_vector2 *p_self, const godot_vector2 *p_b, const godot_vector2 *p_pre_a, const godot_vector2 *p_post_b, const godot_real p_t);
-
-godot_vector2 GDAPI godot_vector2_move_toward(const godot_vector2 *p_self, const godot_vector2 *p_to, const godot_real p_delta);
-
-godot_vector2 GDAPI godot_vector2_rotated(const godot_vector2 *p_self, const godot_real p_phi);
-
-godot_vector2 GDAPI godot_vector2_tangent(const godot_vector2 *p_self);
-
-godot_vector2 GDAPI godot_vector2_floor(const godot_vector2 *p_self);
-
-godot_vector2 GDAPI godot_vector2_sign(const godot_vector2 *p_self);
-
-godot_vector2 GDAPI godot_vector2_snapped(const godot_vector2 *p_self, const godot_vector2 *p_by);
-
-godot_real GDAPI godot_vector2_aspect(const godot_vector2 *p_self);
-
-godot_real GDAPI godot_vector2_dot(const godot_vector2 *p_self, const godot_vector2 *p_with);
-
-godot_vector2 GDAPI godot_vector2_slide(const godot_vector2 *p_self, const godot_vector2 *p_n);
-
-godot_vector2 GDAPI godot_vector2_bounce(const godot_vector2 *p_self, const godot_vector2 *p_n);
-
-godot_vector2 GDAPI godot_vector2_reflect(const godot_vector2 *p_self, const godot_vector2 *p_n);
-
-godot_vector2 GDAPI godot_vector2_abs(const godot_vector2 *p_self);
-
-godot_vector2 GDAPI godot_vector2_clamped(const godot_vector2 *p_self, const godot_real p_length);
-
-godot_vector2 GDAPI godot_vector2_operator_add(const godot_vector2 *p_self, const godot_vector2 *p_b);
-
-godot_vector2 GDAPI godot_vector2_operator_subtract(const godot_vector2 *p_self, const godot_vector2 *p_b);
-
-godot_vector2 GDAPI godot_vector2_operator_multiply_vector(const godot_vector2 *p_self, const godot_vector2 *p_b);
-
-godot_vector2 GDAPI godot_vector2_operator_multiply_scalar(const godot_vector2 *p_self, const godot_real p_b);
-
-godot_vector2 GDAPI godot_vector2_operator_divide_vector(const godot_vector2 *p_self, const godot_vector2 *p_b);
-
-godot_vector2 GDAPI godot_vector2_operator_divide_scalar(const godot_vector2 *p_self, const godot_real p_b);
-
-godot_bool GDAPI godot_vector2_operator_equal(const godot_vector2 *p_self, const godot_vector2 *p_b);
-
-godot_bool GDAPI godot_vector2_operator_less(const godot_vector2 *p_self, const godot_vector2 *p_b);
-
-godot_vector2 GDAPI godot_vector2_operator_neg(const godot_vector2 *p_self);
-
-void GDAPI godot_vector2_set_x(godot_vector2 *p_self, const godot_real p_x);
-
-void GDAPI godot_vector2_set_y(godot_vector2 *p_self, const godot_real p_y);
-
-godot_real GDAPI godot_vector2_get_x(const godot_vector2 *p_self);
-
-godot_real GDAPI godot_vector2_get_y(const godot_vector2 *p_self);
-
-// Vector2i
-
-void GDAPI godot_vector2i_new(godot_vector2i *r_dest, const godot_int p_x, const godot_int p_y);
-
-godot_string GDAPI godot_vector2i_as_string(const godot_vector2i *p_self);
-
-godot_vector2 GDAPI godot_vector2i_as_vector2(const godot_vector2i *p_self);
-
-godot_real GDAPI godot_vector2i_aspect(const godot_vector2i *p_self);
-
-godot_vector2i GDAPI godot_vector2i_abs(const godot_vector2i *p_self);
-
-godot_vector2i GDAPI godot_vector2i_sign(const godot_vector2i *p_self);
-
-godot_vector2i GDAPI godot_vector2i_operator_add(const godot_vector2i *p_self, const godot_vector2i *p_b);
-
-godot_vector2i GDAPI godot_vector2i_operator_subtract(const godot_vector2i *p_self, const godot_vector2i *p_b);
-
-godot_vector2i GDAPI godot_vector2i_operator_multiply_vector(const godot_vector2i *p_self, const godot_vector2i *p_b);
-
-godot_vector2i GDAPI godot_vector2i_operator_multiply_scalar(const godot_vector2i *p_self, const godot_int p_b);
-
-godot_vector2i GDAPI godot_vector2i_operator_divide_vector(const godot_vector2i *p_self, const godot_vector2i *p_b);
-
-godot_vector2i GDAPI godot_vector2i_operator_divide_scalar(const godot_vector2i *p_self, const godot_int p_b);
-
-godot_bool GDAPI godot_vector2i_operator_equal(const godot_vector2i *p_self, const godot_vector2i *p_b);
-
-godot_bool GDAPI godot_vector2i_operator_less(const godot_vector2i *p_self, const godot_vector2i *p_b);
-
-godot_vector2i GDAPI godot_vector2i_operator_neg(const godot_vector2i *p_self);
-
-void GDAPI godot_vector2i_set_x(godot_vector2i *p_self, const godot_int p_x);
-
-void GDAPI godot_vector2i_set_y(godot_vector2i *p_self, const godot_int p_y);
-
-godot_int GDAPI godot_vector2i_get_x(const godot_vector2i *p_self);
-
-godot_int GDAPI godot_vector2i_get_y(const godot_vector2i *p_self);
+void GDAPI godot_vector2_new(godot_vector2 *p_self);
+void GDAPI godot_vector2i_new(godot_vector2i *p_self);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/vector3.h b/modules/gdnative/include/gdnative/vector3.h
index 5127b8789b..354c7555b6 100644
--- a/modules/gdnative/include/gdnative/vector3.h
+++ b/modules/gdnative/include/gdnative/vector3.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,9 +35,9 @@
extern "C" {
#endif
-#include <stdint.h>
+#include <gdnative/math_defs.h>
-#define GODOT_VECTOR3_SIZE 12
+#define GODOT_VECTOR3_SIZE (sizeof(godot_real_t) * 3)
#ifndef GODOT_CORE_API_GODOT_VECTOR3_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_VECTOR3_TYPE_DEFINED
@@ -46,7 +46,7 @@ typedef struct {
} godot_vector3;
#endif
-#define GODOT_VECTOR3I_SIZE 12
+#define GODOT_VECTOR3I_SIZE (sizeof(int32_t) * 3)
#ifndef GODOT_CORE_API_GODOT_VECTOR3I_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_VECTOR3I_TYPE_DEFINED
@@ -55,145 +55,10 @@ typedef struct {
} godot_vector3i;
#endif
-// reduce extern "C" nesting for VS2013
-#ifdef __cplusplus
-}
-#endif
-
-#include <gdnative/basis.h>
#include <gdnative/gdnative.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef enum {
- GODOT_VECTOR3_AXIS_X,
- GODOT_VECTOR3_AXIS_Y,
- GODOT_VECTOR3_AXIS_Z,
-} godot_vector3_axis;
-
-// Vector3
-
-void GDAPI godot_vector3_new(godot_vector3 *r_dest, const godot_real p_x, const godot_real p_y, const godot_real p_z);
-
-godot_string GDAPI godot_vector3_as_string(const godot_vector3 *p_self);
-
-godot_vector3i GDAPI godot_vector3_as_vector3i(const godot_vector3 *p_self);
-
-godot_int GDAPI godot_vector3_min_axis(const godot_vector3 *p_self);
-
-godot_int GDAPI godot_vector3_max_axis(const godot_vector3 *p_self);
-
-godot_real GDAPI godot_vector3_length(const godot_vector3 *p_self);
-
-godot_real GDAPI godot_vector3_length_squared(const godot_vector3 *p_self);
-
-godot_bool GDAPI godot_vector3_is_normalized(const godot_vector3 *p_self);
-
-godot_vector3 GDAPI godot_vector3_normalized(const godot_vector3 *p_self);
-
-godot_vector3 GDAPI godot_vector3_inverse(const godot_vector3 *p_self);
-
-godot_vector3 GDAPI godot_vector3_snapped(const godot_vector3 *p_self, const godot_vector3 *p_by);
-
-godot_vector3 GDAPI godot_vector3_rotated(const godot_vector3 *p_self, const godot_vector3 *p_axis, const godot_real p_phi);
-
-godot_vector3 GDAPI godot_vector3_lerp(const godot_vector3 *p_self, const godot_vector3 *p_b, const godot_real p_t);
-
-godot_vector3 GDAPI godot_vector3_cubic_interpolate(const godot_vector3 *p_self, const godot_vector3 *p_b, const godot_vector3 *p_pre_a, const godot_vector3 *p_post_b, const godot_real p_t);
-
-godot_vector3 GDAPI godot_vector3_move_toward(const godot_vector3 *p_self, const godot_vector3 *p_to, const godot_real p_delta);
-
-godot_real GDAPI godot_vector3_dot(const godot_vector3 *p_self, const godot_vector3 *p_b);
-
-godot_vector3 GDAPI godot_vector3_cross(const godot_vector3 *p_self, const godot_vector3 *p_b);
-
-godot_basis GDAPI godot_vector3_outer(const godot_vector3 *p_self, const godot_vector3 *p_b);
-
-godot_basis GDAPI godot_vector3_to_diagonal_matrix(const godot_vector3 *p_self);
-
-godot_vector3 GDAPI godot_vector3_abs(const godot_vector3 *p_self);
-
-godot_vector3 GDAPI godot_vector3_sign(const godot_vector3 *p_self);
-
-godot_vector3 GDAPI godot_vector3_floor(const godot_vector3 *p_self);
-
-godot_vector3 GDAPI godot_vector3_ceil(const godot_vector3 *p_self);
-
-godot_vector3 GDAPI godot_vector3_direction_to(const godot_vector3 *p_self, const godot_vector3 *p_b);
-
-godot_real GDAPI godot_vector3_distance_to(const godot_vector3 *p_self, const godot_vector3 *p_b);
-
-godot_real GDAPI godot_vector3_distance_squared_to(const godot_vector3 *p_self, const godot_vector3 *p_b);
-
-godot_real GDAPI godot_vector3_angle_to(const godot_vector3 *p_self, const godot_vector3 *p_to);
-
-godot_vector3 GDAPI godot_vector3_slide(const godot_vector3 *p_self, const godot_vector3 *p_n);
-
-godot_vector3 GDAPI godot_vector3_bounce(const godot_vector3 *p_self, const godot_vector3 *p_n);
-
-godot_vector3 GDAPI godot_vector3_reflect(const godot_vector3 *p_self, const godot_vector3 *p_n);
-
-godot_vector3 GDAPI godot_vector3_operator_add(const godot_vector3 *p_self, const godot_vector3 *p_b);
-
-godot_vector3 GDAPI godot_vector3_operator_subtract(const godot_vector3 *p_self, const godot_vector3 *p_b);
-
-godot_vector3 GDAPI godot_vector3_operator_multiply_vector(const godot_vector3 *p_self, const godot_vector3 *p_b);
-
-godot_vector3 GDAPI godot_vector3_operator_multiply_scalar(const godot_vector3 *p_self, const godot_real p_b);
-
-godot_vector3 GDAPI godot_vector3_operator_divide_vector(const godot_vector3 *p_self, const godot_vector3 *p_b);
-
-godot_vector3 GDAPI godot_vector3_operator_divide_scalar(const godot_vector3 *p_self, const godot_real p_b);
-
-godot_bool GDAPI godot_vector3_operator_equal(const godot_vector3 *p_self, const godot_vector3 *p_b);
-
-godot_bool GDAPI godot_vector3_operator_less(const godot_vector3 *p_self, const godot_vector3 *p_b);
-
-godot_vector3 GDAPI godot_vector3_operator_neg(const godot_vector3 *p_self);
-
-void GDAPI godot_vector3_set_axis(godot_vector3 *p_self, const godot_vector3_axis p_axis, const godot_real p_val);
-
-godot_real GDAPI godot_vector3_get_axis(const godot_vector3 *p_self, const godot_vector3_axis p_axis);
-
-// Vector3i
-
-void GDAPI godot_vector3i_new(godot_vector3i *r_dest, const godot_int p_x, const godot_int p_y, const godot_int p_z);
-
-godot_string GDAPI godot_vector3i_as_string(const godot_vector3i *p_self);
-
-godot_vector3 GDAPI godot_vector3i_as_vector3(const godot_vector3i *p_self);
-
-godot_int GDAPI godot_vector3i_min_axis(const godot_vector3i *p_self);
-
-godot_int GDAPI godot_vector3i_max_axis(const godot_vector3i *p_self);
-
-godot_vector3i GDAPI godot_vector3i_abs(const godot_vector3i *p_self);
-
-godot_vector3i GDAPI godot_vector3i_sign(const godot_vector3i *p_self);
-
-godot_vector3i GDAPI godot_vector3i_operator_add(const godot_vector3i *p_self, const godot_vector3i *p_b);
-
-godot_vector3i GDAPI godot_vector3i_operator_subtract(const godot_vector3i *p_self, const godot_vector3i *p_b);
-
-godot_vector3i GDAPI godot_vector3i_operator_multiply_vector(const godot_vector3i *p_self, const godot_vector3i *p_b);
-
-godot_vector3i GDAPI godot_vector3i_operator_multiply_scalar(const godot_vector3i *p_self, const godot_int p_b);
-
-godot_vector3i GDAPI godot_vector3i_operator_divide_vector(const godot_vector3i *p_self, const godot_vector3i *p_b);
-
-godot_vector3i GDAPI godot_vector3i_operator_divide_scalar(const godot_vector3i *p_self, const godot_int p_b);
-
-godot_bool GDAPI godot_vector3i_operator_equal(const godot_vector3i *p_self, const godot_vector3i *p_b);
-
-godot_bool GDAPI godot_vector3i_operator_less(const godot_vector3i *p_self, const godot_vector3i *p_b);
-
-godot_vector3i GDAPI godot_vector3i_operator_neg(const godot_vector3i *p_self);
-
-void GDAPI godot_vector3i_set_axis(godot_vector3i *p_self, const godot_vector3_axis p_axis, const godot_int p_val);
-
-godot_int GDAPI godot_vector3i_get_axis(const godot_vector3i *p_self, const godot_vector3_axis p_axis);
+void GDAPI godot_vector3_new(godot_vector3 *p_self);
+void GDAPI godot_vector3i_new(godot_vector3i *p_self);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/nativescript/godot_nativescript.h b/modules/gdnative/include/nativescript/godot_nativescript.h
index 825033c99c..73b1738b03 100644
--- a/modules/gdnative/include/nativescript/godot_nativescript.h
+++ b/modules/gdnative/include/nativescript/godot_nativescript.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -85,7 +85,6 @@ typedef enum {
} godot_nativescript_property_hint;
typedef enum {
-
GODOT_PROPERTY_USAGE_STORAGE = 1,
GODOT_PROPERTY_USAGE_EDITOR = 2,
GODOT_PROPERTY_USAGE_NETWORK = 4,
diff --git a/modules/gdnative/include/net/godot_net.h b/modules/gdnative/include/net/godot_net.h
index 42804112f2..2fa576a5bf 100644
--- a/modules/gdnative/include/net/godot_net.h
+++ b/modules/gdnative/include/net/godot_net.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnative/include/net/godot_webrtc.h b/modules/gdnative/include/net/godot_webrtc.h
index 15e2df85cc..25aa72dae1 100644
--- a/modules/gdnative/include/net/godot_webrtc.h
+++ b/modules/gdnative/include/net/godot_webrtc.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnative/include/pluginscript/godot_pluginscript.h b/modules/gdnative/include/pluginscript/godot_pluginscript.h
index 406c3ba663..cbd65e3772 100644
--- a/modules/gdnative/include/pluginscript/godot_pluginscript.h
+++ b/modules/gdnative/include/pluginscript/godot_pluginscript.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -72,6 +72,7 @@ typedef struct {
godot_string_name name;
godot_bool is_tool;
godot_string_name base;
+ godot_string icon_path;
// Member lines format: {<string>: <int>}
godot_dictionary member_lines;
@@ -127,6 +128,7 @@ typedef struct {
const char **string_delimiters; // nullptr terminated array
godot_bool has_named_classes;
godot_bool supports_builtin_mode;
+ godot_bool can_inherit_from_file;
godot_string (*get_template_source_code)(godot_pluginscript_language_data *p_data, const godot_string *p_class_name, const godot_string *p_base_class_name);
godot_bool (*validate)(godot_pluginscript_language_data *p_data, const godot_string *p_script, int *r_line_error, int *r_col_error, godot_string *r_test_error, const godot_string *p_path, godot_packed_string_array *r_functions);
diff --git a/modules/gdnative/include/text/godot_text.h b/modules/gdnative/include/text/godot_text.h
new file mode 100644
index 0000000000..44fac3c190
--- /dev/null
+++ b/modules/gdnative/include/text/godot_text.h
@@ -0,0 +1,231 @@
+/*************************************************************************/
+/* godot_text.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GODOT_NATIVETEXT_H
+#define GODOT_NATIVETEXT_H
+
+#include <gdnative/gdnative.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GODOT_TEXT_API_MAJOR 1
+#define GODOT_TEXT_API_MINOR 0
+
+#define GODOT_GLYPH_SIZE 40
+
+#ifndef GODOT_TEXT_API_GODOT_GLYPH_TYPE_DEFINED
+#define GODOT_TEXT_API_GODOT_GLYPH_TYPE_DEFINED
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_GLYPH_SIZE];
+} godot_glyph;
+#endif
+
+#define GODOT_PACKED_GLYPH_ARRAY_SIZE (2 * sizeof(void *))
+
+#ifndef GODOT_TEXT_API_GODOT_PACKED_GLYPH_ARRAY_TYPE_DEFINED
+#define GODOT_TEXT_API_GODOT_PACKED_GLYPH_ARRAY_TYPE_DEFINED
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_PACKED_GLYPH_ARRAY_SIZE];
+} godot_packed_glyph_array;
+#endif
+
+typedef struct {
+ godot_gdnative_api_version version;
+ void *(*constructor)(godot_object *);
+ void (*destructor)(void *);
+ godot_string (*get_name)(const void *);
+ godot_bool (*has_feature)(const void *, godot_int);
+ bool (*load_support_data)(void *, const godot_string *);
+ godot_string (*get_support_data_filename)(const void *);
+ godot_string (*get_support_data_info)(const void *);
+ bool (*save_support_data)(void *, const godot_string *);
+ bool (*is_locale_right_to_left)(void *, const godot_string *);
+ void (*free)(void *, godot_rid *);
+ bool (*has)(void *, godot_rid *);
+ godot_rid (*create_font_system)(void *, const godot_string *, int);
+ godot_rid (*create_font_resource)(void *, const godot_string *, int);
+ godot_rid (*create_font_memory)(void *, const uint8_t *, size_t, godot_string *, int);
+ float (*font_get_height)(void *, godot_rid *, int);
+ float (*font_get_ascent)(void *, godot_rid *, int);
+ float (*font_get_descent)(void *, godot_rid *, int);
+ float (*font_get_underline_position)(void *, godot_rid *, int);
+ float (*font_get_underline_thickness)(void *, godot_rid *, int);
+ void (*font_set_antialiased)(void *, godot_rid *, bool);
+ bool (*font_get_antialiased)(void *, godot_rid *);
+ godot_dictionary (*font_get_feature_list)(void *, godot_rid *);
+ godot_dictionary (*font_get_variation_list)(void *, godot_rid *);
+ void (*font_set_variation)(void *, godot_rid *, const godot_string *, double);
+ double (*font_get_variation)(void *, godot_rid *, const godot_string *);
+ void (*font_set_distance_field_hint)(void *, godot_rid *, bool);
+ bool (*font_get_distance_field_hint)(void *, godot_rid *);
+ void (*font_set_hinting)(void *, godot_rid *, godot_int);
+ godot_int (*font_get_hinting)(void *, godot_rid *);
+ void (*font_set_force_autohinter)(void *, godot_rid *, bool);
+ bool (*font_get_force_autohinter)(void *, godot_rid *);
+ bool (*font_has_char)(void *, godot_rid *, char32_t);
+ godot_string (*font_get_supported_chars)(void *, godot_rid *);
+ bool (*font_has_outline)(void *, godot_rid *);
+ int (*font_get_base_size)(void *, godot_rid *);
+ bool (*font_is_language_supported)(void *, godot_rid *, const godot_string *);
+ void (*font_set_language_support_override)(void *, godot_rid *, const godot_string *, bool);
+ bool (*font_get_language_support_override)(void *, godot_rid *, const godot_string *);
+ void (*font_remove_language_support_override)(void *, godot_rid *, const godot_string *);
+ godot_packed_string_array (*font_get_language_support_overrides)(void *, godot_rid *);
+ bool (*font_is_script_supported)(void *, godot_rid *, const godot_string *);
+ void (*font_set_script_support_override)(void *, godot_rid *, const godot_string *, bool);
+ bool (*font_get_script_support_override)(void *, godot_rid *, const godot_string *);
+ void (*font_remove_script_support_override)(void *, godot_rid *, const godot_string *);
+ godot_packed_string_array (*font_get_script_support_overrides)(void *, godot_rid *);
+ uint32_t (*font_get_glyph_index)(void *, godot_rid *, char32_t, char32_t);
+ godot_vector2 (*font_get_glyph_advance)(void *, godot_rid *, uint32_t, int);
+ godot_vector2 (*font_get_glyph_kerning)(void *, godot_rid *, uint32_t, uint32_t, int);
+ godot_vector2 (*font_draw_glyph)(void *, godot_rid *, godot_rid *, int, const godot_vector2 *, uint32_t, const godot_color *);
+ godot_vector2 (*font_draw_glyph_outline)(void *, godot_rid *, godot_rid *, int, int, const godot_vector2 *, uint32_t, const godot_color *);
+ float (*font_get_oversampling)(void *);
+ void (*font_set_oversampling)(void *, float);
+ godot_packed_string_array (*get_system_fonts)(void *);
+ godot_rid (*create_shaped_text)(void *, godot_int, godot_int);
+ void (*shaped_text_clear)(void *, godot_rid *);
+ void (*shaped_text_set_direction)(void *, godot_rid *, godot_int);
+ godot_int (*shaped_text_get_direction)(void *, godot_rid *);
+ void (*shaped_text_set_bidi_override)(void *, godot_rid *, const godot_packed_vector2i_array *);
+ void (*shaped_text_set_orientation)(void *, godot_rid *, godot_int);
+ godot_int (*shaped_text_get_orientation)(void *, godot_rid *);
+ void (*shaped_text_set_preserve_invalid)(void *, godot_rid *, bool);
+ bool (*shaped_text_get_preserve_invalid)(void *, godot_rid *);
+ void (*shaped_text_set_preserve_control)(void *, godot_rid *, bool);
+ bool (*shaped_text_get_preserve_control)(void *, godot_rid *);
+ bool (*shaped_text_add_string)(void *, godot_rid *, const godot_string *, const godot_rid **, int, const godot_dictionary *, const godot_string *);
+ bool (*shaped_text_add_object)(void *, godot_rid *, const godot_variant *, const godot_vector2 *, godot_int, godot_int);
+ bool (*shaped_text_resize_object)(void *, godot_rid *, const godot_variant *, const godot_vector2 *, godot_int);
+ godot_rid (*shaped_text_substr)(void *, godot_rid *, godot_int, godot_int);
+ godot_rid (*shaped_text_get_parent)(void *, godot_rid *);
+ float (*shaped_text_fit_to_width)(void *, godot_rid *, float, uint8_t);
+ float (*shaped_text_tab_align)(void *, godot_rid *, godot_packed_float32_array *);
+ bool (*shaped_text_shape)(void *, godot_rid *);
+ bool (*shaped_text_update_breaks)(void *, godot_rid *);
+ bool (*shaped_text_update_justification_ops)(void *, godot_rid *);
+ bool (*shaped_text_is_ready)(void *, godot_rid *);
+ godot_packed_glyph_array (*shaped_text_get_glyphs)(void *, godot_rid *);
+ godot_vector2i (*shaped_text_get_range)(void *, godot_rid *);
+ godot_packed_glyph_array (*shaped_text_sort_logical)(void *, godot_rid *);
+ godot_packed_vector2i_array (*shaped_text_get_line_breaks_adv)(void *, godot_rid *, godot_packed_float32_array *, int, bool, uint8_t);
+ godot_packed_vector2i_array (*shaped_text_get_line_breaks)(void *, godot_rid *, float, int, uint8_t);
+ godot_packed_vector2i_array (*shaped_text_get_word_breaks)(void *, godot_rid *);
+ godot_array (*shaped_text_get_objects)(void *, godot_rid *);
+ godot_rect2 (*shaped_text_get_object_rect)(void *, godot_rid *, const godot_variant *);
+ godot_vector2 (*shaped_text_get_size)(void *, godot_rid *);
+ float (*shaped_text_get_ascent)(void *, godot_rid *);
+ float (*shaped_text_get_descent)(void *, godot_rid *);
+ float (*shaped_text_get_width)(void *, godot_rid *);
+ float (*shaped_text_get_underline_position)(void *, godot_rid *);
+ float (*shaped_text_get_underline_thickness)(void *, godot_rid *);
+ godot_string (*format_number)(void *, const godot_string *, const godot_string *);
+ godot_string (*parse_number)(void *, const godot_string *, const godot_string *);
+ godot_string (*percent_sign)(void *, const godot_string *);
+} godot_text_interface_gdnative;
+
+void GDAPI godot_text_register_interface(const godot_text_interface_gdnative *p_interface, const godot_string *p_name, uint32_t p_features);
+
+// Glyph
+
+void GDAPI godot_glyph_new(godot_glyph *r_dest);
+
+godot_vector2i GDAPI godot_glyph_get_range(const godot_glyph *p_self);
+void GDAPI godot_glyph_set_range(godot_glyph *p_self, const godot_vector2i *p_range);
+
+godot_int GDAPI godot_glyph_get_count(const godot_glyph *p_self);
+void GDAPI godot_glyph_set_count(godot_glyph *p_self, godot_int p_count);
+
+godot_int GDAPI godot_glyph_get_repeat(const godot_glyph *p_self);
+void GDAPI godot_glyph_set_repeat(godot_glyph *p_self, godot_int p_repeat);
+
+godot_int GDAPI godot_glyph_get_flags(const godot_glyph *p_self);
+void GDAPI godot_glyph_set_flags(godot_glyph *p_self, godot_int p_flags);
+
+godot_vector2 GDAPI godot_glyph_get_offset(const godot_glyph *p_self);
+void GDAPI godot_glyph_set_offset(godot_glyph *p_self, const godot_vector2 *p_offset);
+
+godot_float GDAPI godot_glyph_get_advance(const godot_glyph *p_self);
+void GDAPI godot_glyph_set_advance(godot_glyph *p_self, godot_float p_advance);
+
+godot_rid GDAPI godot_glyph_get_font(const godot_glyph *p_self);
+void GDAPI godot_glyph_set_font(godot_glyph *p_self, godot_rid *p_font);
+
+godot_int GDAPI godot_glyph_get_font_size(const godot_glyph *p_self);
+void GDAPI godot_glyph_set_font_size(godot_glyph *p_self, godot_int p_size);
+
+godot_int GDAPI godot_glyph_get_index(const godot_glyph *p_self);
+void GDAPI godot_glyph_set_index(godot_glyph *p_self, godot_int p_index);
+
+// GlyphArray
+
+void GDAPI godot_packed_glyph_array_new(godot_packed_glyph_array *r_dest);
+void GDAPI godot_packed_glyph_array_new_copy(godot_packed_glyph_array *r_dest, const godot_packed_glyph_array *p_src);
+
+const godot_glyph GDAPI *godot_packed_glyph_array_ptr(const godot_packed_glyph_array *p_self);
+godot_glyph GDAPI *godot_packed_glyph_array_ptrw(godot_packed_glyph_array *p_self);
+
+void GDAPI godot_packed_glyph_array_append(godot_packed_glyph_array *p_self, const godot_glyph *p_data);
+
+void GDAPI godot_packed_glyph_array_append_array(godot_packed_glyph_array *p_self, const godot_packed_glyph_array *p_array);
+
+godot_error GDAPI godot_packed_glyph_array_insert(godot_packed_glyph_array *p_self, const godot_int p_idx, const godot_glyph *p_data);
+
+godot_bool GDAPI godot_packed_glyph_array_has(godot_packed_glyph_array *p_self, const godot_glyph *p_value);
+
+void GDAPI godot_packed_glyph_array_sort(godot_packed_glyph_array *p_self);
+
+void GDAPI godot_packed_glyph_array_invert(godot_packed_glyph_array *p_self);
+
+void GDAPI godot_packed_glyph_array_push_back(godot_packed_glyph_array *p_self, const godot_glyph *p_data);
+
+void GDAPI godot_packed_glyph_array_remove(godot_packed_glyph_array *p_self, godot_int p_idx);
+
+void GDAPI godot_packed_glyph_array_resize(godot_packed_glyph_array *p_self, godot_int p_size);
+
+void GDAPI godot_packed_glyph_array_set(godot_packed_glyph_array *p_self, godot_int p_idx, const godot_glyph *p_data);
+godot_glyph GDAPI godot_packed_glyph_array_get(const godot_packed_glyph_array *p_self, godot_int p_idx);
+
+godot_int GDAPI godot_packed_glyph_array_size(const godot_packed_glyph_array *p_self);
+
+godot_bool GDAPI godot_packed_glyph_array_is_empty(const godot_packed_glyph_array *p_self);
+
+void GDAPI godot_packed_glyph_array_destroy(godot_packed_glyph_array *p_self);
+
+// Grapheme
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !GODOT_NATIVETEXT_H */
diff --git a/modules/gdnative/include/videodecoder/godot_videodecoder.h b/modules/gdnative/include/videodecoder/godot_videodecoder.h
index 16c92abd22..dc2cf5ec07 100644
--- a/modules/gdnative/include/videodecoder/godot_videodecoder.h
+++ b/modules/gdnative/include/videodecoder/godot_videodecoder.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -49,11 +49,11 @@ typedef struct
const char *(*get_plugin_name)();
const char **(*get_supported_extensions)(int *count);
godot_bool (*open_file)(void *, void *); // data struct, and a FileAccess pointer
- godot_real (*get_length)(const void *);
- godot_real (*get_playback_position)(const void *);
- void (*seek)(void *, godot_real);
+ godot_float (*get_length)(const void *);
+ godot_float (*get_playback_position)(const void *);
+ void (*seek)(void *, godot_float);
void (*set_audio_track)(void *, godot_int);
- void (*update)(void *, godot_real);
+ void (*update)(void *, godot_float);
godot_packed_byte_array *(*get_videoframe)(void *);
godot_int (*get_audioframe)(void *, float *, int);
godot_int (*get_channels)(const void *);
diff --git a/modules/gdnative/include/xr/godot_xr.h b/modules/gdnative/include/xr/godot_xr.h
index 22f7f021c4..7eaf1c7ec3 100644
--- a/modules/gdnative/include/xr/godot_xr.h
+++ b/modules/gdnative/include/xr/godot_xr.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -58,7 +58,7 @@ typedef struct {
void (*uninitialize)(void *);
godot_vector2 (*get_render_targetsize)(const void *);
godot_transform (*get_transform_for_eye)(void *, godot_int, godot_transform *);
- void (*fill_projection_for_eye)(void *, godot_real *, godot_int, godot_real, godot_real, godot_real);
+ void (*fill_projection_for_eye)(void *, godot_float *, godot_int, godot_float, godot_float, godot_float);
void (*commit_for_eye)(void *, godot_int, godot_rid *, godot_rect2 *);
void (*process)(void *);
godot_int (*get_external_texture_for_eye)(void *, godot_int);
@@ -69,7 +69,7 @@ typedef struct {
void GDAPI godot_xr_register_interface(const godot_xr_interface_gdnative *p_interface);
// helper functions to access XRServer data
-godot_real GDAPI godot_xr_get_worldscale();
+godot_float GDAPI godot_xr_get_worldscale();
godot_transform GDAPI godot_xr_get_reference_frame();
// helper functions for rendering
@@ -81,8 +81,8 @@ godot_int GDAPI godot_xr_add_controller(char *p_device_name, godot_int p_hand, g
void GDAPI godot_xr_remove_controller(godot_int p_controller_id);
void GDAPI godot_xr_set_controller_transform(godot_int p_controller_id, godot_transform *p_transform, godot_bool p_tracks_orientation, godot_bool p_tracks_position);
void GDAPI godot_xr_set_controller_button(godot_int p_controller_id, godot_int p_button, godot_bool p_is_pressed);
-void GDAPI godot_xr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_real p_value, godot_bool p_can_be_negative);
-godot_real GDAPI godot_xr_get_controller_rumble(godot_int p_controller_id);
+void GDAPI godot_xr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_float p_value, godot_bool p_can_be_negative);
+godot_float GDAPI godot_xr_get_controller_rumble(godot_int p_controller_id);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp
index 8dbaec4e75..2b824938f2 100644
--- a/modules/gdnative/nativescript/api_generator.cpp
+++ b/modules/gdnative/nativescript/api_generator.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,11 +32,12 @@
#ifdef TOOLS_ENABLED
-#include "core/class_db.h"
-#include "core/engine.h"
-#include "core/global_constants.h"
+#include "core/config/engine.h"
+#include "core/core_constants.h"
+#include "core/object/class_db.h"
#include "core/os/file_access.h"
-#include "core/pair.h"
+#include "core/string/string_builder.h"
+#include "core/templates/pair.h"
// helper stuff
@@ -65,14 +66,14 @@ struct MethodAPI {
Map<int, Variant> default_arguments;
- int argument_count;
- bool has_varargs;
- bool is_editor;
- bool is_noscript;
- bool is_const;
- bool is_reverse;
- bool is_virtual;
- bool is_from_script;
+ int argument_count = 0;
+ bool has_varargs = false;
+ bool is_editor = false;
+ bool is_noscript = false;
+ bool is_const = false;
+ bool is_reverse = false;
+ bool is_virtual = false;
+ bool is_from_script = false;
};
struct PropertyAPI {
@@ -80,12 +81,14 @@ struct PropertyAPI {
String getter;
String setter;
String type;
- int index;
+ int index = 0;
};
struct ConstantAPI {
String constant_name;
- int constant_value;
+ int constant_value = 0;
+ Variant builtin_constant_value; // For builtin types;
+ String builtin_constant_type; // For builtin types;
};
struct SignalAPI {
@@ -100,23 +103,34 @@ struct EnumAPI {
List<Pair<int, String>> values;
};
+struct OperatorAPI { // For builtin types;
+ String name;
+ int oper = Variant::OP_MAX;
+ String other_type;
+ String return_type;
+};
+
struct ClassAPI {
String class_name;
String super_class_name;
- ClassDB::APIType api_type;
+ ClassDB::APIType api_type = ClassDB::API_NONE;
- bool is_singleton;
+ bool is_singleton = false;
String singleton_name;
- bool is_instanciable;
+ bool is_instantiable = false;
// @Unclear
- bool is_reference;
+ bool is_reference = false;
+ bool has_indexing = false; // For builtin types.
+ bool is_keyed = false; // For builtin types.
List<MethodAPI> methods;
+ List<MethodAPI> constructors; // For builtin types.
List<PropertyAPI> properties;
List<ConstantAPI> constants;
List<SignalAPI> signals_;
List<EnumAPI> enums;
+ List<OperatorAPI> operators; // For builtin types.
};
static String get_type_name(const PropertyInfo &info) {
@@ -173,19 +187,19 @@ List<ClassAPI> generate_c_api_classes() {
ClassDB::get_class_list(&classes);
classes.sort_custom<StringName::AlphCompare>();
- // Register global constants as a fake GlobalConstants singleton class
+ // Register global constants as a fake CoreConstants singleton class
{
ClassAPI global_constants_api;
- global_constants_api.class_name = "GlobalConstants";
+ global_constants_api.class_name = "CoreConstants";
global_constants_api.api_type = ClassDB::API_CORE;
global_constants_api.is_singleton = true;
- global_constants_api.singleton_name = "GlobalConstants";
- global_constants_api.is_instanciable = false;
- const int constants_count = GlobalConstants::get_global_constant_count();
+ global_constants_api.singleton_name = "CoreConstants";
+ global_constants_api.is_instantiable = false;
+ const int constants_count = CoreConstants::get_global_constant_count();
for (int i = 0; i < constants_count; ++i) {
ConstantAPI constant_api;
- constant_api.constant_name = GlobalConstants::get_global_constant_name(i);
- constant_api.constant_value = GlobalConstants::get_global_constant_value(i);
+ constant_api.constant_name = CoreConstants::get_global_constant_name(i);
+ constant_api.constant_value = CoreConstants::get_global_constant_value(i);
global_constants_api.constants.push_back(constant_api);
}
global_constants_api.constants.sort_custom<ConstantAPIComparator>();
@@ -195,6 +209,10 @@ List<ClassAPI> generate_c_api_classes() {
for (List<StringName>::Element *e = classes.front(); e != nullptr; e = e->next()) {
StringName class_name = e->get();
+ if (!ClassDB::is_class_exposed(class_name)) {
+ continue;
+ }
+
ClassAPI class_api;
class_api.api_type = ClassDB::get_api_type(e->get());
class_api.class_name = class_name;
@@ -209,7 +227,7 @@ List<ClassAPI> generate_c_api_classes() {
class_api.singleton_name = name;
}
}
- class_api.is_instanciable = !class_api.is_singleton && ClassDB::can_instance(class_name);
+ class_api.is_instantiable = !class_api.is_singleton && ClassDB::can_instance(class_name);
{
List<StringName> inheriters;
@@ -295,7 +313,7 @@ List<ClassAPI> generate_c_api_classes() {
property_api.index = ClassDB::get_property_index(class_name, p->get().name);
- if (!property_api.setter.empty() || !property_api.getter.empty()) {
+ if (!property_api.setter.is_empty() || !property_api.getter.is_empty()) {
class_api.properties.push_back(property_api);
}
}
@@ -402,6 +420,191 @@ List<ClassAPI> generate_c_api_classes() {
}
/*
+ * Reads the builtin Variant API to a list
+ */
+List<ClassAPI> generate_c_builtin_api_types() {
+ List<ClassAPI> api;
+
+ // Special class for the utility methods.
+ {
+ ClassAPI utility_api;
+ utility_api.class_name = "Utilities";
+ utility_api.is_instantiable = false;
+
+ List<StringName> utility_functions;
+ Variant::get_utility_function_list(&utility_functions);
+ for (const List<StringName>::Element *E = utility_functions.front(); E; E = E->next()) {
+ const StringName &function_name = E->get();
+
+ MethodAPI function_api;
+ function_api.method_name = function_name;
+ function_api.has_varargs = Variant::is_utility_function_vararg(function_name);
+ function_api.argument_count = function_api.has_varargs ? 0 : Variant::get_utility_function_argument_count(function_name);
+ function_api.is_const = Variant::get_utility_function_type(function_name) == Variant::UTILITY_FUNC_TYPE_MATH;
+
+ for (int i = 0; i < function_api.argument_count; i++) {
+ function_api.argument_names.push_back(Variant::get_utility_function_argument_name(function_name, i));
+ Variant::Type arg_type = Variant::get_utility_function_argument_type(function_name, i);
+ function_api.argument_types.push_back(arg_type == Variant::NIL ? "Variant" : Variant::get_type_name(arg_type));
+ }
+
+ if (Variant::has_utility_function_return_value(function_name)) {
+ Variant::Type ret_type = Variant::get_utility_function_return_type(function_name);
+ function_api.return_type = ret_type == Variant::NIL ? "Variant" : Variant::get_type_name(ret_type);
+ } else {
+ function_api.return_type = "void";
+ }
+
+ utility_api.methods.push_back(function_api);
+ }
+
+ api.push_back(utility_api);
+ }
+
+ for (int t = 0; t < Variant::VARIANT_MAX; t++) {
+ Variant::Type type = (Variant::Type)t;
+
+ ClassAPI class_api;
+ class_api.class_name = Variant::get_type_name(type);
+ class_api.is_instantiable = true;
+ class_api.has_indexing = Variant::has_indexing(type);
+ class_api.is_keyed = Variant::is_keyed(type);
+ // Types that are passed by reference.
+ switch (type) {
+ case Variant::OBJECT:
+ case Variant::DICTIONARY:
+ case Variant::ARRAY:
+ case Variant::PACKED_BYTE_ARRAY:
+ case Variant::PACKED_INT32_ARRAY:
+ case Variant::PACKED_INT64_ARRAY:
+ case Variant::PACKED_FLOAT32_ARRAY:
+ case Variant::PACKED_FLOAT64_ARRAY:
+ case Variant::PACKED_STRING_ARRAY:
+ case Variant::PACKED_VECTOR2_ARRAY:
+ case Variant::PACKED_VECTOR3_ARRAY:
+ case Variant::PACKED_COLOR_ARRAY:
+ class_api.is_reference = true;
+ break;
+ default:
+ class_api.is_reference = false;
+ break;
+ }
+
+ // Methods.
+
+ List<StringName> methods;
+ Variant::get_builtin_method_list(type, &methods);
+ for (const List<StringName>::Element *E = methods.front(); E; E = E->next()) {
+ const StringName &method_name = E->get();
+
+ MethodAPI method_api;
+
+ method_api.method_name = method_name;
+ method_api.argument_count = Variant::get_builtin_method_argument_count(type, method_name);
+ method_api.has_varargs = Variant::is_builtin_method_vararg(type, method_name);
+ method_api.is_const = Variant::is_builtin_method_const(type, method_name);
+
+ for (int i = 0; i < method_api.argument_count; i++) {
+ method_api.argument_names.push_back(Variant::get_builtin_method_argument_name(type, method_name, i));
+ Variant::Type arg_type = Variant::get_builtin_method_argument_type(type, method_name, i);
+ method_api.argument_types.push_back(arg_type == Variant::NIL ? "Variant" : Variant::get_type_name(arg_type));
+ }
+
+ Vector<Variant> default_arguments = Variant::get_builtin_method_default_arguments(type, method_name);
+
+ int default_start = method_api.argument_names.size() - default_arguments.size();
+
+ for (int i = 0; i < default_arguments.size(); i++) {
+ method_api.default_arguments[default_start + i] = default_arguments[i];
+ }
+
+ if (Variant::has_builtin_method_return_value(type, method_name)) {
+ Variant::Type ret_type = Variant::get_builtin_method_return_type(type, method_name);
+ method_api.return_type = ret_type == Variant::NIL ? "Variant" : Variant::get_type_name(ret_type);
+ } else {
+ method_api.return_type = "void";
+ }
+
+ class_api.methods.push_back(method_api);
+ }
+
+ // Constructors.
+
+ for (int c = 0; c < Variant::get_constructor_count(type); c++) {
+ MethodAPI constructor_api;
+
+ constructor_api.method_name = Variant::get_type_name(type);
+ constructor_api.argument_count = Variant::get_constructor_argument_count(type, c);
+ constructor_api.return_type = Variant::get_type_name(type);
+
+ for (int i = 0; i < constructor_api.argument_count; i++) {
+ constructor_api.argument_names.push_back(Variant::get_constructor_argument_name(type, c, i));
+ Variant::Type arg_type = Variant::get_constructor_argument_type(type, c, i);
+ constructor_api.argument_types.push_back(arg_type == Variant::NIL ? "Variant" : Variant::get_type_name(arg_type));
+ }
+
+ class_api.constructors.push_back(constructor_api);
+ }
+
+ // Constants.
+
+ List<StringName> constants;
+ Variant::get_constants_for_type(type, &constants);
+ for (const List<StringName>::Element *E = constants.front(); E; E = E->next()) {
+ const StringName &constant_name = E->get();
+ ConstantAPI constant_api;
+
+ constant_api.constant_name = constant_name;
+ constant_api.builtin_constant_value = Variant::get_constant_value(type, constant_name);
+ constant_api.builtin_constant_type = Variant::get_type_name(constant_api.builtin_constant_value.get_type());
+
+ class_api.constants.push_back(constant_api);
+ }
+
+ // Members.
+
+ List<StringName> members;
+ Variant::get_member_list(type, &members);
+ for (const List<StringName>::Element *E = members.front(); E; E = E->next()) {
+ const StringName &member_name = E->get();
+
+ PropertyAPI member_api;
+ member_api.name = member_name;
+ Variant::Type member_type = Variant::get_member_type(type, member_name);
+ member_api.type = member_type == Variant::NIL ? "Variant" : Variant::get_type_name(member_type);
+
+ class_api.properties.push_back(member_api);
+ }
+
+ // Operators.
+
+ for (int op = 0; op < Variant::OP_MAX; op++) {
+ Variant::Operator oper = (Variant::Operator)op;
+
+ for (int ot = 0; ot < Variant::VARIANT_MAX; ot++) {
+ Variant::Type other_type = (Variant::Type)ot;
+
+ if (!Variant::get_validated_operator_evaluator(oper, type, other_type)) {
+ continue;
+ }
+
+ OperatorAPI oper_api;
+ oper_api.name = Variant::get_operator_name(oper);
+ oper_api.oper = oper;
+ oper_api.other_type = Variant::get_type_name(other_type);
+ oper_api.return_type = Variant::get_type_name(Variant::get_operator_return_type(oper, type, other_type));
+
+ class_api.operators.push_back(oper_api);
+ }
+ }
+
+ api.push_back(class_api);
+ }
+
+ return api;
+}
+
+/*
* Generates the JSON source from the API in p_api
*/
static List<String> generate_c_api_json(const List<ClassAPI> &p_api) {
@@ -421,9 +624,8 @@ static List<String> generate_c_api_json(const List<ClassAPI> &p_api) {
source.push_back(String("\t\t\"api_type\": \"") + (api.api_type == ClassDB::API_CORE ? "core" : (api.api_type == ClassDB::API_EDITOR ? "tools" : "none")) + "\",\n");
source.push_back(String("\t\t\"singleton\": ") + (api.is_singleton ? "true" : "false") + ",\n");
source.push_back("\t\t\"singleton_name\": \"" + api.singleton_name + "\",\n");
- source.push_back(String("\t\t\"instanciable\": ") + (api.is_instanciable ? "true" : "false") + ",\n");
+ source.push_back(String("\t\t\"instantiable\": ") + (api.is_instantiable ? "true" : "false") + ",\n");
source.push_back(String("\t\t\"is_reference\": ") + (api.is_reference ? "true" : "false") + ",\n");
- // @Unclear
source.push_back("\t\t\"constants\": {\n");
for (List<ConstantAPI>::Element *e = api.constants.front(); e; e = e->next()) {
@@ -508,6 +710,164 @@ static List<String> generate_c_api_json(const List<ClassAPI> &p_api) {
return source;
}
+static int indent_level = 0;
+
+static void append_indented(StringBuilder &p_source, const String &p_text) {
+ for (int i = 0; i < indent_level; i++) {
+ p_source.append("\t");
+ }
+ p_source.append(p_text);
+ p_source.append("\n");
+}
+
+static void append_indented(StringBuilder &p_source, const char *p_text) {
+ for (int i = 0; i < indent_level; i++) {
+ p_source.append("\t");
+ }
+ p_source.append(p_text);
+ p_source.append("\n");
+}
+
+static void write_builtin_method(StringBuilder &p_source, const MethodAPI &p_method) {
+ append_indented(p_source, vformat(R"("name": "%s",)", p_method.method_name));
+ append_indented(p_source, vformat(R"("return_type": "%s",)", p_method.return_type));
+ append_indented(p_source, vformat(R"("is_const": %s,)", p_method.is_const ? "true" : "false"));
+ append_indented(p_source, vformat(R"("has_varargs": %s,)", p_method.has_varargs ? "true" : "false"));
+
+ append_indented(p_source, R"("arguments": [)");
+ indent_level++;
+ for (int i = 0; i < p_method.argument_count; i++) {
+ append_indented(p_source, "{");
+ indent_level++;
+
+ append_indented(p_source, vformat(R"("name": "%s",)", p_method.argument_names[i]));
+ append_indented(p_source, vformat(R"("type": "%s",)", p_method.argument_types[i]));
+ append_indented(p_source, vformat(R"("has_default_value": %s,)", p_method.default_arguments.has(i) ? "true" : "false"));
+ append_indented(p_source, vformat(R"("default_value": "%s")", p_method.default_arguments.has(i) ? p_method.default_arguments[i].operator String() : ""));
+
+ indent_level--;
+ append_indented(p_source, i < p_method.argument_count - 1 ? "}," : "}");
+ }
+ indent_level--;
+ append_indented(p_source, "]");
+}
+
+static List<String> generate_c_builtin_api_json(const List<ClassAPI> &p_api) {
+ StringBuilder source;
+
+ source.append("[\n");
+
+ indent_level = 1;
+
+ for (const List<ClassAPI>::Element *C = p_api.front(); C; C = C->next()) {
+ const ClassAPI &class_api = C->get();
+ append_indented(source, "{");
+ indent_level++;
+
+ append_indented(source, vformat(R"("name": "%s",)", class_api.class_name));
+ append_indented(source, vformat(R"("is_instantiable": %s,)", class_api.is_instantiable ? "true" : "false"));
+ append_indented(source, vformat(R"("is_reference": %s,)", class_api.is_reference ? "true" : "false"));
+ append_indented(source, vformat(R"("has_indexing": %s,)", class_api.has_indexing ? "true" : "false"));
+ append_indented(source, vformat(R"("is_keyed": %s,)", class_api.is_keyed ? "true" : "false"));
+
+ // Constructors.
+ append_indented(source, R"("constructors": [)");
+ indent_level++;
+ for (const List<MethodAPI>::Element *E = class_api.constructors.front(); E; E = E->next()) {
+ const MethodAPI &constructor = E->get();
+ append_indented(source, "{");
+ indent_level++;
+
+ write_builtin_method(source, constructor);
+
+ indent_level--;
+ append_indented(source, E->next() ? "}," : "}");
+ }
+ indent_level--;
+ append_indented(source, "],");
+
+ // Constants.
+ append_indented(source, R"("constants": [)");
+ indent_level++;
+ for (const List<ConstantAPI>::Element *E = class_api.constants.front(); E; E = E->next()) {
+ const ConstantAPI &constant = E->get();
+ append_indented(source, "{");
+ indent_level++;
+
+ append_indented(source, vformat(R"("name": "%s",)", constant.constant_name));
+ append_indented(source, vformat(R"("type": "%s",)", constant.builtin_constant_type));
+ append_indented(source, vformat(R"("value": "%s")", constant.builtin_constant_value.operator String()));
+
+ indent_level--;
+ append_indented(source, E->next() ? "}," : "}");
+ }
+ indent_level--;
+ append_indented(source, "],");
+
+ // Methods.
+ append_indented(source, R"("methods": [)");
+ indent_level++;
+ for (const List<MethodAPI>::Element *E = class_api.methods.front(); E; E = E->next()) {
+ const MethodAPI &method = E->get();
+ append_indented(source, "{");
+ indent_level++;
+
+ write_builtin_method(source, method);
+
+ indent_level--;
+ append_indented(source, E->next() ? "}," : "}");
+ }
+ indent_level--;
+ append_indented(source, "],");
+
+ // Members.
+ append_indented(source, R"("members": [)");
+ indent_level++;
+ for (const List<PropertyAPI>::Element *E = class_api.properties.front(); E; E = E->next()) {
+ const PropertyAPI &member = E->get();
+ append_indented(source, "{");
+ indent_level++;
+
+ append_indented(source, vformat(R"("name": "%s",)", member.name));
+ append_indented(source, vformat(R"("type": "%s")", member.type));
+
+ indent_level--;
+ append_indented(source, E->next() ? "}," : "}");
+ }
+ indent_level--;
+ append_indented(source, "],");
+
+ // Operators.
+ append_indented(source, R"("operators": [)");
+ indent_level++;
+ for (const List<OperatorAPI>::Element *E = class_api.operators.front(); E; E = E->next()) {
+ const OperatorAPI &oper = E->get();
+ append_indented(source, "{");
+ indent_level++;
+
+ append_indented(source, vformat(R"("name": "%s",)", oper.name));
+ append_indented(source, vformat(R"("operator": %d,)", oper.oper));
+ append_indented(source, vformat(R"("other_type": "%s",)", oper.other_type));
+ append_indented(source, vformat(R"("return_type": "%s")", oper.return_type));
+
+ indent_level--;
+ append_indented(source, E->next() ? "}," : "}");
+ }
+ indent_level--;
+ append_indented(source, "]");
+
+ indent_level--;
+ append_indented(source, C->next() ? "}," : "}");
+ }
+
+ indent_level--;
+ source.append("]\n");
+
+ List<String> result;
+ result.push_back(source.as_string());
+ return result;
+}
+
#endif
/*
@@ -526,3 +886,19 @@ Error generate_c_api(const String &p_path) {
return save_file(p_path, json_source);
#endif
}
+/*
+ * Saves the builtin Godot API to a JSON file located at
+ * p_path
+ */
+Error generate_c_builtin_api(const String &p_path) {
+#ifndef TOOLS_ENABLED
+ return ERR_BUG;
+#else
+
+ List<ClassAPI> api = generate_c_builtin_api_types();
+
+ List<String> json_source = generate_c_builtin_api_json(api);
+
+ return save_file(p_path, json_source);
+#endif
+}
diff --git a/modules/gdnative/nativescript/api_generator.h b/modules/gdnative/nativescript/api_generator.h
index edbb1d1f23..611abb2a2d 100644
--- a/modules/gdnative/nativescript/api_generator.h
+++ b/modules/gdnative/nativescript/api_generator.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,9 +31,10 @@
#ifndef API_GENERATOR_H
#define API_GENERATOR_H
+#include "core/string/ustring.h"
#include "core/typedefs.h"
-#include "core/ustring.h"
Error generate_c_api(const String &p_path);
+Error generate_c_builtin_api(const String &p_path);
#endif // API_GENERATOR_H
diff --git a/modules/gdnative/nativescript/godot_nativescript.cpp b/modules/gdnative/nativescript/godot_nativescript.cpp
index e47548f3e9..b2abf8b8ae 100644
--- a/modules/gdnative/nativescript/godot_nativescript.cpp
+++ b/modules/gdnative/nativescript/godot_nativescript.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,11 +30,11 @@
#include "nativescript/godot_nativescript.h"
-#include "core/class_db.h"
-#include "core/error_macros.h"
-#include "core/global_constants.h"
-#include "core/project_settings.h"
-#include "core/variant.h"
+#include "core/config/project_settings.h"
+#include "core/core_constants.h"
+#include "core/error/error_macros.h"
+#include "core/object/class_db.h"
+#include "core/variant/variant.h"
#include "gdnative/gdnative.h"
#include <stdint.h>
diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp
index 632f4e5fee..19cf1f980b 100644
--- a/modules/gdnative/nativescript/nativescript.cpp
+++ b/modules/gdnative/nativescript/nativescript.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,12 +34,12 @@
#include "gdnative/gdnative.h"
+#include "core/config/project_settings.h"
+#include "core/core_constants.h"
#include "core/core_string_names.h"
-#include "core/global_constants.h"
#include "core/io/file_access_encrypted.h"
#include "core/os/file_access.h"
#include "core/os/os.h"
-#include "core/project_settings.h"
#include "scene/main/scene_tree.h"
#include "scene/resources/resource_format_text.h"
@@ -717,7 +717,7 @@ String NativeScript::get_property_documentation(const StringName &p_path) const
}
Variant NativeScript::_new(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
- if (lib_path.empty() || class_name.empty() || library.is_null()) {
+ if (lib_path.is_empty() || class_name.is_empty() || library.is_null()) {
r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
return Variant();
}
@@ -1257,6 +1257,15 @@ void NativeScriptLanguage::init() {
}
exit(0);
}
+
+ E = args.find("--gdnative-generate-json-builtin-api");
+
+ if (E && E->next()) {
+ if (generate_c_builtin_api(E->next()->get()) != OK) {
+ ERR_PRINT("Failed to generate C builtin API\n");
+ }
+ exit(0);
+ }
#endif
#ifdef TOOLS_ENABLED
@@ -1724,6 +1733,12 @@ void NativeScriptLanguage::unregister_script(NativeScript *script) {
S->get().erase(script);
if (S->get().size() == 0) {
library_script_users.erase(S);
+
+ Map<String, Ref<GDNative>>::Element *G = library_gdnatives.find(script->lib_path);
+ if (G) {
+ G->get()->terminate();
+ library_gdnatives.erase(G);
+ }
}
}
#ifndef NO_THREADS
@@ -1800,7 +1815,7 @@ bool NativeScriptLanguage::handles_global_class_type(const String &p_type) const
}
String NativeScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const {
- if (!p_path.empty()) {
+ if (!p_path.is_empty()) {
Ref<NativeScript> script = ResourceLoader::load(p_path, "NativeScript");
if (script.is_valid()) {
if (r_base_type) {
diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h
index 145bf7dcb6..9d72bf39d1 100644
--- a/modules/gdnative/nativescript/nativescript.h
+++ b/modules/gdnative/nativescript/nativescript.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,15 +31,16 @@
#ifndef NATIVE_SCRIPT_H
#define NATIVE_SCRIPT_H
+#include "core/doc_data.h"
+#include "core/io/resource.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
-#include "core/oa_hash_map.h"
-#include "core/ordered_hash_map.h"
+#include "core/object/script_language.h"
#include "core/os/mutex.h"
#include "core/os/thread_safe.h"
-#include "core/resource.h"
-#include "core/script_language.h"
-#include "core/self_list.h"
+#include "core/templates/oa_hash_map.h"
+#include "core/templates/ordered_hash_map.h"
+#include "core/templates/self_list.h"
#include "scene/main/node.h"
#include "modules/gdnative/gdnative.h"
@@ -152,6 +153,13 @@ public:
virtual void set_source_code(const String &p_code) override;
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;
+ return docs;
+ }
+#endif // TOOLS_ENABLED
+
virtual bool has_method(const StringName &p_method) const override;
virtual MethodInfo get_method_info(const StringName &p_method) const override;
diff --git a/modules/gdnative/nativescript/register_types.cpp b/modules/gdnative/nativescript/register_types.cpp
index ac8c7ab2fd..0353ab2092 100644
--- a/modules/gdnative/nativescript/register_types.cpp
+++ b/modules/gdnative/nativescript/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnative/nativescript/register_types.h b/modules/gdnative/nativescript/register_types.h
index 088bf38dd5..d12ac9eda3 100644
--- a/modules/gdnative/nativescript/register_types.h
+++ b/modules/gdnative/nativescript/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnative/net/multiplayer_peer_gdnative.cpp b/modules/gdnative/net/multiplayer_peer_gdnative.cpp
index 997eec6425..8b5fc8db5c 100644
--- a/modules/gdnative/net/multiplayer_peer_gdnative.cpp
+++ b/modules/gdnative/net/multiplayer_peer_gdnative.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnative/net/multiplayer_peer_gdnative.h b/modules/gdnative/net/multiplayer_peer_gdnative.h
index 64d764029f..593b2534dd 100644
--- a/modules/gdnative/net/multiplayer_peer_gdnative.h
+++ b/modules/gdnative/net/multiplayer_peer_gdnative.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnative/net/packet_peer_gdnative.cpp b/modules/gdnative/net/packet_peer_gdnative.cpp
index 6bb21cb48d..3bcdfed8ff 100644
--- a/modules/gdnative/net/packet_peer_gdnative.cpp
+++ b/modules/gdnative/net/packet_peer_gdnative.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnative/net/packet_peer_gdnative.h b/modules/gdnative/net/packet_peer_gdnative.h
index 00de8f7f4c..29013f9367 100644
--- a/modules/gdnative/net/packet_peer_gdnative.h
+++ b/modules/gdnative/net/packet_peer_gdnative.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnative/net/register_types.cpp b/modules/gdnative/net/register_types.cpp
index 4e48a43210..645c43b7e3 100644
--- a/modules/gdnative/net/register_types.cpp
+++ b/modules/gdnative/net/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnative/net/register_types.h b/modules/gdnative/net/register_types.h
index 70b266f9b9..c99c6f6fbf 100644
--- a/modules/gdnative/net/register_types.h
+++ b/modules/gdnative/net/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnative/net/stream_peer_gdnative.cpp b/modules/gdnative/net/stream_peer_gdnative.cpp
index 9dcb184115..72ab72323d 100644
--- a/modules/gdnative/net/stream_peer_gdnative.cpp
+++ b/modules/gdnative/net/stream_peer_gdnative.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnative/net/stream_peer_gdnative.h b/modules/gdnative/net/stream_peer_gdnative.h
index 302fb48012..dd5abceb83 100644
--- a/modules/gdnative/net/stream_peer_gdnative.h
+++ b/modules/gdnative/net/stream_peer_gdnative.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnative/net/webrtc_gdnative.cpp b/modules/gdnative/net/webrtc_gdnative.cpp
index a7355e4d12..76ccbad009 100644
--- a/modules/gdnative/net/webrtc_gdnative.cpp
+++ b/modules/gdnative/net/webrtc_gdnative.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -54,7 +54,7 @@ godot_error GDAPI godot_net_set_webrtc_library(const godot_net_webrtc_library *p
#ifdef WEBRTC_GDNATIVE_ENABLED
return (godot_error)WebRTCPeerConnectionGDNative::set_default_library(p_lib);
#else
- return ERR_UNAVAILABLE;
+ return (godot_error)ERR_UNAVAILABLE;
#endif
}
}
diff --git a/modules/gdnative/pluginscript/pluginscript_instance.cpp b/modules/gdnative/pluginscript/pluginscript_instance.cpp
index 7d17a7d5ab..432aa80325 100644
--- a/modules/gdnative/pluginscript/pluginscript_instance.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_instance.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,7 +32,7 @@
// Godot imports
#include "core/os/os.h"
-#include "core/variant.h"
+#include "core/variant/variant.h"
// PluginScript imports
#include "pluginscript_language.h"
diff --git a/modules/gdnative/pluginscript/pluginscript_instance.h b/modules/gdnative/pluginscript/pluginscript_instance.h
index 690d1a0432..865080fddf 100644
--- a/modules/gdnative/pluginscript/pluginscript_instance.h
+++ b/modules/gdnative/pluginscript/pluginscript_instance.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,7 +32,7 @@
#define PLUGINSCRIPT_INSTANCE_H
// Godot imports
-#include "core/script_language.h"
+#include "core/object/script_language.h"
// PluginScript imports
#include <pluginscript/godot_pluginscript.h>
diff --git a/modules/gdnative/pluginscript/pluginscript_language.cpp b/modules/gdnative/pluginscript/pluginscript_language.cpp
index bccbe95033..3ed1dcaca9 100644
--- a/modules/gdnative/pluginscript/pluginscript_language.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_language.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,9 +29,9 @@
/*************************************************************************/
// Godot imports
+#include "core/config/project_settings.h"
#include "core/os/file_access.h"
#include "core/os/os.h"
-#include "core/project_settings.h"
// PluginScript imports
#include "pluginscript_language.h"
#include "pluginscript_script.h"
@@ -142,6 +142,10 @@ bool PluginScriptLanguage::supports_builtin_mode() const {
return _desc.supports_builtin_mode;
}
+bool PluginScriptLanguage::can_inherit_from_file() const {
+ return _desc.can_inherit_from_file;
+}
+
int PluginScriptLanguage::find_function(const String &p_function, const String &p_code) const {
if (_desc.find_function) {
return _desc.find_function(_data, (godot_string *)&p_function, (godot_string *)&p_code);
@@ -398,6 +402,32 @@ void PluginScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool
#endif
}
+bool PluginScriptLanguage::handles_global_class_type(const String &p_type) const {
+ return p_type == "PluginScript";
+}
+
+String PluginScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const {
+ if (!p_path.is_empty()) {
+ Ref<PluginScript> script = ResourceLoader::load(p_path, "PluginScript");
+ if (script.is_valid()) {
+ if (r_base_type) {
+ *r_base_type = script->get_instance_base_type();
+ }
+ if (r_icon_path) {
+ *r_icon_path = script->get_script_class_icon_path();
+ }
+ return script->get_script_class_name();
+ }
+ if (r_base_type) {
+ *r_base_type = String();
+ }
+ if (r_icon_path) {
+ *r_icon_path = String();
+ }
+ }
+ return String();
+}
+
void PluginScriptLanguage::lock() {
_lock.lock();
}
diff --git a/modules/gdnative/pluginscript/pluginscript_language.h b/modules/gdnative/pluginscript/pluginscript_language.h
index dd6758713f..226b039265 100644
--- a/modules/gdnative/pluginscript/pluginscript_language.h
+++ b/modules/gdnative/pluginscript/pluginscript_language.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,9 +34,9 @@
// Godot imports
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
-#include "core/map.h"
-#include "core/script_language.h"
-#include "core/self_list.h"
+#include "core/object/script_language.h"
+#include "core/templates/map.h"
+#include "core/templates/self_list.h"
// PluginScript imports
#include "pluginscript_loader.h"
#include <pluginscript/godot_pluginscript.h>
@@ -78,7 +78,7 @@ public:
virtual Script *create_script() const;
virtual bool has_named_classes() const;
virtual bool supports_builtin_mode() const;
- virtual bool can_inherit_from_file() { return true; }
+ virtual bool can_inherit_from_file() const;
virtual int find_function(const String &p_function, const String &p_code) const;
virtual String make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const;
virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_force, String &r_call_hint);
@@ -122,6 +122,11 @@ public:
virtual void frame();
+ /* GLOBAL CLASSES */
+
+ virtual bool handles_global_class_type(const String &p_type) const;
+ virtual String get_global_class_name(const String &p_path, String *r_base_type = nullptr, String *r_icon_path = nullptr) const;
+
void lock();
void unlock();
diff --git a/modules/gdnative/pluginscript/pluginscript_loader.cpp b/modules/gdnative/pluginscript/pluginscript_loader.cpp
index 4feee4f4a5..cd1879a13e 100644
--- a/modules/gdnative/pluginscript/pluginscript_loader.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_loader.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnative/pluginscript/pluginscript_loader.h b/modules/gdnative/pluginscript/pluginscript_loader.h
index 35fc79c2ca..7b1a7f5423 100644
--- a/modules/gdnative/pluginscript/pluginscript_loader.h
+++ b/modules/gdnative/pluginscript/pluginscript_loader.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,7 +34,7 @@
// Godot imports
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
-#include "core/script_language.h"
+#include "core/object/script_language.h"
class PluginScriptLanguage;
diff --git a/modules/gdnative/pluginscript/pluginscript_script.cpp b/modules/gdnative/pluginscript/pluginscript_script.cpp
index 87c6288806..31e6a81975 100644
--- a/modules/gdnative/pluginscript/pluginscript_script.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_script.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -302,6 +302,7 @@ Error PluginScript::reload(bool p_keep_state) {
_data = manifest.data;
_name = *(StringName *)&manifest.name;
_tool = manifest.is_tool;
+ _icon_path = *(String *)&manifest.icon_path;
Dictionary *members = (Dictionary *)&manifest.member_lines;
for (const Variant *key = members->next(); key != nullptr; key = members->next(key)) {
diff --git a/modules/gdnative/pluginscript/pluginscript_script.h b/modules/gdnative/pluginscript/pluginscript_script.h
index 9cd38cd4b4..1c86f2056d 100644
--- a/modules/gdnative/pluginscript/pluginscript_script.h
+++ b/modules/gdnative/pluginscript/pluginscript_script.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,7 +32,9 @@
#define PLUGINSCRIPT_SCRIPT_H
// Godot imports
-#include "core/script_language.h"
+
+#include "core/doc_data.h"
+#include "core/object/script_language.h"
// PluginScript imports
#include "pluginscript_language.h"
#include <pluginscript/godot_pluginscript.h>
@@ -67,6 +69,7 @@ private:
String _source;
String _path;
StringName _name;
+ String _icon_path;
protected:
static void _bind_methods();
@@ -82,6 +85,14 @@ protected:
virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) override;
#endif
public:
+ String get_script_class_name() const {
+ return _name;
+ }
+
+ String get_script_class_icon_path() const {
+ return _icon_path;
+ }
+
virtual bool can_instance() const override;
virtual Ref<Script> get_base_script() const override; //for script inheritance
@@ -97,6 +108,13 @@ public:
// TODO: load_source_code only allow utf-8 file, should handle bytecode as well ?
virtual Error load_source_code(const String &p_path);
+#ifdef TOOLS_ENABLED
+ virtual const Vector<DocData::ClassDoc> &get_documentation() const override {
+ static Vector<DocData::ClassDoc> docs;
+ return docs;
+ }
+#endif // TOOLS_ENABLED
+
virtual bool has_method(const StringName &p_method) const override;
virtual MethodInfo get_method_info(const StringName &p_method) const override;
diff --git a/modules/gdnative/pluginscript/register_types.cpp b/modules/gdnative/pluginscript/register_types.cpp
index 97a48b0e89..b94538b2f7 100644
--- a/modules/gdnative/pluginscript/register_types.cpp
+++ b/modules/gdnative/pluginscript/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,11 +30,11 @@
#include "register_types.h"
+#include "core/config/project_settings.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/os/dir_access.h"
#include "core/os/os.h"
-#include "core/project_settings.h"
#include "scene/main/scene_tree.h"
#include "pluginscript_language.h"
diff --git a/modules/gdnative/pluginscript/register_types.h b/modules/gdnative/pluginscript/register_types.h
index c6a64b4f40..2118f668e9 100644
--- a/modules/gdnative/pluginscript/register_types.h
+++ b/modules/gdnative/pluginscript/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp
index 3a2d0b09a3..31f4fecb19 100644
--- a/modules/gdnative/register_types.cpp
+++ b/modules/gdnative/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -40,11 +40,11 @@
#include "videodecoder/register_types.h"
#include "xr/register_types.h"
-#include "core/engine.h"
+#include "core/config/engine.h"
+#include "core/config/project_settings.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/os/os.h"
-#include "core/project_settings.h"
#ifdef TOOLS_ENABLED
#include "editor/editor_export.h"
diff --git a/modules/gdnative/register_types.h b/modules/gdnative/register_types.h
index b5c182f8b7..662c638442 100644
--- a/modules/gdnative/register_types.h
+++ b/modules/gdnative/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnative/tests/test_string.h b/modules/gdnative/tests/test_string.h
deleted file mode 100644
index aeb855a1c4..0000000000
--- a/modules/gdnative/tests/test_string.h
+++ /dev/null
@@ -1,1980 +0,0 @@
-/*************************************************************************/
-/* test_string.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef TEST_GDNATIVE_STRING_H
-#define TEST_GDNATIVE_STRING_H
-
-namespace TestGDNativeString {
-
-#include "gdnative/string.h"
-
-#include "tests/test_macros.h"
-
-int u32scmp(const char32_t *l, const char32_t *r) {
- for (; *l == *r && *l && *r; l++, r++)
- ;
- return *l - *r;
-}
-
-TEST_CASE("[GDNative String] Construct from Latin-1 char string") {
- godot_string s;
-
- godot_string_new_with_latin1_chars(&s, "Hello");
- CHECK(u32scmp(godot_string_get_data(&s), U"Hello") == 0);
- godot_string_destroy(&s);
-
- godot_string_new_with_latin1_chars_and_len(&s, "Hello", 3);
- CHECK(u32scmp(godot_string_get_data(&s), U"Hel") == 0);
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] Construct from wchar_t string") {
- godot_string s;
-
- godot_string_new_with_wide_chars(&s, L"Give me");
- CHECK(u32scmp(godot_string_get_data(&s), U"Give me") == 0);
- godot_string_destroy(&s);
-
- godot_string_new_with_wide_chars_and_len(&s, L"Give me", 3);
- CHECK(u32scmp(godot_string_get_data(&s), U"Giv") == 0);
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] Construct from UTF-8 char string") {
- static const char32_t u32str[] = { 0x0045, 0x0020, 0x304A, 0x360F, 0x3088, 0x3046, 0x1F3A4, 0 };
- static const char32_t u32str_short[] = { 0x0045, 0x0020, 0x304A, 0 };
- static const uint8_t u8str[] = { 0x45, 0x20, 0xE3, 0x81, 0x8A, 0xE3, 0x98, 0x8F, 0xE3, 0x82, 0x88, 0xE3, 0x81, 0x86, 0xF0, 0x9F, 0x8E, 0xA4, 0 };
-
- godot_string s;
-
- godot_string_new_with_utf8_chars(&s, (const char *)u8str);
- CHECK(u32scmp(godot_string_get_data(&s), u32str) == 0);
- godot_string_destroy(&s);
-
- godot_string_new_with_utf8_chars_and_len(&s, (const char *)u8str, 5);
- CHECK(u32scmp(godot_string_get_data(&s), u32str_short) == 0);
- godot_string_destroy(&s);
-
- godot_string_new_with_utf32_chars(&s, u32str);
- godot_char_string cs = godot_string_utf8(&s);
- godot_string_parse_utf8(&s, godot_char_string_get_data(&cs));
- CHECK(u32scmp(godot_string_get_data(&s), u32str) == 0);
- godot_string_destroy(&s);
- godot_char_string_destroy(&cs);
-
- godot_string_new_with_utf32_chars(&s, u32str);
- cs = godot_string_utf8(&s);
- godot_string_parse_utf8_with_len(&s, godot_char_string_get_data(&cs), godot_char_string_length(&cs));
- CHECK(u32scmp(godot_string_get_data(&s), u32str) == 0);
- godot_string_destroy(&s);
- godot_char_string_destroy(&cs);
-}
-
-TEST_CASE("[GDNative String] Construct from UTF-8 string with BOM") {
- static const char32_t u32str[] = { 0x0045, 0x0020, 0x304A, 0x360F, 0x3088, 0x3046, 0x1F3A4, 0 };
- static const char32_t u32str_short[] = { 0x0045, 0x0020, 0x304A, 0 };
- static const uint8_t u8str[] = { 0xEF, 0xBB, 0xBF, 0x45, 0x20, 0xE3, 0x81, 0x8A, 0xE3, 0x98, 0x8F, 0xE3, 0x82, 0x88, 0xE3, 0x81, 0x86, 0xF0, 0x9F, 0x8E, 0xA4, 0 };
-
- godot_string s;
-
- godot_string_new_with_utf8_chars(&s, (const char *)u8str);
- CHECK(u32scmp(godot_string_get_data(&s), u32str) == 0);
- godot_string_destroy(&s);
-
- godot_string_new_with_utf8_chars_and_len(&s, (const char *)u8str, 8);
- CHECK(u32scmp(godot_string_get_data(&s), u32str_short) == 0);
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] Construct from UTF-16 string") {
- static const char32_t u32str[] = { 0x0045, 0x0020, 0x1F3A4, 0x360F, 0x3088, 0x3046, 0x1F3A4, 0 };
- static const char32_t u32str_short[] = { 0x0045, 0x0020, 0x1F3A4, 0 };
- static const char16_t u16str[] = { 0x0045, 0x0020, 0xD83C, 0xDFA4, 0x360F, 0x3088, 0x3046, 0xD83C, 0xDFA4, 0 };
-
- godot_string s;
-
- godot_string_new_with_utf16_chars(&s, u16str);
- CHECK(u32scmp(godot_string_get_data(&s), u32str) == 0);
- godot_string_destroy(&s);
-
- godot_string_new_with_utf16_chars_and_len(&s, u16str, 4);
- CHECK(u32scmp(godot_string_get_data(&s), u32str_short) == 0);
- godot_string_destroy(&s);
-
- godot_string_new_with_utf32_chars(&s, u32str);
- godot_char16_string cs = godot_string_utf16(&s);
- godot_string_parse_utf16(&s, godot_char16_string_get_data(&cs));
- CHECK(u32scmp(godot_string_get_data(&s), u32str) == 0);
- godot_string_destroy(&s);
- godot_char16_string_destroy(&cs);
-
- godot_string_new_with_utf32_chars(&s, u32str);
- cs = godot_string_utf16(&s);
- godot_string_parse_utf16_with_len(&s, godot_char16_string_get_data(&cs), godot_char16_string_length(&cs));
- CHECK(u32scmp(godot_string_get_data(&s), u32str) == 0);
- godot_string_destroy(&s);
- godot_char16_string_destroy(&cs);
-}
-
-TEST_CASE("[GDNative String] Construct from UTF-16 string with BOM ") {
- static const char32_t u32str[] = { 0x0045, 0x0020, 0x1F3A4, 0x360F, 0x3088, 0x3046, 0x1F3A4, 0 };
- static const char32_t u32str_short[] = { 0x0045, 0x0020, 0x1F3A4, 0 };
- static const char16_t u16str[] = { 0xFEFF, 0x0045, 0x0020, 0xD83C, 0xDFA4, 0x360F, 0x3088, 0x3046, 0xD83C, 0xDFA4, 0 };
- static const char16_t u16str_swap[] = { 0xFFFE, 0x4500, 0x2000, 0x3CD8, 0xA4DF, 0x0F36, 0x8830, 0x4630, 0x3CD8, 0xA4DF, 0 };
-
- godot_string s;
-
- godot_string_new_with_utf16_chars(&s, u16str);
- CHECK(u32scmp(godot_string_get_data(&s), u32str) == 0);
- godot_string_destroy(&s);
-
- godot_string_new_with_utf16_chars(&s, u16str_swap);
- CHECK(u32scmp(godot_string_get_data(&s), u32str) == 0);
- godot_string_destroy(&s);
-
- godot_string_new_with_utf16_chars_and_len(&s, u16str, 5);
- CHECK(u32scmp(godot_string_get_data(&s), u32str_short) == 0);
- godot_string_destroy(&s);
-
- godot_string_new_with_utf16_chars_and_len(&s, u16str_swap, 5);
- CHECK(u32scmp(godot_string_get_data(&s), u32str_short) == 0);
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] Construct string copy") {
- godot_string s, t;
-
- godot_string_new_with_latin1_chars(&s, "Hello");
- godot_string_new_copy(&t, &s);
- CHECK(u32scmp(godot_string_get_data(&t), U"Hello") == 0);
- godot_string_destroy(&t);
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] Construct empty string") {
- godot_string s;
-
- godot_string_new(&s);
- CHECK(u32scmp(godot_string_get_data(&s), U"") == 0);
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] ASCII/Latin-1") {
- godot_string s;
- godot_string_new_with_utf32_chars(&s, U"Primero Leche");
-
- godot_char_string cs = godot_string_ascii(&s);
- CHECK(strcmp(godot_char_string_get_data(&cs), "Primero Leche") == 0);
- godot_char_string_destroy(&cs);
-
- cs = godot_string_latin1(&s);
- CHECK(strcmp(godot_char_string_get_data(&cs), "Primero Leche") == 0);
- godot_char_string_destroy(&cs);
-
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] Comparisons (equal)") {
- godot_string s, t;
-
- godot_string_new_with_latin1_chars(&s, "Test Compare");
- godot_string_new_with_latin1_chars(&t, "Test Compare");
- CHECK(godot_string_operator_equal(&s, &t));
- godot_string_destroy(&s);
- godot_string_destroy(&t);
-}
-
-TEST_CASE("[GDNative String] Comparisons (operator <)") {
- godot_string s, t;
-
- godot_string_new_with_latin1_chars(&s, "Bees");
-
- godot_string_new_with_latin1_chars(&t, "Elephant");
- CHECK(godot_string_operator_less(&s, &t));
- godot_string_destroy(&t);
-
- godot_string_new_with_latin1_chars(&t, "Amber");
- CHECK(!godot_string_operator_less(&s, &t));
- godot_string_destroy(&t);
-
- godot_string_new_with_latin1_chars(&t, "Beatrix");
- CHECK(!godot_string_operator_less(&s, &t));
- godot_string_destroy(&t);
-
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] Concatenation (operator +)") {
- godot_string s, t, x;
-
- godot_string_new_with_latin1_chars(&s, "Hel");
- godot_string_new_with_latin1_chars(&t, "lo");
- x = godot_string_operator_plus(&s, &t);
- CHECK(u32scmp(godot_string_get_data(&x), U"Hello") == 0);
- godot_string_destroy(&x);
- godot_string_destroy(&s);
- godot_string_destroy(&t);
-}
-
-TEST_CASE("[GDNative String] Testing size and length of string") {
- godot_string s;
-
- godot_string_new_with_latin1_chars(&s, "Mellon");
- CHECK(godot_string_length(&s) == 6);
- godot_string_destroy(&s);
-
- godot_string_new_with_latin1_chars(&s, "Mellon1");
- CHECK(godot_string_length(&s) == 7);
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] Testing for empty string") {
- godot_string s;
-
- godot_string_new_with_latin1_chars(&s, "Mellon");
- CHECK(!godot_string_empty(&s));
- godot_string_destroy(&s);
-
- godot_string_new_with_latin1_chars(&s, "");
- CHECK(godot_string_empty(&s));
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] Test chr") {
- godot_string s;
-
- s = godot_string_chr('H');
- CHECK(u32scmp(godot_string_get_data(&s), U"H") == 0);
- godot_string_destroy(&s);
-
- s = godot_string_chr(0x3012);
- CHECK(godot_string_operator_index_const(&s, 0) == 0x3012);
- godot_string_destroy(&s);
-
- ERR_PRINT_OFF
- s = godot_string_chr(0xd812);
- CHECK(godot_string_operator_index_const(&s, 0) == 0xfffd); // Unpaired UTF-16 surrogate
- godot_string_destroy(&s);
-
- s = godot_string_chr(0x20d812);
- CHECK(godot_string_operator_index_const(&s, 0) == 0xfffd); // Outside UTF-32 range
- godot_string_destroy(&s);
- ERR_PRINT_ON
-}
-
-TEST_CASE("[GDNative String] Operator []") {
- godot_string s;
-
- godot_string_new_with_latin1_chars(&s, "Hello");
- CHECK(*godot_string_operator_index(&s, 1) == 'e');
- CHECK(godot_string_operator_index_const(&s, 0) == 'H');
- CHECK(godot_string_ord_at(&s, 0) == 'H');
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] Case function test") {
- godot_string s, t;
-
- godot_string_new_with_latin1_chars(&s, "MoMoNgA");
-
- t = godot_string_to_upper(&s);
- CHECK(u32scmp(godot_string_get_data(&t), U"MOMONGA") == 0);
- godot_string_destroy(&t);
-
- t = godot_string_to_lower(&s);
- CHECK(u32scmp(godot_string_get_data(&t), U"momonga") == 0);
- godot_string_destroy(&t);
-
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] Case compare function test") {
- godot_string s, t;
-
- godot_string_new_with_latin1_chars(&s, "MoMoNgA");
- godot_string_new_with_latin1_chars(&t, "momonga");
-
- CHECK(godot_string_casecmp_to(&s, &t) != 0);
- CHECK(godot_string_nocasecmp_to(&s, &t) == 0);
-
- godot_string_destroy(&s);
- godot_string_destroy(&t);
-}
-
-TEST_CASE("[GDNative String] Natural compare function test") {
- godot_string s, t;
-
- godot_string_new_with_latin1_chars(&s, "img2.png");
- godot_string_new_with_latin1_chars(&t, "img10.png");
-
- CHECK(godot_string_nocasecmp_to(&s, &t) > 0);
- CHECK(godot_string_naturalnocasecmp_to(&s, &t) < 0);
-
- godot_string_destroy(&s);
- godot_string_destroy(&t);
-}
-
-TEST_CASE("[GDNative String] hex_encode_buffer") {
- static const uint8_t u8str[] = { 0x45, 0xE3, 0x81, 0x8A, 0x8F, 0xE3 };
- godot_string s = godot_string_hex_encode_buffer(u8str, 6);
- CHECK(u32scmp(godot_string_get_data(&s), U"45e3818a8fe3") == 0);
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] Substr") {
- godot_string s, t;
- godot_string_new_with_latin1_chars(&s, "Killer Baby");
- t = godot_string_substr(&s, 3, 4);
- CHECK(u32scmp(godot_string_get_data(&t), U"ler ") == 0);
- godot_string_destroy(&t);
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] Find") {
- godot_string s, t;
- godot_string_new_with_latin1_chars(&s, "Pretty Woman Woman");
-
- godot_string_new_with_latin1_chars(&t, "Revenge of the Monster Truck");
- CHECK(godot_string_find(&s, &t) == -1);
- godot_string_destroy(&t);
-
- godot_string_new_with_latin1_chars(&t, "tty");
- CHECK(godot_string_find(&s, &t) == 3);
- godot_string_destroy(&t);
-
- godot_string_new_with_latin1_chars(&t, "Wo");
- CHECK(godot_string_find_from(&s, &t, 9) == 13);
- godot_string_destroy(&t);
-
- godot_string_new_with_latin1_chars(&t, "man");
- CHECK(godot_string_rfind(&s, &t) == 15);
- godot_string_destroy(&t);
-
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] Find no case") {
- godot_string s, t;
- godot_string_new_with_latin1_chars(&s, "Pretty Whale Whale");
-
- godot_string_new_with_latin1_chars(&t, "WHA");
- CHECK(godot_string_findn(&s, &t) == 7);
- godot_string_destroy(&t);
-
- godot_string_new_with_latin1_chars(&t, "WHA");
- CHECK(godot_string_findn_from(&s, &t, 9) == 13);
- godot_string_destroy(&t);
-
- godot_string_new_with_latin1_chars(&t, "WHA");
- CHECK(godot_string_rfindn(&s, &t) == 13);
- godot_string_destroy(&t);
-
- godot_string_new_with_latin1_chars(&t, "Revenge of the Monster SawFish");
- CHECK(godot_string_findn(&s, &t) == -1);
- godot_string_destroy(&t);
-
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] Find MK") {
- godot_packed_string_array keys;
- godot_packed_string_array_new(&keys);
-
-#define PUSH_KEY(x) \
- { \
- godot_string t; \
- godot_string_new_with_latin1_chars(&t, x); \
- godot_packed_string_array_push_back(&keys, &t); \
- godot_string_destroy(&t); \
- }
-
- PUSH_KEY("sty")
- PUSH_KEY("tty")
- PUSH_KEY("man")
-
- godot_string s;
- godot_string_new_with_latin1_chars(&s, "Pretty Woman");
- godot_int key = 0;
-
- CHECK(godot_string_findmk(&s, &keys) == 3);
- CHECK(godot_string_findmk_from_in_place(&s, &keys, 0, &key) == 3);
- CHECK(key == 1);
-
- CHECK(godot_string_findmk_from(&s, &keys, 5) == 9);
- CHECK(godot_string_findmk_from_in_place(&s, &keys, 5, &key) == 9);
- CHECK(key == 2);
-
- godot_string_destroy(&s);
- godot_packed_string_array_destroy(&keys);
-
-#undef PUSH_KEY
-}
-
-TEST_CASE("[GDNative String] Find and replace") {
- godot_string s, c, w;
- godot_string_new_with_latin1_chars(&s, "Happy Birthday, Anna!");
- godot_string_new_with_latin1_chars(&c, "Birthday");
- godot_string_new_with_latin1_chars(&w, "Halloween");
- godot_string t = godot_string_replace(&s, &c, &w);
- CHECK(u32scmp(godot_string_get_data(&t), U"Happy Halloween, Anna!") == 0);
- godot_string_destroy(&s);
- godot_string_destroy(&c);
- godot_string_destroy(&w);
-
- godot_string_new_with_latin1_chars(&c, "H");
- godot_string_new_with_latin1_chars(&w, "W");
- s = godot_string_replace_first(&t, &c, &w);
- godot_string_destroy(&t);
- godot_string_destroy(&c);
- godot_string_destroy(&w);
-
- CHECK(u32scmp(godot_string_get_data(&s), U"Wappy Halloween, Anna!") == 0);
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] Insertion") {
- godot_string s, t, r, u;
- godot_string_new_with_latin1_chars(&s, "Who is Frederic?");
- godot_string_new_with_latin1_chars(&t, "?");
- godot_string_new_with_latin1_chars(&r, " Chopin");
-
- u = godot_string_insert(&s, godot_string_find(&s, &t), &r);
- CHECK(u32scmp(godot_string_get_data(&u), U"Who is Frederic Chopin?") == 0);
-
- godot_string_destroy(&s);
- godot_string_destroy(&t);
- godot_string_destroy(&r);
- godot_string_destroy(&u);
-}
-
-TEST_CASE("[GDNative String] Number to string") {
- godot_string s;
- s = godot_string_num(3.141593);
- CHECK(u32scmp(godot_string_get_data(&s), U"3.141593") == 0);
- godot_string_destroy(&s);
-
- s = godot_string_num_with_decimals(3.141593, 3);
- CHECK(u32scmp(godot_string_get_data(&s), U"3.142") == 0);
- godot_string_destroy(&s);
-
- s = godot_string_num_real(3.141593);
- CHECK(u32scmp(godot_string_get_data(&s), U"3.141593") == 0);
- godot_string_destroy(&s);
-
- s = godot_string_num_scientific(30000000);
- CHECK(u32scmp(godot_string_get_data(&s), U"3e+07") == 0);
- godot_string_destroy(&s);
-
- s = godot_string_num_int64(3141593, 10);
- CHECK(u32scmp(godot_string_get_data(&s), U"3141593") == 0);
- godot_string_destroy(&s);
-
- s = godot_string_num_int64(0xA141593, 16);
- CHECK(u32scmp(godot_string_get_data(&s), U"a141593") == 0);
- godot_string_destroy(&s);
-
- s = godot_string_num_int64_capitalized(0xA141593, 16, true);
- CHECK(u32scmp(godot_string_get_data(&s), U"A141593") == 0);
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] String to integer") {
- static const wchar_t *wnums[4] = { L"1237461283", L"- 22", L"0", L" - 1123412" };
- static const char *nums[4] = { "1237461283", "- 22", "0", " - 1123412" };
- static const int num[4] = { 1237461283, -22, 0, -1123412 };
-
- for (int i = 0; i < 4; i++) {
- godot_string s;
- godot_string_new_with_latin1_chars(&s, nums[i]);
- CHECK(godot_string_to_int(&s) == num[i]);
- godot_string_destroy(&s);
-
- CHECK(godot_string_char_to_int(nums[i]) == num[i]);
- CHECK(godot_string_wchar_to_int(wnums[i]) == num[i]);
- }
-}
-
-TEST_CASE("[GDNative String] Hex to integer") {
- static const char *nums[4] = { "0xFFAE", "22", "0", "AADDAD" };
- static const int64_t num[4] = { 0xFFAE, 0x22, 0, 0xAADDAD };
- static const bool wo_prefix[4] = { false, true, true, true };
- static const bool w_prefix[4] = { true, false, true, false };
-
- for (int i = 0; i < 4; i++) {
- godot_string s;
- godot_string_new_with_latin1_chars(&s, nums[i]);
- CHECK((godot_string_hex_to_int_with_prefix(&s) == num[i]) == w_prefix[i]);
- CHECK((godot_string_hex_to_int(&s) == num[i]) == wo_prefix[i]);
- godot_string_destroy(&s);
- }
-}
-
-TEST_CASE("[GDNative String] String to float") {
- static const wchar_t *wnums[4] = { L"-12348298412.2", L"0.05", L"2.0002", L" -0.0001" };
- static const char *nums[4] = { "-12348298412.2", "0.05", "2.0002", " -0.0001" };
- static const double num[4] = { -12348298412.2, 0.05, 2.0002, -0.0001 };
-
- for (int i = 0; i < 4; i++) {
- godot_string s;
- godot_string_new_with_latin1_chars(&s, nums[i]);
- CHECK(!(ABS(godot_string_to_float(&s) - num[i]) > 0.00001));
- godot_string_destroy(&s);
-
- CHECK(!(ABS(godot_string_char_to_float(nums[i]) - num[i]) > 0.00001));
- CHECK(!(ABS(godot_string_wchar_to_float(wnums[i], nullptr) - num[i]) > 0.00001));
- }
-}
-
-TEST_CASE("[GDNative String] CamelCase to underscore") {
- godot_string s, t;
- godot_string_new_with_latin1_chars(&s, "TestTestStringGD");
-
- t = godot_string_camelcase_to_underscore(&s);
- CHECK(u32scmp(godot_string_get_data(&t), U"Test_Test_String_GD") == 0);
- godot_string_destroy(&t);
-
- t = godot_string_camelcase_to_underscore_lowercased(&s);
- CHECK(u32scmp(godot_string_get_data(&t), U"test_test_string_gd") == 0);
- godot_string_destroy(&t);
-
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] Slicing") {
- godot_string s, c;
- godot_string_new_with_latin1_chars(&s, "Mars,Jupiter,Saturn,Uranus");
- godot_string_new_with_latin1_chars(&c, ",");
-
- const char32_t *slices[4] = { U"Mars", U"Jupiter", U"Saturn", U"Uranus" };
- for (int i = 0; i < godot_string_get_slice_count(&s, &c); i++) {
- godot_string t;
- t = godot_string_get_slice(&s, &c, i);
- CHECK(u32scmp(godot_string_get_data(&t), slices[i]) == 0);
- godot_string_destroy(&t);
-
- t = godot_string_get_slicec(&s, U',', i);
- CHECK(u32scmp(godot_string_get_data(&t), slices[i]) == 0);
- godot_string_destroy(&t);
- }
-
- godot_string_destroy(&c);
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] Splitting") {
- godot_string s, c;
- godot_string_new_with_latin1_chars(&s, "Mars,Jupiter,Saturn,Uranus");
- godot_string_new_with_latin1_chars(&c, ",");
-
- godot_packed_string_array l;
-
- const char32_t *slices_l[3] = { U"Mars", U"Jupiter", U"Saturn,Uranus" };
- const char32_t *slices_r[3] = { U"Mars,Jupiter", U"Saturn", U"Uranus" };
-
- l = godot_string_split_with_maxsplit(&s, &c, true, 2);
- CHECK(godot_packed_string_array_size(&l) == 3);
- for (int i = 0; i < godot_packed_string_array_size(&l); i++) {
- godot_string t = godot_packed_string_array_get(&l, i);
- CHECK(u32scmp(godot_string_get_data(&t), slices_l[i]) == 0);
- godot_string_destroy(&t);
- }
- godot_packed_string_array_destroy(&l);
-
- l = godot_string_rsplit_with_maxsplit(&s, &c, true, 2);
- CHECK(godot_packed_string_array_size(&l) == 3);
- for (int i = 0; i < godot_packed_string_array_size(&l); i++) {
- godot_string t = godot_packed_string_array_get(&l, i);
- CHECK(u32scmp(godot_string_get_data(&t), slices_r[i]) == 0);
- godot_string_destroy(&t);
- }
- godot_packed_string_array_destroy(&l);
- godot_string_destroy(&s);
-
- godot_string_new_with_latin1_chars(&s, "Mars Jupiter Saturn Uranus");
- const char32_t *slices_s[4] = { U"Mars", U"Jupiter", U"Saturn", U"Uranus" };
- l = godot_string_split_spaces(&s);
- for (int i = 0; i < godot_packed_string_array_size(&l); i++) {
- godot_string t = godot_packed_string_array_get(&l, i);
- CHECK(u32scmp(godot_string_get_data(&t), slices_s[i]) == 0);
- godot_string_destroy(&t);
- }
- godot_packed_string_array_destroy(&l);
- godot_string_destroy(&s);
-
- godot_string c1, c2;
- godot_string_new_with_latin1_chars(&c1, ";");
- godot_string_new_with_latin1_chars(&c2, " ");
-
- godot_string_new_with_latin1_chars(&s, "1.2;2.3 4.5");
- const double slices_d[3] = { 1.2, 2.3, 4.5 };
-
- godot_packed_float32_array lf = godot_string_split_floats_allow_empty(&s, &c1);
- CHECK(godot_packed_float32_array_size(&lf) == 2);
- for (int i = 0; i < godot_packed_float32_array_size(&lf); i++) {
- CHECK(ABS(godot_packed_float32_array_get(&lf, i) - slices_d[i]) <= 0.00001);
- }
- godot_packed_float32_array_destroy(&lf);
-
- godot_packed_string_array keys;
- godot_packed_string_array_new(&keys);
- godot_packed_string_array_push_back(&keys, &c1);
- godot_packed_string_array_push_back(&keys, &c2);
-
- lf = godot_string_split_floats_mk_allow_empty(&s, &keys);
- CHECK(godot_packed_float32_array_size(&lf) == 3);
- for (int i = 0; i < godot_packed_float32_array_size(&lf); i++) {
- CHECK(ABS(godot_packed_float32_array_get(&lf, i) - slices_d[i]) <= 0.00001);
- }
- godot_packed_float32_array_destroy(&lf);
-
- godot_string_destroy(&s);
- godot_string_new_with_latin1_chars(&s, "1;2 4");
- const int slices_i[3] = { 1, 2, 4 };
-
- godot_packed_int32_array li = godot_string_split_ints_allow_empty(&s, &c1);
- CHECK(godot_packed_int32_array_size(&li) == 2);
- for (int i = 0; i < godot_packed_int32_array_size(&li); i++) {
- CHECK(godot_packed_int32_array_get(&li, i) == slices_i[i]);
- }
- godot_packed_int32_array_destroy(&li);
-
- li = godot_string_split_ints_mk_allow_empty(&s, &keys);
- CHECK(godot_packed_int32_array_size(&li) == 3);
- for (int i = 0; i < godot_packed_int32_array_size(&li); i++) {
- CHECK(godot_packed_int32_array_get(&li, i) == slices_i[i]);
- }
- godot_packed_int32_array_destroy(&li);
-
- godot_string_destroy(&s);
- godot_string_destroy(&c);
- godot_string_destroy(&c1);
- godot_string_destroy(&c2);
- godot_packed_string_array_destroy(&keys);
-}
-
-TEST_CASE("[GDNative String] Erasing") {
- godot_string s, t;
- godot_string_new_with_latin1_chars(&s, "Josephine is such a cute girl!");
- godot_string_new_with_latin1_chars(&t, "cute ");
-
- godot_string_erase(&s, godot_string_find(&s, &t), godot_string_length(&t));
-
- CHECK(u32scmp(godot_string_get_data(&s), U"Josephine is such a girl!") == 0);
-
- godot_string_destroy(&s);
- godot_string_destroy(&t);
-}
-
-struct test_27_data {
- char const *data;
- char const *part;
- bool expected;
-};
-
-TEST_CASE("[GDNative String] Begins with") {
- test_27_data tc[] = {
- { "res://foobar", "res://", true },
- { "res", "res://", false },
- { "abc", "abc", true }
- };
- size_t count = sizeof(tc) / sizeof(tc[0]);
- bool state = true;
- for (size_t i = 0; state && i < count; ++i) {
- godot_string s;
- godot_string_new_with_latin1_chars(&s, tc[i].data);
-
- state = godot_string_begins_with_char_array(&s, tc[i].part) == tc[i].expected;
- if (state) {
- godot_string t;
- godot_string_new_with_latin1_chars(&t, tc[i].part);
- state = godot_string_begins_with(&s, &t) == tc[i].expected;
- godot_string_destroy(&t);
- }
- godot_string_destroy(&s);
-
- CHECK(state);
- if (!state) {
- break;
- }
- };
- CHECK(state);
-}
-
-TEST_CASE("[GDNative String] Ends with") {
- test_27_data tc[] = {
- { "res://foobar", "foobar", true },
- { "res", "res://", false },
- { "abc", "abc", true }
- };
- size_t count = sizeof(tc) / sizeof(tc[0]);
- bool state = true;
- for (size_t i = 0; state && i < count; ++i) {
- godot_string s;
- godot_string_new_with_latin1_chars(&s, tc[i].data);
-
- state = godot_string_ends_with_char_array(&s, tc[i].part) == tc[i].expected;
- if (state) {
- godot_string t;
- godot_string_new_with_latin1_chars(&t, tc[i].part);
- state = godot_string_ends_with(&s, &t) == tc[i].expected;
- godot_string_destroy(&t);
- }
- godot_string_destroy(&s);
-
- CHECK(state);
- if (!state) {
- break;
- }
- };
- CHECK(state);
-}
-
-TEST_CASE("[GDNative String] format") {
- godot_string value_format, t;
- godot_string_new_with_latin1_chars(&value_format, "red=\"$red\" green=\"$green\" blue=\"$blue\" alpha=\"$alpha\"");
-
- godot_variant key_v, val_v;
- godot_dictionary value_dictionary;
- godot_dictionary_new(&value_dictionary);
-
- godot_string_new_with_latin1_chars(&t, "red");
- godot_variant_new_string(&key_v, &t);
- godot_string_destroy(&t);
- godot_variant_new_int(&val_v, 10);
- godot_dictionary_set(&value_dictionary, &key_v, &val_v);
- godot_variant_destroy(&key_v);
- godot_variant_destroy(&val_v);
-
- godot_string_new_with_latin1_chars(&t, "green");
- godot_variant_new_string(&key_v, &t);
- godot_string_destroy(&t);
- godot_variant_new_int(&val_v, 20);
- godot_dictionary_set(&value_dictionary, &key_v, &val_v);
- godot_variant_destroy(&key_v);
- godot_variant_destroy(&val_v);
-
- godot_string_new_with_latin1_chars(&t, "blue");
- godot_variant_new_string(&key_v, &t);
- godot_string_destroy(&t);
- godot_string_new_with_latin1_chars(&t, "bla");
- godot_variant_new_string(&val_v, &t);
- godot_string_destroy(&t);
- godot_dictionary_set(&value_dictionary, &key_v, &val_v);
- godot_variant_destroy(&key_v);
- godot_variant_destroy(&val_v);
-
- godot_string_new_with_latin1_chars(&t, "alpha");
- godot_variant_new_string(&key_v, &t);
- godot_string_destroy(&t);
- godot_variant_new_real(&val_v, 0.4);
- godot_dictionary_set(&value_dictionary, &key_v, &val_v);
- godot_variant_destroy(&key_v);
- godot_variant_destroy(&val_v);
-
- godot_variant dict_v;
- godot_variant_new_dictionary(&dict_v, &value_dictionary);
- godot_string s = godot_string_format_with_custom_placeholder(&value_format, &dict_v, "$_");
-
- CHECK(u32scmp(godot_string_get_data(&s), U"red=\"10\" green=\"20\" blue=\"bla\" alpha=\"0.4\"") == 0);
-
- godot_dictionary_destroy(&value_dictionary);
- godot_string_destroy(&s);
- godot_variant_destroy(&dict_v);
- godot_string_destroy(&value_format);
-}
-
-TEST_CASE("[GDNative String] sprintf") {
- //godot_string GDAPI (const godot_string *p_self, const godot_array *p_values, godot_bool *p_error);
- godot_string format, output;
- godot_array args;
- bool error;
-
-#define ARRAY_PUSH_STRING(x) \
- { \
- godot_variant v; \
- godot_string t; \
- godot_string_new_with_latin1_chars(&t, x); \
- godot_variant_new_string(&v, &t); \
- godot_string_destroy(&t); \
- godot_array_push_back(&args, &v); \
- godot_variant_destroy(&v); \
- }
-
-#define ARRAY_PUSH_INT(x) \
- { \
- godot_variant v; \
- godot_variant_new_int(&v, x); \
- godot_array_push_back(&args, &v); \
- godot_variant_destroy(&v); \
- }
-
-#define ARRAY_PUSH_REAL(x) \
- { \
- godot_variant v; \
- godot_variant_new_real(&v, x); \
- godot_array_push_back(&args, &v); \
- godot_variant_destroy(&v); \
- }
-
- godot_array_new(&args);
-
- // %%
- godot_string_new_with_latin1_chars(&format, "fish %% frog");
- godot_array_clear(&args);
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- CHECK(u32scmp(godot_string_get_data(&output), U"fish % frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
- //////// INTS
-
- // Int
- godot_string_new_with_latin1_chars(&format, "fish %d frog");
- godot_array_clear(&args);
- ARRAY_PUSH_INT(5);
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- CHECK(u32scmp(godot_string_get_data(&output), U"fish 5 frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // Int left padded with zeroes.
- godot_string_new_with_latin1_chars(&format, "fish %05d frog");
- godot_array_clear(&args);
- ARRAY_PUSH_INT(5);
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- CHECK(u32scmp(godot_string_get_data(&output), U"fish 00005 frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // Int left padded with spaces.
- godot_string_new_with_latin1_chars(&format, "fish %5d frog");
- godot_array_clear(&args);
- ARRAY_PUSH_INT(5);
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- CHECK(u32scmp(godot_string_get_data(&output), U"fish 5 frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // Int right padded with spaces.
- godot_string_new_with_latin1_chars(&format, "fish %-5d frog");
- godot_array_clear(&args);
- ARRAY_PUSH_INT(5);
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- CHECK(u32scmp(godot_string_get_data(&output), U"fish 5 frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // Int with sign (positive).
- godot_string_new_with_latin1_chars(&format, "fish %+d frog");
- godot_array_clear(&args);
- ARRAY_PUSH_INT(5);
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- CHECK(u32scmp(godot_string_get_data(&output), U"fish +5 frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // Negative int.
- godot_string_new_with_latin1_chars(&format, "fish %d frog");
- godot_array_clear(&args);
- ARRAY_PUSH_INT(-5);
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- CHECK(u32scmp(godot_string_get_data(&output), U"fish -5 frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // Hex (lower)
- godot_string_new_with_latin1_chars(&format, "fish %x frog");
- godot_array_clear(&args);
- ARRAY_PUSH_INT(45);
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- CHECK(u32scmp(godot_string_get_data(&output), U"fish 2d frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // Hex (upper)
- godot_string_new_with_latin1_chars(&format, "fish %X frog");
- godot_array_clear(&args);
- ARRAY_PUSH_INT(45);
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- CHECK(u32scmp(godot_string_get_data(&output), U"fish 2D frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // Octal
- godot_string_new_with_latin1_chars(&format, "fish %o frog");
- godot_array_clear(&args);
- ARRAY_PUSH_INT(99);
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- CHECK(u32scmp(godot_string_get_data(&output), U"fish 143 frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
- ////// REALS
-
- // Real
- godot_string_new_with_latin1_chars(&format, "fish %f frog");
- godot_array_clear(&args);
- ARRAY_PUSH_REAL(99.99);
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- CHECK(u32scmp(godot_string_get_data(&output), U"fish 99.990000 frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // Real left-padded
- godot_string_new_with_latin1_chars(&format, "fish %11f frog");
- godot_array_clear(&args);
- ARRAY_PUSH_REAL(99.99);
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- CHECK(u32scmp(godot_string_get_data(&output), U"fish 99.990000 frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // Real right-padded
- godot_string_new_with_latin1_chars(&format, "fish %-11f frog");
- godot_array_clear(&args);
- ARRAY_PUSH_REAL(99.99);
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- CHECK(u32scmp(godot_string_get_data(&output), U"fish 99.990000 frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // Real given int.
- godot_string_new_with_latin1_chars(&format, "fish %f frog");
- godot_array_clear(&args);
- ARRAY_PUSH_REAL(99);
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- CHECK(u32scmp(godot_string_get_data(&output), U"fish 99.000000 frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // Real with sign (positive).
- godot_string_new_with_latin1_chars(&format, "fish %+f frog");
- godot_array_clear(&args);
- ARRAY_PUSH_REAL(99.99);
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- CHECK(u32scmp(godot_string_get_data(&output), U"fish +99.990000 frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // Real with 1 decimals.
- godot_string_new_with_latin1_chars(&format, "fish %.1f frog");
- godot_array_clear(&args);
- ARRAY_PUSH_REAL(99.99);
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- CHECK(u32scmp(godot_string_get_data(&output), U"fish 100.0 frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // Real with 12 decimals.
- godot_string_new_with_latin1_chars(&format, "fish %.12f frog");
- godot_array_clear(&args);
- ARRAY_PUSH_REAL(99.99);
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- CHECK(u32scmp(godot_string_get_data(&output), U"fish 99.990000000000 frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // Real with no decimals.
- godot_string_new_with_latin1_chars(&format, "fish %.f frog");
- godot_array_clear(&args);
- ARRAY_PUSH_REAL(99.99);
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- CHECK(u32scmp(godot_string_get_data(&output), U"fish 100 frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- /////// Strings.
-
- // String
- godot_string_new_with_latin1_chars(&format, "fish %s frog");
- godot_array_clear(&args);
- ARRAY_PUSH_STRING("cheese");
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- CHECK(u32scmp(godot_string_get_data(&output), U"fish cheese frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // String left-padded
- godot_string_new_with_latin1_chars(&format, "fish %10s frog");
- godot_array_clear(&args);
- ARRAY_PUSH_STRING("cheese");
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- CHECK(u32scmp(godot_string_get_data(&output), U"fish cheese frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // String right-padded
- godot_string_new_with_latin1_chars(&format, "fish %-10s frog");
- godot_array_clear(&args);
- ARRAY_PUSH_STRING("cheese");
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- CHECK(u32scmp(godot_string_get_data(&output), U"fish cheese frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- ///// Characters
-
- // Character as string.
- godot_string_new_with_latin1_chars(&format, "fish %c frog");
- godot_array_clear(&args);
- ARRAY_PUSH_STRING("A");
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- CHECK(u32scmp(godot_string_get_data(&output), U"fish A frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // Character as int.
- godot_string_new_with_latin1_chars(&format, "fish %c frog");
- godot_array_clear(&args);
- ARRAY_PUSH_INT(65);
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- CHECK(u32scmp(godot_string_get_data(&output), U"fish A frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- ///// Dynamic width
-
- // String dynamic width
- godot_string_new_with_latin1_chars(&format, "fish %*s frog");
- godot_array_clear(&args);
- ARRAY_PUSH_INT(10);
- ARRAY_PUSH_STRING("cheese");
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- REQUIRE(u32scmp(godot_string_get_data(&output), U"fish cheese frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // Int dynamic width
- godot_string_new_with_latin1_chars(&format, "fish %*d frog");
- godot_array_clear(&args);
- ARRAY_PUSH_INT(10);
- ARRAY_PUSH_INT(99);
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- REQUIRE(u32scmp(godot_string_get_data(&output), U"fish 99 frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // Float dynamic width
- godot_string_new_with_latin1_chars(&format, "fish %*.*f frog");
- godot_array_clear(&args);
- ARRAY_PUSH_INT(10);
- ARRAY_PUSH_INT(3);
- ARRAY_PUSH_REAL(99.99);
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error == false);
- CHECK(u32scmp(godot_string_get_data(&output), U"fish 99.990 frog") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- ///// Errors
-
- // More formats than arguments.
- godot_string_new_with_latin1_chars(&format, "fish %s %s frog");
- godot_array_clear(&args);
- ARRAY_PUSH_STRING("cheese");
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error);
- CHECK(u32scmp(godot_string_get_data(&output), U"not enough arguments for format string") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // More arguments than formats.
- godot_string_new_with_latin1_chars(&format, "fish %s frog");
- godot_array_clear(&args);
- ARRAY_PUSH_STRING("hello");
- ARRAY_PUSH_STRING("cheese");
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error);
- CHECK(u32scmp(godot_string_get_data(&output), U"not all arguments converted during string formatting") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // Incomplete format.
- godot_string_new_with_latin1_chars(&format, "fish %10");
- godot_array_clear(&args);
- ARRAY_PUSH_STRING("cheese");
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error);
- CHECK(u32scmp(godot_string_get_data(&output), U"incomplete format") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // Bad character in format string
- godot_string_new_with_latin1_chars(&format, "fish %&f frog");
- godot_array_clear(&args);
- ARRAY_PUSH_STRING("cheese");
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error);
- CHECK(u32scmp(godot_string_get_data(&output), U"unsupported format character") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // Too many decimals.
- godot_string_new_with_latin1_chars(&format, "fish %2.2.2f frog");
- godot_array_clear(&args);
- ARRAY_PUSH_REAL(99.99);
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error);
- CHECK(u32scmp(godot_string_get_data(&output), U"too many decimal points in format") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // * not a number
- godot_string_new_with_latin1_chars(&format, "fish %*f frog");
- godot_array_clear(&args);
- ARRAY_PUSH_STRING("cheese");
- ARRAY_PUSH_REAL(99.99);
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error);
- CHECK(u32scmp(godot_string_get_data(&output), U"* wants number") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // Character too long.
- godot_string_new_with_latin1_chars(&format, "fish %c frog");
- godot_array_clear(&args);
- ARRAY_PUSH_STRING("sc");
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error);
- CHECK(u32scmp(godot_string_get_data(&output), U"%c requires number or single-character string") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- // Character bad type.
- godot_string_new_with_latin1_chars(&format, "fish %c frog");
- godot_array_clear(&args);
- godot_array t;
- godot_array_new(&t);
- godot_variant v;
- godot_variant_new_array(&v, &t);
- godot_array_destroy(&t);
- godot_array_push_back(&args, &v);
- godot_variant_destroy(&v);
- output = godot_string_sprintf(&format, &args, &error);
- REQUIRE(error);
- CHECK(u32scmp(godot_string_get_data(&output), U"%c requires number or single-character string") == 0);
- godot_string_destroy(&format);
- godot_string_destroy(&output);
-
- godot_array_destroy(&args);
-#undef ARRAY_PUSH_INT
-#undef ARRAY_PUSH_REAL
-#undef ARRAY_PUSH_STRING
-}
-
-TEST_CASE("[GDNative String] is_numeric") {
-#define IS_NUM_TEST(x, r) \
- { \
- godot_string t; \
- godot_string_new_with_latin1_chars(&t, x); \
- CHECK(godot_string_is_numeric(&t) == r); \
- godot_string_destroy(&t); \
- }
-
- IS_NUM_TEST("12", true);
- IS_NUM_TEST("1.2", true);
- IS_NUM_TEST("AF", false);
- IS_NUM_TEST("-12", true);
- IS_NUM_TEST("-1.2", true);
-
-#undef IS_NUM_TEST
-}
-
-TEST_CASE("[GDNative String] pad") {
- godot_string s, c;
- godot_string_new_with_latin1_chars(&s, "test");
- godot_string_new_with_latin1_chars(&c, "x");
-
- godot_string l = godot_string_lpad_with_custom_character(&s, 10, &c);
- CHECK(u32scmp(godot_string_get_data(&l), U"xxxxxxtest") == 0);
- godot_string_destroy(&l);
-
- godot_string r = godot_string_rpad_with_custom_character(&s, 10, &c);
- CHECK(u32scmp(godot_string_get_data(&r), U"testxxxxxx") == 0);
- godot_string_destroy(&r);
-
- godot_string_destroy(&s);
- godot_string_destroy(&c);
-
- godot_string_new_with_latin1_chars(&s, "10.10");
- c = godot_string_pad_decimals(&s, 4);
- CHECK(u32scmp(godot_string_get_data(&c), U"10.1000") == 0);
- godot_string_destroy(&c);
- c = godot_string_pad_zeros(&s, 4);
- CHECK(u32scmp(godot_string_get_data(&c), U"0010.10") == 0);
- godot_string_destroy(&c);
-
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] is_subsequence_of") {
- godot_string a, t;
- godot_string_new_with_latin1_chars(&a, "is subsequence of");
-
- godot_string_new_with_latin1_chars(&t, "sub");
- CHECK(godot_string_is_subsequence_of(&t, &a));
- godot_string_destroy(&t);
-
- godot_string_new_with_latin1_chars(&t, "Sub");
- CHECK(!godot_string_is_subsequence_of(&t, &a));
- godot_string_destroy(&t);
-
- godot_string_new_with_latin1_chars(&t, "Sub");
- CHECK(godot_string_is_subsequence_ofi(&t, &a));
- godot_string_destroy(&t);
-
- godot_string_destroy(&a);
-}
-
-TEST_CASE("[GDNative String] match") {
- godot_string s, t;
- godot_string_new_with_latin1_chars(&s, "*.png");
-
- godot_string_new_with_latin1_chars(&t, "img1.png");
- CHECK(godot_string_match(&t, &s));
- godot_string_destroy(&t);
-
- godot_string_new_with_latin1_chars(&t, "img1.jpeg");
- CHECK(!godot_string_match(&t, &s));
- godot_string_destroy(&t);
-
- godot_string_new_with_latin1_chars(&t, "img1.Png");
- CHECK(!godot_string_match(&t, &s));
- CHECK(godot_string_matchn(&t, &s));
- godot_string_destroy(&t);
-
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] IPVX address to string") {
- godot_string ip;
-
- godot_string_new_with_latin1_chars(&ip, "192.168.0.1");
- CHECK(godot_string_is_valid_ip_address(&ip));
- godot_string_destroy(&ip);
-
- godot_string_new_with_latin1_chars(&ip, "192.368.0.1");
- CHECK(!godot_string_is_valid_ip_address(&ip));
- godot_string_destroy(&ip);
-
- godot_string_new_with_latin1_chars(&ip, "2001:0db8:85a3:0000:0000:8a2e:0370:7334");
- CHECK(godot_string_is_valid_ip_address(&ip));
- godot_string_destroy(&ip);
-
- godot_string_new_with_latin1_chars(&ip, "2001:0db8:85j3:0000:0000:8a2e:0370:7334");
- CHECK(!godot_string_is_valid_ip_address(&ip));
- godot_string_destroy(&ip);
-
- godot_string_new_with_latin1_chars(&ip, "2001:0db8:85f345:0000:0000:8a2e:0370:7334");
- CHECK(!godot_string_is_valid_ip_address(&ip));
- godot_string_destroy(&ip);
-
- godot_string_new_with_latin1_chars(&ip, "2001:0db8::0:8a2e:370:7334");
- CHECK(godot_string_is_valid_ip_address(&ip));
- godot_string_destroy(&ip);
-
- godot_string_new_with_latin1_chars(&ip, "::ffff:192.168.0.1");
- CHECK(godot_string_is_valid_ip_address(&ip));
- godot_string_destroy(&ip);
-}
-
-TEST_CASE("[GDNative String] Capitalize against many strings") {
-#define CAP_TEST(i, o) \
- godot_string_new_with_latin1_chars(&input, i); \
- godot_string_new_with_latin1_chars(&output, o); \
- test = godot_string_capitalize(&input); \
- CHECK(u32scmp(godot_string_get_data(&output), godot_string_get_data(&test)) == 0); \
- godot_string_destroy(&input); \
- godot_string_destroy(&output); \
- godot_string_destroy(&test);
-
- godot_string input, output, test;
-
- CAP_TEST("bytes2var", "Bytes 2 Var");
- CAP_TEST("linear2db", "Linear 2 Db");
- CAP_TEST("vector3", "Vector 3");
- CAP_TEST("sha256", "Sha 256");
- CAP_TEST("2db", "2 Db");
- CAP_TEST("PascalCase", "Pascal Case");
- CAP_TEST("PascalPascalCase", "Pascal Pascal Case");
- CAP_TEST("snake_case", "Snake Case");
- CAP_TEST("snake_snake_case", "Snake Snake Case");
- CAP_TEST("sha256sum", "Sha 256 Sum");
- CAP_TEST("cat2dog", "Cat 2 Dog");
- CAP_TEST("function(name)", "Function(name)");
- CAP_TEST("snake_case_function(snake_case_arg)", "Snake Case Function(snake Case Arg)");
- CAP_TEST("snake_case_function( snake_case_arg )", "Snake Case Function( Snake Case Arg )");
-
-#undef CAP_TEST
-}
-
-TEST_CASE("[GDNative String] lstrip and rstrip") {
-#define LSTRIP_TEST(x, y, z) \
- { \
- godot_string xx, yy, zz, rr; \
- godot_string_new_with_latin1_chars(&xx, x); \
- godot_string_new_with_latin1_chars(&yy, y); \
- godot_string_new_with_latin1_chars(&zz, z); \
- rr = godot_string_lstrip(&xx, &yy); \
- state = state && (u32scmp(godot_string_get_data(&rr), godot_string_get_data(&zz)) == 0); \
- godot_string_destroy(&xx); \
- godot_string_destroy(&yy); \
- godot_string_destroy(&zz); \
- godot_string_destroy(&rr); \
- }
-
-#define RSTRIP_TEST(x, y, z) \
- { \
- godot_string xx, yy, zz, rr; \
- godot_string_new_with_latin1_chars(&xx, x); \
- godot_string_new_with_latin1_chars(&yy, y); \
- godot_string_new_with_latin1_chars(&zz, z); \
- rr = godot_string_rstrip(&xx, &yy); \
- state = state && (u32scmp(godot_string_get_data(&rr), godot_string_get_data(&zz)) == 0); \
- godot_string_destroy(&xx); \
- godot_string_destroy(&yy); \
- godot_string_destroy(&zz); \
- godot_string_destroy(&rr); \
- }
-
-#define LSTRIP_UTF8_TEST(x, y, z) \
- { \
- godot_string xx, yy, zz, rr; \
- godot_string_new_with_utf8_chars(&xx, x); \
- godot_string_new_with_utf8_chars(&yy, y); \
- godot_string_new_with_utf8_chars(&zz, z); \
- rr = godot_string_lstrip(&xx, &yy); \
- state = state && (u32scmp(godot_string_get_data(&rr), godot_string_get_data(&zz)) == 0); \
- godot_string_destroy(&xx); \
- godot_string_destroy(&yy); \
- godot_string_destroy(&zz); \
- godot_string_destroy(&rr); \
- }
-
-#define RSTRIP_UTF8_TEST(x, y, z) \
- { \
- godot_string xx, yy, zz, rr; \
- godot_string_new_with_utf8_chars(&xx, x); \
- godot_string_new_with_utf8_chars(&yy, y); \
- godot_string_new_with_utf8_chars(&zz, z); \
- rr = godot_string_rstrip(&xx, &yy); \
- state = state && (u32scmp(godot_string_get_data(&rr), godot_string_get_data(&zz)) == 0); \
- godot_string_destroy(&xx); \
- godot_string_destroy(&yy); \
- godot_string_destroy(&zz); \
- godot_string_destroy(&rr); \
- }
-
- bool state = true;
-
- // strip none
- LSTRIP_TEST("abc", "", "abc");
- RSTRIP_TEST("abc", "", "abc");
- // strip one
- LSTRIP_TEST("abc", "a", "bc");
- RSTRIP_TEST("abc", "c", "ab");
- // strip lots
- LSTRIP_TEST("bababbababccc", "ab", "ccc");
- RSTRIP_TEST("aaabcbcbcbbcbbc", "cb", "aaa");
- // strip empty string
- LSTRIP_TEST("", "", "");
- RSTRIP_TEST("", "", "");
- // strip to empty string
- LSTRIP_TEST("abcabcabc", "bca", "");
- RSTRIP_TEST("abcabcabc", "bca", "");
- // don't strip wrong end
- LSTRIP_TEST("abc", "c", "abc");
- LSTRIP_TEST("abca", "a", "bca");
- RSTRIP_TEST("abc", "a", "abc");
- RSTRIP_TEST("abca", "a", "abc");
- // in utf-8 "¿" (\u00bf) has the same first byte as "µ" (\u00b5)
- // and the same second as "ÿ" (\u00ff)
- LSTRIP_UTF8_TEST("¿", "µÿ", "¿");
- RSTRIP_UTF8_TEST("¿", "µÿ", "¿");
- LSTRIP_UTF8_TEST("µ¿ÿ", "µÿ", "¿ÿ");
- RSTRIP_UTF8_TEST("µ¿ÿ", "µÿ", "µ¿");
-
- // the above tests repeated with additional superfluous strip chars
-
- // strip none
- LSTRIP_TEST("abc", "qwjkl", "abc");
- RSTRIP_TEST("abc", "qwjkl", "abc");
- // strip one
- LSTRIP_TEST("abc", "qwajkl", "bc");
- RSTRIP_TEST("abc", "qwcjkl", "ab");
- // strip lots
- LSTRIP_TEST("bababbababccc", "qwabjkl", "ccc");
- RSTRIP_TEST("aaabcbcbcbbcbbc", "qwcbjkl", "aaa");
- // strip empty string
- LSTRIP_TEST("", "qwjkl", "");
- RSTRIP_TEST("", "qwjkl", "");
- // strip to empty string
- LSTRIP_TEST("abcabcabc", "qwbcajkl", "");
- RSTRIP_TEST("abcabcabc", "qwbcajkl", "");
- // don't strip wrong end
- LSTRIP_TEST("abc", "qwcjkl", "abc");
- LSTRIP_TEST("abca", "qwajkl", "bca");
- RSTRIP_TEST("abc", "qwajkl", "abc");
- RSTRIP_TEST("abca", "qwajkl", "abc");
- // in utf-8 "¿" (\u00bf) has the same first byte as "µ" (\u00b5)
- // and the same second as "ÿ" (\u00ff)
- LSTRIP_UTF8_TEST("¿", "qwaµÿjkl", "¿");
- RSTRIP_UTF8_TEST("¿", "qwaµÿjkl", "¿");
- LSTRIP_UTF8_TEST("µ¿ÿ", "qwaµÿjkl", "¿ÿ");
- RSTRIP_UTF8_TEST("µ¿ÿ", "qwaµÿjkl", "µ¿");
-
- CHECK(state);
-
-#undef LSTRIP_TEST
-#undef RSTRIP_TEST
-#undef LSTRIP_UTF8_TEST
-#undef RSTRIP_UTF8_TEST
-}
-
-TEST_CASE("[GDNative String] Cyrillic to_lower()") {
- godot_string upper, lower, test;
- godot_string_new_with_utf8_chars(&upper, "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ");
- godot_string_new_with_utf8_chars(&lower, "абвгдеёжзийклмнопрстуфхцчшщъыьэюя");
-
- test = godot_string_to_lower(&upper);
-
- CHECK((u32scmp(godot_string_get_data(&test), godot_string_get_data(&lower)) == 0));
-
- godot_string_destroy(&upper);
- godot_string_destroy(&lower);
- godot_string_destroy(&test);
-}
-
-TEST_CASE("[GDNative String] Count and countn functionality") {
-#define COUNT_TEST(x, y, r) \
- { \
- godot_string s, t; \
- godot_string_new_with_latin1_chars(&s, x); \
- godot_string_new_with_latin1_chars(&t, y); \
- state = state && (godot_string_count(&s, &t, 0, 0) == r); \
- godot_string_destroy(&s); \
- godot_string_destroy(&t); \
- }
-
-#define COUNTR_TEST(x, y, a, b, r) \
- { \
- godot_string s, t; \
- godot_string_new_with_latin1_chars(&s, x); \
- godot_string_new_with_latin1_chars(&t, y); \
- state = state && (godot_string_count(&s, &t, a, b) == r); \
- godot_string_destroy(&s); \
- godot_string_destroy(&t); \
- }
-
-#define COUNTN_TEST(x, y, r) \
- { \
- godot_string s, t; \
- godot_string_new_with_latin1_chars(&s, x); \
- godot_string_new_with_latin1_chars(&t, y); \
- state = state && (godot_string_countn(&s, &t, 0, 0) == r); \
- godot_string_destroy(&s); \
- godot_string_destroy(&t); \
- }
-
-#define COUNTNR_TEST(x, y, a, b, r) \
- { \
- godot_string s, t; \
- godot_string_new_with_latin1_chars(&s, x); \
- godot_string_new_with_latin1_chars(&t, y); \
- state = state && (godot_string_countn(&s, &t, a, b) == r); \
- godot_string_destroy(&s); \
- godot_string_destroy(&t); \
- }
- bool state = true;
-
- COUNT_TEST("", "Test", 0);
- COUNT_TEST("Test", "", 0);
- COUNT_TEST("Test", "test", 0);
- COUNT_TEST("Test", "TEST", 0);
- COUNT_TEST("TEST", "TEST", 1);
- COUNT_TEST("Test", "Test", 1);
- COUNT_TEST("aTest", "Test", 1);
- COUNT_TEST("Testa", "Test", 1);
- COUNT_TEST("TestTestTest", "Test", 3);
- COUNT_TEST("TestTestTest", "TestTest", 1);
- COUNT_TEST("TestGodotTestGodotTestGodot", "Test", 3);
-
- COUNTR_TEST("TestTestTestTest", "Test", 4, 8, 1);
- COUNTR_TEST("TestTestTestTest", "Test", 4, 12, 2);
- COUNTR_TEST("TestTestTestTest", "Test", 4, 16, 3);
- COUNTR_TEST("TestTestTestTest", "Test", 4, 0, 3);
-
- COUNTN_TEST("Test", "test", 1);
- COUNTN_TEST("Test", "TEST", 1);
- COUNTN_TEST("testTest-Testatest", "tEst", 4);
- COUNTNR_TEST("testTest-TeStatest", "tEsT", 4, 16, 2);
-
- CHECK(state);
-
-#undef COUNT_TEST
-#undef COUNTR_TEST
-#undef COUNTN_TEST
-#undef COUNTNR_TEST
-}
-
-TEST_CASE("[GDNative String] Bigrams") {
- godot_string s, t;
- godot_string_new_with_latin1_chars(&s, "abcd");
- godot_packed_string_array bigr = godot_string_bigrams(&s);
- godot_string_destroy(&s);
-
- CHECK(godot_packed_string_array_size(&bigr) == 3);
-
- t = godot_packed_string_array_get(&bigr, 0);
- CHECK(u32scmp(godot_string_get_data(&t), U"ab") == 0);
- godot_string_destroy(&t);
-
- t = godot_packed_string_array_get(&bigr, 1);
- CHECK(u32scmp(godot_string_get_data(&t), U"bc") == 0);
- godot_string_destroy(&t);
-
- t = godot_packed_string_array_get(&bigr, 2);
- CHECK(u32scmp(godot_string_get_data(&t), U"cd") == 0);
- godot_string_destroy(&t);
-
- godot_packed_string_array_destroy(&bigr);
-}
-
-TEST_CASE("[GDNative String] c-escape/unescape") {
- godot_string s;
- godot_string_new_with_latin1_chars(&s, "\\1\a2\b\f3\n45\r6\t7\v8\'9\?0\"");
- godot_string t = godot_string_c_escape(&s);
- godot_string u = godot_string_c_unescape(&t);
- CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&s)) == 0);
- godot_string_destroy(&u);
- godot_string_destroy(&t);
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] dedent") {
- godot_string s, t;
- godot_string_new_with_latin1_chars(&s, " aaa\n bbb");
- godot_string_new_with_latin1_chars(&t, "aaa\nbbb");
- godot_string u = godot_string_dedent(&s);
- CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
- godot_string_destroy(&u);
- godot_string_destroy(&t);
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] Path functions") {
- static const char *path[4] = { "C:\\Godot\\project\\test.tscn", "/Godot/project/test.xscn", "../Godot/project/test.scn", "Godot\\test.doc" };
- static const char *base_dir[4] = { "C:\\Godot\\project", "/Godot/project", "../Godot/project", "Godot" };
- static const char *base_name[4] = { "C:\\Godot\\project\\test", "/Godot/project/test", "../Godot/project/test", "Godot\\test" };
- static const char *ext[4] = { "tscn", "xscn", "scn", "doc" };
- static const char *file[4] = { "test.tscn", "test.xscn", "test.scn", "test.doc" };
- static const bool abs[4] = { true, true, false, false };
-
- for (int i = 0; i < 4; i++) {
- godot_string s, t, u, f;
- godot_string_new_with_latin1_chars(&s, path[i]);
-
- t = godot_string_get_base_dir(&s);
- godot_string_new_with_latin1_chars(&u, base_dir[i]);
- CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
- godot_string_destroy(&u);
- godot_string_destroy(&t);
-
- t = godot_string_get_basename(&s);
- godot_string_new_with_latin1_chars(&u, base_name[i]);
- CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
- godot_string_destroy(&u);
- godot_string_destroy(&t);
-
- t = godot_string_get_extension(&s);
- godot_string_new_with_latin1_chars(&u, ext[i]);
- CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
- godot_string_destroy(&u);
- godot_string_destroy(&t);
-
- t = godot_string_get_file(&s);
- godot_string_new_with_latin1_chars(&u, file[i]);
- CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
- godot_string_destroy(&u);
- godot_string_destroy(&t);
-
- godot_string s_simp;
- s_simp = godot_string_simplify_path(&s);
- t = godot_string_get_base_dir(&s_simp);
- godot_string_new_with_latin1_chars(&u, file[i]);
- f = godot_string_plus_file(&t, &u);
- CHECK(u32scmp(godot_string_get_data(&f), godot_string_get_data(&s_simp)) == 0);
- godot_string_destroy(&f);
- godot_string_destroy(&u);
- godot_string_destroy(&t);
- godot_string_destroy(&s_simp);
-
- CHECK(godot_string_is_abs_path(&s) == abs[i]);
- CHECK(godot_string_is_rel_path(&s) != abs[i]);
-
- godot_string_destroy(&s);
- }
-
- static const char *file_name[3] = { "test.tscn", "test://.xscn", "?tes*t.scn" };
- static const bool valid[3] = { true, false, false };
- for (int i = 0; i < 3; i++) {
- godot_string s;
- godot_string_new_with_latin1_chars(&s, file_name[i]);
- CHECK(godot_string_is_valid_filename(&s) == valid[i]);
- godot_string_destroy(&s);
- }
-}
-
-TEST_CASE("[GDNative String] hash") {
- godot_string a, b, c;
- godot_string_new_with_latin1_chars(&a, "Test");
- godot_string_new_with_latin1_chars(&b, "Test");
- godot_string_new_with_latin1_chars(&c, "West");
- CHECK(godot_string_hash(&a) == godot_string_hash(&b));
- CHECK(godot_string_hash(&a) != godot_string_hash(&c));
-
- CHECK(godot_string_hash64(&a) == godot_string_hash64(&b));
- CHECK(godot_string_hash64(&a) != godot_string_hash64(&c));
-
- godot_string_destroy(&a);
- godot_string_destroy(&b);
- godot_string_destroy(&c);
-}
-
-TEST_CASE("[GDNative String] http_escape/unescape") {
- godot_string s, t, u;
- godot_string_new_with_latin1_chars(&s, "Godot Engine:'docs'");
- godot_string_new_with_latin1_chars(&t, "Godot%20Engine%3A%27docs%27");
-
- u = godot_string_http_escape(&s);
- CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
- godot_string_destroy(&u);
-
- u = godot_string_http_unescape(&t);
- CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&s)) == 0);
- godot_string_destroy(&u);
-
- godot_string_destroy(&s);
- godot_string_destroy(&t);
-}
-
-TEST_CASE("[GDNative String] percent_encode/decode") {
- godot_string s, t, u;
- godot_string_new_with_latin1_chars(&s, "Godot Engine:'docs'");
- godot_string_new_with_latin1_chars(&t, "Godot%20Engine%3a%27docs%27");
-
- u = godot_string_percent_encode(&s);
- CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
- godot_string_destroy(&u);
-
- u = godot_string_percent_decode(&t);
- CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&s)) == 0);
- godot_string_destroy(&u);
-
- godot_string_destroy(&s);
- godot_string_destroy(&t);
-}
-
-TEST_CASE("[GDNative String] xml_escape/unescape") {
- godot_string s, t, u;
- godot_string_new_with_latin1_chars(&s, "\"Test\" <test@test&'test'>");
-
- t = godot_string_xml_escape_with_quotes(&s);
- u = godot_string_xml_unescape(&t);
- CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&s)) == 0);
- godot_string_destroy(&u);
- godot_string_destroy(&t);
-
- t = godot_string_xml_escape(&s);
- u = godot_string_xml_unescape(&t);
- CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&s)) == 0);
- godot_string_destroy(&u);
- godot_string_destroy(&t);
-
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] Strip escapes") {
- godot_string s, t, u;
- godot_string_new_with_latin1_chars(&s, "\t\tTest Test\r\n Test");
- godot_string_new_with_latin1_chars(&t, "Test Test Test");
-
- u = godot_string_strip_escapes(&s);
- CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
- godot_string_destroy(&u);
-
- godot_string_destroy(&t);
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] Strip edges") {
- godot_string s, t, u;
- godot_string_new_with_latin1_chars(&s, "\t Test Test ");
-
- godot_string_new_with_latin1_chars(&t, "Test Test ");
- u = godot_string_strip_edges(&s, true, false);
- CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
- godot_string_destroy(&u);
- godot_string_destroy(&t);
-
- godot_string_new_with_latin1_chars(&t, "\t Test Test");
- u = godot_string_strip_edges(&s, false, true);
- CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
- godot_string_destroy(&u);
- godot_string_destroy(&t);
-
- godot_string_new_with_latin1_chars(&t, "Test Test");
- u = godot_string_strip_edges(&s, true, true);
- CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
- godot_string_destroy(&u);
- godot_string_destroy(&t);
-
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] Similarity") {
- godot_string a, b, c;
- godot_string_new_with_latin1_chars(&a, "Test");
- godot_string_new_with_latin1_chars(&b, "West");
- godot_string_new_with_latin1_chars(&c, "Toad");
-
- CHECK(godot_string_similarity(&a, &b) > godot_string_similarity(&a, &c));
-
- godot_string_destroy(&a);
- godot_string_destroy(&b);
- godot_string_destroy(&c);
-}
-
-TEST_CASE("[GDNative String] Trim") {
- godot_string s, t, u, p;
- godot_string_new_with_latin1_chars(&s, "aaaTestbbb");
-
- godot_string_new_with_latin1_chars(&p, "aaa");
- godot_string_new_with_latin1_chars(&t, "Testbbb");
- u = godot_string_trim_prefix(&s, &p);
- CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
- godot_string_destroy(&u);
- godot_string_destroy(&t);
- godot_string_destroy(&p);
-
- godot_string_new_with_latin1_chars(&p, "bbb");
- godot_string_new_with_latin1_chars(&t, "aaaTest");
- u = godot_string_trim_suffix(&s, &p);
- CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
- godot_string_destroy(&u);
- godot_string_destroy(&t);
- godot_string_destroy(&p);
-
- godot_string_new_with_latin1_chars(&p, "Test");
- u = godot_string_trim_suffix(&s, &p);
- CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&s)) == 0);
- godot_string_destroy(&u);
- godot_string_destroy(&p);
-
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] Right/Left") {
- godot_string s, t, u;
- godot_string_new_with_latin1_chars(&s, "aaaTestbbb");
- // ^
-
- godot_string_new_with_latin1_chars(&t, "tbbb");
- u = godot_string_right(&s, 6);
- CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
- godot_string_destroy(&u);
- godot_string_destroy(&t);
-
- godot_string_new_with_latin1_chars(&t, "aaaTes");
- u = godot_string_left(&s, 6);
- CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
- godot_string_destroy(&u);
- godot_string_destroy(&t);
-
- godot_string_destroy(&s);
-}
-
-TEST_CASE("[GDNative String] Repeat") {
- godot_string t, u;
- godot_string_new_with_latin1_chars(&t, "ab");
-
- u = godot_string_repeat(&t, 4);
- CHECK(u32scmp(godot_string_get_data(&u), U"abababab") == 0);
- godot_string_destroy(&u);
-
- godot_string_destroy(&t);
-}
-
-TEST_CASE("[GDNative String] SHA1/SHA256/MD5") {
- godot_string s, t, sha1, sha256, md5;
- godot_string_new_with_latin1_chars(&s, "Godot");
- godot_string_new_with_latin1_chars(&sha1, "a1e91f39b9fce6a9998b14bdbe2aa2b39dc2d201");
- static uint8_t sha1_buf[20] = {
- 0xA1, 0xE9, 0x1F, 0x39, 0xB9, 0xFC, 0xE6, 0xA9, 0x99, 0x8B, 0x14, 0xBD, 0xBE, 0x2A, 0xA2, 0xB3,
- 0x9D, 0xC2, 0xD2, 0x01
- };
- godot_string_new_with_latin1_chars(&sha256, "2a02b2443f7985d89d09001086ae3dcfa6eb0f55c6ef170715d42328e16e6cb8");
- static uint8_t sha256_buf[32] = {
- 0x2A, 0x02, 0xB2, 0x44, 0x3F, 0x79, 0x85, 0xD8, 0x9D, 0x09, 0x00, 0x10, 0x86, 0xAE, 0x3D, 0xCF,
- 0xA6, 0xEB, 0x0F, 0x55, 0xC6, 0xEF, 0x17, 0x07, 0x15, 0xD4, 0x23, 0x28, 0xE1, 0x6E, 0x6C, 0xB8
- };
- godot_string_new_with_latin1_chars(&md5, "4a336d087aeb0390da10ee2ea7cb87f8");
- static uint8_t md5_buf[16] = {
- 0x4A, 0x33, 0x6D, 0x08, 0x7A, 0xEB, 0x03, 0x90, 0xDA, 0x10, 0xEE, 0x2E, 0xA7, 0xCB, 0x87, 0xF8
- };
-
- godot_packed_byte_array buf = godot_string_sha1_buffer(&s);
- CHECK(memcmp(sha1_buf, godot_packed_byte_array_ptr(&buf), 20) == 0);
- godot_packed_byte_array_destroy(&buf);
-
- t = godot_string_sha1_text(&s);
- CHECK(u32scmp(godot_string_get_data(&t), godot_string_get_data(&sha1)) == 0);
- godot_string_destroy(&t);
-
- buf = godot_string_sha256_buffer(&s);
- CHECK(memcmp(sha256_buf, godot_packed_byte_array_ptr(&buf), 32) == 0);
- godot_packed_byte_array_destroy(&buf);
-
- t = godot_string_sha256_text(&s);
- CHECK(u32scmp(godot_string_get_data(&t), godot_string_get_data(&sha256)) == 0);
- godot_string_destroy(&t);
-
- buf = godot_string_md5_buffer(&s);
- CHECK(memcmp(md5_buf, godot_packed_byte_array_ptr(&buf), 16) == 0);
- godot_packed_byte_array_destroy(&buf);
-
- t = godot_string_md5_text(&s);
- CHECK(u32scmp(godot_string_get_data(&t), godot_string_get_data(&md5)) == 0);
- godot_string_destroy(&t);
-
- godot_string_destroy(&s);
- godot_string_destroy(&sha1);
- godot_string_destroy(&sha256);
- godot_string_destroy(&md5);
-}
-
-TEST_CASE("[GDNative String] Join") {
- godot_string s, t, u;
- godot_string_new_with_latin1_chars(&s, ", ");
-
- godot_packed_string_array parts;
- godot_packed_string_array_new(&parts);
- godot_string_new_with_latin1_chars(&t, "One");
- godot_packed_string_array_push_back(&parts, &t);
- godot_string_destroy(&t);
- godot_string_new_with_latin1_chars(&t, "B");
- godot_packed_string_array_push_back(&parts, &t);
- godot_string_destroy(&t);
- godot_string_new_with_latin1_chars(&t, "C");
- godot_packed_string_array_push_back(&parts, &t);
- godot_string_destroy(&t);
-
- godot_string_new_with_latin1_chars(&u, "One, B, C");
- t = godot_string_join(&s, &parts);
- CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
- godot_string_destroy(&u);
- godot_string_destroy(&t);
-
- godot_string_destroy(&s);
- godot_packed_string_array_destroy(&parts);
-}
-
-TEST_CASE("[GDNative String] Is_*") {
- static const char *data[12] = { "-30", "100", "10.1", "10,1", "1e2", "1e-2", "1e2e3", "0xAB", "AB", "Test1", "1Test", "Test*1" };
- static bool isnum[12] = { true, true, true, false, false, false, false, false, false, false, false, false };
- static bool isint[12] = { true, true, false, false, false, false, false, false, false, false, false, false };
- static bool ishex[12] = { true, true, false, false, true, false, true, false, true, false, false, false };
- static bool ishex_p[12] = { false, false, false, false, false, false, false, true, false, false, false, false };
- static bool isflt[12] = { true, true, true, false, true, true, false, false, false, false, false, false };
- static bool isid[12] = { false, false, false, false, false, false, false, false, true, true, false, false };
-
- for (int i = 0; i < 12; i++) {
- godot_string s;
- godot_string_new_with_latin1_chars(&s, data[i]);
- CHECK(godot_string_is_numeric(&s) == isnum[i]);
- CHECK(godot_string_is_valid_integer(&s) == isint[i]);
- CHECK(godot_string_is_valid_hex_number(&s, false) == ishex[i]);
- CHECK(godot_string_is_valid_hex_number(&s, true) == ishex_p[i]);
- CHECK(godot_string_is_valid_float(&s) == isflt[i]);
- CHECK(godot_string_is_valid_identifier(&s) == isid[i]);
- godot_string_destroy(&s);
- }
-}
-
-TEST_CASE("[GDNative String] humanize_size") {
- godot_string s;
-
- s = godot_string_humanize_size(1000);
- CHECK(u32scmp(godot_string_get_data(&s), U"1000 B") == 0);
- godot_string_destroy(&s);
-
- s = godot_string_humanize_size(1025);
- CHECK(u32scmp(godot_string_get_data(&s), U"1.00 KiB") == 0);
- godot_string_destroy(&s);
-
- s = godot_string_humanize_size(1025300);
- CHECK(u32scmp(godot_string_get_data(&s), U"1001.2 KiB") == 0);
- godot_string_destroy(&s);
-
- s = godot_string_humanize_size(100523550);
- CHECK(u32scmp(godot_string_get_data(&s), U"95.86 MiB") == 0);
- godot_string_destroy(&s);
-
- s = godot_string_humanize_size(5345555000);
- CHECK(u32scmp(godot_string_get_data(&s), U"4.97 GiB") == 0);
- godot_string_destroy(&s);
-}
-
-} // namespace TestGDNativeString
-
-#endif // TEST_GDNATIVE_STRING_H
diff --git a/modules/gdnative/tests/test_variant.h b/modules/gdnative/tests/test_variant.h
new file mode 100644
index 0000000000..5284bf26f0
--- /dev/null
+++ b/modules/gdnative/tests/test_variant.h
@@ -0,0 +1,204 @@
+/*************************************************************************/
+/* test_variant.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_GDNATIVE_VARIANT_H
+#define TEST_GDNATIVE_VARIANT_H
+
+#include <gdnative/gdnative.h>
+#include <gdnative/variant.h>
+
+#include "tests/test_macros.h"
+
+namespace TestGDNativeVariant {
+
+TEST_CASE("[GDNative Variant] New Variant with copy") {
+ godot_variant src;
+ godot_variant_new_int(&src, 42);
+
+ godot_variant copy;
+ godot_variant_new_copy(&copy, &src);
+
+ CHECK(godot_variant_as_int(&copy) == 42);
+ CHECK(godot_variant_get_type(&copy) == GODOT_VARIANT_TYPE_INT);
+
+ godot_variant_destroy(&src);
+ godot_variant_destroy(&copy);
+}
+
+TEST_CASE("[GDNative Variant] New Variant with Nil") {
+ godot_variant val;
+ godot_variant_new_nil(&val);
+
+ CHECK(godot_variant_get_type(&val) == GODOT_VARIANT_TYPE_NIL);
+
+ godot_variant_destroy(&val);
+}
+
+TEST_CASE("[GDNative Variant] New Variant with bool") {
+ godot_variant val;
+ godot_variant_new_bool(&val, true);
+
+ CHECK(godot_variant_as_bool(&val));
+ CHECK(godot_variant_get_type(&val) == GODOT_VARIANT_TYPE_BOOL);
+
+ godot_variant_destroy(&val);
+}
+
+TEST_CASE("[GDNative Variant] New Variant with float") {
+ godot_variant val;
+ godot_variant_new_float(&val, 4.2);
+
+ CHECK(godot_variant_as_float(&val) == 4.2);
+ CHECK(godot_variant_get_type(&val) == GODOT_VARIANT_TYPE_FLOAT);
+
+ godot_variant_destroy(&val);
+}
+
+TEST_CASE("[GDNative Variant] New Variant with String") {
+ String str = "something";
+
+ godot_variant val;
+ godot_variant_new_string(&val, (godot_string *)&str);
+ godot_string gd_str = godot_variant_as_string(&val);
+ String *result = (String *)&gd_str;
+
+ CHECK(*result == String("something"));
+ CHECK(godot_variant_get_type(&val) == GODOT_VARIANT_TYPE_STRING);
+
+ godot_variant_destroy(&val);
+ godot_string_destroy(&gd_str);
+}
+
+TEST_CASE("[GDNative Variant] Variant call") {
+ String str("something");
+ godot_variant self;
+ godot_variant_new_string(&self, (godot_string *)&str);
+
+ godot_variant ret;
+
+ godot_string_name method;
+ godot_string_name_new_with_latin1_chars(&method, "is_valid_identifier");
+
+ godot_variant_call_error error;
+ godot_variant_call(&self, &method, NULL, 0, &ret, &error);
+
+ CHECK(godot_variant_get_type(&ret) == GODOT_VARIANT_TYPE_BOOL);
+ CHECK(godot_variant_as_bool(&ret));
+
+ godot_variant_destroy(&ret);
+ godot_variant_destroy(&self);
+ godot_string_name_destroy(&method);
+}
+
+TEST_CASE("[GDNative Variant] Variant evaluate") {
+ godot_variant one;
+ godot_variant_new_int(&one, 1);
+ godot_variant two;
+ godot_variant_new_int(&two, 2);
+
+ godot_variant three;
+ bool valid = false;
+
+ godot_variant_evaluate(GODOT_VARIANT_OP_ADD, &one, &two, &three, &valid);
+
+ CHECK(godot_variant_get_type(&three) == GODOT_VARIANT_TYPE_INT);
+ CHECK(godot_variant_as_int(&three) == 3);
+ CHECK(valid);
+
+ godot_variant_destroy(&one);
+ godot_variant_destroy(&two);
+ godot_variant_destroy(&three);
+}
+
+TEST_CASE("[GDNative Variant] Variant set/get named") {
+ godot_string_name x;
+ godot_string_name_new_with_latin1_chars(&x, "x");
+
+ Vector2 vec(0, 0);
+ godot_variant self;
+ godot_variant_new_vector2(&self, (godot_vector2 *)&vec);
+
+ godot_variant set;
+ godot_variant_new_float(&set, 1.0);
+
+ bool set_valid = false;
+ godot_variant_set_named(&self, &x, &set, &set_valid);
+
+ bool get_valid = false;
+ godot_variant get = godot_variant_get_named(&self, &x, &get_valid);
+
+ CHECK(get_valid);
+ CHECK(set_valid);
+ CHECK(godot_variant_get_type(&get) == GODOT_VARIANT_TYPE_FLOAT);
+ CHECK(godot_variant_as_float(&get) == 1.0);
+
+ godot_string_name_destroy(&x);
+ godot_variant_destroy(&self);
+ godot_variant_destroy(&set);
+ godot_variant_destroy(&get);
+}
+
+TEST_CASE("[GDNative Variant] Get utility function argument name") {
+ godot_string_name function;
+ godot_string_name_new_with_latin1_chars(&function, "pow");
+
+ godot_string arg_name = godot_variant_get_utility_function_argument_name(&function, 0);
+
+ String *arg_name_str = (String *)&arg_name;
+
+ CHECK(*arg_name_str == "base");
+
+ godot_string_destroy(&arg_name);
+ godot_string_name_destroy(&function);
+}
+
+TEST_CASE("[GDNative Variant] Get utility function list") {
+ int count = godot_variant_get_utility_function_count();
+
+ godot_string_name *c_list = (godot_string_name *)godot_alloc(count * sizeof(godot_string_name));
+ godot_variant_get_utility_function_list(c_list);
+
+ List<StringName> cpp_list;
+ Variant::get_utility_function_list(&cpp_list);
+
+ godot_string_name *cur = c_list;
+
+ for (const List<StringName>::Element *E = cpp_list.front(); E; E = E->next()) {
+ const StringName &cpp_name = E->get();
+ StringName *c_name = (StringName *)cur++;
+
+ CHECK(*c_name == cpp_name);
+ }
+
+ godot_free(c_list);
+}
+} // namespace TestGDNativeVariant
+
+#endif // TEST_GDNATIVE_VARIANT_H
diff --git a/modules/gdnative/text/SCsub b/modules/gdnative/text/SCsub
new file mode 100644
index 0000000000..0b2db3b504
--- /dev/null
+++ b/modules/gdnative/text/SCsub
@@ -0,0 +1,6 @@
+#!/usr/bin/env python
+
+Import("env")
+Import("env_gdnative")
+
+env_gdnative.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/gdnative/xr/config.py b/modules/gdnative/text/config.py
index d22f9454ed..d22f9454ed 100644
--- a/modules/gdnative/xr/config.py
+++ b/modules/gdnative/text/config.py
diff --git a/modules/camera/camera_ios.h b/modules/gdnative/text/register_types.cpp
index 7da43e4851..67385d2fbf 100644
--- a/modules/camera/camera_ios.h
+++ b/modules/gdnative/text/register_types.cpp
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* camera_ios.h */
+/* register_types.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -28,18 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef CAMERAIOS_H
-#define CAMERAIOS_H
+#include "register_types.h"
+#include "text_server_gdnative.h"
-#include "servers/camera_server.h"
+void register_text_server_gdn_types() {}
-class CameraIOS : public CameraServer {
-private:
-public:
- CameraIOS();
- ~CameraIOS();
-
- void update_feeds();
-};
-
-#endif /* CAMERAIOS_H */
+void unregister_text_server_gdn_types() {}
diff --git a/modules/gdnative/text/register_types.h b/modules/gdnative/text/register_types.h
new file mode 100644
index 0000000000..cd4f2a3089
--- /dev/null
+++ b/modules/gdnative/text/register_types.h
@@ -0,0 +1,37 @@
+/*************************************************************************/
+/* register_types.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEXT_REGISTER_TYPES_H
+#define TEXT_REGISTER_TYPES_H
+
+void register_text_server_gdn_types();
+void unregister_text_server_gdn_types();
+
+#endif // TEXT_REGISTER_TYPES_H
diff --git a/modules/gdnative/text/text_server_gdnative.cpp b/modules/gdnative/text/text_server_gdnative.cpp
new file mode 100644
index 0000000000..f7a3cb8135
--- /dev/null
+++ b/modules/gdnative/text/text_server_gdnative.cpp
@@ -0,0 +1,853 @@
+/*************************************************************************/
+/* text_server_gdnative.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "text_server_gdnative.h"
+
+bool TextServerGDNative::has_feature(Feature p_feature) {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+ return interface->has_feature(data, (godot_int)p_feature);
+}
+
+String TextServerGDNative::get_name() const {
+ ERR_FAIL_COND_V(interface == nullptr, String());
+ godot_string result = interface->get_name(data);
+ String name = *(String *)&result;
+ godot_string_destroy(&result);
+ return name;
+}
+
+void TextServerGDNative::free(RID p_rid) {
+ ERR_FAIL_COND(interface == nullptr);
+ interface->free(data, (godot_rid *)&p_rid);
+}
+
+bool TextServerGDNative::has(RID p_rid) {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+ return interface->has(data, (godot_rid *)&p_rid);
+}
+
+bool TextServerGDNative::load_support_data(const String &p_filename) {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+ return interface->load_support_data(data, (godot_string *)&p_filename);
+}
+
+#ifdef TOOLS_ENABLED
+
+String TextServerGDNative::get_support_data_filename() {
+ ERR_FAIL_COND_V(interface == nullptr, String());
+ godot_string result = interface->get_support_data_filename(data);
+ String name = *(String *)&result;
+ godot_string_destroy(&result);
+ return name;
+}
+
+String TextServerGDNative::get_support_data_info() {
+ ERR_FAIL_COND_V(interface == nullptr, String());
+ godot_string result = interface->get_support_data_info(data);
+ String info = *(String *)&result;
+ godot_string_destroy(&result);
+ return info;
+}
+
+bool TextServerGDNative::save_support_data(const String &p_filename) {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+ return interface->save_support_data(data, (godot_string *)&p_filename);
+}
+
+#endif
+
+bool TextServerGDNative::is_locale_right_to_left(const String &p_locale) {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+ return interface->is_locale_right_to_left(data, (godot_string *)&p_locale);
+}
+
+/*************************************************************************/
+/* Font interface */
+/*************************************************************************/
+
+RID TextServerGDNative::create_font_system(const String &p_name, int p_base_size) {
+ ERR_FAIL_COND_V(interface == nullptr, RID());
+ godot_rid result = interface->create_font_system(data, (const godot_string *)&p_name, p_base_size);
+ RID rid = *(RID *)&result;
+ return rid;
+}
+
+RID TextServerGDNative::create_font_resource(const String &p_filename, int p_base_size) {
+ ERR_FAIL_COND_V(interface == nullptr, RID());
+ godot_rid result = interface->create_font_resource(data, (const godot_string *)&p_filename, p_base_size);
+ RID rid = *(RID *)&result;
+ return rid;
+}
+
+RID TextServerGDNative::create_font_memory(const uint8_t *p_data, size_t p_size, const String &p_type, int p_base_size) {
+ ERR_FAIL_COND_V(interface == nullptr, RID());
+ godot_rid result = interface->create_font_memory(data, p_data, p_size, (godot_string *)&p_type, p_base_size);
+ RID rid = *(RID *)&result;
+ return rid;
+}
+
+float TextServerGDNative::font_get_height(RID p_font, int p_size) const {
+ ERR_FAIL_COND_V(interface == nullptr, 0.f);
+ return interface->font_get_height(data, (godot_rid *)&p_font, p_size);
+}
+
+float TextServerGDNative::font_get_ascent(RID p_font, int p_size) const {
+ ERR_FAIL_COND_V(interface == nullptr, 0.f);
+ return interface->font_get_ascent(data, (godot_rid *)&p_font, p_size);
+}
+
+float TextServerGDNative::font_get_descent(RID p_font, int p_size) const {
+ ERR_FAIL_COND_V(interface == nullptr, 0.f);
+ return interface->font_get_descent(data, (godot_rid *)&p_font, p_size);
+}
+
+float TextServerGDNative::font_get_underline_position(RID p_font, int p_size) const {
+ ERR_FAIL_COND_V(interface == nullptr, 0.f);
+ return interface->font_get_underline_position(data, (godot_rid *)&p_font, p_size);
+}
+
+float TextServerGDNative::font_get_underline_thickness(RID p_font, int p_size) const {
+ ERR_FAIL_COND_V(interface == nullptr, 0.f);
+ return interface->font_get_underline_thickness(data, (godot_rid *)&p_font, p_size);
+}
+
+void TextServerGDNative::font_set_antialiased(RID p_font, bool p_antialiased) {
+ ERR_FAIL_COND(interface == nullptr);
+ interface->font_set_antialiased(data, (godot_rid *)&p_font, p_antialiased);
+}
+
+bool TextServerGDNative::font_get_antialiased(RID p_font) const {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+ return interface->font_get_antialiased(data, (godot_rid *)&p_font);
+}
+
+Dictionary TextServerGDNative::font_get_variation_list(RID p_font) const {
+ ERR_FAIL_COND_V(interface == nullptr, Dictionary());
+ godot_dictionary result = interface->font_get_variation_list(data, (godot_rid *)&p_font);
+ Dictionary info = *(Dictionary *)&result;
+ godot_dictionary_destroy(&result);
+
+ return info;
+}
+
+void TextServerGDNative::font_set_variation(RID p_font, const String &p_name, double p_value) {
+ ERR_FAIL_COND(interface == nullptr);
+ interface->font_set_variation(data, (godot_rid *)&p_font, (godot_string *)&p_name, p_value);
+}
+
+double TextServerGDNative::font_get_variation(RID p_font, const String &p_name) const {
+ return interface->font_get_variation(data, (godot_rid *)&p_font, (godot_string *)&p_name);
+}
+
+void TextServerGDNative::font_set_hinting(RID p_font, TextServer::Hinting p_hinting) {
+ ERR_FAIL_COND(interface == nullptr);
+ interface->font_set_hinting(data, (godot_rid *)&p_font, (godot_int)p_hinting);
+}
+
+TextServer::Hinting TextServerGDNative::font_get_hinting(RID p_font) const {
+ ERR_FAIL_COND_V(interface == nullptr, TextServer::HINTING_NONE);
+ return (TextServer::Hinting)interface->font_get_hinting(data, (godot_rid *)&p_font);
+}
+
+Dictionary TextServerGDNative::font_get_feature_list(RID p_font) const {
+ ERR_FAIL_COND_V(interface == nullptr, Dictionary());
+ godot_dictionary result = interface->font_get_feature_list(data, (godot_rid *)&p_font);
+ Dictionary info = *(Dictionary *)&result;
+ godot_dictionary_destroy(&result);
+
+ return info;
+}
+
+void TextServerGDNative::font_set_distance_field_hint(RID p_font, bool p_distance_field) {
+ ERR_FAIL_COND(interface == nullptr);
+ interface->font_set_distance_field_hint(data, (godot_rid *)&p_font, p_distance_field);
+}
+
+bool TextServerGDNative::font_get_distance_field_hint(RID p_font) const {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+ return interface->font_get_distance_field_hint(data, (godot_rid *)&p_font);
+}
+
+void TextServerGDNative::font_set_force_autohinter(RID p_font, bool p_enabeld) {
+ ERR_FAIL_COND(interface == nullptr);
+ interface->font_set_force_autohinter(data, (godot_rid *)&p_font, p_enabeld);
+}
+
+bool TextServerGDNative::font_get_force_autohinter(RID p_font) const {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+ return interface->font_get_force_autohinter(data, (godot_rid *)&p_font);
+}
+
+bool TextServerGDNative::font_has_char(RID p_font, char32_t p_char) const {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+ return interface->font_has_char(data, (godot_rid *)&p_font, p_char);
+}
+
+String TextServerGDNative::font_get_supported_chars(RID p_font) const {
+ ERR_FAIL_COND_V(interface == nullptr, String());
+ godot_string result = interface->font_get_supported_chars(data, (godot_rid *)&p_font);
+ String ret = *(String *)&result;
+ godot_string_destroy(&result);
+ return ret;
+}
+
+bool TextServerGDNative::font_has_outline(RID p_font) const {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+ return interface->font_has_outline(data, (godot_rid *)&p_font);
+}
+
+float TextServerGDNative::font_get_base_size(RID p_font) const {
+ ERR_FAIL_COND_V(interface == nullptr, 0.f);
+ return interface->font_get_base_size(data, (godot_rid *)&p_font);
+}
+
+bool TextServerGDNative::font_is_language_supported(RID p_font, const String &p_language) const {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+ return interface->font_is_language_supported(data, (godot_rid *)&p_font, (godot_string *)&p_language);
+}
+
+void TextServerGDNative::font_set_language_support_override(RID p_font, const String &p_language, bool p_supported) {
+ ERR_FAIL_COND(interface == nullptr);
+ return interface->font_set_language_support_override(data, (godot_rid *)&p_font, (godot_string *)&p_language, p_supported);
+}
+
+bool TextServerGDNative::font_get_language_support_override(RID p_font, const String &p_language) {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+ return interface->font_get_language_support_override(data, (godot_rid *)&p_font, (godot_string *)&p_language);
+}
+
+void TextServerGDNative::font_remove_language_support_override(RID p_font, const String &p_language) {
+ ERR_FAIL_COND(interface == nullptr);
+ interface->font_remove_language_support_override(data, (godot_rid *)&p_font, (godot_string *)&p_language);
+}
+
+Vector<String> TextServerGDNative::font_get_language_support_overrides(RID p_font) {
+ ERR_FAIL_COND_V(interface == nullptr, Vector<String>());
+ godot_packed_string_array result = interface->font_get_language_support_overrides(data, (godot_rid *)&p_font);
+ Vector<String> ret = *(Vector<String> *)&result;
+ godot_packed_string_array_destroy(&result);
+ return ret;
+}
+
+bool TextServerGDNative::font_is_script_supported(RID p_font, const String &p_script) const {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+ return interface->font_is_script_supported(data, (godot_rid *)&p_font, (godot_string *)&p_script);
+}
+
+void TextServerGDNative::font_set_script_support_override(RID p_font, const String &p_script, bool p_supported) {
+ ERR_FAIL_COND(interface == nullptr);
+ return interface->font_set_script_support_override(data, (godot_rid *)&p_font, (godot_string *)&p_script, p_supported);
+}
+
+bool TextServerGDNative::font_get_script_support_override(RID p_font, const String &p_script) {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+ return interface->font_get_script_support_override(data, (godot_rid *)&p_font, (godot_string *)&p_script);
+}
+
+void TextServerGDNative::font_remove_script_support_override(RID p_font, const String &p_script) {
+ ERR_FAIL_COND(interface == nullptr);
+ interface->font_remove_script_support_override(data, (godot_rid *)&p_font, (godot_string *)&p_script);
+}
+
+Vector<String> TextServerGDNative::font_get_script_support_overrides(RID p_font) {
+ ERR_FAIL_COND_V(interface == nullptr, Vector<String>());
+ godot_packed_string_array result = interface->font_get_script_support_overrides(data, (godot_rid *)&p_font);
+ Vector<String> ret = *(Vector<String> *)&result;
+ godot_packed_string_array_destroy(&result);
+ return ret;
+}
+
+uint32_t TextServerGDNative::font_get_glyph_index(RID p_font, char32_t p_char, char32_t p_variation_selector) const {
+ ERR_FAIL_COND_V(interface == nullptr, 0);
+ return interface->font_get_glyph_index(data, (godot_rid *)&p_font, p_char, p_variation_selector);
+}
+
+Vector2 TextServerGDNative::font_get_glyph_advance(RID p_font, uint32_t p_index, int p_size) const {
+ ERR_FAIL_COND_V(interface == nullptr, Vector2());
+ godot_vector2 result = interface->font_get_glyph_advance(data, (godot_rid *)&p_font, p_index, p_size);
+ Vector2 advance = *(Vector2 *)&result;
+ return advance;
+}
+
+Vector2 TextServerGDNative::font_get_glyph_kerning(RID p_font, uint32_t p_index_a, uint32_t p_index_b, int p_size) const {
+ ERR_FAIL_COND_V(interface == nullptr, Vector2());
+ godot_vector2 result = interface->font_get_glyph_kerning(data, (godot_rid *)&p_font, p_index_a, p_index_b, p_size);
+ Vector2 kerning = *(Vector2 *)&result;
+ return kerning;
+}
+
+Vector2 TextServerGDNative::font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const {
+ ERR_FAIL_COND_V(interface == nullptr, Vector2());
+ godot_vector2 result = interface->font_draw_glyph(data, (godot_rid *)&p_font, (godot_rid *)&p_canvas, p_size, (const godot_vector2 *)&p_pos, p_index, (const godot_color *)&p_color);
+ Vector2 advance = *(Vector2 *)&result;
+ return advance;
+}
+
+Vector2 TextServerGDNative::font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const {
+ ERR_FAIL_COND_V(interface == nullptr, Vector2());
+ godot_vector2 result = interface->font_draw_glyph_outline(data, (godot_rid *)&p_font, (godot_rid *)&p_canvas, p_size, p_outline_size, (const godot_vector2 *)&p_pos, p_index, (const godot_color *)&p_color);
+ Vector2 advance = *(Vector2 *)&result;
+ return advance;
+}
+
+float TextServerGDNative::font_get_oversampling() const {
+ ERR_FAIL_COND_V(interface == nullptr, 1.f);
+ return interface->font_get_oversampling(data);
+}
+
+void TextServerGDNative::font_set_oversampling(float p_oversampling) {
+ ERR_FAIL_COND(interface == nullptr);
+ return interface->font_set_oversampling(data, p_oversampling);
+}
+
+Vector<String> TextServerGDNative::get_system_fonts() const {
+ ERR_FAIL_COND_V(interface == nullptr, Vector<String>());
+ godot_packed_string_array result = interface->get_system_fonts(data);
+ Vector<String> fonts = *(Vector<String> *)&result;
+ godot_packed_string_array_destroy(&result);
+ return fonts;
+}
+
+/*************************************************************************/
+/* Shaped text buffer interface */
+/*************************************************************************/
+
+RID TextServerGDNative::create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
+ ERR_FAIL_COND_V(interface == nullptr, RID());
+ godot_rid result = interface->create_shaped_text(data, (godot_int)p_direction, (godot_int)p_orientation);
+ RID rid = *(RID *)&result;
+ return rid;
+}
+
+void TextServerGDNative::shaped_text_clear(RID p_shaped) {
+ ERR_FAIL_COND(interface == nullptr);
+ interface->shaped_text_clear(data, (godot_rid *)&p_shaped);
+}
+
+void TextServerGDNative::shaped_text_set_direction(RID p_shaped, TextServer::Direction p_direction) {
+ ERR_FAIL_COND(interface == nullptr);
+ interface->shaped_text_set_direction(data, (godot_rid *)&p_shaped, (godot_int)p_direction);
+}
+
+TextServer::Direction TextServerGDNative::shaped_text_get_direction(RID p_shaped) const {
+ ERR_FAIL_COND_V(interface == nullptr, TextServer::DIRECTION_LTR);
+ return (TextServer::Direction)interface->shaped_text_get_direction(data, (godot_rid *)&p_shaped);
+}
+
+void TextServerGDNative::shaped_text_set_orientation(RID p_shaped, TextServer::Orientation p_orientation) {
+ ERR_FAIL_COND(interface == nullptr);
+ interface->shaped_text_set_orientation(data, (godot_rid *)&p_shaped, (godot_int)p_orientation);
+}
+
+TextServer::Orientation TextServerGDNative::shaped_text_get_orientation(RID p_shaped) const {
+ ERR_FAIL_COND_V(interface == nullptr, TextServer::ORIENTATION_HORIZONTAL);
+ return (TextServer::Orientation)interface->shaped_text_get_orientation(data, (godot_rid *)&p_shaped);
+}
+
+void TextServerGDNative::shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) {
+ ERR_FAIL_COND(interface == nullptr);
+ interface->shaped_text_set_bidi_override(data, (godot_rid *)&p_shaped, (const godot_packed_vector2i_array *)&p_override);
+}
+
+void TextServerGDNative::shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) {
+ ERR_FAIL_COND(interface == nullptr);
+ interface->shaped_text_set_preserve_invalid(data, (godot_rid *)&p_shaped, p_enabled);
+}
+
+bool TextServerGDNative::shaped_text_get_preserve_invalid(RID p_shaped) const {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+ return (TextServer::Orientation)interface->shaped_text_get_preserve_invalid(data, (godot_rid *)&p_shaped);
+}
+
+void TextServerGDNative::shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) {
+ ERR_FAIL_COND(interface == nullptr);
+ interface->shaped_text_set_preserve_control(data, (godot_rid *)&p_shaped, p_enabled);
+}
+
+bool TextServerGDNative::shaped_text_get_preserve_control(RID p_shaped) const {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+ return (TextServer::Orientation)interface->shaped_text_get_preserve_control(data, (godot_rid *)&p_shaped);
+}
+
+bool TextServerGDNative::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) {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+ return interface->shaped_text_add_string(data, (godot_rid *)&p_shaped, (const godot_string *)&p_text, (const godot_rid **)p_fonts.ptr(), p_size, (const godot_dictionary *)&p_opentype_features, (const godot_string *)&p_language);
+}
+
+bool TextServerGDNative::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align, int p_length) {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+ return interface->shaped_text_add_object(data, (godot_rid *)&p_shaped, (const godot_variant *)&p_key, (const godot_vector2 *)&p_size, (godot_int)p_inline_align, p_length);
+}
+
+bool TextServerGDNative::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align) {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+ return interface->shaped_text_resize_object(data, (godot_rid *)&p_shaped, (const godot_variant *)&p_key, (const godot_vector2 *)&p_size, (godot_int)p_inline_align);
+}
+
+RID TextServerGDNative::shaped_text_substr(RID p_shaped, int p_start, int p_length) const {
+ ERR_FAIL_COND_V(interface == nullptr, RID());
+ godot_rid result = interface->shaped_text_substr(data, (godot_rid *)&p_shaped, (godot_int)p_start, (godot_int)p_length);
+ RID rid = *(RID *)&result;
+ return rid;
+}
+
+RID TextServerGDNative::shaped_text_get_parent(RID p_shaped) const {
+ ERR_FAIL_COND_V(interface == nullptr, RID());
+ godot_rid result = interface->shaped_text_get_parent(data, (godot_rid *)&p_shaped);
+ RID rid = *(RID *)&result;
+ return rid;
+}
+
+float TextServerGDNative::shaped_text_fit_to_width(RID p_shaped, float p_width, uint8_t p_jst_flags) {
+ ERR_FAIL_COND_V(interface == nullptr, 0.f);
+ return interface->shaped_text_fit_to_width(data, (godot_rid *)&p_shaped, p_width, p_jst_flags);
+}
+
+float TextServerGDNative::shaped_text_tab_align(RID p_shaped, const Vector<float> &p_tab_stops) {
+ ERR_FAIL_COND_V(interface == nullptr, 0.f);
+ return interface->shaped_text_tab_align(data, (godot_rid *)&p_shaped, (godot_packed_float32_array *)&p_tab_stops);
+}
+
+bool TextServerGDNative::shaped_text_shape(RID p_shaped) {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+ return interface->shaped_text_shape(data, (godot_rid *)&p_shaped);
+}
+
+bool TextServerGDNative::shaped_text_update_breaks(RID p_shaped) {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+ return interface->shaped_text_update_breaks(data, (godot_rid *)&p_shaped);
+}
+
+bool TextServerGDNative::shaped_text_update_justification_ops(RID p_shaped) {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+ return interface->shaped_text_update_justification_ops(data, (godot_rid *)&p_shaped);
+}
+
+bool TextServerGDNative::shaped_text_is_ready(RID p_shaped) const {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+ return interface->shaped_text_is_ready(data, (godot_rid *)&p_shaped);
+}
+
+Vector<TextServer::Glyph> TextServerGDNative::shaped_text_get_glyphs(RID p_shaped) const {
+ ERR_FAIL_COND_V(interface == nullptr, Vector<TextServer::Glyph>());
+ godot_packed_glyph_array result = interface->shaped_text_get_glyphs(data, (godot_rid *)&p_shaped);
+ Vector<TextServer::Glyph> glyphs = *(Vector<TextServer::Glyph> *)&result;
+ godot_packed_glyph_array_destroy(&result);
+ return glyphs;
+}
+
+Vector2i TextServerGDNative::shaped_text_get_range(RID p_shaped) const {
+ ERR_FAIL_COND_V(interface == nullptr, Vector2i());
+ godot_vector2i result = interface->shaped_text_get_range(data, (godot_rid *)&p_shaped);
+ Vector2i range = *(Vector2i *)&result;
+ return range;
+}
+
+Vector<TextServer::Glyph> TextServerGDNative::shaped_text_sort_logical(RID p_shaped) {
+ ERR_FAIL_COND_V(interface == nullptr, Vector<TextServer::Glyph>());
+ godot_packed_glyph_array result = interface->shaped_text_sort_logical(data, (godot_rid *)&p_shaped);
+ Vector<TextServer::Glyph> glyphs = *(Vector<TextServer::Glyph> *)&result;
+ godot_packed_glyph_array_destroy(&result);
+ return glyphs;
+}
+
+Vector<Vector2i> TextServerGDNative::shaped_text_get_line_breaks_adv(RID p_shaped, const Vector<float> &p_width, int p_start, bool p_once, uint8_t p_break_flags) const {
+ ERR_FAIL_COND_V(interface == nullptr, Vector<Vector2i>());
+ if (interface->shaped_text_get_line_breaks_adv != nullptr) {
+ godot_packed_vector2i_array result = interface->shaped_text_get_line_breaks_adv(data, (godot_rid *)&p_shaped, (godot_packed_float32_array *)&p_width, p_start, p_once, p_break_flags);
+ Vector<Vector2i> breaks = *(Vector<Vector2i> *)&result;
+ godot_packed_vector2i_array_destroy(&result);
+ return breaks;
+ } else {
+ return TextServer::shaped_text_get_line_breaks_adv(p_shaped, p_width, p_break_flags);
+ }
+}
+
+Vector<Vector2i> TextServerGDNative::shaped_text_get_line_breaks(RID p_shaped, float p_width, int p_start, uint8_t p_break_flags) const {
+ ERR_FAIL_COND_V(interface == nullptr, Vector<Vector2i>());
+ if (interface->shaped_text_get_line_breaks != nullptr) {
+ godot_packed_vector2i_array result = interface->shaped_text_get_line_breaks(data, (godot_rid *)&p_shaped, p_width, p_start, p_break_flags);
+ Vector<Vector2i> breaks = *(Vector<Vector2i> *)&result;
+ godot_packed_vector2i_array_destroy(&result);
+ return breaks;
+ } else {
+ return TextServer::shaped_text_get_line_breaks(p_shaped, p_width, p_break_flags);
+ }
+}
+
+Vector<Vector2i> TextServerGDNative::shaped_text_get_word_breaks(RID p_shaped) const {
+ ERR_FAIL_COND_V(interface == nullptr, Vector<Vector2i>());
+ if (interface->shaped_text_get_word_breaks != nullptr) {
+ godot_packed_vector2i_array result = interface->shaped_text_get_word_breaks(data, (godot_rid *)&p_shaped);
+ Vector<Vector2i> breaks = *(Vector<Vector2i> *)&result;
+ godot_packed_vector2i_array_destroy(&result);
+ return breaks;
+ } else {
+ return TextServer::shaped_text_get_word_breaks(p_shaped);
+ }
+}
+
+Array TextServerGDNative::shaped_text_get_objects(RID p_shaped) const {
+ ERR_FAIL_COND_V(interface == nullptr, Array());
+ godot_array result = interface->shaped_text_get_objects(data, (godot_rid *)&p_shaped);
+ Array rect = *(Array *)&result;
+ return rect;
+}
+
+Rect2 TextServerGDNative::shaped_text_get_object_rect(RID p_shaped, Variant p_key) const {
+ ERR_FAIL_COND_V(interface == nullptr, Rect2());
+ godot_rect2 result = interface->shaped_text_get_object_rect(data, (godot_rid *)&p_shaped, (const godot_variant *)&p_key);
+ Rect2 rect = *(Rect2 *)&result;
+ return rect;
+}
+
+Size2 TextServerGDNative::shaped_text_get_size(RID p_shaped) const {
+ ERR_FAIL_COND_V(interface == nullptr, Size2());
+ godot_vector2 result = interface->shaped_text_get_size(data, (godot_rid *)&p_shaped);
+ Size2 size = *(Size2 *)&result;
+ return size;
+}
+
+float TextServerGDNative::shaped_text_get_ascent(RID p_shaped) const {
+ ERR_FAIL_COND_V(interface == nullptr, 0.f);
+ return interface->shaped_text_get_ascent(data, (godot_rid *)&p_shaped);
+}
+
+float TextServerGDNative::shaped_text_get_descent(RID p_shaped) const {
+ ERR_FAIL_COND_V(interface == nullptr, 0.f);
+ return interface->shaped_text_get_descent(data, (godot_rid *)&p_shaped);
+}
+
+float TextServerGDNative::shaped_text_get_width(RID p_shaped) const {
+ ERR_FAIL_COND_V(interface == nullptr, 0.f);
+ return interface->shaped_text_get_width(data, (godot_rid *)&p_shaped);
+}
+
+float TextServerGDNative::shaped_text_get_underline_position(RID p_shaped) const {
+ ERR_FAIL_COND_V(interface == nullptr, 0.f);
+ return interface->shaped_text_get_underline_position(data, (godot_rid *)&p_shaped);
+}
+
+float TextServerGDNative::shaped_text_get_underline_thickness(RID p_shaped) const {
+ ERR_FAIL_COND_V(interface == nullptr, 0.f);
+ return interface->shaped_text_get_underline_thickness(data, (godot_rid *)&p_shaped);
+}
+
+String TextServerGDNative::format_number(const String &p_string, const String &p_language) const {
+ ERR_FAIL_COND_V(interface == nullptr, String());
+ godot_string result = interface->format_number(data, (const godot_string *)&p_string, (const godot_string *)&p_language);
+ if (interface->format_number == nullptr) {
+ return p_string;
+ }
+ String ret = *(String *)&result;
+ godot_string_destroy(&result);
+ return ret;
+}
+
+String TextServerGDNative::parse_number(const String &p_string, const String &p_language) const {
+ ERR_FAIL_COND_V(interface == nullptr, String());
+ if (interface->parse_number == nullptr) {
+ return p_string;
+ }
+ godot_string result = interface->parse_number(data, (const godot_string *)&p_string, (const godot_string *)&p_language);
+ String ret = *(String *)&result;
+ godot_string_destroy(&result);
+ return ret;
+}
+
+String TextServerGDNative::percent_sign(const String &p_language) const {
+ ERR_FAIL_COND_V(interface == nullptr, String());
+ if (interface->percent_sign == nullptr) {
+ return "%";
+ }
+ godot_string result = interface->percent_sign(data, (const godot_string *)&p_language);
+ String ret = *(String *)&result;
+ godot_string_destroy(&result);
+ return ret;
+}
+
+TextServer *TextServerGDNative::create_func(Error &r_error, void *p_user_data) {
+ const godot_text_interface_gdnative *interface = (const godot_text_interface_gdnative *)p_user_data;
+ r_error = OK;
+
+ TextServerGDNative *server = memnew(TextServerGDNative());
+ server->interface = interface;
+ server->data = interface->constructor((godot_object *)server);
+
+ return server;
+}
+
+TextServerGDNative::TextServerGDNative() {
+ data = nullptr;
+ interface = nullptr;
+}
+
+TextServerGDNative::~TextServerGDNative() {
+ if (interface != nullptr) {
+ interface->destructor(data);
+ data = nullptr;
+ interface = nullptr;
+ }
+}
+
+/*************************************************************************/
+/* GDNative functions */
+/*************************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static_assert(sizeof(godot_glyph) == sizeof(TextServer::Glyph), "Glyph size mismatch");
+static_assert(sizeof(godot_packed_glyph_array) == sizeof(Vector<TextServer::Glyph>), "Vector<Glyph> size mismatch");
+
+void GDAPI godot_text_register_interface(const godot_text_interface_gdnative *p_interface, const godot_string *p_name, uint32_t p_features) {
+ ERR_FAIL_COND(p_interface->version.major != 1);
+ String name = *(String *)p_name;
+ TextServerManager::register_create_function(name + "(GDNative)", p_features, TextServerGDNative::create_func, (void *)p_interface);
+}
+
+// Glyph
+
+void GDAPI godot_glyph_new(godot_glyph *r_dest) {
+ TextServer::Glyph *dest = (TextServer::Glyph *)r_dest;
+ *dest = TextServer::Glyph();
+}
+
+godot_vector2i GDAPI godot_glyph_get_range(const godot_glyph *p_self) {
+ godot_vector2i dest;
+ Vector2i *d = (Vector2i *)&dest;
+ const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
+ d->x = self->start;
+ d->y = self->end;
+ return dest;
+}
+
+void GDAPI godot_glyph_set_range(godot_glyph *p_self, const godot_vector2i *p_range) {
+ TextServer::Glyph *self = (TextServer::Glyph *)p_self;
+ const Vector2i *range = (const Vector2i *)p_range;
+ self->start = range->x;
+ self->end = range->y;
+}
+
+godot_int GDAPI godot_glyph_get_count(const godot_glyph *p_self) {
+ const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
+ return self->count;
+}
+
+void GDAPI godot_glyph_set_count(godot_glyph *p_self, godot_int p_count) {
+ TextServer::Glyph *self = (TextServer::Glyph *)p_self;
+ self->count = p_count;
+}
+
+godot_int GDAPI godot_glyph_get_repeat(const godot_glyph *p_self) {
+ const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
+ return self->repeat;
+}
+
+void GDAPI godot_glyph_set_repeat(godot_glyph *p_self, godot_int p_repeat) {
+ TextServer::Glyph *self = (TextServer::Glyph *)p_self;
+ self->repeat = p_repeat;
+}
+
+godot_int GDAPI godot_glyph_get_flags(const godot_glyph *p_self) {
+ const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
+ return self->flags;
+}
+
+void GDAPI godot_glyph_set_flags(godot_glyph *p_self, godot_int p_flags) {
+ TextServer::Glyph *self = (TextServer::Glyph *)p_self;
+ self->flags = p_flags;
+}
+
+godot_vector2 GDAPI godot_glyph_get_offset(const godot_glyph *p_self) {
+ godot_vector2 dest;
+ Vector2 *d = (Vector2 *)&dest;
+ const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
+ d->x = self->x_off;
+ d->y = self->y_off;
+ return dest;
+}
+
+void GDAPI godot_glyph_set_offset(godot_glyph *p_self, const godot_vector2 *p_offset) {
+ TextServer::Glyph *self = (TextServer::Glyph *)p_self;
+ const Vector2 *offset = (const Vector2 *)p_offset;
+ self->x_off = offset->x;
+ self->y_off = offset->y;
+}
+
+godot_float GDAPI godot_glyph_get_advance(const godot_glyph *p_self) {
+ const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
+ return self->advance;
+}
+
+void GDAPI godot_glyph_set_advance(godot_glyph *p_self, godot_float p_advance) {
+ TextServer::Glyph *self = (TextServer::Glyph *)p_self;
+ self->advance = p_advance;
+}
+
+godot_rid GDAPI godot_glyph_get_font(const godot_glyph *p_self) {
+ godot_rid dest;
+ RID *d = (RID *)&dest;
+ const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
+ *d = self->font_rid;
+ return dest;
+}
+
+void GDAPI godot_glyph_set_font(godot_glyph *p_self, godot_rid *p_font) {
+ TextServer::Glyph *self = (TextServer::Glyph *)p_self;
+ const RID *font = (const RID *)p_font;
+ self->font_rid = *font;
+}
+
+godot_int GDAPI godot_glyph_get_font_size(const godot_glyph *p_self) {
+ const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
+ return self->font_size;
+}
+
+void GDAPI godot_glyph_set_font_size(godot_glyph *p_self, godot_int p_size) {
+ TextServer::Glyph *self = (TextServer::Glyph *)p_self;
+ self->font_size = p_size;
+}
+
+godot_int GDAPI godot_glyph_get_index(const godot_glyph *p_self) {
+ const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
+ return self->index;
+}
+
+void GDAPI godot_glyph_set_index(godot_glyph *p_self, godot_int p_index) {
+ TextServer::Glyph *self = (TextServer::Glyph *)p_self;
+ self->index = p_index;
+}
+
+// GlyphArray
+
+void GDAPI godot_packed_glyph_array_new(godot_packed_glyph_array *r_dest) {
+ Vector<TextServer::Glyph> *dest = (Vector<TextServer::Glyph> *)r_dest;
+ memnew_placement(dest, Vector<TextServer::Glyph>);
+}
+
+void GDAPI godot_packed_glyph_array_new_copy(godot_packed_glyph_array *r_dest, const godot_packed_glyph_array *p_src) {
+ Vector<TextServer::Glyph> *dest = (Vector<TextServer::Glyph> *)r_dest;
+ const Vector<TextServer::Glyph> *src = (const Vector<TextServer::Glyph> *)p_src;
+ memnew_placement(dest, Vector<TextServer::Glyph>(*src));
+}
+
+const godot_glyph GDAPI *godot_packed_glyph_array_ptr(const godot_packed_glyph_array *p_self) {
+ const Vector<TextServer::Glyph> *self = (const Vector<TextServer::Glyph> *)p_self;
+ return (const godot_glyph *)self->ptr();
+}
+
+godot_glyph GDAPI *godot_packed_glyph_array_ptrw(godot_packed_glyph_array *p_self) {
+ Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
+ return (godot_glyph *)self->ptrw();
+}
+
+void GDAPI godot_packed_glyph_array_append(godot_packed_glyph_array *p_self, const godot_glyph *p_data) {
+ Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
+ TextServer::Glyph &s = *(TextServer::Glyph *)p_data;
+ self->push_back(s);
+}
+
+void GDAPI godot_packed_glyph_array_append_array(godot_packed_glyph_array *p_self, const godot_packed_glyph_array *p_array) {
+ Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
+ Vector<TextServer::Glyph> *array = (Vector<TextServer::Glyph> *)p_array;
+ self->append_array(*array);
+}
+
+godot_error GDAPI godot_packed_glyph_array_insert(godot_packed_glyph_array *p_self, const godot_int p_idx, const godot_glyph *p_data) {
+ Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
+ TextServer::Glyph &s = *(TextServer::Glyph *)p_data;
+ return (godot_error)self->insert(p_idx, s);
+}
+
+godot_bool GDAPI godot_packed_glyph_array_has(godot_packed_glyph_array *p_self, const godot_glyph *p_value) {
+ Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
+ TextServer::Glyph &v = *(TextServer::Glyph *)p_value;
+ return (godot_bool)self->has(v);
+}
+
+void GDAPI godot_packed_glyph_array_sort(godot_packed_glyph_array *p_self) {
+ Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
+ self->sort();
+}
+
+void GDAPI godot_packed_glyph_array_invert(godot_packed_glyph_array *p_self) {
+ Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
+ self->invert();
+}
+
+void GDAPI godot_packed_glyph_array_push_back(godot_packed_glyph_array *p_self, const godot_glyph *p_data) {
+ Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
+ TextServer::Glyph &s = *(TextServer::Glyph *)p_data;
+ self->push_back(s);
+}
+
+void GDAPI godot_packed_glyph_array_remove(godot_packed_glyph_array *p_self, const godot_int p_idx) {
+ Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
+ self->remove(p_idx);
+}
+
+void GDAPI godot_packed_glyph_array_resize(godot_packed_glyph_array *p_self, const godot_int p_size) {
+ Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
+ self->resize(p_size);
+}
+
+void GDAPI godot_packed_glyph_array_set(godot_packed_glyph_array *p_self, const godot_int p_idx, const godot_glyph *p_data) {
+ Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
+ TextServer::Glyph &s = *(TextServer::Glyph *)p_data;
+ self->set(p_idx, s);
+}
+
+godot_glyph GDAPI godot_packed_glyph_array_get(const godot_packed_glyph_array *p_self, const godot_int p_idx) {
+ const Vector<TextServer::Glyph> *self = (const Vector<TextServer::Glyph> *)p_self;
+ godot_glyph v;
+ TextServer::Glyph *s = (TextServer::Glyph *)&v;
+ *s = self->get(p_idx);
+ return v;
+}
+
+godot_int GDAPI godot_packed_glyph_array_size(const godot_packed_glyph_array *p_self) {
+ const Vector<TextServer::Glyph> *self = (const Vector<TextServer::Glyph> *)p_self;
+ return self->size();
+}
+
+godot_bool GDAPI godot_packed_glyph_array_is_empty(const godot_packed_glyph_array *p_self) {
+ const Vector<TextServer::Glyph> *self = (const Vector<TextServer::Glyph> *)p_self;
+ return self->is_empty();
+}
+
+void GDAPI godot_packed_glyph_array_destroy(godot_packed_glyph_array *p_self) {
+ ((Vector<TextServer::Glyph> *)p_self)->~Vector();
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/gdnative/text/text_server_gdnative.h b/modules/gdnative/text/text_server_gdnative.h
new file mode 100644
index 0000000000..9cbb94217e
--- /dev/null
+++ b/modules/gdnative/text/text_server_gdnative.h
@@ -0,0 +1,187 @@
+/*************************************************************************/
+/* text_server_gdnative.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEXT_SERVER_GDNATIVE_H
+#define TEXT_SERVER_GDNATIVE_H
+
+#include "modules/gdnative/gdnative.h"
+
+#include "servers/text_server.h"
+
+class TextServerGDNative : public TextServer {
+ GDCLASS(TextServerGDNative, TextServer);
+
+ const godot_text_interface_gdnative *interface = nullptr;
+ void *data = nullptr;
+
+protected:
+ static void _bind_methods(){};
+
+public:
+ virtual bool has_feature(Feature p_feature) override;
+ virtual String get_name() const override;
+
+ virtual void free(RID p_rid) override;
+ virtual bool has(RID p_rid) override;
+ virtual bool load_support_data(const String &p_filename) override;
+
+#ifdef TOOLS_ENABLED
+ virtual String get_support_data_filename() override;
+ virtual String get_support_data_info() override;
+ virtual bool save_support_data(const String &p_filename) override;
+#endif
+
+ virtual bool is_locale_right_to_left(const String &p_locale) override;
+
+ /* Font interface */
+ virtual RID create_font_system(const String &p_name, int p_base_size = 16) override;
+ virtual RID create_font_resource(const String &p_filename, int p_base_size = 16) override;
+ virtual RID create_font_memory(const uint8_t *p_data, size_t p_size, const String &p_type, int p_base_size = 16) override;
+
+ virtual float font_get_height(RID p_font, int p_size) const override;
+ virtual float font_get_ascent(RID p_font, int p_size) const override;
+ virtual float font_get_descent(RID p_font, int p_size) const override;
+
+ virtual float font_get_underline_position(RID p_font, int p_size) const override;
+ virtual float font_get_underline_thickness(RID p_font, int p_size) const override;
+
+ virtual void font_set_antialiased(RID p_font, bool p_antialiased) override;
+ virtual bool font_get_antialiased(RID p_font) const override;
+
+ virtual Dictionary font_get_feature_list(RID p_font) const override;
+ virtual Dictionary font_get_variation_list(RID p_font) const override;
+
+ virtual void font_set_variation(RID p_font, const String &p_name, double p_value) override;
+ virtual double font_get_variation(RID p_font, const String &p_name) const override;
+
+ virtual void font_set_hinting(RID p_font, Hinting p_hinting) override;
+ virtual Hinting font_get_hinting(RID p_font) const override;
+
+ virtual void font_set_distance_field_hint(RID p_font, bool p_distance_field) override;
+ virtual bool font_get_distance_field_hint(RID p_font) const override;
+
+ virtual void font_set_force_autohinter(RID p_font, bool p_enabeld) override;
+ virtual bool font_get_force_autohinter(RID p_font) const override;
+
+ virtual bool font_has_char(RID p_font, char32_t p_char) const override;
+ virtual String font_get_supported_chars(RID p_font) const override;
+
+ virtual bool font_has_outline(RID p_font) const override;
+ virtual float font_get_base_size(RID p_font) const override;
+
+ virtual bool font_is_language_supported(RID p_font, const String &p_language) const override;
+ virtual void font_set_language_support_override(RID p_font, const String &p_language, bool p_supported) override;
+ virtual bool font_get_language_support_override(RID p_font, const String &p_language) override;
+ virtual void font_remove_language_support_override(RID p_font, const String &p_language) override;
+ Vector<String> font_get_language_support_overrides(RID p_font) override;
+
+ virtual bool font_is_script_supported(RID p_font, const String &p_script) const override;
+ virtual void font_set_script_support_override(RID p_font, const String &p_script, bool p_supported) override;
+ virtual bool font_get_script_support_override(RID p_font, const String &p_script) override;
+ virtual void font_remove_script_support_override(RID p_font, const String &p_script) override;
+ Vector<String> font_get_script_support_overrides(RID p_font) override;
+
+ virtual uint32_t font_get_glyph_index(RID p_font, char32_t p_char, char32_t p_variation_selector = 0x0000) const override;
+ virtual Vector2 font_get_glyph_advance(RID p_font, uint32_t p_index, int p_size) const override;
+ virtual Vector2 font_get_glyph_kerning(RID p_font, uint32_t p_index_a, uint32_t p_index_b, int p_size) const override;
+
+ virtual Vector2 font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
+ virtual Vector2 font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
+
+ virtual float font_get_oversampling() const override;
+ virtual void font_set_oversampling(float p_oversampling) override;
+
+ virtual Vector<String> get_system_fonts() const 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_set_direction(RID p_shaped, Direction p_direction = DIRECTION_AUTO) override;
+ virtual Direction shaped_text_get_direction(RID p_shaped) const override;
+
+ virtual void shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) 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(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(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(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 = "") override;
+ virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1) override;
+ virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER) 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 float shaped_text_fit_to_width(RID p_shaped, float p_width, uint8_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override;
+ virtual float shaped_text_tab_align(RID p_shaped, const Vector<float> &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_is_ready(RID p_shaped) const override;
+
+ virtual Vector<Glyph> shaped_text_get_glyphs(RID p_shaped) const override;
+
+ virtual Vector2i shaped_text_get_range(RID p_shaped) const override;
+
+ virtual Vector<Glyph> shaped_text_sort_logical(RID p_shaped) override;
+ virtual Vector<Vector2i> shaped_text_get_line_breaks_adv(RID p_shaped, const Vector<float> &p_width, int p_start = 0, bool p_once = true, uint8_t /*TextBreakFlag*/ p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const override;
+ virtual Vector<Vector2i> shaped_text_get_line_breaks(RID p_shaped, float p_width, int p_start = 0, uint8_t p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const override;
+ virtual Vector<Vector2i> shaped_text_get_word_breaks(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 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 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;
+
+ static TextServer *create_func(Error &r_error, void *p_user_data);
+
+ TextServerGDNative();
+ ~TextServerGDNative();
+};
+
+#endif // TEXT_SERVER_GDNATIVE_H
diff --git a/modules/gdnative/videodecoder/register_types.cpp b/modules/gdnative/videodecoder/register_types.cpp
index 4181d8813f..394831daeb 100644
--- a/modules/gdnative/videodecoder/register_types.cpp
+++ b/modules/gdnative/videodecoder/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,7 +30,7 @@
#include "register_types.h"
-#include "core/class_db.h"
+#include "core/object/class_db.h"
#include "video_stream_gdnative.h"
static Ref<ResourceFormatLoaderVideoStreamGDNative> resource_loader_vsgdnative;
diff --git a/modules/gdnative/videodecoder/register_types.h b/modules/gdnative/videodecoder/register_types.h
index b1a83d4071..809225c925 100644
--- a/modules/gdnative/videodecoder/register_types.h
+++ b/modules/gdnative/videodecoder/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnative/videodecoder/video_stream_gdnative.cpp b/modules/gdnative/videodecoder/video_stream_gdnative.cpp
index fe7c10cad9..18d26a9528 100644
--- a/modules/gdnative/videodecoder/video_stream_gdnative.cpp
+++ b/modules/gdnative/videodecoder/video_stream_gdnative.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,7 +30,7 @@
#include "video_stream_gdnative.h"
-#include "core/project_settings.h"
+#include "core/config/project_settings.h"
#include "servers/audio_server.h"
VideoDecoderServer *VideoDecoderServer::instance = nullptr;
diff --git a/modules/gdnative/videodecoder/video_stream_gdnative.h b/modules/gdnative/videodecoder/video_stream_gdnative.h
index 408d4a2454..e64cda6602 100644
--- a/modules/gdnative/videodecoder/video_stream_gdnative.h
+++ b/modules/gdnative/videodecoder/video_stream_gdnative.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnative/xr/register_types.cpp b/modules/gdnative/xr/register_types.cpp
index da3a7dc4b8..b60a04f470 100644
--- a/modules/gdnative/xr/register_types.cpp
+++ b/modules/gdnative/xr/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnative/xr/register_types.h b/modules/gdnative/xr/register_types.h
index 2501d28651..4e7469abe9 100644
--- a/modules/gdnative/xr/register_types.h
+++ b/modules/gdnative/xr/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnative/xr/xr_interface_gdnative.cpp b/modules/gdnative/xr/xr_interface_gdnative.cpp
index d03fc33935..5bbf70174c 100644
--- a/modules/gdnative/xr/xr_interface_gdnative.cpp
+++ b/modules/gdnative/xr/xr_interface_gdnative.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -190,7 +190,7 @@ CameraMatrix XRInterfaceGDNative::get_projection_for_eye(XRInterface::Eyes p_eye
ERR_FAIL_COND_V(interface == nullptr, CameraMatrix());
- interface->fill_projection_for_eye(data, (godot_real *)cm.matrix, (godot_int)p_eye, p_aspect, p_z_near, p_z_far);
+ interface->fill_projection_for_eye(data, (godot_float *)cm.matrix, (godot_int)p_eye, p_aspect, p_z_near, p_z_far);
return cm;
}
@@ -234,7 +234,7 @@ void GDAPI godot_xr_register_interface(const godot_xr_interface_gdnative *p_inte
XRServer::get_singleton()->add_interface(new_interface);
}
-godot_real GDAPI godot_xr_get_worldscale() {
+godot_float GDAPI godot_xr_get_worldscale() {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, 1.0);
@@ -249,7 +249,7 @@ godot_transform GDAPI godot_xr_get_reference_frame() {
if (xr_server != nullptr) {
*reference_frame_ptr = xr_server->get_reference_frame();
} else {
- godot_transform_new_identity(&reference_frame);
+ memnew_placement(&reference_frame, Transform);
}
return reference_frame;
@@ -302,12 +302,12 @@ godot_int GDAPI godot_xr_add_controller(char *p_device_name, godot_int p_hand, g
ERR_FAIL_NULL_V(input, 0);
XRPositionalTracker *new_tracker = memnew(XRPositionalTracker);
- new_tracker->set_name(p_device_name);
- new_tracker->set_type(XRServer::TRACKER_CONTROLLER);
+ new_tracker->set_tracker_name(p_device_name);
+ new_tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER);
if (p_hand == 1) {
- new_tracker->set_hand(XRPositionalTracker::TRACKER_LEFT_HAND);
+ new_tracker->set_tracker_hand(XRPositionalTracker::TRACKER_HAND_LEFT);
} else if (p_hand == 2) {
- new_tracker->set_hand(XRPositionalTracker::TRACKER_RIGHT_HAND);
+ new_tracker->set_tracker_hand(XRPositionalTracker::TRACKER_HAND_RIGHT);
}
// also register as joystick...
@@ -387,7 +387,7 @@ void GDAPI godot_xr_set_controller_button(godot_int p_controller_id, godot_int p
}
}
-void GDAPI godot_xr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_real p_value, godot_bool p_can_be_negative) {
+void GDAPI godot_xr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_float p_value, godot_bool p_can_be_negative) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
@@ -406,7 +406,7 @@ void GDAPI godot_xr_set_controller_axis(godot_int p_controller_id, godot_int p_a
}
}
-godot_real GDAPI godot_xr_get_controller_rumble(godot_int p_controller_id) {
+godot_float GDAPI godot_xr_get_controller_rumble(godot_int p_controller_id) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, 0.0);
diff --git a/modules/gdnative/xr/xr_interface_gdnative.h b/modules/gdnative/xr/xr_interface_gdnative.h
index de96487397..84bd8fc731 100644
--- a/modules/gdnative/xr/xr_interface_gdnative.h
+++ b/modules/gdnative/xr/xr_interface_gdnative.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnavigation/SCsub b/modules/gdnavigation/SCsub
index 877d601c6a..22b5509b32 100644
--- a/modules/gdnavigation/SCsub
+++ b/modules/gdnavigation/SCsub
@@ -5,6 +5,10 @@ Import("env_modules")
env_navigation = env_modules.Clone()
+# Thirdparty source files
+
+thirdparty_obj = []
+
# Recast Thirdparty source files
if env["builtin_recast"]:
thirdparty_dir = "#thirdparty/recastnavigation/Recast/"
@@ -23,28 +27,37 @@ if env["builtin_recast"]:
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
- env_navigation.Prepend(CPPPATH=[thirdparty_dir + "/Include"])
+ env_navigation.Prepend(CPPPATH=[thirdparty_dir + "Include"])
env_thirdparty = env_navigation.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
-
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
# RVO Thirdparty source files
if env["builtin_rvo2"]:
- thirdparty_dir = "#thirdparty/rvo2"
+ thirdparty_dir = "#thirdparty/rvo2/"
thirdparty_sources = [
- "/src/Agent.cpp",
- "/src/KdTree.cpp",
+ "Agent.cpp",
+ "KdTree.cpp",
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
- env_navigation.Prepend(CPPPATH=[thirdparty_dir + "/src"])
+ env_navigation.Prepend(CPPPATH=[thirdparty_dir])
env_thirdparty = env_navigation.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+
+
+env.modules_sources += thirdparty_obj
# Godot source files
-env_navigation.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_navigation.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/gdnavigation/gd_navigation_server.cpp b/modules/gdnavigation/gd_navigation_server.cpp
index c80cdcfeab..4f61ad5040 100644
--- a/modules/gdnavigation/gd_navigation_server.cpp
+++ b/modules/gdnavigation/gd_navigation_server.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnavigation/gd_navigation_server.h b/modules/gdnavigation/gd_navigation_server.h
index e3e02f3d7c..92f4ccfdd5 100644
--- a/modules/gdnavigation/gd_navigation_server.h
+++ b/modules/gdnavigation/gd_navigation_server.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,8 +31,8 @@
#ifndef GD_NAVIGATION_SERVER_H
#define GD_NAVIGATION_SERVER_H
-#include "core/rid.h"
-#include "core/rid_owner.h"
+#include "core/templates/rid.h"
+#include "core/templates/rid_owner.h"
#include "servers/navigation_server_3d.h"
#include "nav_map.h"
diff --git a/modules/gdnavigation/nav_map.cpp b/modules/gdnavigation/nav_map.cpp
index 7919e6a01f..2646a4cc0c 100644
--- a/modules/gdnavigation/nav_map.cpp
+++ b/modules/gdnavigation/nav_map.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -707,7 +707,7 @@ void NavMap::sync() {
}
if (regenerate_links) {
- map_update_id = map_update_id + 1 % 9999999;
+ map_update_id = (map_update_id + 1) % 9999999;
}
if (agents_dirty) {
diff --git a/modules/gdnavigation/nav_map.h b/modules/gdnavigation/nav_map.h
index 892755f3f9..bffc1fbc1a 100644
--- a/modules/gdnavigation/nav_map.h
+++ b/modules/gdnavigation/nav_map.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnavigation/nav_region.cpp b/modules/gdnavigation/nav_region.cpp
index 51fba67cc3..383b0f15a6 100644
--- a/modules/gdnavigation/nav_region.cpp
+++ b/modules/gdnavigation/nav_region.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnavigation/nav_region.h b/modules/gdnavigation/nav_region.h
index 731855bfb5..954780033b 100644
--- a/modules/gdnavigation/nav_region.h
+++ b/modules/gdnavigation/nav_region.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnavigation/nav_rid.h b/modules/gdnavigation/nav_rid.h
index c119ecc5e0..a0a60a3643 100644
--- a/modules/gdnavigation/nav_rid.h
+++ b/modules/gdnavigation/nav_rid.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,7 +31,7 @@
#ifndef NAV_RID_H
#define NAV_RID_H
-#include "core/rid.h"
+#include "core/templates/rid.h"
/**
@author AndreaCatania
diff --git a/modules/gdnavigation/nav_utils.h b/modules/gdnavigation/nav_utils.h
index 40e54df553..d1d1687a1f 100644
--- a/modules/gdnavigation/nav_utils.h
+++ b/modules/gdnavigation/nav_utils.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnavigation/navigation_mesh_editor_plugin.cpp b/modules/gdnavigation/navigation_mesh_editor_plugin.cpp
index 648f4f7cdd..aa9248d2a1 100644
--- a/modules/gdnavigation/navigation_mesh_editor_plugin.cpp
+++ b/modules/gdnavigation/navigation_mesh_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -142,7 +142,7 @@ void NavigationMeshEditorPlugin::make_visible(bool p_visible) {
NavigationMeshEditorPlugin::NavigationMeshEditorPlugin(EditorNode *p_node) {
editor = p_node;
navigation_mesh_editor = memnew(NavigationMeshEditor);
- editor->get_viewport()->add_child(navigation_mesh_editor);
+ editor->get_main_control()->add_child(navigation_mesh_editor);
add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, navigation_mesh_editor->bake_hbox);
navigation_mesh_editor->hide();
navigation_mesh_editor->bake_hbox->hide();
diff --git a/modules/gdnavigation/navigation_mesh_editor_plugin.h b/modules/gdnavigation/navigation_mesh_editor_plugin.h
index f09182fff4..c39269865b 100644
--- a/modules/gdnavigation/navigation_mesh_editor_plugin.h
+++ b/modules/gdnavigation/navigation_mesh_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnavigation/navigation_mesh_generator.cpp b/modules/gdnavigation/navigation_mesh_generator.cpp
index 5329600e39..a7d4e79148 100644
--- a/modules/gdnavigation/navigation_mesh_generator.cpp
+++ b/modules/gdnavigation/navigation_mesh_generator.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -151,7 +151,7 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform,
if (Object::cast_to<CSGShape3D>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS) {
CSGShape3D *csg_shape = Object::cast_to<CSGShape3D>(p_node);
Array meshes = csg_shape->get_meshes();
- if (!meshes.empty()) {
+ if (!meshes.is_empty()) {
Ref<Mesh> mesh = meshes[1];
if (mesh.is_valid()) {
_add_mesh(mesh, p_accumulated_transform * csg_shape->get_transform(), p_verticies, p_indices);
@@ -176,10 +176,10 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform,
BoxShape3D *box = Object::cast_to<BoxShape3D>(*s);
if (box) {
- Ref<CubeMesh> cube_mesh;
- cube_mesh.instance();
- cube_mesh->set_size(box->get_extents() * 2.0);
- mesh = cube_mesh;
+ Ref<BoxMesh> box_mesh;
+ box_mesh.instance();
+ box_mesh->set_size(box->get_size());
+ mesh = box_mesh;
}
CapsuleShape3D *capsule = Object::cast_to<CapsuleShape3D>(*s);
diff --git a/modules/gdnavigation/navigation_mesh_generator.h b/modules/gdnavigation/navigation_mesh_generator.h
index c5f7b2ab81..88ccdb1c41 100644
--- a/modules/gdnavigation/navigation_mesh_generator.h
+++ b/modules/gdnavigation/navigation_mesh_generator.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnavigation/register_types.cpp b/modules/gdnavigation/register_types.cpp
index 088b26bf17..8443d3d242 100644
--- a/modules/gdnavigation/register_types.cpp
+++ b/modules/gdnavigation/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,7 +30,7 @@
#include "register_types.h"
-#include "core/engine.h"
+#include "core/config/engine.h"
#include "gd_navigation_server.h"
#include "servers/navigation_server_3d.h"
diff --git a/modules/gdnavigation/register_types.h b/modules/gdnavigation/register_types.h
index cdbff1b937..c2bb08c649 100644
--- a/modules/gdnavigation/register_types.h
+++ b/modules/gdnavigation/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnavigation/rvo_agent.cpp b/modules/gdnavigation/rvo_agent.cpp
index 1e1bdbd07d..21e43d08c1 100644
--- a/modules/gdnavigation/rvo_agent.cpp
+++ b/modules/gdnavigation/rvo_agent.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdnavigation/rvo_agent.h b/modules/gdnavigation/rvo_agent.h
index f5c579ba84..d9e3345498 100644
--- a/modules/gdnavigation/rvo_agent.h
+++ b/modules/gdnavigation/rvo_agent.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,8 +31,9 @@
#ifndef RVO_AGENT_H
#define RVO_AGENT_H
-#include "core/object.h"
+#include "core/object/class_db.h"
#include "nav_rid.h"
+
#include <Agent.h>
/**
diff --git a/modules/gdscript/config.py b/modules/gdscript/config.py
index 6fc227e7f5..61ce6185a5 100644
--- a/modules/gdscript/config.py
+++ b/modules/gdscript/config.py
@@ -10,7 +10,6 @@ def get_doc_classes():
return [
"@GDScript",
"GDScript",
- "GDScriptFunctionState",
]
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index fc27892099..9e974b6fdc 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -7,6 +7,7 @@
List of core built-in GDScript functions. Math functions and other utilities. Everything else is provided by objects. (Keywords: builtin, built in, global functions.)
</description>
<tutorials>
+ <link title="Random number generation">https://docs.godotengine.org/en/latest/tutorials/math/random_number_generation.html</link>
</tutorials>
<methods>
<method name="Color8">
@@ -31,60 +32,6 @@
[/codeblock]
</description>
</method>
- <method name="ColorN">
- <return type="Color">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="alpha" type="float" default="1.0">
- </argument>
- <description>
- Returns a color according to the standardized [code]name[/code] with [code]alpha[/code] ranging from 0 to 1.
- [codeblock]
- red = ColorN("red", 1)
- [/codeblock]
- Supported color names are the same as the constants defined in [Color].
- </description>
- </method>
- <method name="abs">
- <return type="float">
- </return>
- <argument index="0" name="s" type="float">
- </argument>
- <description>
- Returns the absolute value of parameter [code]s[/code] (i.e. positive value).
- [codeblock]
- # a is 1
- a = abs(-1)
- [/codeblock]
- </description>
- </method>
- <method name="acos">
- <return type="float">
- </return>
- <argument index="0" name="s" type="float">
- </argument>
- <description>
- Returns the arc cosine of [code]s[/code] in radians. Use to get the angle of cosine [code]s[/code].
- [codeblock]
- # c is 0.523599 or 30 degrees if converted with rad2deg(s)
- c = acos(0.866025)
- [/codeblock]
- </description>
- </method>
- <method name="asin">
- <return type="float">
- </return>
- <argument index="0" name="s" type="float">
- </argument>
- <description>
- Returns the arc sine of [code]s[/code] in radians. Use to get the angle of sine [code]s[/code].
- [codeblock]
- # s is 0.523599 or 30 degrees if converted with rad2deg(s)
- s = asin(0.5)
- [/codeblock]
- </description>
- </method>
<method name="assert">
<return type="void">
</return>
@@ -93,87 +40,23 @@
<argument index="1" name="message" type="String" default="&quot;&quot;">
</argument>
<description>
- Asserts that the [code]condition[/code] is [code]true[/code]. If the [code]condition[/code] is [code]false[/code], an error is generated and the program is halted until you resume it. Only executes in debug builds, or when running the game from the editor. Use it for debugging purposes, to make sure a statement is [code]true[/code] during development.
+ Asserts that the [code]condition[/code] is [code]true[/code]. If the [code]condition[/code] is [code]false[/code], an error is generated. When running from the editor, the running project will also be paused until you resume it. This can be used as a stronger form of [method @GlobalScope.push_error] for reporting errors to project developers or add-on users.
+ [b]Note:[/b] For performance reasons, the code inside [method assert] is only executed in debug builds or when running the project from the editor. Don't include code that has side effects in an [method assert] call. Otherwise, the project will behave differently when exported in release mode.
The optional [code]message[/code] argument, if given, is shown in addition to the generic "Assertion failed" message. You can use this to provide additional details about why the assertion failed.
[codeblock]
- # Imagine we always want speed to be between 0 and 20
- speed = -10
+ # Imagine we always want speed to be between 0 and 20.
+ var speed = -10
assert(speed &lt; 20) # True, the program will continue
assert(speed &gt;= 0) # False, the program will stop
- assert(speed &gt;= 0 &amp;&amp; speed &lt; 20) # You can also combine the two conditional statements in one check
+ assert(speed &gt;= 0 and speed &lt; 20) # You can also combine the two conditional statements in one check
assert(speed &lt; 20, "speed = %f, but the speed limit is 20" % speed) # Show a message with clarifying details
[/codeblock]
</description>
</method>
- <method name="atan">
- <return type="float">
- </return>
- <argument index="0" name="s" type="float">
- </argument>
- <description>
- Returns the arc tangent of [code]s[/code] in radians. Use it to get the angle from an angle's tangent in trigonometry: [code]atan(tan(angle)) == angle[/code].
- The method cannot know in which quadrant the angle should fall. See [method atan2] if you have both [code]y[/code] and [code]x[/code].
- [codeblock]
- a = atan(0.5) # a is 0.463648
- [/codeblock]
- </description>
- </method>
- <method name="atan2">
- <return type="float">
- </return>
- <argument index="0" name="y" type="float">
- </argument>
- <argument index="1" name="x" type="float">
- </argument>
- <description>
- Returns the arc tangent of [code]y/x[/code] in radians. Use to get the angle of tangent [code]y/x[/code]. To compute the value, the method takes into account the sign of both arguments in order to determine the quadrant.
- Important note: The Y coordinate comes first, by convention.
- [codeblock]
- a = atan2(0, -1) # a is 3.141593
- [/codeblock]
- </description>
- </method>
- <method name="bytes2var">
- <return type="Variant">
- </return>
- <argument index="0" name="bytes" type="PackedByteArray">
- </argument>
- <argument index="1" name="allow_objects" type="bool" default="false">
- </argument>
- <description>
- Decodes a byte array back to a value. When [code]allow_objects[/code] is [code]true[/code] decoding objects is allowed.
- [b]WARNING:[/b] Deserialized object can contain code which gets executed. Do not use this option if the serialized object comes from untrusted sources to avoid potential security threats (remote code execution).
- </description>
- </method>
- <method name="cartesian2polar">
- <return type="Vector2">
- </return>
- <argument index="0" name="x" type="float">
- </argument>
- <argument index="1" name="y" type="float">
- </argument>
- <description>
- Converts a 2D point expressed in the cartesian coordinate system (X and Y axis) to the polar coordinate system (a distance from the origin and an angle).
- </description>
- </method>
- <method name="ceil">
- <return type="float">
- </return>
- <argument index="0" name="s" type="float">
- </argument>
- <description>
- Rounds [code]s[/code] upward (towards positive infinity), returning the smallest whole number that is not less than [code]s[/code].
- [codeblock]
- i = ceil(1.45) # i is 2
- i = ceil(1.001) # i is 2
- [/codeblock]
- See also [method floor], [method round], and [method stepify].
- </description>
- </method>
<method name="char">
<return type="String">
</return>
- <argument index="0" name="code" type="int">
+ <argument index="0" name="char" type="int">
</argument>
<description>
Returns a character as a String of the given Unicode code point (which is compatible with ASCII code).
@@ -182,29 +65,6 @@
a = char(65 + 32) # a is "a"
a = char(8364) # a is "€"
[/codeblock]
- This is the inverse of [method ord].
- </description>
- </method>
- <method name="clamp">
- <return type="float">
- </return>
- <argument index="0" name="value" type="float">
- </argument>
- <argument index="1" name="min" type="float">
- </argument>
- <argument index="2" name="max" type="float">
- </argument>
- <description>
- Clamps [code]value[/code] and returns a value not less than [code]min[/code] and not more than [code]max[/code].
- [codeblock]
- speed = 1000
- # a is 20
- a = clamp(speed, 1, 20)
-
- speed = -10
- # a is 1
- a = clamp(speed, 1, 20)
- [/codeblock]
</description>
</method>
<method name="convert">
@@ -226,181 +86,13 @@
[/codeblock]
</description>
</method>
- <method name="cos">
- <return type="float">
- </return>
- <argument index="0" name="s" type="float">
- </argument>
- <description>
- Returns the cosine of angle [code]s[/code] in radians.
- [codeblock]
- # Prints 1 then -1
- print(cos(PI * 2))
- print(cos(PI))
- [/codeblock]
- </description>
- </method>
- <method name="cosh">
- <return type="float">
- </return>
- <argument index="0" name="s" type="float">
- </argument>
- <description>
- Returns the hyperbolic cosine of [code]s[/code] in radians.
- [codeblock]
- # Prints 1.543081
- print(cosh(1))
- [/codeblock]
- </description>
- </method>
- <method name="db2linear">
- <return type="float">
- </return>
- <argument index="0" name="db" type="float">
- </argument>
- <description>
- Converts from decibels to linear energy (audio).
- </description>
- </method>
- <method name="dectime">
- <return type="float">
- </return>
- <argument index="0" name="value" type="float">
- </argument>
- <argument index="1" name="amount" type="float">
- </argument>
- <argument index="2" name="step" type="float">
- </argument>
- <description>
- Returns the result of [code]value[/code] decreased by [code]step[/code] * [code]amount[/code].
- [codeblock]
- # a = 59
- a = dectime(60, 10, 0.1))
- [/codeblock]
- </description>
- </method>
- <method name="deg2rad">
- <return type="float">
- </return>
- <argument index="0" name="deg" type="float">
- </argument>
- <description>
- Converts an angle expressed in degrees to radians.
- [codeblock]
- # r is 3.141593
- r = deg2rad(180)
- [/codeblock]
- </description>
- </method>
<method name="dict2inst">
<return type="Object">
</return>
- <argument index="0" name="dict" type="Dictionary">
+ <argument index="0" name="dictionary" type="Dictionary">
</argument>
<description>
- Converts a previously converted instance to a dictionary, back into an instance. Useful for deserializing.
- </description>
- </method>
- <method name="ease">
- <return type="float">
- </return>
- <argument index="0" name="s" type="float">
- </argument>
- <argument index="1" name="curve" type="float">
- </argument>
- <description>
- Easing function, based on exponent. The curve values are: 0 is constant, 1 is linear, 0 to 1 is ease-in, 1+ is ease out. Negative values are in-out/out in.
- </description>
- </method>
- <method name="exp">
- <return type="float">
- </return>
- <argument index="0" name="s" type="float">
- </argument>
- <description>
- The natural exponential function. It raises the mathematical constant [b]e[/b] to the power of [code]s[/code] and returns it.
- [b]e[/b] has an approximate value of 2.71828, and can be obtained with [code]exp(1)[/code].
- For exponents to other bases use the method [method pow].
- [codeblock]
- a = exp(2) # Approximately 7.39
- [/codeblock]
- </description>
- </method>
- <method name="floor">
- <return type="float">
- </return>
- <argument index="0" name="s" type="float">
- </argument>
- <description>
- Rounds [code]s[/code] downward (towards negative infinity), returning the largest whole number that is not more than [code]s[/code].
- [codeblock]
- # a is 2.0
- a = floor(2.99)
- # a is -3.0
- a = floor(-2.99)
- [/codeblock]
- See also [method ceil], [method round], and [method stepify].
- [b]Note:[/b] This method returns a float. If you need an integer, you can use [code]int(s)[/code] directly.
- </description>
- </method>
- <method name="fmod">
- <return type="float">
- </return>
- <argument index="0" name="a" type="float">
- </argument>
- <argument index="1" name="b" type="float">
- </argument>
- <description>
- Returns the floating-point remainder of [code]a/b[/code], keeping the sign of [code]a[/code].
- [codeblock]
- # Remainder is 1.5
- var remainder = fmod(7, 5.5)
- [/codeblock]
- For the integer remainder operation, use the % operator.
- </description>
- </method>
- <method name="fposmod">
- <return type="float">
- </return>
- <argument index="0" name="a" type="float">
- </argument>
- <argument index="1" name="b" type="float">
- </argument>
- <description>
- Returns the floating-point modulus of [code]a/b[/code] that wraps equally in positive and negative.
- [codeblock]
- for i in 7:
- var x = 0.5 * i - 1.5
- print("%4.1f %4.1f %4.1f" % [x, fmod(x, 1.5), fposmod(x, 1.5)])
- [/codeblock]
- Produces:
- [codeblock]
- -1.5 -0.0 0.0
- -1.0 -1.0 0.5
- -0.5 -0.5 1.0
- 0.0 0.0 0.0
- 0.5 0.5 0.5
- 1.0 1.0 1.0
- 1.5 0.0 0.0
- [/codeblock]
- </description>
- </method>
- <method name="funcref">
- <return type="FuncRef">
- </return>
- <argument index="0" name="instance" type="Object">
- </argument>
- <argument index="1" name="funcname" type="String">
- </argument>
- <description>
- Returns a reference to the specified function [code]funcname[/code] in the [code]instance[/code] node. As functions aren't first-class objects in GDscript, use [code]funcref[/code] to store a [FuncRef] in a variable and call it later.
- [codeblock]
- func foo():
- return("bar")
-
- a = funcref(self, "foo")
- print(a.call_func()) # Prints bar
- [/codeblock]
+ Converts a dictionary (previously created with [method inst2dict]) back to an instance. Useful for deserializing.
</description>
</method>
<method name="get_stack">
@@ -424,22 +116,10 @@
[/codeblock]
</description>
</method>
- <method name="hash">
- <return type="int">
- </return>
- <argument index="0" name="var" type="Variant">
- </argument>
- <description>
- Returns the integer hash of the variable passed.
- [codeblock]
- print(hash("a")) # Prints 177670
- [/codeblock]
- </description>
- </method>
<method name="inst2dict">
<return type="Dictionary">
</return>
- <argument index="0" name="inst" type="Object">
+ <argument index="0" name="instance" type="Object">
</argument>
<description>
Returns the passed instance converted to a dictionary (useful for serializing).
@@ -457,92 +137,6 @@
[/codeblock]
</description>
</method>
- <method name="instance_from_id">
- <return type="Object">
- </return>
- <argument index="0" name="instance_id" type="int">
- </argument>
- <description>
- Returns the Object that corresponds to [code]instance_id[/code]. All Objects have a unique instance ID.
- [codeblock]
- var foo = "bar"
- func _ready():
- var id = get_instance_id()
- var inst = instance_from_id(id)
- print(inst.foo) # Prints bar
- [/codeblock]
- </description>
- </method>
- <method name="inverse_lerp">
- <return type="float">
- </return>
- <argument index="0" name="from" type="float">
- </argument>
- <argument index="1" name="to" type="float">
- </argument>
- <argument index="2" name="weight" type="float">
- </argument>
- <description>
- Returns a normalized value considering the given range. This is the opposite of [method lerp].
- [codeblock]
- var middle = lerp(20, 30, 0.75)
- # `middle` is now 27.5.
- # Now, we pretend to have forgotten the original ratio and want to get it back.
- var ratio = inverse_lerp(20, 30, 27.5)
- # `ratio` is now 0.75.
- [/codeblock]
- </description>
- </method>
- <method name="is_equal_approx">
- <return type="bool">
- </return>
- <argument index="0" name="a" type="float">
- </argument>
- <argument index="1" name="b" type="float">
- </argument>
- <description>
- Returns [code]true[/code] if [code]a[/code] and [code]b[/code] are approximately equal to each other.
- Here, approximately equal means that [code]a[/code] and [code]b[/code] are within a small internal epsilon of each other, which scales with the magnitude of the numbers.
- Infinity values of the same sign are considered equal.
- </description>
- </method>
- <method name="is_inf">
- <return type="bool">
- </return>
- <argument index="0" name="s" type="float">
- </argument>
- <description>
- Returns whether [code]s[/code] is an infinity value (either positive infinity or negative infinity).
- </description>
- </method>
- <method name="is_instance_valid">
- <return type="bool">
- </return>
- <argument index="0" name="instance" type="Object">
- </argument>
- <description>
- Returns whether [code]instance[/code] is a valid object (e.g. has not been deleted from memory).
- </description>
- </method>
- <method name="is_nan">
- <return type="bool">
- </return>
- <argument index="0" name="s" type="float">
- </argument>
- <description>
- Returns whether [code]s[/code] is a NaN ("Not a Number" or invalid) value.
- </description>
- </method>
- <method name="is_zero_approx">
- <return type="bool">
- </return>
- <argument index="0" name="s" type="float">
- </argument>
- <description>
- Returns [code]true[/code] if [code]s[/code] is zero or almost zero.
- This method is faster than using [method is_equal_approx] with one value as zero.
- </description>
- </method>
<method name="len">
<return type="int">
</return>
@@ -557,63 +151,6 @@
[/codeblock]
</description>
</method>
- <method name="lerp">
- <return type="Variant">
- </return>
- <argument index="0" name="from" type="Variant">
- </argument>
- <argument index="1" name="to" type="Variant">
- </argument>
- <argument index="2" name="weight" type="float">
- </argument>
- <description>
- Linearly interpolates between two values by a normalized value. This is the opposite of [method inverse_lerp].
- If the [code]from[/code] and [code]to[/code] arguments are of type [int] or [float], the return value is a [float].
- If both are of the same vector type ([Vector2], [Vector3] or [Color]), the return value will be of the same type ([code]lerp[/code] then calls the vector type's [code]lerp[/code] method).
- [codeblock]
- lerp(0, 4, 0.75) # Returns 3.0
- lerp(Vector2(1, 5), Vector2(3, 2), 0.5) # Returns Vector2(2, 3.5)
- [/codeblock]
- </description>
- </method>
- <method name="lerp_angle">
- <return type="float">
- </return>
- <argument index="0" name="from" type="float">
- </argument>
- <argument index="1" name="to" type="float">
- </argument>
- <argument index="2" name="weight" type="float">
- </argument>
- <description>
- Linearly interpolates between two angles (in radians) by a normalized value.
- Similar to [method lerp], but interpolates correctly when the angles wrap around [constant @GDScript.TAU].
- [codeblock]
- extends Sprite
- var elapsed = 0.0
- func _process(delta):
- var min_angle = deg2rad(0.0)
- var max_angle = deg2rad(90.0)
- rotation = lerp_angle(min_angle, max_angle, elapsed)
- elapsed += delta
- [/codeblock]
- </description>
- </method>
- <method name="linear2db">
- <return type="float">
- </return>
- <argument index="0" name="nrg" type="float">
- </argument>
- <description>
- Converts from linear energy to decibels (audio). This can be used to implement volume sliders that behave as expected (since volume isn't linear). Example:
- [codeblock]
- # "Slider" refers to a node that inherits Range such as HSlider or VSlider.
- # Its range must be configured to go from 0 to 1.
- # Change the bus name if you'd like to change the volume of a specific bus only.
- AudioServer.set_bus_volume_db(AudioServer.get_bus_index("Master"), linear2db($Slider.value))
- [/codeblock]
- </description>
- </method>
<method name="load">
<return type="Resource">
</return>
@@ -630,172 +167,6 @@
This method is a simplified version of [method ResourceLoader.load], which can be used for more advanced scenarios.
</description>
</method>
- <method name="log">
- <return type="float">
- </return>
- <argument index="0" name="s" type="float">
- </argument>
- <description>
- Natural logarithm. The amount of time needed to reach a certain level of continuous growth.
- [b]Note:[/b] This is not the same as the "log" function on most calculators, which uses a base 10 logarithm.
- [codeblock]
- log(10) # Returns 2.302585
- [/codeblock]
- [b]Note:[/b] The logarithm of [code]0[/code] returns [code]-inf[/code], while negative values return [code]-nan[/code].
- </description>
- </method>
- <method name="max">
- <return type="float">
- </return>
- <argument index="0" name="a" type="float">
- </argument>
- <argument index="1" name="b" type="float">
- </argument>
- <description>
- Returns the maximum of two values.
- [codeblock]
- max(1, 2) # Returns 2
- max(-3.99, -4) # Returns -3.99
- [/codeblock]
- </description>
- </method>
- <method name="min">
- <return type="float">
- </return>
- <argument index="0" name="a" type="float">
- </argument>
- <argument index="1" name="b" type="float">
- </argument>
- <description>
- Returns the minimum of two values.
- [codeblock]
- min(1, 2) # Returns 1
- min(-3.99, -4) # Returns -4
- [/codeblock]
- </description>
- </method>
- <method name="move_toward">
- <return type="float">
- </return>
- <argument index="0" name="from" type="float">
- </argument>
- <argument index="1" name="to" type="float">
- </argument>
- <argument index="2" name="delta" type="float">
- </argument>
- <description>
- Moves [code]from[/code] toward [code]to[/code] by the [code]delta[/code] value.
- Use a negative [code]delta[/code] value to move away.
- [codeblock]
- move_toward(5, 10, 4) # Returns 9
- move_toward(10, 5, 4) # Returns 6
- move_toward(10, 5, -1.5) # Returns 11.5
- [/codeblock]
- </description>
- </method>
- <method name="nearest_po2">
- <return type="int">
- </return>
- <argument index="0" name="value" type="int">
- </argument>
- <description>
- Returns the nearest equal or larger power of 2 for integer [code]value[/code].
- In other words, returns the smallest value [code]a[/code] where [code]a = pow(2, n)[/code] such that [code]value &lt;= a[/code] for some non-negative integer [code]n[/code].
- [codeblock]
- nearest_po2(3) # Returns 4
- nearest_po2(4) # Returns 4
- nearest_po2(5) # Returns 8
-
- nearest_po2(0) # Returns 0 (this may not be what you expect)
- nearest_po2(-1) # Returns 0 (this may not be what you expect)
- [/codeblock]
- [b]WARNING:[/b] Due to the way it is implemented, this function returns [code]0[/code] rather than [code]1[/code] for non-positive values of [code]value[/code] (in reality, 1 is the smallest integer power of 2).
- </description>
- </method>
- <method name="ord">
- <return type="int">
- </return>
- <argument index="0" name="char" type="String">
- </argument>
- <description>
- Returns an integer representing the Unicode code point of the given Unicode character [code]char[/code].
- [codeblock]
- a = ord("A") # a is 65
- a = ord("a") # a is 97
- a = ord("€") # a is 8364
- [/codeblock]
- This is the inverse of [method char].
- </description>
- </method>
- <method name="parse_json">
- <return type="Variant">
- </return>
- <argument index="0" name="json" type="String">
- </argument>
- <description>
- Parse JSON text to a Variant. (Use [method typeof] to check if the Variant's type is what you expect.)
- [b]Note:[/b] The JSON specification does not define integer or float types, but only a [i]number[/i] type. Therefore, parsing a JSON text will convert all numerical values to [float] types.
- [b]Note:[/b] JSON objects do not preserve key order like Godot dictionaries, thus, you should not rely on keys being in a certain order if a dictionary is constructed from JSON. In contrast, JSON arrays retain the order of their elements:
- [codeblock]
- var p = JSON.parse('["hello", "world", "!"]')
- if typeof(p.result) == TYPE_ARRAY:
- print(p.result[0]) # Prints "hello"
- else:
- push_error("Unexpected results.")
- [/codeblock]
- See also [JSON] for an alternative way to parse JSON text.
- </description>
- </method>
- <method name="polar2cartesian">
- <return type="Vector2">
- </return>
- <argument index="0" name="r" type="float">
- </argument>
- <argument index="1" name="th" type="float">
- </argument>
- <description>
- Converts a 2D point expressed in the polar coordinate system (a distance from the origin [code]r[/code] and an angle [code]th[/code]) to the cartesian coordinate system (X and Y axis).
- </description>
- </method>
- <method name="posmod">
- <return type="int">
- </return>
- <argument index="0" name="a" type="int">
- </argument>
- <argument index="1" name="b" type="int">
- </argument>
- <description>
- Returns the integer modulus of [code]a/b[/code] that wraps equally in positive and negative.
- [codeblock]
- for i in range(-3, 4):
- print("%2d %2d %2d" % [i, i % 3, posmod(i, 3)])
- [/codeblock]
- Produces:
- [codeblock]
- -3 0 0
- -2 -2 1
- -1 -1 2
- 0 0 0
- 1 1 1
- 2 2 2
- 3 0 0
- [/codeblock]
- </description>
- </method>
- <method name="pow">
- <return type="float">
- </return>
- <argument index="0" name="base" type="float">
- </argument>
- <argument index="1" name="exp" type="float">
- </argument>
- <description>
- Returns the result of [code]x[/code] raised to the power of [code]y[/code].
- [codeblock]
- pow(2, 5) # Returns 32
- [/codeblock]
- </description>
- </method>
<method name="preload">
<return type="Resource">
</return>
@@ -810,23 +181,11 @@
[/codeblock]
</description>
</method>
- <method name="print" qualifiers="vararg">
- <return type="void">
- </return>
- <description>
- Converts one or more arguments to strings in the best way possible and prints them to the console.
- [codeblock]
- a = [1, 2, 3]
- print("a", "b", a) # Prints ab[1, 2, 3]
- [/codeblock]
- [b]Note:[/b] Consider using [method push_error] and [method push_warning] to print error and warning messages instead of [method print]. This distinguishes them from print messages used for debugging purposes, while also displaying a stack trace when an error or warning is printed.
- </description>
- </method>
<method name="print_debug" qualifiers="vararg">
<return type="void">
</return>
<description>
- Like [method print], but prints only when used in debug mode.
+ Like [method @GlobalScope.print], but prints only when used in debug mode.
</description>
</method>
<method name="print_stack">
@@ -840,143 +199,6 @@
[/codeblock]
</description>
</method>
- <method name="printerr" qualifiers="vararg">
- <return type="void">
- </return>
- <description>
- Prints one or more arguments to strings in the best way possible to standard error line.
- [codeblock]
- printerr("prints to stderr")
- [/codeblock]
- </description>
- </method>
- <method name="printraw" qualifiers="vararg">
- <return type="void">
- </return>
- <description>
- Prints one or more arguments to strings in the best way possible to console. No newline is added at the end.
- [codeblock]
- printraw("A")
- printraw("B")
- # Prints AB
- [/codeblock]
- [b]Note:[/b] Due to limitations with Godot's built-in console, this only prints to the terminal. If you need to print in the editor, use another method, such as [method print].
- </description>
- </method>
- <method name="prints" qualifiers="vararg">
- <return type="void">
- </return>
- <description>
- Prints one or more arguments to the console with a space between each argument.
- [codeblock]
- prints("A", "B", "C") # Prints A B C
- [/codeblock]
- </description>
- </method>
- <method name="printt" qualifiers="vararg">
- <return type="void">
- </return>
- <description>
- Prints one or more arguments to the console with a tab between each argument.
- [codeblock]
- printt("A", "B", "C") # Prints A B C
- [/codeblock]
- </description>
- </method>
- <method name="push_error">
- <return type="void">
- </return>
- <argument index="0" name="message" type="String">
- </argument>
- <description>
- Pushes an error message to Godot's built-in debugger and to the OS terminal.
- [codeblock]
- push_error("test error") # Prints "test error" to debugger and terminal as error call
- [/codeblock]
- [b]Note:[/b] Errors printed this way will not pause project execution. To print an error message and pause project execution in debug builds, use [code]assert(false, "test error")[/code] instead.
- </description>
- </method>
- <method name="push_warning">
- <return type="void">
- </return>
- <argument index="0" name="message" type="String">
- </argument>
- <description>
- Pushes a warning message to Godot's built-in debugger and to the OS terminal.
- [codeblock]
- push_warning("test warning") # Prints "test warning" to debugger and terminal as warning call
- [/codeblock]
- </description>
- </method>
- <method name="rad2deg">
- <return type="float">
- </return>
- <argument index="0" name="rad" type="float">
- </argument>
- <description>
- Converts an angle expressed in radians to degrees.
- [codeblock]
- rad2deg(0.523599) # Returns 30
- [/codeblock]
- </description>
- </method>
- <method name="rand_range">
- <return type="float">
- </return>
- <argument index="0" name="from" type="float">
- </argument>
- <argument index="1" name="to" type="float">
- </argument>
- <description>
- Random range, any floating point value between [code]from[/code] and [code]to[/code].
- [codeblock]
- prints(rand_range(0, 1), rand_range(0, 1)) # Prints e.g. 0.135591 0.405263
- [/codeblock]
- </description>
- </method>
- <method name="rand_seed">
- <return type="Array">
- </return>
- <argument index="0" name="seed" type="int">
- </argument>
- <description>
- Random from seed: pass a [code]seed[/code], and an array with both number and new seed is returned. "Seed" here refers to the internal state of the pseudo random number generator. The internal state of the current implementation is 64 bits.
- </description>
- </method>
- <method name="randf">
- <return type="float">
- </return>
- <description>
- Returns a random floating point value on the interval [code][0, 1][/code].
- [codeblock]
- randf() # Returns e.g. 0.375671
- [/codeblock]
- </description>
- </method>
- <method name="randi">
- <return type="int">
- </return>
- <description>
- Returns a random unsigned 32 bit integer. Use remainder to obtain a random value in the interval [code][0, N - 1][/code] (where N is smaller than 2^32).
- [codeblock]
- randi() # Returns random integer between 0 and 2^32 - 1
- randi() % 20 # Returns random integer between 0 and 19
- randi() % 100 # Returns random integer between 0 and 99
- randi() % 100 + 1 # Returns random integer between 1 and 100
- [/codeblock]
- </description>
- </method>
- <method name="randomize">
- <return type="void">
- </return>
- <description>
- Randomizes the seed (or the internal state) of the random number generator. Current implementation reseeds using a number based on time.
- [codeblock]
- func _ready():
- randomize()
- [/codeblock]
- </description>
- </method>
<method name="range" qualifiers="vararg">
<return type="Array">
</return>
@@ -995,158 +217,6 @@
[/codeblock]
</description>
</method>
- <method name="range_lerp">
- <return type="float">
- </return>
- <argument index="0" name="value" type="float">
- </argument>
- <argument index="1" name="istart" type="float">
- </argument>
- <argument index="2" name="istop" type="float">
- </argument>
- <argument index="3" name="ostart" type="float">
- </argument>
- <argument index="4" name="ostop" type="float">
- </argument>
- <description>
- Maps a [code]value[/code] from range [code][istart, istop][/code] to [code][ostart, ostop][/code].
- [codeblock]
- range_lerp(75, 0, 100, -1, 1) # Returns 0.5
- [/codeblock]
- </description>
- </method>
- <method name="round">
- <return type="float">
- </return>
- <argument index="0" name="s" type="float">
- </argument>
- <description>
- Rounds [code]s[/code] to the nearest whole number, with halfway cases rounded away from zero.
- [codeblock]
- round(2.6) # Returns 3
- [/codeblock]
- See also [method floor], [method ceil], and [method stepify].
- </description>
- </method>
- <method name="seed">
- <return type="void">
- </return>
- <argument index="0" name="seed" type="int">
- </argument>
- <description>
- Sets seed for the random number generator.
- [codeblock]
- my_seed = "Godot Rocks"
- seed(my_seed.hash())
- [/codeblock]
- </description>
- </method>
- <method name="sign">
- <return type="float">
- </return>
- <argument index="0" name="s" type="float">
- </argument>
- <description>
- Returns the sign of [code]s[/code]: -1 or 1. Returns 0 if [code]s[/code] is 0.
- [codeblock]
- sign(-6) # Returns -1
- sign(0) # Returns 0
- sign(6) # Returns 1
- [/codeblock]
- </description>
- </method>
- <method name="sin">
- <return type="float">
- </return>
- <argument index="0" name="s" type="float">
- </argument>
- <description>
- Returns the sine of angle [code]s[/code] in radians.
- [codeblock]
- sin(0.523599) # Returns 0.5
- [/codeblock]
- </description>
- </method>
- <method name="sinh">
- <return type="float">
- </return>
- <argument index="0" name="s" type="float">
- </argument>
- <description>
- Returns the hyperbolic sine of [code]s[/code].
- [codeblock]
- a = log(2.0) # Returns 0.693147
- sinh(a) # Returns 0.75
- [/codeblock]
- </description>
- </method>
- <method name="smoothstep">
- <return type="float">
- </return>
- <argument index="0" name="from" type="float">
- </argument>
- <argument index="1" name="to" type="float">
- </argument>
- <argument index="2" name="s" type="float">
- </argument>
- <description>
- Returns the result of smoothly interpolating the value of [code]s[/code] between [code]0[/code] and [code]1[/code], based on the where [code]s[/code] lies with respect to the edges [code]from[/code] and [code]to[/code].
- The return value is [code]0[/code] if [code]s &lt;= from[/code], and [code]1[/code] if [code]s &gt;= to[/code]. If [code]s[/code] lies between [code]from[/code] and [code]to[/code], the returned value follows an S-shaped curve that maps [code]s[/code] between [code]0[/code] and [code]1[/code].
- This S-shaped curve is the cubic Hermite interpolator, given by [code]f(s) = 3*s^2 - 2*s^3[/code].
- [codeblock]
- smoothstep(0, 2, -5.0) # Returns 0.0
- smoothstep(0, 2, 0.5) # Returns 0.15625
- smoothstep(0, 2, 1.0) # Returns 0.5
- smoothstep(0, 2, 2.0) # Returns 1.0
- [/codeblock]
- </description>
- </method>
- <method name="sqrt">
- <return type="float">
- </return>
- <argument index="0" name="s" type="float">
- </argument>
- <description>
- Returns the square root of [code]s[/code], where [code]s[/code] is a non-negative number.
- [codeblock]
- sqrt(9) # Returns 3
- [/codeblock]
- [b]Note:[/b]Negative values of [code]s[/code] return NaN. If you need negative inputs, use [code]System.Numerics.Complex[/code] in C#.
- </description>
- </method>
- <method name="step_decimals">
- <return type="int">
- </return>
- <argument index="0" name="step" type="float">
- </argument>
- <description>
- Returns the position of the first non-zero digit, after the decimal point. Note that the maximum return value is 10, which is a design decision in the implementation.
- [codeblock]
- # n is 0
- n = step_decimals(5)
- # n is 4
- n = step_decimals(1.0005)
- # n is 9
- n = step_decimals(0.000000005)
- [/codeblock]
- </description>
- </method>
- <method name="stepify">
- <return type="float">
- </return>
- <argument index="0" name="s" type="float">
- </argument>
- <argument index="1" name="step" type="float">
- </argument>
- <description>
- Snaps float value [code]s[/code] to a given [code]step[/code]. This can also be used to round a floating point number to an arbitrary number of decimals.
- [codeblock]
- stepify(100, 32) # Returns 96
- stepify(3.14159, 0.01) # Returns 3.14
- [/codeblock]
- See also [method ceil], [method floor], and [method round].
- </description>
- </method>
<method name="str" qualifiers="vararg">
<return type="String">
</return>
@@ -1160,200 +230,12 @@
[/codeblock]
</description>
</method>
- <method name="str2var">
- <return type="Variant">
- </return>
- <argument index="0" name="string" type="String">
- </argument>
- <description>
- Converts a formatted string that was returned by [method var2str] to the original value.
- [codeblock]
- a = '{ "a": 1, "b": 2 }'
- b = str2var(a)
- print(b["a"]) # Prints 1
- [/codeblock]
- </description>
- </method>
- <method name="tan">
- <return type="float">
- </return>
- <argument index="0" name="s" type="float">
- </argument>
- <description>
- Returns the tangent of angle [code]s[/code] in radians.
- [codeblock]
- tan(deg2rad(45)) # Returns 1
- [/codeblock]
- </description>
- </method>
- <method name="tanh">
- <return type="float">
- </return>
- <argument index="0" name="s" type="float">
- </argument>
- <description>
- Returns the hyperbolic tangent of [code]s[/code].
- [codeblock]
- a = log(2.0) # Returns 0.693147
- tanh(a) # Returns 0.6
- [/codeblock]
- </description>
- </method>
- <method name="to_json">
- <return type="String">
- </return>
- <argument index="0" name="var" type="Variant">
- </argument>
- <description>
- Converts a [Variant] [code]var[/code] to JSON text and return the result. Useful for serializing data to store or send over the network.
- [codeblock]
- # Both numbers below are integers.
- a = { "a": 1, "b": 2 }
- b = to_json(a)
- print(b) # {"a":1, "b":2}
- # Both numbers above are floats, even if they display without any decimal places.
- [/codeblock]
- [b]Note:[/b] The JSON specification does not define integer or float types, but only a [i]number[/i] type. Therefore, converting a [Variant] to JSON text will convert all numerical values to [float] types.
- See also [JSON] for an alternative way to convert a [Variant] to JSON text.
- </description>
- </method>
<method name="type_exists">
<return type="bool">
</return>
- <argument index="0" name="type" type="String">
- </argument>
- <description>
- Returns whether the given class exists in [ClassDB].
- [codeblock]
- type_exists("Sprite2D") # Returns true
- type_exists("Variant") # Returns false
- [/codeblock]
- </description>
- </method>
- <method name="typeof">
- <return type="int">
- </return>
- <argument index="0" name="what" type="Variant">
- </argument>
- <description>
- Returns the internal type of the given Variant object, using the [enum Variant.Type] values.
- [codeblock]
- p = parse_json('["a", "b", "c"]')
- if typeof(p) == TYPE_ARRAY:
- print(p[0]) # Prints a
- else:
- print("unexpected results")
- [/codeblock]
- </description>
- </method>
- <method name="validate_json">
- <return type="String">
- </return>
- <argument index="0" name="json" type="String">
- </argument>
- <description>
- Checks that [code]json[/code] is valid JSON data. Returns an empty string if valid, or an error message otherwise.
- [codeblock]
- j = to_json([1, 2, 3])
- v = validate_json(j)
- if not v:
- print("Valid JSON.")
- else:
- push_error("Invalid JSON: " + v)
- [/codeblock]
- </description>
- </method>
- <method name="var2bytes">
- <return type="PackedByteArray">
- </return>
- <argument index="0" name="var" type="Variant">
- </argument>
- <argument index="1" name="full_objects" type="bool" default="false">
- </argument>
- <description>
- Encodes a variable value to a byte array. When [code]full_objects[/code] is [code]true[/code] encoding objects is allowed (and can potentially include code).
- </description>
- </method>
- <method name="var2str">
- <return type="String">
- </return>
- <argument index="0" name="var" type="Variant">
- </argument>
- <description>
- Converts a Variant [code]var[/code] to a formatted string that can later be parsed using [method str2var].
- [codeblock]
- a = { "a": 1, "b": 2 }
- print(var2str(a))
- [/codeblock]
- prints
- [codeblock]
- {
- "a": 1,
- "b": 2
- }
- [/codeblock]
- </description>
- </method>
- <method name="weakref">
- <return type="WeakRef">
- </return>
- <argument index="0" name="obj" type="Object">
- </argument>
- <description>
- Returns a weak reference to an object.
- A weak reference to an object is not enough to keep the object alive: when the only remaining references to a referent are weak references, garbage collection is free to destroy the referent and reuse its memory for something else. However, until the object is actually destroyed the weak reference may return the object even if there are no strong references to it.
- </description>
- </method>
- <method name="wrapf">
- <return type="float">
- </return>
- <argument index="0" name="value" type="float">
- </argument>
- <argument index="1" name="min" type="float">
- </argument>
- <argument index="2" name="max" type="float">
+ <argument index="0" name="type" type="StringName">
</argument>
<description>
- Wraps float [code]value[/code] between [code]min[/code] and [code]max[/code].
- Usable for creating loop-alike behavior or infinite surfaces.
- [codeblock]
- # Infinite loop between 5.0 and 9.9
- value = wrapf(value + 0.1, 5.0, 10.0)
- [/codeblock]
- [codeblock]
- # Infinite rotation (in radians)
- angle = wrapf(angle + 0.1, 0.0, TAU)
- [/codeblock]
- [codeblock]
- # Infinite rotation (in radians)
- angle = wrapf(angle + 0.1, -PI, PI)
- [/codeblock]
- [b]Note:[/b] If [code]min[/code] is [code]0[/code], this is equivalent to [method fposmod], so prefer using that instead.
- [code]wrapf[/code] is more flexible than using the [method fposmod] approach by giving the user control over the minimum value.
- </description>
- </method>
- <method name="wrapi">
- <return type="int">
- </return>
- <argument index="0" name="value" type="int">
- </argument>
- <argument index="1" name="min" type="int">
- </argument>
- <argument index="2" name="max" type="int">
- </argument>
- <description>
- Wraps integer [code]value[/code] between [code]min[/code] and [code]max[/code].
- Usable for creating loop-alike behavior or infinite surfaces.
- [codeblock]
- # Infinite loop between 5 and 9
- frame = wrapi(frame + 1, 5, 10)
- [/codeblock]
- [codeblock]
- # result is -2
- var result = wrapi(-6, -5, -1)
- [/codeblock]
- [b]Note:[/b] If [code]min[/code] is [code]0[/code], this is equivalent to [method posmod], so prefer using that instead.
- [code]wrapi[/code] is more flexible than using the [method posmod] approach by giving the user control over the minimum value.
</description>
</method>
</methods>
diff --git a/modules/gdscript/doc_classes/GDScriptFunctionState.xml b/modules/gdscript/doc_classes/GDScriptFunctionState.xml
deleted file mode 100644
index 5e369b32d9..0000000000
--- a/modules/gdscript/doc_classes/GDScriptFunctionState.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GDScriptFunctionState" inherits="Reference" version="4.0">
- <brief_description>
- State of a function call after yielding.
- </brief_description>
- <description>
- FIXME: Outdated docs as of GDScript rewrite in 4.0.
- Calling [code]yield[/code] within a function will cause that function to yield and return its current state as an object of this type. The yielded function call can then be resumed later by calling [method resume] on this state object.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="is_valid" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="extended_check" type="bool" default="false">
- </argument>
- <description>
- Check whether the function call may be resumed. This is not the case if the function state was already resumed.
- If [code]extended_check[/code] is enabled, it also checks if the associated script and object still exist. The extended check is done in debug mode as part of [method GDScriptFunctionState.resume], but you can use this if you know you may be trying to resume without knowing for sure the object and/or script have survived up to that point.
- </description>
- </method>
- <method name="resume">
- <return type="Variant">
- </return>
- <argument index="0" name="arg" type="Variant" default="null">
- </argument>
- <description>
- Resume execution of the yielded function call.
- If handed an argument, return the argument from the [code]yield[/code] call in the yielded function call. You can pass e.g. an [Array] to hand multiple arguments.
- This function returns what the resumed function call returns, possibly another function state if yielded again.
- </description>
- </method>
- </methods>
- <signals>
- <signal name="completed">
- <argument index="0" name="result" type="Variant">
- </argument>
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index 7f7410a92c..ccc942d86b 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -269,19 +269,21 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting(int p_line)
col = keywords[word];
} else if (member_keywords.has(word)) {
col = member_keywords[word];
+ }
+
+ if (col != Color()) {
for (int k = j - 1; k >= 0; k--) {
if (str[k] == '.') {
- col = Color(); //member indexing not allowed
+ col = Color(); // keyword & member indexing not allowed
break;
} else if (str[k] > 32) {
break;
}
}
- }
-
- if (col != Color()) {
- in_keyword = true;
- keyword_color = col;
+ if (col != Color()) {
+ in_keyword = true;
+ keyword_color = col;
+ }
}
}
diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h
index 49357f3d2e..1b57cb1923 100644
--- a/modules/gdscript/editor/gdscript_highlighter.h
+++ b/modules/gdscript/editor/gdscript_highlighter.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -42,7 +42,7 @@ private:
Color color;
String start_key;
String end_key;
- bool line_only;
+ bool line_only = false;
};
Vector<ColorRegion> color_regions;
Map<int, int> color_region_cache;
diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
index 944ed859f5..6e930b6bf4 100644
--- a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
+++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.h b/modules/gdscript/editor/gdscript_translation_parser_plugin.h
index 5ea416d4cc..5358a77140 100644
--- a/modules/gdscript/editor/gdscript_translation_parser_plugin.h
+++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,7 +31,7 @@
#ifndef GDSCRIPT_TRANSLATION_PARSER_PLUGIN_H
#define GDSCRIPT_TRANSLATION_PARSER_PLUGIN_H
-#include "core/set.h"
+#include "core/templates/set.h"
#include "editor/editor_translation_parser.h"
#include "modules/gdscript/gdscript_parser.h"
#include "modules/regex/regex.h"
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index e70e3f7272..502e294275 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,13 +32,13 @@
#include <stdint.h>
+#include "core/config/engine.h"
+#include "core/config/project_settings.h"
+#include "core/core_constants.h"
#include "core/core_string_names.h"
-#include "core/engine.h"
-#include "core/global_constants.h"
#include "core/io/file_access_encrypted.h"
#include "core/os/file_access.h"
#include "core/os/os.h"
-#include "core/project_settings.h"
#include "gdscript_analyzer.h"
#include "gdscript_cache.h"
#include "gdscript_compiler.h"
@@ -231,7 +231,7 @@ void GDScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) {
}
#endif
-void GDScript::get_script_method_list(List<MethodInfo> *p_list) const {
+void GDScript::_get_script_method_list(List<MethodInfo> *r_list, bool p_include_base) const {
const GDScript *current = this;
while (current) {
for (const Map<StringName, GDScriptFunction *>::Element *E = current->member_functions.front(); E; E = E->next()) {
@@ -239,18 +239,29 @@ void GDScript::get_script_method_list(List<MethodInfo> *p_list) const {
MethodInfo mi;
mi.name = E->key();
for (int i = 0; i < func->get_argument_count(); i++) {
- mi.arguments.push_back(func->get_argument_type(i));
+ PropertyInfo arginfo = func->get_argument_type(i);
+#ifdef TOOLS_ENABLED
+ arginfo.name = func->get_argument_name(i);
+#endif
+ mi.arguments.push_back(arginfo);
}
mi.return_val = func->get_return_type();
- p_list->push_back(mi);
+ r_list->push_back(mi);
+ }
+ if (!p_include_base) {
+ return;
}
current = current->_base;
}
}
-void GDScript::get_script_property_list(List<PropertyInfo> *p_list) const {
+void GDScript::get_script_method_list(List<MethodInfo> *r_list) const {
+ _get_script_method_list(r_list, true);
+}
+
+void GDScript::_get_script_property_list(List<PropertyInfo> *r_list, bool p_include_base) const {
const GDScript *sptr = this;
List<PropertyInfo> props;
@@ -269,15 +280,22 @@ void GDScript::get_script_property_list(List<PropertyInfo> *p_list) const {
for (int i = 0; i < msort.size(); i++) {
props.push_front(sptr->member_info[msort[i].name]);
}
+ if (!p_include_base) {
+ break;
+ }
sptr = sptr->_base;
}
for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
- p_list->push_back(E->get());
+ r_list->push_back(E->get());
}
}
+void GDScript::get_script_property_list(List<PropertyInfo> *r_list) const {
+ _get_script_property_list(r_list, true);
+}
+
bool GDScript::has_method(const StringName &p_method) const {
return member_functions.has(p_method);
}
@@ -383,6 +401,183 @@ void GDScript::_update_exports_values(Map<StringName, Variant> &values, List<Pro
propnames.push_back(E->get());
}
}
+
+void GDScript::_add_doc(const DocData::ClassDoc &p_inner_class) {
+ if (_owner) {
+ _owner->_add_doc(p_inner_class);
+ } else {
+ for (int i = 0; i < docs.size(); i++) {
+ if (docs[i].name == p_inner_class.name) {
+ docs.remove(i);
+ break;
+ }
+ }
+ docs.append(p_inner_class);
+ }
+}
+
+void GDScript::_clear_doc() {
+ docs.clear();
+ doc = DocData::ClassDoc();
+}
+
+void GDScript::_update_doc() {
+ _clear_doc();
+
+ doc.script_path = "\"" + get_path().get_slice("://", 1) + "\"";
+ if (!name.is_empty()) {
+ doc.name = name;
+ } else {
+ doc.name = doc.script_path;
+ }
+
+ if (_owner) {
+ doc.name = _owner->doc.name + "." + doc.name;
+ doc.script_path = doc.script_path + "." + doc.name;
+ }
+
+ doc.is_script_doc = true;
+
+ if (base.is_valid() && base->is_valid()) {
+ if (base->doc.name != String()) {
+ doc.inherits = base->doc.name;
+ } else {
+ doc.inherits = base->get_instance_base_type();
+ }
+ } else if (native.is_valid()) {
+ doc.inherits = native->get_name();
+ }
+
+ doc.brief_description = doc_brief_description;
+ doc.description = doc_description;
+ doc.tutorials = doc_tutorials;
+
+ for (Map<String, DocData::EnumDoc>::Element *E = doc_enums.front(); E; E = E->next()) {
+ if (E->value().description != "") {
+ doc.enums[E->key()] = E->value().description;
+ }
+ }
+
+ List<MethodInfo> methods;
+ _get_script_method_list(&methods, false);
+ for (int i = 0; i < methods.size(); i++) {
+ // Ignore internal methods.
+ if (methods[i].name[0] == '@') {
+ continue;
+ }
+
+ DocData::MethodDoc method_doc;
+ const String &class_name = methods[i].name;
+ if (member_functions.has(class_name)) {
+ GDScriptFunction *fn = member_functions[class_name];
+
+ // Change class name if return type is script reference.
+ GDScriptDataType return_type = fn->get_return_type();
+ if (return_type.kind == GDScriptDataType::GDSCRIPT) {
+ methods[i].return_val.class_name = _get_gdscript_reference_class_name(Object::cast_to<GDScript>(return_type.script_type));
+ }
+
+ // Change class name if argumetn is script reference.
+ for (int j = 0; j < fn->get_argument_count(); j++) {
+ GDScriptDataType arg_type = fn->get_argument_type(j);
+ if (arg_type.kind == GDScriptDataType::GDSCRIPT) {
+ methods[i].arguments[j].class_name = _get_gdscript_reference_class_name(Object::cast_to<GDScript>(arg_type.script_type));
+ }
+ }
+ }
+ if (doc_functions.has(methods[i].name)) {
+ DocData::method_doc_from_methodinfo(method_doc, methods[i], doc_functions[methods[i].name]);
+ } else {
+ DocData::method_doc_from_methodinfo(method_doc, methods[i], String());
+ }
+ doc.methods.push_back(method_doc);
+ }
+
+ List<PropertyInfo> props;
+ _get_script_property_list(&props, false);
+ for (int i = 0; i < props.size(); i++) {
+ ScriptMemberInfo scr_member_info;
+ scr_member_info.propinfo = props[i];
+ scr_member_info.propinfo.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+ if (member_indices.has(props[i].name)) {
+ const MemberInfo &mi = member_indices[props[i].name];
+ scr_member_info.setter = mi.setter;
+ scr_member_info.getter = mi.getter;
+ if (mi.data_type.kind == GDScriptDataType::GDSCRIPT) {
+ scr_member_info.propinfo.class_name = _get_gdscript_reference_class_name(
+ Object::cast_to<GDScript>(mi.data_type.script_type));
+ }
+ }
+ if (member_default_values.has(props[i].name)) {
+ scr_member_info.has_default_value = true;
+ scr_member_info.default_value = member_default_values[props[i].name];
+ }
+ if (doc_variables.has(props[i].name)) {
+ scr_member_info.doc_string = doc_variables[props[i].name];
+ }
+
+ DocData::PropertyDoc prop_doc;
+ DocData::property_doc_from_scriptmemberinfo(prop_doc, scr_member_info);
+ doc.properties.push_back(prop_doc);
+ }
+
+ List<MethodInfo> signals;
+ _get_script_signal_list(&signals, false);
+ for (int i = 0; i < signals.size(); i++) {
+ DocData::MethodDoc signal_doc;
+ if (doc_signals.has(signals[i].name)) {
+ DocData::signal_doc_from_methodinfo(signal_doc, signals[i], signals[i].name);
+ } else {
+ DocData::signal_doc_from_methodinfo(signal_doc, signals[i], String());
+ }
+ doc.signals.push_back(signal_doc);
+ }
+
+ for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) {
+ if (subclasses.has(E->key())) {
+ continue;
+ }
+
+ // Enums.
+ bool is_enum = false;
+ if (E->value().get_type() == Variant::DICTIONARY) {
+ if (doc_enums.has(E->key())) {
+ is_enum = true;
+ for (int i = 0; i < doc_enums[E->key()].values.size(); i++) {
+ doc_enums[E->key()].values.write[i].enumeration = E->key();
+ doc.constants.push_back(doc_enums[E->key()].values[i]);
+ }
+ }
+ }
+ if (!is_enum && doc_enums.has("@unnamed_enums")) {
+ for (int i = 0; i < doc_enums["@unnamed_enums"].values.size(); i++) {
+ if (E->key() == doc_enums["@unnamed_enums"].values[i].name) {
+ is_enum = true;
+ DocData::ConstantDoc constant_doc;
+ constant_doc.enumeration = "@unnamed_enums";
+ DocData::constant_doc_from_variant(constant_doc, E->key(), E->value(), doc_enums["@unnamed_enums"].values[i].description);
+ doc.constants.push_back(constant_doc);
+ break;
+ }
+ }
+ }
+ if (!is_enum) {
+ DocData::ConstantDoc constant_doc;
+ String doc_description;
+ if (doc_constants.has(E->key())) {
+ doc_description = doc_constants[E->key()];
+ }
+ DocData::constant_doc_from_variant(constant_doc, E->key(), E->value(), doc_description);
+ doc.constants.push_back(constant_doc);
+ }
+ }
+
+ for (Map<StringName, Ref<GDScript>>::Element *E = subclasses.front(); E; E = E->next()) {
+ E->get()->_update_doc();
+ }
+
+ _add_doc(doc);
+}
#endif
bool GDScript::_update_exports(bool *r_err, bool p_recursive_call) {
@@ -598,10 +793,10 @@ Error GDScript::reload(bool p_keep_state) {
{
String source_path = path;
- if (source_path.empty()) {
+ if (source_path.is_empty()) {
source_path = get_path();
}
- if (!source_path.empty()) {
+ if (!source_path.is_empty()) {
MutexLock lock(GDScriptCache::singleton->lock);
if (!GDScriptCache::singleton->shallow_gdscript_cache.has(source_path)) {
GDScriptCache::singleton->shallow_gdscript_cache[source_path] = this;
@@ -617,7 +812,7 @@ Error GDScript::reload(bool p_keep_state) {
GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), parser.get_errors().front()->get().line, "Parser Error: " + parser.get_errors().front()->get().message);
}
// TODO: Show all error messages.
- _err_print_error("GDScript::reload", path.empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_errors().front()->get().line, ("Parse Error: " + parser.get_errors().front()->get().message).utf8().get_data(), ERR_HANDLER_SCRIPT);
+ _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_errors().front()->get().line, ("Parse Error: " + parser.get_errors().front()->get().message).utf8().get_data(), ERR_HANDLER_SCRIPT);
ERR_FAIL_V(ERR_PARSE_ERROR);
}
@@ -628,8 +823,12 @@ Error GDScript::reload(bool p_keep_state) {
if (EngineDebugger::is_active()) {
GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), parser.get_errors().front()->get().line, "Parser Error: " + parser.get_errors().front()->get().message);
}
- // TODO: Show all error messages.
- _err_print_error("GDScript::reload", path.empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_errors().front()->get().line, ("Parse Error: " + parser.get_errors().front()->get().message).utf8().get_data(), ERR_HANDLER_SCRIPT);
+
+ const List<GDScriptParser::ParserError>::Element *e = parser.get_errors().front();
+ while (e != nullptr) {
+ _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), e->get().line, ("Parse Error: " + e->get().message).utf8().get_data(), ERR_HANDLER_SCRIPT);
+ e = e->next();
+ }
ERR_FAIL_V(ERR_PARSE_ERROR);
}
@@ -638,12 +837,16 @@ Error GDScript::reload(bool p_keep_state) {
GDScriptCompiler compiler;
err = compiler.compile(&parser, this, p_keep_state);
+#ifdef TOOLS_ENABLED
+ _update_doc();
+#endif
+
if (err) {
if (can_run) {
if (EngineDebugger::is_active()) {
GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), compiler.get_error_line(), "Parser Error: " + compiler.get_error());
}
- _err_print_error("GDScript::reload", path.empty() ? "built-in" : (const char *)path.utf8().get_data(), compiler.get_error_line(), ("Compile Error: " + compiler.get_error()).utf8().get_data(), ERR_HANDLER_SCRIPT);
+ _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), compiler.get_error_line(), ("Compile Error: " + compiler.get_error()).utf8().get_data(), ERR_HANDLER_SCRIPT);
ERR_FAIL_V(ERR_COMPILATION_FAILED);
} else {
return err;
@@ -911,7 +1114,7 @@ bool GDScript::has_script_signal(const StringName &p_signal) const {
return false;
}
-void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
+void GDScript::_get_script_signal_list(List<MethodInfo> *r_list, bool p_include_base) const {
for (const Map<StringName, Vector<StringName>>::Element *E = _signals.front(); E; E = E->next()) {
MethodInfo mi;
mi.name = E->key();
@@ -920,20 +1123,43 @@ void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
arg.name = E->get()[i];
mi.arguments.push_back(arg);
}
- r_signals->push_back(mi);
+ r_list->push_back(mi);
+ }
+
+ if (!p_include_base) {
+ return;
}
if (base.is_valid()) {
- base->get_script_signal_list(r_signals);
+ base->get_script_signal_list(r_list);
}
#ifdef TOOLS_ENABLED
else if (base_cache.is_valid()) {
- base_cache->get_script_signal_list(r_signals);
+ base_cache->get_script_signal_list(r_list);
}
#endif
}
+void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
+ _get_script_signal_list(r_signals, true);
+}
+
+String GDScript::_get_gdscript_reference_class_name(const GDScript *p_gdscript) {
+ ERR_FAIL_NULL_V(p_gdscript, String());
+
+ String class_name;
+ while (p_gdscript) {
+ if (class_name == "") {
+ class_name = p_gdscript->get_script_class_name();
+ } else {
+ class_name = p_gdscript->get_script_class_name() + "." + class_name;
+ }
+ p_gdscript = p_gdscript->_owner;
+ }
+ return class_name;
+}
+
GDScript::GDScript() :
script_list(this) {
valid = false;
@@ -1061,6 +1287,13 @@ GDScript::~GDScript() {
_save_orphaned_subclasses();
+#ifdef TOOLS_ENABLED
+ // Clearing inner class doc, script doc only cleared when the script source deleted.
+ if (_owner) {
+ _clear_doc();
+ }
+#endif
+
#ifdef DEBUG_ENABLED
{
MutexLock lock(GDScriptLanguage::get_singleton()->lock);
@@ -1092,7 +1325,8 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
// Try conversion
Callable::CallError ce;
const Variant *value = &p_value;
- Variant converted = Variant::construct(member->data_type.builtin_type, &value, 1, ce);
+ Variant converted;
+ Variant::construct(member->data_type.builtin_type, converted, &value, 1, ce);
if (ce.error == Callable::CallError::CALL_OK) {
members.write[member->index] = converted;
return true;
@@ -1500,9 +1734,9 @@ void GDScriptLanguage::remove_named_global_constant(const StringName &p_name) {
void GDScriptLanguage::init() {
//populate global constants
- int gcc = GlobalConstants::get_global_constant_count();
+ int gcc = CoreConstants::get_global_constant_count();
for (int i = 0; i < gcc; i++) {
- _add_global(StaticCString::create(GlobalConstants::get_global_constant_name(i)), GlobalConstants::get_global_constant_value(i));
+ _add_global(StaticCString::create(CoreConstants::get_global_constant_name(i)), CoreConstants::get_global_constant_value(i));
}
_add_global(StaticCString::create("PI"), Math_PI);
@@ -1888,8 +2122,11 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
w++;
}
- for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) {
- p_words->push_back(GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i)));
+ List<StringName> functions;
+ GDScriptUtilityFunctions::get_function_list(&functions);
+
+ for (const List<StringName>::Element *E = functions.front(); E; E = E->next()) {
+ p_words->push_back(String(E->get()));
}
}
@@ -1914,7 +2151,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
if (err == OK) {
const GDScriptParser::ClassNode *c = parser.get_tree();
if (r_icon_path) {
- if (c->icon_path.empty() || c->icon_path.is_abs_path()) {
+ if (c->icon_path.is_empty() || c->icon_path.is_abs_path()) {
*r_icon_path = c->icon_path;
} else if (c->icon_path.is_rel_path()) {
*r_icon_path = p_path.get_base_dir().plus_file(c->icon_path).simplify_path();
@@ -1926,7 +2163,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
GDScriptParser subparser;
while (subclass) {
if (subclass->extends_used) {
- if (!subclass->extends_path.empty()) {
+ if (!subclass->extends_path.is_empty()) {
if (subclass->extends.size() == 0) {
get_global_class_name(subclass->extends_path, r_base_type);
subclass = nullptr;
@@ -1940,7 +2177,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
}
String subsource = subfile->get_as_utf8_string();
- if (subsource.empty()) {
+ if (subsource.is_empty()) {
break;
}
String subpath = subclass->extends_path;
@@ -2137,7 +2374,7 @@ void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<S
ERR_FAIL_COND_MSG(!file, "Cannot open file '" + p_path + "'.");
String source = file->get_as_utf8_string();
- if (source.empty()) {
+ if (source.is_empty()) {
return;
}
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 79317ff846..37f01b2571 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,9 +33,10 @@
#include "core/debugger/engine_debugger.h"
#include "core/debugger/script_debugger.h"
+#include "core/doc_data.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
-#include "core/script_language.h"
+#include "core/object/script_language.h"
#include "gdscript_function.h"
class GDScriptNativeClass : public Reference {
@@ -71,8 +72,8 @@ class GDScript : public Script {
friend class GDScriptFunction;
friend class GDScriptAnalyzer;
friend class GDScriptCompiler;
- friend class GDScriptFunctions;
friend class GDScriptLanguage;
+ friend struct GDScriptUtilityFunctionsDefinitions;
Ref<GDScriptNativeClass> native;
Ref<GDScript> base;
@@ -91,9 +92,7 @@ class GDScript : public Script {
#ifdef TOOLS_ENABLED
Map<StringName, int> member_lines;
-
Map<StringName, Variant> member_default_values;
-
List<PropertyInfo> members_cache;
Map<StringName, Variant> member_default_values_cache;
Ref<GDScript> base_cache;
@@ -102,6 +101,20 @@ class GDScript : public Script {
bool placeholder_fallback_enabled;
void _update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames);
+ DocData::ClassDoc doc;
+ Vector<DocData::ClassDoc> docs;
+ String doc_brief_description;
+ String doc_description;
+ Vector<DocData::TutorialDoc> doc_tutorials;
+ Map<String, String> doc_functions;
+ Map<String, String> doc_variables;
+ Map<String, String> doc_constants;
+ Map<String, String> doc_signals;
+ Map<String, DocData::EnumDoc> doc_enums;
+ void _clear_doc();
+ void _update_doc();
+ void _add_doc(const DocData::ClassDoc &p_inner_class);
+
#endif
Map<StringName, PropertyInfo> member_info;
@@ -141,6 +154,13 @@ class GDScript : public Script {
void _save_orphaned_subclasses();
void _init_rpc_methods_properties();
+ void _get_script_property_list(List<PropertyInfo> *r_list, bool p_include_base) const;
+ void _get_script_method_list(List<MethodInfo> *r_list, bool p_include_base) const;
+ void _get_script_signal_list(List<MethodInfo> *r_list, bool p_include_base) const;
+
+ // This method will map the class name from "Reference" to "MyClass.InnerClass".
+ static String _get_gdscript_reference_class_name(const GDScript *p_gdscript);
+
protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
bool _set(const StringName &p_name, const Variant &p_value);
@@ -191,6 +211,12 @@ public:
virtual void set_source_code(const String &p_code) override;
virtual void update_exports() override;
+#ifdef TOOLS_ENABLED
+ virtual const Vector<DocData::ClassDoc> &get_documentation() const override {
+ return docs;
+ }
+#endif // TOOLS_ENABLED
+
virtual Error reload(bool p_keep_state = false) override;
void set_script_path(const String &p_path) { path = p_path; } //because subclasses need a path too...
@@ -244,8 +270,8 @@ public:
class GDScriptInstance : public ScriptInstance {
friend class GDScript;
friend class GDScriptFunction;
- friend class GDScriptFunctions;
friend class GDScriptCompiler;
+ friend struct GDScriptUtilityFunctionsDefinitions;
ObjectID owner_id;
Object *owner;
@@ -444,7 +470,8 @@ public:
virtual Script *create_script() const;
virtual bool has_named_classes() const;
virtual bool supports_builtin_mode() const;
- virtual bool can_inherit_from_file() { return true; }
+ virtual bool supports_documentation() const;
+ virtual bool can_inherit_from_file() const { return true; }
virtual int find_function(const String &p_function, const String &p_code) const;
virtual String make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const;
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);
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 943a49060f..a6138cc564 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,13 +30,14 @@
#include "gdscript_analyzer.h"
-#include "core/class_db.h"
-#include "core/hash_map.h"
+#include "core/config/project_settings.h"
#include "core/io/resource_loader.h"
+#include "core/object/class_db.h"
+#include "core/object/script_language.h"
#include "core/os/file_access.h"
-#include "core/project_settings.h"
-#include "core/script_language.h"
+#include "core/templates/hash_map.h"
#include "gdscript.h"
+#include "gdscript_utility_functions.h"
// TODO: Move this to a central location (maybe core?).
static HashMap<StringName, StringName> underscore_map;
@@ -59,7 +60,7 @@ static const char *underscore_classes[] = {
nullptr,
};
static StringName get_real_class_name(const StringName &p_source) {
- if (underscore_map.empty()) {
+ if (underscore_map.is_empty()) {
const char **class_name = underscore_classes;
while (*class_name != nullptr) {
underscore_map[*class_name] = String("_") + *class_name;
@@ -72,6 +73,39 @@ static StringName get_real_class_name(const StringName &p_source) {
return p_source;
}
+static MethodInfo info_from_utility_func(const StringName &p_function) {
+ ERR_FAIL_COND_V(!Variant::has_utility_function(p_function), MethodInfo());
+
+ MethodInfo info(p_function);
+
+ if (Variant::has_utility_function_return_value(p_function)) {
+ info.return_val.type = Variant::get_utility_function_return_type(p_function);
+ if (info.return_val.type == Variant::NIL) {
+ info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+ }
+ }
+
+ if (Variant::is_utility_function_vararg(p_function)) {
+ info.flags |= METHOD_FLAG_VARARG;
+ } else {
+ for (int i = 0; i < Variant::get_utility_function_argument_count(p_function); i++) {
+ PropertyInfo pi;
+#ifdef DEBUG_METHODS_ENABLED
+ pi.name = Variant::get_utility_function_argument_name(p_function, i);
+#else
+ pi.name = "arg" + itos(i + 1);
+#endif
+ pi.type = Variant::get_utility_function_argument_type(p_function, i);
+ if (pi.type == Variant::NIL) {
+ pi.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+ }
+ info.arguments.push_back(pi);
+ }
+ }
+
+ return info;
+}
+
void GDScriptAnalyzer::cleanup() {
underscore_map.clear();
}
@@ -175,7 +209,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
int extends_index = 0;
- if (!p_class->extends_path.empty()) {
+ if (!p_class->extends_path.is_empty()) {
Ref<GDScriptParserRef> parser = get_parser_for(p_class->extends_path);
if (parser.is_null()) {
push_error(vformat(R"(Could not resolve super class path "%s".)", p_class->extends_path), p_class);
@@ -190,7 +224,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
base = parser->get_parser()->head->get_datatype();
} else {
- if (p_class->extends.empty()) {
+ if (p_class->extends.is_empty()) {
return ERR_PARSE_ERROR;
}
const StringName &name = p_class->extends[extends_index++];
@@ -342,7 +376,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
result.type_source = result.ANNOTATED_EXPLICIT;
result.builtin_type = Variant::OBJECT;
- if (p_type->type_chain.empty()) {
+ if (p_type->type_chain.is_empty()) {
// void.
result.kind = GDScriptParser::DataType::BUILTIN;
result.builtin_type = Variant::NIL;
@@ -577,6 +611,12 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
GDScriptParser::DataType datatype = member.constant->get_datatype();
if (member.constant->initializer) {
+ if (member.constant->initializer->type == GDScriptParser::Node::ARRAY) {
+ const_fold_array(static_cast<GDScriptParser::ArrayNode *>(member.constant->initializer));
+ } else if (member.constant->initializer->type == GDScriptParser::Node::DICTIONARY) {
+ const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(member.constant->initializer));
+ }
+
if (!member.constant->initializer->is_constant) {
push_error(R"(Initializer for a constant must be a constant expression.)", member.constant->initializer);
}
@@ -854,7 +894,12 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
parser->push_warning(p_function->parameters[i]->identifier, GDScriptWarning::UNUSED_PARAMETER, p_function->identifier->name, p_function->parameters[i]->identifier->name);
}
is_shadowing(p_function->parameters[i]->identifier, "function parameter");
-#endif
+#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);
+ }
+#endif // TOOLS_ENABLED
}
if (p_function->identifier->name == "_init") {
@@ -972,17 +1017,19 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
if (!call->arguments[i]->is_constant) {
all_is_constant = false;
- } else {
+ } else if (all_is_constant) {
args.write[i] = call->arguments[i]->reduced_value;
}
GDScriptParser::DataType arg_type = call->arguments[i]->get_datatype();
- if (arg_type.kind != GDScriptParser::DataType::BUILTIN) {
- all_is_constant = false;
- push_error(vformat(R"*(Invalid argument for "range()" call. Argument %d should be int or float but "%s" was given.)*", i + 1, arg_type.to_string()), call->arguments[i]);
- } else if (arg_type.builtin_type != Variant::INT && arg_type.builtin_type != Variant::FLOAT) {
- all_is_constant = false;
- push_error(vformat(R"*(Invalid argument for "range()" call. Argument %d should be int or float but "%s" was given.)*", i + 1, arg_type.to_string()), call->arguments[i]);
+ if (!arg_type.is_variant()) {
+ if (arg_type.kind != GDScriptParser::DataType::BUILTIN) {
+ all_is_constant = false;
+ push_error(vformat(R"*(Invalid argument for "range()" call. Argument %d should be int or float but "%s" was given.)*", i + 1, arg_type.to_string()), call->arguments[i]);
+ } else if (arg_type.builtin_type != Variant::INT && arg_type.builtin_type != Variant::FLOAT) {
+ all_is_constant = false;
+ push_error(vformat(R"*(Invalid argument for "range()" call. Argument %d should be int or float but "%s" was given.)*", i + 1, arg_type.to_string()), call->arguments[i]);
+ }
}
}
@@ -1005,11 +1052,15 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
}
}
- GDScriptParser::DataType list_type;
- list_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
- list_type.kind = GDScriptParser::DataType::BUILTIN;
- list_type.builtin_type = Variant::ARRAY;
- p_for->list->set_datatype(list_type);
+ if (p_for->list->is_constant) {
+ p_for->list->set_datatype(type_from_variant(p_for->list->reduced_value, p_for->list));
+ } else {
+ GDScriptParser::DataType list_type;
+ list_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
+ list_type.kind = GDScriptParser::DataType::BUILTIN;
+ list_type.builtin_type = Variant::ARRAY;
+ p_for->list->set_datatype(list_type);
+ }
}
}
}
@@ -1112,19 +1163,26 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable
void GDScriptAnalyzer::resolve_constant(GDScriptParser::ConstantNode *p_constant) {
GDScriptParser::DataType type;
- reduce_expression(p_constant->initializer);
+ if (p_constant->initializer != nullptr) {
+ reduce_expression(p_constant->initializer);
+ if (p_constant->initializer->type == GDScriptParser::Node::ARRAY) {
+ const_fold_array(static_cast<GDScriptParser::ArrayNode *>(p_constant->initializer));
+ } else if (p_constant->initializer->type == GDScriptParser::Node::DICTIONARY) {
+ const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(p_constant->initializer));
+ }
- if (!p_constant->initializer->is_constant) {
- push_error(vformat(R"(Assigned value for constant "%s" isn't a constant expression.)", p_constant->identifier->name), p_constant->initializer);
- }
+ if (!p_constant->initializer->is_constant) {
+ push_error(vformat(R"(Assigned value for constant "%s" isn't a constant expression.)", p_constant->identifier->name), p_constant->initializer);
+ }
- type = p_constant->initializer->get_datatype();
+ type = p_constant->initializer->get_datatype();
#ifdef DEBUG_ENABLED
- if (p_constant->initializer->type == GDScriptParser::Node::CALL && type.kind == GDScriptParser::DataType::BUILTIN && type.builtin_type == Variant::NIL) {
- parser->push_warning(p_constant->initializer, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_constant->initializer)->function_name);
- }
+ if (p_constant->initializer->type == GDScriptParser::Node::CALL && type.kind == GDScriptParser::DataType::BUILTIN && type.builtin_type == Variant::NIL) {
+ parser->push_warning(p_constant->initializer, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_constant->initializer)->function_name);
+ }
#endif
+ }
if (p_constant->datatype_specifier != nullptr) {
GDScriptParser::DataType explicit_type = resolve_datatype(p_constant->datatype_specifier);
@@ -1159,7 +1217,10 @@ void GDScriptAnalyzer::resolve_constant(GDScriptParser::ConstantNode *p_constant
void GDScriptAnalyzer::resolve_assert(GDScriptParser::AssertNode *p_assert) {
reduce_expression(p_assert->condition);
if (p_assert->message != nullptr) {
- reduce_literal(p_assert->message);
+ reduce_expression(p_assert->message);
+ if (!p_assert->message->is_constant || p_assert->message->reduced_value.get_type() != Variant::STRING) {
+ push_error(R"(Expected constant string for assert error message.)", p_assert->message);
+ }
}
p_assert->set_datatype(p_assert->condition->get_datatype());
@@ -1422,22 +1483,9 @@ void GDScriptAnalyzer::reduce_expression(GDScriptParser::ExpressionNode *p_expre
}
void GDScriptAnalyzer::reduce_array(GDScriptParser::ArrayNode *p_array) {
- bool all_is_constant = true;
-
for (int i = 0; i < p_array->elements.size(); i++) {
GDScriptParser::ExpressionNode *element = p_array->elements[i];
reduce_expression(element);
- all_is_constant = all_is_constant && element->is_constant;
- }
-
- if (all_is_constant) {
- Array array;
- array.resize(p_array->elements.size());
- for (int i = 0; i < p_array->elements.size(); i++) {
- array[i] = p_array->elements[i]->reduced_value;
- }
- p_array->is_constant = true;
- p_array->reduced_value = array;
}
// It's array in any case.
@@ -1607,7 +1655,7 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o
if (p_binary_op->reduced_value.get_type() == Variant::STRING) {
push_error(vformat(R"(%s in operator %s.)", p_binary_op->reduced_value, Variant::get_operator_name(p_binary_op->variant_op)), p_binary_op);
} else {
- push_error(vformat(R"(Invalid operands to operator %s, %s and %s.".)",
+ push_error(vformat(R"(Invalid operands to operator %s, %s and %s.)",
Variant::get_operator_name(p_binary_op->variant_op),
Variant::get_type_name(p_binary_op->left_operand->reduced_value.get_type()),
Variant::get_type_name(p_binary_op->right_operand->reduced_value.get_type())),
@@ -1692,7 +1740,6 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
// Call to name directly.
StringName function_name = p_call->function_name;
Variant::Type builtin_type = GDScriptParser::get_builtin_type(function_name);
- GDScriptFunctions::Function builtin_function = GDScriptParser::get_builtin_function(function_name);
if (builtin_type < Variant::VARIANT_MAX) {
// Is a builtin constructor.
@@ -1705,7 +1752,29 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
call_type.native_type = function_name; // "Object".
}
- if (all_is_constant) {
+ bool safe_to_fold = true;
+ switch (builtin_type) {
+ // Those are stored by reference so not suited for compile-time construction.
+ // Because in this case they would be the same reference in all constructed values.
+ case Variant::OBJECT:
+ case Variant::DICTIONARY:
+ case Variant::ARRAY:
+ case Variant::PACKED_BYTE_ARRAY:
+ case Variant::PACKED_INT32_ARRAY:
+ case Variant::PACKED_INT64_ARRAY:
+ case Variant::PACKED_FLOAT32_ARRAY:
+ case Variant::PACKED_FLOAT64_ARRAY:
+ case Variant::PACKED_STRING_ARRAY:
+ case Variant::PACKED_VECTOR2_ARRAY:
+ case Variant::PACKED_VECTOR3_ARRAY:
+ case Variant::PACKED_COLOR_ARRAY:
+ safe_to_fold = false;
+ break;
+ default:
+ break;
+ }
+
+ if (all_is_constant && safe_to_fold) {
// Construct here.
Vector<const Variant *> args;
for (int i = 0; i < p_call->arguments.size(); i++) {
@@ -1713,7 +1782,8 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
}
Callable::CallError err;
- Variant value = Variant::construct(builtin_type, (const Variant **)args.ptr(), args.size(), err);
+ Variant value;
+ Variant::construct(builtin_type, value, (const Variant **)args.ptr(), args.size(), err);
switch (err.error) {
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT:
@@ -1813,10 +1883,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
}
p_call->set_datatype(call_type);
return;
- } else if (builtin_function < GDScriptFunctions::FUNC_MAX) {
- MethodInfo function_info = GDScriptFunctions::get_info(builtin_function);
+ } else if (GDScriptUtilityFunctions::function_exists(function_name)) {
+ MethodInfo function_info = GDScriptUtilityFunctions::get_function_info(function_name);
- if (all_is_constant && GDScriptFunctions::is_deterministic(builtin_function)) {
+ if (all_is_constant && GDScriptUtilityFunctions::is_function_constant(function_name)) {
// Can call on compilation.
Vector<const Variant *> args;
for (int i = 0; i < p_call->arguments.size(); i++) {
@@ -1825,23 +1895,65 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
Variant value;
Callable::CallError err;
- GDScriptFunctions::call(builtin_function, (const Variant **)args.ptr(), args.size(), value, err);
+ GDScriptUtilityFunctions::get_function(function_name)(&value, (const Variant **)args.ptr(), args.size(), err);
switch (err.error) {
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: {
PropertyInfo wrong_arg = function_info.arguments[err.argument];
- push_error(vformat(R"*(Invalid argument for "%s()" function: argument %d should be %s but is %s.)*", GDScriptFunctions::get_func_name(builtin_function), err.argument + 1,
+ push_error(vformat(R"*(Invalid argument for "%s()" function: argument %d should be %s but is %s.)*", function_name, err.argument + 1,
type_from_property(wrong_arg).to_string(), p_call->arguments[err.argument]->get_datatype().to_string()),
p_call->arguments[err.argument]);
} break;
case Callable::CallError::CALL_ERROR_INVALID_METHOD:
- push_error(vformat(R"(Invalid call for function "%s".)", GDScriptFunctions::get_func_name(builtin_function)), p_call);
+ push_error(vformat(R"(Invalid call for function "%s".)", function_name), p_call);
break;
case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS:
- push_error(vformat(R"*(Too many arguments for "%s()" call. Expected at most %d but received %d.)*", GDScriptFunctions::get_func_name(builtin_function), err.expected, p_call->arguments.size()), p_call);
+ push_error(vformat(R"*(Too many arguments for "%s()" call. Expected at most %d but received %d.)*", function_name, err.expected, p_call->arguments.size()), p_call);
break;
case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
- push_error(vformat(R"*(Too few arguments for "%s()" call. Expected at least %d but received %d.)*", GDScriptFunctions::get_func_name(builtin_function), err.expected, p_call->arguments.size()), p_call);
+ push_error(vformat(R"*(Too few arguments for "%s()" call. Expected at least %d but received %d.)*", function_name, err.expected, p_call->arguments.size()), p_call);
+ break;
+ case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL:
+ break; // Can't happen in a builtin constructor.
+ case Callable::CallError::CALL_OK:
+ p_call->is_constant = true;
+ p_call->reduced_value = value;
+ break;
+ }
+ } else {
+ validate_call_arg(function_info, p_call);
+ }
+ p_call->set_datatype(type_from_property(function_info.return_val));
+ return;
+ } else if (Variant::has_utility_function(function_name)) {
+ MethodInfo function_info = info_from_utility_func(function_name);
+
+ if (all_is_constant && Variant::get_utility_function_type(function_name) == Variant::UTILITY_FUNC_TYPE_MATH) {
+ // Can call on compilation.
+ Vector<const Variant *> args;
+ for (int i = 0; i < p_call->arguments.size(); i++) {
+ args.push_back(&(p_call->arguments[i]->reduced_value));
+ }
+
+ Variant value;
+ Callable::CallError err;
+ Variant::call_utility_function(function_name, &value, (const Variant **)args.ptr(), args.size(), err);
+
+ switch (err.error) {
+ case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: {
+ PropertyInfo wrong_arg = function_info.arguments[err.argument];
+ push_error(vformat(R"*(Invalid argument for "%s()" function: argument %d should be %s but is %s.)*", function_name, err.argument + 1,
+ type_from_property(wrong_arg).to_string(), p_call->arguments[err.argument]->get_datatype().to_string()),
+ p_call->arguments[err.argument]);
+ } break;
+ case Callable::CallError::CALL_ERROR_INVALID_METHOD:
+ push_error(vformat(R"(Invalid call for function "%s".)", function_name), p_call);
+ break;
+ case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS:
+ push_error(vformat(R"*(Too many arguments for "%s()" call. Expected at most %d but received %d.)*", function_name, err.expected, p_call->arguments.size()), p_call);
+ break;
+ case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
+ push_error(vformat(R"*(Too few arguments for "%s()" call. Expected at least %d but received %d.)*", function_name, err.expected, p_call->arguments.size()), p_call);
break;
case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL:
break; // Can't happen in a builtin constructor.
@@ -1924,14 +2036,14 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
push_error(vformat(R"*(Name "%s" called as a function but is a "%s".)*", p_call->function_name, callee_datatype.to_string()), p_call->callee);
}
#ifdef DEBUG_ENABLED
- } else if (!is_self) {
+ } else if (!is_self && !(base_type.is_hard_type() && base_type.kind == GDScriptParser::DataType::BUILTIN)) {
parser->push_warning(p_call, GDScriptWarning::UNSAFE_METHOD_ACCESS, p_call->function_name, base_type.to_string());
mark_node_unsafe(p_call);
#endif
}
}
}
- if (!found && is_self) {
+ 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);
}
@@ -1984,8 +2096,6 @@ void GDScriptAnalyzer::reduce_cast(GDScriptParser::CastNode *p_cast) {
}
void GDScriptAnalyzer::reduce_dictionary(GDScriptParser::DictionaryNode *p_dictionary) {
- bool all_is_constant = true;
-
HashMap<Variant, GDScriptParser::ExpressionNode *, VariantHasher, VariantComparator> elements;
for (int i = 0; i < p_dictionary->elements.size(); i++) {
@@ -1994,7 +2104,6 @@ void GDScriptAnalyzer::reduce_dictionary(GDScriptParser::DictionaryNode *p_dicti
reduce_expression(element.key);
}
reduce_expression(element.value);
- all_is_constant = all_is_constant && element.key->is_constant && element.value->is_constant;
if (element.key->is_constant) {
if (elements.has(element.key->reduced_value)) {
@@ -2005,16 +2114,6 @@ void GDScriptAnalyzer::reduce_dictionary(GDScriptParser::DictionaryNode *p_dicti
}
}
- if (all_is_constant) {
- Dictionary dict;
- for (int i = 0; i < p_dictionary->elements.size(); i++) {
- const GDScriptParser::DictionaryNode::Pair &element = p_dictionary->elements[i];
- dict[element.key->reduced_value] = element.value->reduced_value;
- }
- p_dictionary->is_constant = true;
- p_dictionary->reduced_value = dict;
- }
-
// It's dictionary in any case.
GDScriptParser::DataType dict_type;
dict_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
@@ -2039,9 +2138,17 @@ void GDScriptAnalyzer::reduce_get_node(GDScriptParser::GetNodeNode *p_get_node)
p_get_node->set_datatype(result);
}
-GDScriptParser::DataType GDScriptAnalyzer::make_global_class_meta_type(const StringName &p_class_name) {
+GDScriptParser::DataType GDScriptAnalyzer::make_global_class_meta_type(const StringName &p_class_name, const GDScriptParser::Node *p_source) {
Ref<GDScriptParserRef> ref = get_parser_for(ScriptServer::get_global_class_path(p_class_name));
- ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
+ Error err = ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
+
+ if (err) {
+ push_error(vformat(R"(Could not resolve class "%s", because of a parser error.)", p_class_name), p_source);
+ GDScriptParser::DataType type;
+ type.type_source = GDScriptParser::DataType::UNDETECTED;
+ type.kind = GDScriptParser::DataType::VARIANT;
+ return type;
+ }
GDScriptParser::DataType type;
type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
@@ -2090,7 +2197,8 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
}
default: {
Callable::CallError temp;
- Variant dummy = Variant::construct(base.builtin_type, nullptr, 0, temp);
+ Variant dummy;
+ Variant::construct(base.builtin_type, dummy, nullptr, 0, temp);
List<PropertyInfo> properties;
dummy.get_property_list(&properties);
for (const List<PropertyInfo>::Element *E = properties.front(); E != nullptr; E = E->next()) {
@@ -2294,10 +2402,12 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
StringName name = p_identifier->name;
p_identifier->source = GDScriptParser::IdentifierNode::UNDEFINED_SOURCE;
- // Check globals.
- if (GDScriptParser::get_builtin_type(name) < Variant::VARIANT_MAX) {
+ // Check globals. We make an exception for Variant::OBJECT because it's the base class for
+ // non-builtin types so we allow doing e.g. Object.new()
+ Variant::Type builtin_type = GDScriptParser::get_builtin_type(name);
+ if (builtin_type != Variant::OBJECT && builtin_type < Variant::VARIANT_MAX) {
if (can_be_builtin) {
- p_identifier->set_datatype(make_builtin_meta_type(GDScriptParser::get_builtin_type(name)));
+ p_identifier->set_datatype(make_builtin_meta_type(builtin_type));
return;
} else {
push_error(R"(Builtin type cannot be used as a name on its own.)", p_identifier);
@@ -2310,7 +2420,7 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
}
if (ScriptServer::is_global_class(name)) {
- p_identifier->set_datatype(make_global_class_meta_type(name));
+ p_identifier->set_datatype(make_global_class_meta_type(name, p_identifier));
return;
}
@@ -2357,7 +2467,7 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
// Not found.
// Check if it's a builtin function.
- if (parser->get_builtin_function(name) < GDScriptFunctions::FUNC_MAX) {
+ if (GDScriptUtilityFunctions::function_exists(name)) {
push_error(vformat(R"(Built-in function "%s" cannot be used as an identifier.)", name), p_identifier);
} else {
push_error(vformat(R"(Identifier "%s" not declared in the current scope.)", name), p_identifier);
@@ -2451,7 +2561,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
if (p_subscript->base->is_constant) {
// Just try to get it.
bool valid = false;
- Variant value = p_subscript->base->reduced_value.get_named(p_subscript->attribute->name, &valid);
+ Variant value = p_subscript->base->reduced_value.get_named(p_subscript->attribute->name, valid);
if (!valid) {
push_error(vformat(R"(Cannot get member "%s" from "%s".)", p_subscript->attribute->name, p_subscript->base->reduced_value), p_subscript->index);
} else {
@@ -2552,7 +2662,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
error = index_type.builtin_type != Variant::INT && index_type.builtin_type != Variant::STRING;
break;
// Don't support indexing, but we will check it later.
- case Variant::_RID:
+ case Variant::RID:
case Variant::BOOL:
case Variant::CALLABLE:
case Variant::FLOAT:
@@ -2585,7 +2695,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
switch (base_type.builtin_type) {
// Can't index at all.
- case Variant::_RID:
+ case Variant::RID:
case Variant::BOOL:
case Variant::CALLABLE:
case Variant::FLOAT:
@@ -2727,7 +2837,7 @@ void GDScriptAnalyzer::reduce_unary_op(GDScriptParser::UnaryOpNode *p_unary_op)
mark_node_unsafe(p_unary_op);
} else {
bool valid = false;
- result = get_operation_type(p_unary_op->variant_op, p_unary_op->operand->get_datatype(), p_unary_op->operand->get_datatype(), valid, p_unary_op);
+ result = get_operation_type(p_unary_op->variant_op, p_unary_op->operand->get_datatype(), valid, p_unary_op);
if (!valid) {
push_error(vformat(R"(Invalid operand of type "%s" for unary operator "%s".)", p_unary_op->operand->get_datatype().to_string(), Variant::get_operator_name(p_unary_op->variant_op)), p_unary_op->operand);
@@ -2737,6 +2847,46 @@ void GDScriptAnalyzer::reduce_unary_op(GDScriptParser::UnaryOpNode *p_unary_op)
p_unary_op->set_datatype(result);
}
+void GDScriptAnalyzer::const_fold_array(GDScriptParser::ArrayNode *p_array) {
+ bool all_is_constant = true;
+
+ for (int i = 0; i < p_array->elements.size(); i++) {
+ GDScriptParser::ExpressionNode *element = p_array->elements[i];
+ all_is_constant = all_is_constant && element->is_constant;
+ if (!all_is_constant) {
+ return;
+ }
+ }
+
+ Array array;
+ array.resize(p_array->elements.size());
+ for (int i = 0; i < p_array->elements.size(); i++) {
+ array[i] = p_array->elements[i]->reduced_value;
+ }
+ p_array->is_constant = true;
+ p_array->reduced_value = array;
+}
+
+void GDScriptAnalyzer::const_fold_dictionary(GDScriptParser::DictionaryNode *p_dictionary) {
+ bool all_is_constant = true;
+
+ for (int i = 0; i < p_dictionary->elements.size(); i++) {
+ const GDScriptParser::DictionaryNode::Pair &element = p_dictionary->elements[i];
+ all_is_constant = all_is_constant && element.key->is_constant && element.value->is_constant;
+ if (!all_is_constant) {
+ return;
+ }
+ }
+
+ Dictionary dict;
+ for (int i = 0; i < p_dictionary->elements.size(); i++) {
+ const GDScriptParser::DictionaryNode::Pair &element = p_dictionary->elements[i];
+ dict[element.key->reduced_value] = element.value->reduced_value;
+ }
+ p_dictionary->is_constant = true;
+ p_dictionary->reduced_value = dict;
+}
+
GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_value, const GDScriptParser::Node *p_source) {
GDScriptParser::DataType result;
result.is_constant = true;
@@ -2842,7 +2992,8 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, GD
if (p_base_type.kind == GDScriptParser::DataType::BUILTIN) {
// Construct a base type to get methods.
Callable::CallError err;
- Variant dummy = Variant::construct(p_base_type.builtin_type, nullptr, 0, err);
+ Variant dummy;
+ Variant::construct(p_base_type.builtin_type, dummy, nullptr, 0, err);
if (err.error != Callable::CallError::CALL_OK) {
ERR_FAIL_V_MSG(false, "Could not construct base Variant type.");
}
@@ -3052,81 +3203,31 @@ bool GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_local, con
}
#endif
-GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, const GDScriptParser::DataType &p_b, bool &r_valid, const GDScriptParser::Node *p_source) {
- // This function creates dummy variant values and apply the operation to those. Less error-prone than keeping a table of valid operations.
+GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, bool &r_valid, const GDScriptParser::Node *p_source) {
+ // Unary version.
+ GDScriptParser::DataType nil_type;
+ nil_type.builtin_type = Variant::NIL;
+ return get_operation_type(p_operation, p_a, nil_type, r_valid, p_source);
+}
+GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, const GDScriptParser::DataType &p_b, bool &r_valid, const GDScriptParser::Node *p_source) {
GDScriptParser::DataType result;
result.kind = GDScriptParser::DataType::VARIANT;
Variant::Type a_type = p_a.builtin_type;
Variant::Type b_type = p_b.builtin_type;
- Variant a;
- REF a_ref;
- if (a_type == Variant::OBJECT) {
- a_ref.instance();
- a = a_ref;
- } else {
- Callable::CallError err;
- a = Variant::construct(a_type, nullptr, 0, err);
- if (err.error != Callable::CallError::CALL_OK) {
- r_valid = false;
- ERR_FAIL_V_MSG(result, vformat("Could not construct value of type %s", Variant::get_type_name(a_type)));
- }
- }
- Variant b;
- REF b_ref;
- if (b_type == Variant::OBJECT) {
- b_ref.instance();
- b = b_ref;
- } else {
- Callable::CallError err;
- b = Variant::construct(b_type, nullptr, 0, err);
- if (err.error != Callable::CallError::CALL_OK) {
- r_valid = false;
- ERR_FAIL_V_MSG(result, vformat("Could not construct value of type %s", Variant::get_type_name(b_type)));
- }
- }
-
- // Avoid division by zero.
- switch (b_type) {
- case Variant::INT:
- b = 1;
- break;
- case Variant::FLOAT:
- b = 1.0;
- break;
- case Variant::VECTOR2:
- b = Vector2(1.0, 1.0);
- break;
- case Variant::VECTOR2I:
- b = Vector2i(1, 1);
- break;
- case Variant::VECTOR3:
- b = Vector3(1.0, 1.0, 1.0);
- break;
- case Variant::VECTOR3I:
- b = Vector3i(1, 1, 1);
- break;
- case Variant::COLOR:
- b = Color(1.0, 1.0, 1.0, 1.0);
- break;
- default:
- // No change needed.
- break;
- }
+ Variant::ValidatedOperatorEvaluator op_eval = Variant::get_validated_operator_evaluator(p_operation, a_type, b_type);
- // Avoid error in formatting operator (%) where it doesn't find a placeholder.
- if (a_type == Variant::STRING && b_type != Variant::ARRAY) {
- a = String("%s");
+ if (op_eval == nullptr) {
+ r_valid = false;
+ return result;
}
- Variant ret;
- Variant::evaluate(p_operation, a, b, ret, r_valid);
+ r_valid = true;
- if (r_valid) {
- return type_from_variant(ret, p_source);
- }
+ result.kind = GDScriptParser::DataType::BUILTIN;
+ result.builtin_type = Variant::get_operator_return_type(p_operation, a_type, b_type);
return result;
}
@@ -3308,12 +3409,12 @@ Error GDScriptAnalyzer::resolve_inheritance() {
Error GDScriptAnalyzer::resolve_interface() {
resolve_class_interface(parser->head);
- return parser->errors.empty() ? OK : ERR_PARSE_ERROR;
+ return parser->errors.is_empty() ? OK : ERR_PARSE_ERROR;
}
Error GDScriptAnalyzer::resolve_body() {
resolve_class_body(parser->head);
- return parser->errors.empty() ? OK : ERR_PARSE_ERROR;
+ return parser->errors.is_empty() ? OK : ERR_PARSE_ERROR;
}
Error GDScriptAnalyzer::resolve_program() {
@@ -3328,8 +3429,7 @@ Error GDScriptAnalyzer::resolve_program() {
}
depended_parsers[E->get()]->raise_status(GDScriptParserRef::FULLY_SOLVED);
}
- depended_parsers.clear();
- return parser->errors.empty() ? OK : ERR_PARSE_ERROR;
+ return parser->errors.is_empty() ? OK : ERR_PARSE_ERROR;
}
Error GDScriptAnalyzer::analyze() {
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index c3911cce76..dab5b032a3 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,9 +31,9 @@
#ifndef GDSCRIPT_ANALYZER_H
#define GDSCRIPT_ANALYZER_H
-#include "core/object.h"
-#include "core/reference.h"
-#include "core/set.h"
+#include "core/object/object.h"
+#include "core/object/reference.h"
+#include "core/templates/set.h"
#include "gdscript_cache.h"
#include "gdscript_parser.h"
@@ -89,16 +89,20 @@ class GDScriptAnalyzer {
void reduce_ternary_op(GDScriptParser::TernaryOpNode *p_ternary_op);
void reduce_unary_op(GDScriptParser::UnaryOpNode *p_unary_op);
+ void const_fold_array(GDScriptParser::ArrayNode *p_array);
+ void const_fold_dictionary(GDScriptParser::DictionaryNode *p_dictionary);
+
// Helpers.
GDScriptParser::DataType type_from_variant(const Variant &p_value, const GDScriptParser::Node *p_source);
GDScriptParser::DataType type_from_metatype(const GDScriptParser::DataType &p_meta_type) const;
GDScriptParser::DataType type_from_property(const PropertyInfo &p_property) const;
- GDScriptParser::DataType make_global_class_meta_type(const StringName &p_class_name);
+ GDScriptParser::DataType make_global_class_meta_type(const StringName &p_class_name, const GDScriptParser::Node *p_source);
bool get_function_signature(GDScriptParser::Node *p_source, GDScriptParser::DataType base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg);
bool function_signature_from_info(const MethodInfo &p_info, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg);
bool validate_call_arg(const List<GDScriptParser::DataType> &p_par_types, int p_default_args_count, bool p_is_vararg, const GDScriptParser::CallNode *p_call);
bool validate_call_arg(const MethodInfo &p_method, const GDScriptParser::CallNode *p_call);
GDScriptParser::DataType get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, const GDScriptParser::DataType &p_b, bool &r_valid, const GDScriptParser::Node *p_source);
+ GDScriptParser::DataType get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, bool &r_valid, const GDScriptParser::Node *p_source);
bool is_type_compatible(const GDScriptParser::DataType &p_target, const GDScriptParser::DataType &p_source, bool p_allow_implicit_conversion = false) const;
void push_error(const String &p_message, const GDScriptParser::Node *p_origin);
void mark_node_unsafe(const GDScriptParser::Node *p_node);
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index eabf53581d..58c6b31a77 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -40,10 +40,6 @@ uint32_t GDScriptByteCodeGenerator::add_parameter(const StringName &p_name, bool
function->_argument_count++;
function->argument_types.push_back(p_type);
if (p_is_optional) {
- if (function->_default_arg_count == 0) {
- append(GDScriptFunction::OPCODE_JUMP_TO_DEF_ARGUMENT);
- }
- function->default_arguments.push_back(opcodes.size());
function->_default_arg_count++;
}
@@ -77,15 +73,31 @@ uint32_t GDScriptByteCodeGenerator::add_or_get_name(const StringName &p_name) {
uint32_t GDScriptByteCodeGenerator::add_temporary() {
current_temporaries++;
- return increase_stack();
+ int idx = increase_stack();
+#ifdef DEBUG_ENABLED
+ temp_stack.push_back(idx);
+#endif
+ return idx;
}
void GDScriptByteCodeGenerator::pop_temporary() {
+ ERR_FAIL_COND(current_temporaries == 0);
current_stack_size--;
+#ifdef DEBUG_ENABLED
+ if (temp_stack.back()->get() != current_stack_size) {
+ ERR_PRINT("Mismatched popping of temporary value");
+ }
+ temp_stack.pop_back();
+#endif
current_temporaries--;
}
-void GDScriptByteCodeGenerator::start_parameters() {}
+void GDScriptByteCodeGenerator::start_parameters() {
+ if (function->_default_arg_count > 0) {
+ append(GDScriptFunction::OPCODE_JUMP_TO_DEF_ARGUMENT);
+ function->default_arguments.push_back(opcodes.size());
+ }
+}
void GDScriptByteCodeGenerator::end_parameters() {
function->default_arguments.invert();
@@ -111,7 +123,12 @@ void GDScriptByteCodeGenerator::write_start(GDScript *p_script, const StringName
}
GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
- append(GDScriptFunction::OPCODE_END);
+#ifdef DEBUG_ENABLED
+ if (current_temporaries != 0) {
+ ERR_PRINT("Non-zero temporary variables at end of function: " + itos(current_temporaries));
+ }
+#endif
+ append(GDScriptFunction::OPCODE_END, 0);
if (constant_map.size()) {
function->_constant_count = constant_map.size();
@@ -151,18 +168,163 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
}
if (function->default_arguments.size()) {
- function->_default_arg_count = function->default_arguments.size();
+ function->_default_arg_count = function->default_arguments.size() - 1;
function->_default_arg_ptr = &function->default_arguments[0];
} else {
function->_default_arg_count = 0;
function->_default_arg_ptr = nullptr;
}
+ if (operator_func_map.size()) {
+ function->operator_funcs.resize(operator_func_map.size());
+ function->_operator_funcs_count = function->operator_funcs.size();
+ function->_operator_funcs_ptr = function->operator_funcs.ptr();
+ for (const Map<Variant::ValidatedOperatorEvaluator, int>::Element *E = operator_func_map.front(); E; E = E->next()) {
+ function->operator_funcs.write[E->get()] = E->key();
+ }
+ } else {
+ function->_operator_funcs_count = 0;
+ function->_operator_funcs_ptr = nullptr;
+ }
+
+ if (setters_map.size()) {
+ function->setters.resize(setters_map.size());
+ function->_setters_count = function->setters.size();
+ function->_setters_ptr = function->setters.ptr();
+ for (const Map<Variant::ValidatedSetter, int>::Element *E = setters_map.front(); E; E = E->next()) {
+ function->setters.write[E->get()] = E->key();
+ }
+ } else {
+ function->_setters_count = 0;
+ function->_setters_ptr = nullptr;
+ }
+
+ if (getters_map.size()) {
+ function->getters.resize(getters_map.size());
+ function->_getters_count = function->getters.size();
+ function->_getters_ptr = function->getters.ptr();
+ for (const Map<Variant::ValidatedGetter, int>::Element *E = getters_map.front(); E; E = E->next()) {
+ function->getters.write[E->get()] = E->key();
+ }
+ } else {
+ function->_getters_count = 0;
+ function->_getters_ptr = nullptr;
+ }
+
+ if (keyed_setters_map.size()) {
+ function->keyed_setters.resize(keyed_setters_map.size());
+ function->_keyed_setters_count = function->keyed_setters.size();
+ function->_keyed_setters_ptr = function->keyed_setters.ptr();
+ for (const Map<Variant::ValidatedKeyedSetter, int>::Element *E = keyed_setters_map.front(); E; E = E->next()) {
+ function->keyed_setters.write[E->get()] = E->key();
+ }
+ } else {
+ function->_keyed_setters_count = 0;
+ function->_keyed_setters_ptr = nullptr;
+ }
+
+ if (keyed_getters_map.size()) {
+ function->keyed_getters.resize(keyed_getters_map.size());
+ function->_keyed_getters_count = function->keyed_getters.size();
+ function->_keyed_getters_ptr = function->keyed_getters.ptr();
+ for (const Map<Variant::ValidatedKeyedGetter, int>::Element *E = keyed_getters_map.front(); E; E = E->next()) {
+ function->keyed_getters.write[E->get()] = E->key();
+ }
+ } else {
+ function->_keyed_getters_count = 0;
+ function->_keyed_getters_ptr = nullptr;
+ }
+
+ if (indexed_setters_map.size()) {
+ function->indexed_setters.resize(indexed_setters_map.size());
+ function->_indexed_setters_count = function->indexed_setters.size();
+ function->_indexed_setters_ptr = function->indexed_setters.ptr();
+ for (const Map<Variant::ValidatedIndexedSetter, int>::Element *E = indexed_setters_map.front(); E; E = E->next()) {
+ function->indexed_setters.write[E->get()] = E->key();
+ }
+ } else {
+ function->_indexed_setters_count = 0;
+ function->_indexed_setters_ptr = nullptr;
+ }
+
+ if (indexed_getters_map.size()) {
+ function->indexed_getters.resize(indexed_getters_map.size());
+ function->_indexed_getters_count = function->indexed_getters.size();
+ function->_indexed_getters_ptr = function->indexed_getters.ptr();
+ for (const Map<Variant::ValidatedIndexedGetter, int>::Element *E = indexed_getters_map.front(); E; E = E->next()) {
+ function->indexed_getters.write[E->get()] = E->key();
+ }
+ } else {
+ function->_indexed_getters_count = 0;
+ function->_indexed_getters_ptr = nullptr;
+ }
+
+ if (builtin_method_map.size()) {
+ function->builtin_methods.resize(builtin_method_map.size());
+ function->_builtin_methods_ptr = function->builtin_methods.ptr();
+ function->_builtin_methods_count = builtin_method_map.size();
+ for (const Map<Variant::ValidatedBuiltInMethod, int>::Element *E = builtin_method_map.front(); E; E = E->next()) {
+ function->builtin_methods.write[E->get()] = E->key();
+ }
+ } else {
+ function->_builtin_methods_ptr = nullptr;
+ function->_builtin_methods_count = 0;
+ }
+
+ if (constructors_map.size()) {
+ function->constructors.resize(constructors_map.size());
+ function->_constructors_ptr = function->constructors.ptr();
+ function->_constructors_count = constructors_map.size();
+ for (const Map<Variant::ValidatedConstructor, int>::Element *E = constructors_map.front(); E; E = E->next()) {
+ function->constructors.write[E->get()] = E->key();
+ }
+ } else {
+ function->_constructors_ptr = nullptr;
+ function->_constructors_count = 0;
+ }
+
+ if (utilities_map.size()) {
+ function->utilities.resize(utilities_map.size());
+ function->_utilities_ptr = function->utilities.ptr();
+ function->_utilities_count = utilities_map.size();
+ for (const Map<Variant::ValidatedUtilityFunction, int>::Element *E = utilities_map.front(); E; E = E->next()) {
+ function->utilities.write[E->get()] = E->key();
+ }
+ } else {
+ function->_utilities_ptr = nullptr;
+ function->_utilities_count = 0;
+ }
+
+ if (gds_utilities_map.size()) {
+ function->gds_utilities.resize(gds_utilities_map.size());
+ function->_gds_utilities_ptr = function->gds_utilities.ptr();
+ function->_gds_utilities_count = gds_utilities_map.size();
+ for (const Map<GDScriptUtilityFunctions::FunctionPtr, int>::Element *E = gds_utilities_map.front(); E; E = E->next()) {
+ function->gds_utilities.write[E->get()] = E->key();
+ }
+ } else {
+ function->_gds_utilities_ptr = nullptr;
+ function->_gds_utilities_count = 0;
+ }
+
+ if (method_bind_map.size()) {
+ function->methods.resize(method_bind_map.size());
+ function->_methods_ptr = function->methods.ptrw();
+ function->_methods_count = method_bind_map.size();
+ for (const Map<MethodBind *, int>::Element *E = method_bind_map.front(); E; E = E->next()) {
+ function->methods.write[E->get()] = E->key();
+ }
+ } else {
+ function->_methods_ptr = nullptr;
+ function->_methods_count = 0;
+ }
+
if (debug_stack) {
function->stack_debug = stack_debug;
}
function->_stack_size = stack_max;
- function->_call_size = call_max;
+ function->_instruction_args_size = instr_args_max;
+ function->_ptrcall_args_size = ptrcall_max;
ended = true;
return function;
@@ -178,37 +340,77 @@ void GDScriptByteCodeGenerator::set_initial_line(int p_line) {
function->_initial_line = p_line;
}
-void GDScriptByteCodeGenerator::write_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) {
- append(GDScriptFunction::OPCODE_OPERATOR);
+#define HAS_BUILTIN_TYPE(m_var) \
+ (m_var.type.has_type && m_var.type.kind == GDScriptDataType::BUILTIN)
+
+#define IS_BUILTIN_TYPE(m_var, m_type) \
+ (m_var.type.has_type && m_var.type.kind == GDScriptDataType::BUILTIN && m_var.type.builtin_type == m_type)
+
+void GDScriptByteCodeGenerator::write_unary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand) {
+ if (HAS_BUILTIN_TYPE(p_left_operand)) {
+ // Gather specific operator.
+ Variant::ValidatedOperatorEvaluator op_func = Variant::get_validated_operator_evaluator(p_operator, p_left_operand.type.builtin_type, Variant::NIL);
+
+ append(GDScriptFunction::OPCODE_OPERATOR_VALIDATED, 3);
+ append(p_left_operand);
+ append(Address());
+ append(p_target);
+ append(op_func);
+ return;
+ }
+
+ // No specific types, perform variant evaluation.
+ append(GDScriptFunction::OPCODE_OPERATOR, 3);
+ append(p_left_operand);
+ append(Address());
+ append(p_target);
append(p_operator);
+}
+
+void GDScriptByteCodeGenerator::write_binary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) {
+ if (HAS_BUILTIN_TYPE(p_left_operand) && HAS_BUILTIN_TYPE(p_right_operand)) {
+ // Gather specific operator.
+ Variant::ValidatedOperatorEvaluator op_func = Variant::get_validated_operator_evaluator(p_operator, p_left_operand.type.builtin_type, p_right_operand.type.builtin_type);
+
+ append(GDScriptFunction::OPCODE_OPERATOR_VALIDATED, 3);
+ append(p_left_operand);
+ append(p_right_operand);
+ append(p_target);
+ append(op_func);
+ return;
+ }
+
+ // No specific types, perform variant evaluation.
+ append(GDScriptFunction::OPCODE_OPERATOR, 3);
append(p_left_operand);
append(p_right_operand);
append(p_target);
+ append(p_operator);
}
void GDScriptByteCodeGenerator::write_type_test(const Address &p_target, const Address &p_source, const Address &p_type) {
- append(GDScriptFunction::OPCODE_EXTENDS_TEST);
+ append(GDScriptFunction::OPCODE_EXTENDS_TEST, 3);
append(p_source);
append(p_type);
append(p_target);
}
void GDScriptByteCodeGenerator::write_type_test_builtin(const Address &p_target, const Address &p_source, Variant::Type p_type) {
- append(GDScriptFunction::OPCODE_IS_BUILTIN);
+ append(GDScriptFunction::OPCODE_IS_BUILTIN, 3);
append(p_source);
- append(p_type);
append(p_target);
+ append(p_type);
}
void GDScriptByteCodeGenerator::write_and_left_operand(const Address &p_left_operand) {
- append(GDScriptFunction::OPCODE_JUMP_IF_NOT);
+ append(GDScriptFunction::OPCODE_JUMP_IF_NOT, 1);
append(p_left_operand);
logic_op_jump_pos1.push_back(opcodes.size());
append(0); // Jump target, will be patched.
}
void GDScriptByteCodeGenerator::write_and_right_operand(const Address &p_right_operand) {
- append(GDScriptFunction::OPCODE_JUMP_IF_NOT);
+ append(GDScriptFunction::OPCODE_JUMP_IF_NOT, 1);
append(p_right_operand);
logic_op_jump_pos2.push_back(opcodes.size());
append(0); // Jump target, will be patched.
@@ -216,29 +418,29 @@ void GDScriptByteCodeGenerator::write_and_right_operand(const Address &p_right_o
void GDScriptByteCodeGenerator::write_end_and(const Address &p_target) {
// If here means both operands are true.
- append(GDScriptFunction::OPCODE_ASSIGN_TRUE);
+ append(GDScriptFunction::OPCODE_ASSIGN_TRUE, 1);
append(p_target);
// Jump away from the fail condition.
- append(GDScriptFunction::OPCODE_JUMP);
+ append(GDScriptFunction::OPCODE_JUMP, 0);
append(opcodes.size() + 3);
// Here it means one of operands is false.
patch_jump(logic_op_jump_pos1.back()->get());
patch_jump(logic_op_jump_pos2.back()->get());
logic_op_jump_pos1.pop_back();
logic_op_jump_pos2.pop_back();
- append(GDScriptFunction::OPCODE_ASSIGN_FALSE);
+ append(GDScriptFunction::OPCODE_ASSIGN_FALSE, 1);
append(p_target);
}
void GDScriptByteCodeGenerator::write_or_left_operand(const Address &p_left_operand) {
- append(GDScriptFunction::OPCODE_JUMP_IF);
+ append(GDScriptFunction::OPCODE_JUMP_IF, 1);
append(p_left_operand);
logic_op_jump_pos1.push_back(opcodes.size());
append(0); // Jump target, will be patched.
}
void GDScriptByteCodeGenerator::write_or_right_operand(const Address &p_right_operand) {
- append(GDScriptFunction::OPCODE_JUMP_IF);
+ append(GDScriptFunction::OPCODE_JUMP_IF, 1);
append(p_right_operand);
logic_op_jump_pos2.push_back(opcodes.size());
append(0); // Jump target, will be patched.
@@ -246,17 +448,17 @@ void GDScriptByteCodeGenerator::write_or_right_operand(const Address &p_right_op
void GDScriptByteCodeGenerator::write_end_or(const Address &p_target) {
// If here means both operands are false.
- append(GDScriptFunction::OPCODE_ASSIGN_FALSE);
+ append(GDScriptFunction::OPCODE_ASSIGN_FALSE, 1);
append(p_target);
// Jump away from the success condition.
- append(GDScriptFunction::OPCODE_JUMP);
+ append(GDScriptFunction::OPCODE_JUMP, 0);
append(opcodes.size() + 3);
- // Here it means one of operands is false.
+ // Here it means one of operands is true.
patch_jump(logic_op_jump_pos1.back()->get());
patch_jump(logic_op_jump_pos2.back()->get());
logic_op_jump_pos1.pop_back();
logic_op_jump_pos2.pop_back();
- append(GDScriptFunction::OPCODE_ASSIGN_TRUE);
+ append(GDScriptFunction::OPCODE_ASSIGN_TRUE, 1);
append(p_target);
}
@@ -265,18 +467,18 @@ void GDScriptByteCodeGenerator::write_start_ternary(const Address &p_target) {
}
void GDScriptByteCodeGenerator::write_ternary_condition(const Address &p_condition) {
- append(GDScriptFunction::OPCODE_JUMP_IF_NOT);
+ append(GDScriptFunction::OPCODE_JUMP_IF_NOT, 1);
append(p_condition);
ternary_jump_fail_pos.push_back(opcodes.size());
append(0); // Jump target, will be patched.
}
void GDScriptByteCodeGenerator::write_ternary_true_expr(const Address &p_expr) {
- append(GDScriptFunction::OPCODE_ASSIGN);
+ append(GDScriptFunction::OPCODE_ASSIGN, 2);
append(ternary_result.back()->get());
append(p_expr);
// Jump away from the false path.
- append(GDScriptFunction::OPCODE_JUMP);
+ append(GDScriptFunction::OPCODE_JUMP, 0);
ternary_jump_skip_pos.push_back(opcodes.size());
append(0);
// Fail must jump here.
@@ -285,7 +487,7 @@ void GDScriptByteCodeGenerator::write_ternary_true_expr(const Address &p_expr) {
}
void GDScriptByteCodeGenerator::write_ternary_false_expr(const Address &p_expr) {
- append(GDScriptFunction::OPCODE_ASSIGN);
+ append(GDScriptFunction::OPCODE_ASSIGN, 2);
append(ternary_result.back()->get());
append(p_expr);
}
@@ -296,43 +498,100 @@ void GDScriptByteCodeGenerator::write_end_ternary() {
}
void GDScriptByteCodeGenerator::write_set(const Address &p_target, const Address &p_index, const Address &p_source) {
- append(GDScriptFunction::OPCODE_SET);
+ if (HAS_BUILTIN_TYPE(p_target)) {
+ if (IS_BUILTIN_TYPE(p_index, Variant::INT) && Variant::get_member_validated_indexed_setter(p_target.type.builtin_type)) {
+ // Use indexed setter instead.
+ Variant::ValidatedIndexedSetter setter = Variant::get_member_validated_indexed_setter(p_target.type.builtin_type);
+ append(GDScriptFunction::OPCODE_SET_INDEXED_VALIDATED, 3);
+ append(p_target);
+ append(p_index);
+ append(p_source);
+ append(setter);
+ return;
+ } else if (Variant::get_member_validated_keyed_setter(p_target.type.builtin_type)) {
+ Variant::ValidatedKeyedSetter setter = Variant::get_member_validated_keyed_setter(p_target.type.builtin_type);
+ append(GDScriptFunction::OPCODE_SET_KEYED_VALIDATED, 3);
+ append(p_target);
+ append(p_index);
+ append(p_source);
+ append(setter);
+ return;
+ }
+ }
+
+ append(GDScriptFunction::OPCODE_SET_KEYED, 3);
append(p_target);
append(p_index);
append(p_source);
}
void GDScriptByteCodeGenerator::write_get(const Address &p_target, const Address &p_index, const Address &p_source) {
- append(GDScriptFunction::OPCODE_GET);
+ if (HAS_BUILTIN_TYPE(p_source)) {
+ if (IS_BUILTIN_TYPE(p_index, Variant::INT) && Variant::get_member_validated_indexed_getter(p_source.type.builtin_type)) {
+ // Use indexed getter instead.
+ Variant::ValidatedIndexedGetter getter = Variant::get_member_validated_indexed_getter(p_source.type.builtin_type);
+ append(GDScriptFunction::OPCODE_GET_INDEXED_VALIDATED, 3);
+ append(p_source);
+ append(p_index);
+ append(p_target);
+ append(getter);
+ return;
+ } else if (Variant::get_member_validated_keyed_getter(p_source.type.builtin_type)) {
+ Variant::ValidatedKeyedGetter getter = Variant::get_member_validated_keyed_getter(p_source.type.builtin_type);
+ append(GDScriptFunction::OPCODE_GET_KEYED_VALIDATED, 3);
+ append(p_source);
+ append(p_index);
+ append(p_target);
+ append(getter);
+ return;
+ }
+ }
+ append(GDScriptFunction::OPCODE_GET_KEYED, 3);
append(p_source);
append(p_index);
append(p_target);
}
void GDScriptByteCodeGenerator::write_set_named(const Address &p_target, const StringName &p_name, const Address &p_source) {
- append(GDScriptFunction::OPCODE_SET_NAMED);
+ if (HAS_BUILTIN_TYPE(p_target) && Variant::get_member_validated_setter(p_target.type.builtin_type, p_name)) {
+ Variant::ValidatedSetter setter = Variant::get_member_validated_setter(p_target.type.builtin_type, p_name);
+ append(GDScriptFunction::OPCODE_SET_NAMED_VALIDATED, 2);
+ append(p_target);
+ append(p_source);
+ append(setter);
+ return;
+ }
+ append(GDScriptFunction::OPCODE_SET_NAMED, 2);
append(p_target);
- append(p_name);
append(p_source);
+ append(p_name);
}
void GDScriptByteCodeGenerator::write_get_named(const Address &p_target, const StringName &p_name, const Address &p_source) {
- append(GDScriptFunction::OPCODE_GET_NAMED);
+ if (HAS_BUILTIN_TYPE(p_source) && Variant::get_member_validated_getter(p_source.type.builtin_type, p_name)) {
+ Variant::ValidatedGetter getter = Variant::get_member_validated_getter(p_source.type.builtin_type, p_name);
+ append(GDScriptFunction::OPCODE_GET_NAMED_VALIDATED, 2);
+ append(p_source);
+ append(p_target);
+ append(getter);
+ return;
+ }
+ append(GDScriptFunction::OPCODE_GET_NAMED, 2);
append(p_source);
- append(p_name);
append(p_target);
+ append(p_name);
}
void GDScriptByteCodeGenerator::write_set_member(const Address &p_value, const StringName &p_name) {
- append(GDScriptFunction::OPCODE_SET_MEMBER);
- append(p_name);
+ append(GDScriptFunction::OPCODE_SET_MEMBER, 1);
append(p_value);
+ append(p_name);
}
void GDScriptByteCodeGenerator::write_get_member(const Address &p_target, const StringName &p_name) {
- append(GDScriptFunction::OPCODE_GET_MEMBER);
- append(p_name);
+ append(GDScriptFunction::OPCODE_GET_MEMBER, 1);
append(p_target);
+ append(p_name);
}
void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Address &p_source) {
@@ -340,34 +599,35 @@ void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Addr
// Typed assignment.
switch (p_target.type.kind) {
case GDScriptDataType::BUILTIN: {
- append(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN);
- append(p_target.type.builtin_type);
+ append(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN, 2);
append(p_target);
append(p_source);
+ append(p_target.type.builtin_type);
} break;
case GDScriptDataType::NATIVE: {
int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_target.type.native_type];
class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS);
- append(GDScriptFunction::OPCODE_ASSIGN_TYPED_NATIVE);
- append(class_idx);
+ append(GDScriptFunction::OPCODE_ASSIGN_TYPED_NATIVE, 3);
append(p_target);
append(p_source);
+ append(class_idx);
} break;
case GDScriptDataType::SCRIPT:
case GDScriptDataType::GDSCRIPT: {
Variant script = p_target.type.script_type;
int idx = get_constant_pos(script);
+ idx |= (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
- append(GDScriptFunction::OPCODE_ASSIGN_TYPED_SCRIPT);
- append(idx);
+ append(GDScriptFunction::OPCODE_ASSIGN_TYPED_SCRIPT, 3);
append(p_target);
append(p_source);
+ append(idx);
} break;
default: {
ERR_PRINT("Compiler bug: unresolved assign.");
// Shouldn't get here, but fail-safe to a regular assignment
- append(GDScriptFunction::OPCODE_ASSIGN);
+ append(GDScriptFunction::OPCODE_ASSIGN, 2);
append(p_target);
append(p_source);
}
@@ -375,13 +635,13 @@ void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Addr
} else {
if (p_target.type.kind == GDScriptDataType::BUILTIN && p_source.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type != p_source.type.builtin_type) {
// Need conversion..
- append(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN);
- append(p_target.type.builtin_type);
+ append(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN, 2);
append(p_target);
append(p_source);
+ append(p_target.type.builtin_type);
} else {
// Either untyped assignment or already type-checked by the parser
- append(GDScriptFunction::OPCODE_ASSIGN);
+ append(GDScriptFunction::OPCODE_ASSIGN, 2);
append(p_target);
append(p_source);
}
@@ -389,34 +649,42 @@ void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Addr
}
void GDScriptByteCodeGenerator::write_assign_true(const Address &p_target) {
- append(GDScriptFunction::OPCODE_ASSIGN_TRUE);
+ append(GDScriptFunction::OPCODE_ASSIGN_TRUE, 1);
append(p_target);
}
void GDScriptByteCodeGenerator::write_assign_false(const Address &p_target) {
- append(GDScriptFunction::OPCODE_ASSIGN_FALSE);
+ append(GDScriptFunction::OPCODE_ASSIGN_FALSE, 1);
append(p_target);
}
+void GDScriptByteCodeGenerator::write_assign_default_parameter(const Address &p_dst, const Address &p_src) {
+ write_assign(p_dst, p_src);
+ function->default_arguments.push_back(opcodes.size());
+}
+
void GDScriptByteCodeGenerator::write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) {
+ int index = 0;
+
switch (p_type.kind) {
case GDScriptDataType::BUILTIN: {
- append(GDScriptFunction::OPCODE_CAST_TO_BUILTIN);
- append(p_type.builtin_type);
+ append(GDScriptFunction::OPCODE_CAST_TO_BUILTIN, 2);
+ index = p_type.builtin_type;
} break;
case GDScriptDataType::NATIVE: {
int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_type.native_type];
class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS);
- append(GDScriptFunction::OPCODE_CAST_TO_NATIVE);
- append(class_idx);
+ append(GDScriptFunction::OPCODE_CAST_TO_NATIVE, 3);
+ index = class_idx;
} break;
case GDScriptDataType::SCRIPT:
case GDScriptDataType::GDSCRIPT: {
Variant script = p_type.script_type;
int idx = get_constant_pos(script);
+ idx |= (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
- append(GDScriptFunction::OPCODE_CAST_TO_SCRIPT);
- append(idx);
+ append(GDScriptFunction::OPCODE_CAST_TO_SCRIPT, 3);
+ index = idx;
} break;
default: {
return;
@@ -425,147 +693,318 @@ void GDScriptByteCodeGenerator::write_cast(const Address &p_target, const Addres
append(p_source);
append(p_target);
+ append(index);
}
void GDScriptByteCodeGenerator::write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) {
- append(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN);
- append(p_arguments.size());
- append(p_base);
- append(p_function_name);
+ append(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN, 2 + p_arguments.size());
for (int i = 0; i < p_arguments.size(); i++) {
append(p_arguments[i]);
}
+ append(p_base);
append(p_target);
- alloc_call(p_arguments.size());
+ append(p_arguments.size());
+ append(p_function_name);
}
void GDScriptByteCodeGenerator::write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) {
- append(GDScriptFunction::OPCODE_CALL_SELF_BASE);
- append(p_function_name);
- append(p_arguments.size());
+ append(GDScriptFunction::OPCODE_CALL_SELF_BASE, 1 + p_arguments.size());
for (int i = 0; i < p_arguments.size(); i++) {
append(p_arguments[i]);
}
append(p_target);
- alloc_call(p_arguments.size());
+ append(p_arguments.size());
+ append(p_function_name);
}
void GDScriptByteCodeGenerator::write_call_async(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) {
- append(GDScriptFunction::OPCODE_CALL_ASYNC);
- append(p_arguments.size());
- append(p_base);
- append(p_function_name);
+ append(GDScriptFunction::OPCODE_CALL_ASYNC, 2 + p_arguments.size());
for (int i = 0; i < p_arguments.size(); i++) {
append(p_arguments[i]);
}
+ append(p_base);
append(p_target);
- alloc_call(p_arguments.size());
+ append(p_arguments.size());
+ append(p_function_name);
}
-void GDScriptByteCodeGenerator::write_call_builtin(const Address &p_target, GDScriptFunctions::Function p_function, const Vector<Address> &p_arguments) {
- append(GDScriptFunction::OPCODE_CALL_BUILT_IN);
- append(p_function);
- append(p_arguments.size());
+void GDScriptByteCodeGenerator::write_call_gdscript_utility(const Address &p_target, GDScriptUtilityFunctions::FunctionPtr p_function, const Vector<Address> &p_arguments) {
+ append(GDScriptFunction::OPCODE_CALL_GDSCRIPT_UTILITY, 1 + p_arguments.size());
for (int i = 0; i < p_arguments.size(); i++) {
append(p_arguments[i]);
}
append(p_target);
- alloc_call(p_arguments.size());
+ append(p_arguments.size());
+ append(p_function);
}
-void GDScriptByteCodeGenerator::write_call_method_bind(const Address &p_target, const Address &p_base, const MethodBind *p_method, const Vector<Address> &p_arguments) {
- append(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN);
- append(p_arguments.size());
- append(p_base);
- append(p_method->get_name());
+void GDScriptByteCodeGenerator::write_call_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) {
+ bool is_validated = true;
+ if (Variant::is_utility_function_vararg(p_function)) {
+ is_validated = true; // Vararg works fine with any argument, since they can be any type.
+ } else if (p_arguments.size() == Variant::get_utility_function_argument_count(p_function)) {
+ bool all_types_exact = true;
+ for (int i = 0; i < p_arguments.size(); i++) {
+ if (!IS_BUILTIN_TYPE(p_arguments[i], Variant::get_utility_function_argument_type(p_function, i))) {
+ all_types_exact = false;
+ break;
+ }
+ }
+
+ is_validated = all_types_exact;
+ }
+
+ if (is_validated) {
+ append(GDScriptFunction::OPCODE_CALL_UTILITY_VALIDATED, 1 + p_arguments.size());
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(p_target);
+ append(p_arguments.size());
+ append(Variant::get_validated_utility_function(p_function));
+ } else {
+ append(GDScriptFunction::OPCODE_CALL_UTILITY, 1 + p_arguments.size());
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(p_target);
+ append(p_arguments.size());
+ append(p_function);
+ }
+}
+
+void GDScriptByteCodeGenerator::write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) {
+ bool is_validated = false;
+
+ // Check if all types are correct.
+ if (Variant::is_builtin_method_vararg(p_type, p_method)) {
+ is_validated = true; // Vararg works fine with any argument, since they can be any type.
+ } else if (p_arguments.size() == Variant::get_builtin_method_argument_count(p_type, p_method)) {
+ bool all_types_exact = true;
+ for (int i = 0; i < p_arguments.size(); i++) {
+ if (!IS_BUILTIN_TYPE(p_arguments[i], Variant::get_builtin_method_argument_type(p_type, p_method, i))) {
+ all_types_exact = false;
+ break;
+ }
+ }
+
+ is_validated = all_types_exact;
+ }
+
+ if (!is_validated) {
+ // Perform regular call.
+ write_call(p_target, p_base, p_method, p_arguments);
+ return;
+ }
+
+ append(GDScriptFunction::OPCODE_CALL_BUILTIN_TYPE_VALIDATED, 2 + p_arguments.size());
+
for (int i = 0; i < p_arguments.size(); i++) {
append(p_arguments[i]);
}
+ append(p_base);
append(p_target);
- alloc_call(p_arguments.size());
+ append(p_arguments.size());
+ append(Variant::get_validated_builtin_method(p_type, p_method));
}
-void GDScriptByteCodeGenerator::write_call_ptrcall(const Address &p_target, const Address &p_base, const MethodBind *p_method, const Vector<Address> &p_arguments) {
- append(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN);
- append(p_arguments.size());
+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++) {
+ append(p_arguments[i]);
+ }
append(p_base);
- append(p_method->get_name());
+ append(p_target);
+ append(p_arguments.size());
+ append(p_method);
+}
+
+void GDScriptByteCodeGenerator::write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) {
+#define CASE_TYPE(m_type) \
+ case Variant::m_type: \
+ append(GDScriptFunction::OPCODE_CALL_PTRCALL_##m_type, 2 + p_arguments.size()); \
+ break
+
+ bool is_ptrcall = true;
+
+ if (p_method->has_return()) {
+ MethodInfo info;
+ ClassDB::get_method_info(p_method->get_instance_class(), p_method->get_name(), &info);
+ switch (info.return_val.type) {
+ CASE_TYPE(BOOL);
+ CASE_TYPE(INT);
+ CASE_TYPE(FLOAT);
+ CASE_TYPE(STRING);
+ CASE_TYPE(VECTOR2);
+ CASE_TYPE(VECTOR2I);
+ CASE_TYPE(RECT2);
+ CASE_TYPE(RECT2I);
+ CASE_TYPE(VECTOR3);
+ CASE_TYPE(VECTOR3I);
+ CASE_TYPE(TRANSFORM2D);
+ CASE_TYPE(PLANE);
+ CASE_TYPE(AABB);
+ CASE_TYPE(BASIS);
+ CASE_TYPE(TRANSFORM);
+ CASE_TYPE(COLOR);
+ CASE_TYPE(STRING_NAME);
+ CASE_TYPE(NODE_PATH);
+ CASE_TYPE(RID);
+ CASE_TYPE(QUAT);
+ CASE_TYPE(OBJECT);
+ CASE_TYPE(CALLABLE);
+ CASE_TYPE(SIGNAL);
+ CASE_TYPE(DICTIONARY);
+ CASE_TYPE(ARRAY);
+ CASE_TYPE(PACKED_BYTE_ARRAY);
+ CASE_TYPE(PACKED_INT32_ARRAY);
+ CASE_TYPE(PACKED_INT64_ARRAY);
+ CASE_TYPE(PACKED_FLOAT32_ARRAY);
+ CASE_TYPE(PACKED_FLOAT64_ARRAY);
+ CASE_TYPE(PACKED_STRING_ARRAY);
+ CASE_TYPE(PACKED_VECTOR2_ARRAY);
+ CASE_TYPE(PACKED_VECTOR3_ARRAY);
+ CASE_TYPE(PACKED_COLOR_ARRAY);
+ default:
+ append(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL_METHOD_BIND : GDScriptFunction::OPCODE_CALL_METHOD_BIND_RET, 2 + p_arguments.size());
+ is_ptrcall = false;
+ break;
+ }
+ } else {
+ append(GDScriptFunction::OPCODE_CALL_PTRCALL_NO_RETURN, 2 + p_arguments.size());
+ }
+
for (int i = 0; i < p_arguments.size(); i++) {
append(p_arguments[i]);
}
+ append(p_base);
append(p_target);
- alloc_call(p_arguments.size());
+ append(p_arguments.size());
+ append(p_method);
+ if (is_ptrcall) {
+ alloc_ptrcall(p_arguments.size());
+ }
+
+#undef CASE_TYPE
}
void GDScriptByteCodeGenerator::write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) {
- append(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN);
- append(p_arguments.size());
+ append(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN, 2 + p_arguments.size());
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
append(GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS);
+ append(p_target);
+ append(p_arguments.size());
append(p_function_name);
+}
+
+void GDScriptByteCodeGenerator::write_call_self_async(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) {
+ append(GDScriptFunction::OPCODE_CALL_ASYNC, 2 + p_arguments.size());
for (int i = 0; i < p_arguments.size(); i++) {
append(p_arguments[i]);
}
+ append(GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS);
append(p_target);
- alloc_call(p_arguments.size());
+ append(p_arguments.size());
+ append(p_function_name);
}
void GDScriptByteCodeGenerator::write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) {
- append(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN);
- append(p_arguments.size());
- append(p_base);
- append(p_function_name);
+ append(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN, 2 + p_arguments.size());
for (int i = 0; i < p_arguments.size(); i++) {
append(p_arguments[i]);
}
+ append(p_base);
append(p_target);
- alloc_call(p_arguments.size());
+ append(p_arguments.size());
+ append(p_function_name);
}
void GDScriptByteCodeGenerator::write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) {
- append(GDScriptFunction::OPCODE_CONSTRUCT);
- append(p_type);
- append(p_arguments.size());
+ // Try to find an appropriate constructor.
+ bool all_have_type = true;
+ Vector<Variant::Type> arg_types;
+ for (int i = 0; i < p_arguments.size(); i++) {
+ if (!HAS_BUILTIN_TYPE(p_arguments[i])) {
+ all_have_type = false;
+ break;
+ }
+ arg_types.push_back(p_arguments[i].type.builtin_type);
+ }
+ if (all_have_type) {
+ int valid_constructor = -1;
+ for (int i = 0; i < Variant::get_constructor_count(p_type); i++) {
+ if (Variant::get_constructor_argument_count(p_type, i) != p_arguments.size()) {
+ continue;
+ }
+ int types_correct = true;
+ for (int j = 0; j < arg_types.size(); j++) {
+ if (arg_types[j] != Variant::get_constructor_argument_type(p_type, i, j)) {
+ types_correct = false;
+ break;
+ }
+ }
+ if (types_correct) {
+ valid_constructor = i;
+ break;
+ }
+ }
+ if (valid_constructor >= 0) {
+ append(GDScriptFunction::OPCODE_CONSTRUCT_VALIDATED, 1 + p_arguments.size());
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(p_target);
+ append(p_arguments.size());
+ append(Variant::get_validated_constructor(p_type, valid_constructor));
+ return;
+ }
+ }
+
+ append(GDScriptFunction::OPCODE_CONSTRUCT, 1 + p_arguments.size());
for (int i = 0; i < p_arguments.size(); i++) {
append(p_arguments[i]);
}
append(p_target);
- alloc_call(p_arguments.size());
+ append(p_arguments.size());
+ append(p_type);
}
void GDScriptByteCodeGenerator::write_construct_array(const Address &p_target, const Vector<Address> &p_arguments) {
- append(GDScriptFunction::OPCODE_CONSTRUCT_ARRAY);
- append(p_arguments.size());
+ append(GDScriptFunction::OPCODE_CONSTRUCT_ARRAY, 1 + p_arguments.size());
for (int i = 0; i < p_arguments.size(); i++) {
append(p_arguments[i]);
}
append(p_target);
+ append(p_arguments.size());
}
void GDScriptByteCodeGenerator::write_construct_dictionary(const Address &p_target, const Vector<Address> &p_arguments) {
- append(GDScriptFunction::OPCODE_CONSTRUCT_DICTIONARY);
- append(p_arguments.size() / 2); // This is number of key-value pairs, so only half of actual arguments.
+ append(GDScriptFunction::OPCODE_CONSTRUCT_DICTIONARY, 1 + p_arguments.size());
for (int i = 0; i < p_arguments.size(); i++) {
append(p_arguments[i]);
}
append(p_target);
+ append(p_arguments.size() / 2); // This is number of key-value pairs, so only half of actual arguments.
}
void GDScriptByteCodeGenerator::write_await(const Address &p_target, const Address &p_operand) {
- append(GDScriptFunction::OPCODE_AWAIT);
+ append(GDScriptFunction::OPCODE_AWAIT, 1);
append(p_operand);
- append(GDScriptFunction::OPCODE_AWAIT_RESUME);
+ append(GDScriptFunction::OPCODE_AWAIT_RESUME, 1);
append(p_target);
}
void GDScriptByteCodeGenerator::write_if(const Address &p_condition) {
- append(GDScriptFunction::OPCODE_JUMP_IF_NOT);
+ append(GDScriptFunction::OPCODE_JUMP_IF_NOT, 1);
append(p_condition);
if_jmp_addrs.push_back(opcodes.size());
append(0); // Jump destination, will be patched.
}
void GDScriptByteCodeGenerator::write_else() {
- append(GDScriptFunction::OPCODE_JUMP); // Jump from true if block;
+ append(GDScriptFunction::OPCODE_JUMP, 0); // Jump from true if block;
int else_jmp_addr = opcodes.size();
append(0); // Jump destination, will be patched.
@@ -579,41 +1018,144 @@ void GDScriptByteCodeGenerator::write_endif() {
if_jmp_addrs.pop_back();
}
-void GDScriptByteCodeGenerator::write_for(const Address &p_variable, const Address &p_list) {
- int counter_pos = increase_stack() | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
- int container_pos = increase_stack() | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
+void GDScriptByteCodeGenerator::start_for(const GDScriptDataType &p_iterator_type, const GDScriptDataType &p_list_type) {
+ Address counter(Address::LOCAL_VARIABLE, add_local("@counter_pos", p_iterator_type), p_iterator_type);
+ Address container(Address::LOCAL_VARIABLE, add_local("@container_pos", p_list_type), p_list_type);
- current_breaks_to_patch.push_back(List<int>());
+ // Store state.
+ for_counter_variables.push_back(counter);
+ for_container_variables.push_back(container);
+}
+
+void GDScriptByteCodeGenerator::write_for_assignment(const Address &p_variable, const Address &p_list) {
+ const Address &container = for_container_variables.back()->get();
// Assign container.
- append(GDScriptFunction::OPCODE_ASSIGN);
- append(container_pos);
+ append(GDScriptFunction::OPCODE_ASSIGN, 2);
+ append(container);
append(p_list);
+ for_iterator_variables.push_back(p_variable);
+}
+
+void GDScriptByteCodeGenerator::write_for() {
+ const Address &iterator = for_iterator_variables.back()->get();
+ const Address &counter = for_counter_variables.back()->get();
+ const Address &container = for_container_variables.back()->get();
+
+ current_breaks_to_patch.push_back(List<int>());
+
+ GDScriptFunction::Opcode begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN;
+ GDScriptFunction::Opcode iterate_opcode = GDScriptFunction::OPCODE_ITERATE;
+
+ if (container.type.has_type) {
+ if (container.type.kind == GDScriptDataType::BUILTIN) {
+ switch (container.type.builtin_type) {
+ case Variant::INT:
+ begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_INT;
+ iterate_opcode = GDScriptFunction::OPCODE_ITERATE_INT;
+ break;
+ case Variant::FLOAT:
+ begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_FLOAT;
+ iterate_opcode = GDScriptFunction::OPCODE_ITERATE_FLOAT;
+ break;
+ case Variant::VECTOR2:
+ begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_VECTOR2;
+ iterate_opcode = GDScriptFunction::OPCODE_ITERATE_VECTOR2;
+ break;
+ case Variant::VECTOR2I:
+ begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_VECTOR2I;
+ iterate_opcode = GDScriptFunction::OPCODE_ITERATE_VECTOR2I;
+ break;
+ case Variant::VECTOR3:
+ begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_VECTOR3;
+ iterate_opcode = GDScriptFunction::OPCODE_ITERATE_VECTOR3;
+ break;
+ case Variant::VECTOR3I:
+ begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_VECTOR3I;
+ iterate_opcode = GDScriptFunction::OPCODE_ITERATE_VECTOR3I;
+ break;
+ case Variant::STRING:
+ begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_STRING;
+ iterate_opcode = GDScriptFunction::OPCODE_ITERATE_STRING;
+ break;
+ case Variant::DICTIONARY:
+ begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_DICTIONARY;
+ iterate_opcode = GDScriptFunction::OPCODE_ITERATE_DICTIONARY;
+ break;
+ case Variant::ARRAY:
+ begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_ARRAY;
+ iterate_opcode = GDScriptFunction::OPCODE_ITERATE_ARRAY;
+ break;
+ case Variant::PACKED_BYTE_ARRAY:
+ begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_BYTE_ARRAY;
+ iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_BYTE_ARRAY;
+ break;
+ case Variant::PACKED_INT32_ARRAY:
+ begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_INT32_ARRAY;
+ iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_INT32_ARRAY;
+ break;
+ case Variant::PACKED_INT64_ARRAY:
+ begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_INT64_ARRAY;
+ iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_INT64_ARRAY;
+ break;
+ case Variant::PACKED_FLOAT32_ARRAY:
+ begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_FLOAT32_ARRAY;
+ iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_FLOAT32_ARRAY;
+ break;
+ case Variant::PACKED_FLOAT64_ARRAY:
+ begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_FLOAT64_ARRAY;
+ iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_FLOAT64_ARRAY;
+ break;
+ case Variant::PACKED_STRING_ARRAY:
+ begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_STRING_ARRAY;
+ iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_STRING_ARRAY;
+ break;
+ case Variant::PACKED_VECTOR2_ARRAY:
+ begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_VECTOR2_ARRAY;
+ iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_VECTOR2_ARRAY;
+ break;
+ case Variant::PACKED_VECTOR3_ARRAY:
+ begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_VECTOR3_ARRAY;
+ iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_VECTOR3_ARRAY;
+ break;
+ case Variant::PACKED_COLOR_ARRAY:
+ begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_COLOR_ARRAY;
+ iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_COLOR_ARRAY;
+ break;
+ default:
+ break;
+ }
+ } else {
+ begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_OBJECT;
+ iterate_opcode = GDScriptFunction::OPCODE_ITERATE_OBJECT;
+ }
+ }
+
// Begin loop.
- append(GDScriptFunction::OPCODE_ITERATE_BEGIN);
- append(counter_pos);
- append(container_pos);
+ append(begin_opcode, 3);
+ append(counter);
+ append(container);
+ append(iterator);
for_jmp_addrs.push_back(opcodes.size());
append(0); // End of loop address, will be patched.
- append(p_variable);
- append(GDScriptFunction::OPCODE_JUMP);
+ append(GDScriptFunction::OPCODE_JUMP, 0);
append(opcodes.size() + 6); // Skip over 'continue' code.
// Next iteration.
int continue_addr = opcodes.size();
continue_addrs.push_back(continue_addr);
- append(GDScriptFunction::OPCODE_ITERATE);
- append(counter_pos);
- append(container_pos);
+ append(iterate_opcode, 3);
+ append(counter);
+ append(container);
+ append(iterator);
for_jmp_addrs.push_back(opcodes.size());
append(0); // Jump destination, will be patched.
- append(p_variable);
}
void GDScriptByteCodeGenerator::write_endfor() {
// Jump back to loop check.
- append(GDScriptFunction::OPCODE_JUMP);
+ append(GDScriptFunction::OPCODE_JUMP, 0);
append(continue_addrs.back()->get());
continue_addrs.pop_back();
@@ -629,7 +1171,10 @@ void GDScriptByteCodeGenerator::write_endfor() {
}
current_breaks_to_patch.pop_back();
- current_stack_size -= 2; // Remove loop temporaries.
+ // Pop state.
+ for_iterator_variables.pop_back();
+ for_counter_variables.pop_back();
+ for_container_variables.pop_back();
}
void GDScriptByteCodeGenerator::start_while_condition() {
@@ -639,7 +1184,7 @@ void GDScriptByteCodeGenerator::start_while_condition() {
void GDScriptByteCodeGenerator::write_while(const Address &p_condition) {
// Condition check.
- append(GDScriptFunction::OPCODE_JUMP_IF_NOT);
+ append(GDScriptFunction::OPCODE_JUMP_IF_NOT, 1);
append(p_condition);
while_jmp_addrs.push_back(opcodes.size());
append(0); // End of loop address, will be patched.
@@ -647,7 +1192,7 @@ void GDScriptByteCodeGenerator::write_while(const Address &p_condition) {
void GDScriptByteCodeGenerator::write_endwhile() {
// Jump back to loop check.
- append(GDScriptFunction::OPCODE_JUMP);
+ append(GDScriptFunction::OPCODE_JUMP, 0);
append(continue_addrs.back()->get());
continue_addrs.pop_back();
@@ -685,39 +1230,39 @@ void GDScriptByteCodeGenerator::end_match() {
}
void GDScriptByteCodeGenerator::write_break() {
- append(GDScriptFunction::OPCODE_JUMP);
+ append(GDScriptFunction::OPCODE_JUMP, 0);
current_breaks_to_patch.back()->get().push_back(opcodes.size());
append(0);
}
void GDScriptByteCodeGenerator::write_continue() {
- append(GDScriptFunction::OPCODE_JUMP);
+ append(GDScriptFunction::OPCODE_JUMP, 0);
append(continue_addrs.back()->get());
}
void GDScriptByteCodeGenerator::write_continue_match() {
- append(GDScriptFunction::OPCODE_JUMP);
+ append(GDScriptFunction::OPCODE_JUMP, 0);
match_continues_to_patch.back()->get().push_back(opcodes.size());
append(0);
}
void GDScriptByteCodeGenerator::write_breakpoint() {
- append(GDScriptFunction::OPCODE_BREAKPOINT);
+ append(GDScriptFunction::OPCODE_BREAKPOINT, 0);
}
void GDScriptByteCodeGenerator::write_newline(int p_line) {
- append(GDScriptFunction::OPCODE_LINE);
+ append(GDScriptFunction::OPCODE_LINE, 0);
append(p_line);
current_line = p_line;
}
void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) {
- append(GDScriptFunction::OPCODE_RETURN);
+ append(GDScriptFunction::OPCODE_RETURN, 1);
append(p_return_value);
}
void GDScriptByteCodeGenerator::write_assert(const Address &p_test, const Address &p_message) {
- append(GDScriptFunction::OPCODE_ASSERT);
+ append(GDScriptFunction::OPCODE_ASSERT, 2);
append(p_test);
append(p_message);
}
diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h
index 62438b6dd2..1e66af269a 100644
--- a/modules/gdscript/gdscript_byte_codegen.h
+++ b/modules/gdscript/gdscript_byte_codegen.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,6 +33,9 @@
#include "gdscript_codegen.h"
+#include "gdscript_function.h"
+#include "gdscript_utility_functions.h"
+
class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
bool ended = false;
GDScriptFunction *function = nullptr;
@@ -41,6 +44,7 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
Vector<int> opcodes;
List<Map<StringName, int>> stack_id_stack;
Map<StringName, int> stack_identifiers;
+ List<int> stack_identifiers_counts;
Map<StringName, int> local_constants;
List<GDScriptFunction::StackDebug> stack_debug;
@@ -49,18 +53,40 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
int current_stack_size = 0;
int current_temporaries = 0;
+ int current_locals = 0;
+ int current_line = 0;
+ int stack_max = 0;
+ int instr_args_max = 0;
+ int ptrcall_max = 0;
+
+#ifdef DEBUG_ENABLED
+ List<int> temp_stack;
+#endif
HashMap<Variant, int, VariantHasher, VariantComparator> constant_map;
Map<StringName, int> name_map;
#ifdef TOOLS_ENABLED
Vector<StringName> named_globals;
#endif
- int current_line = 0;
- int stack_max = 0;
- int call_max = 0;
-
- List<int> if_jmp_addrs; // List since this can be nested.
+ Map<Variant::ValidatedOperatorEvaluator, int> operator_func_map;
+ Map<Variant::ValidatedSetter, int> setters_map;
+ Map<Variant::ValidatedGetter, int> getters_map;
+ Map<Variant::ValidatedKeyedSetter, int> keyed_setters_map;
+ Map<Variant::ValidatedKeyedGetter, int> keyed_getters_map;
+ Map<Variant::ValidatedIndexedSetter, int> indexed_setters_map;
+ Map<Variant::ValidatedIndexedGetter, int> indexed_getters_map;
+ Map<Variant::ValidatedBuiltInMethod, int> builtin_method_map;
+ Map<Variant::ValidatedConstructor, int> constructors_map;
+ Map<Variant::ValidatedUtilityFunction, int> utilities_map;
+ Map<GDScriptUtilityFunctions::FunctionPtr, int> gds_utilities_map;
+ Map<MethodBind *, int> method_bind_map;
+
+ // Lists since these can be nested.
+ List<int> if_jmp_addrs;
List<int> for_jmp_addrs;
+ List<Address> for_iterator_variables;
+ List<Address> for_counter_variables;
+ List<Address> for_container_variables;
List<int> while_jmp_addrs;
List<int> continue_addrs;
@@ -76,6 +102,7 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
List<List<int>> match_continues_to_patch;
void add_stack_identifier(const StringName &p_id, int p_stackpos) {
+ current_locals++;
stack_identifiers[p_id] = p_stackpos;
if (debug_stack) {
block_identifiers[p_id] = p_stackpos;
@@ -89,17 +116,26 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
}
void push_stack_identifiers() {
+ stack_identifiers_counts.push_back(current_locals);
stack_id_stack.push_back(stack_identifiers);
if (debug_stack) {
- block_identifier_stack.push_back(block_identifiers);
+ Map<StringName, int> block_ids(block_identifiers);
+ block_identifier_stack.push_back(block_ids);
block_identifiers.clear();
}
}
void pop_stack_identifiers() {
+ current_locals = stack_identifiers_counts.back()->get();
+ stack_identifiers_counts.pop_back();
stack_identifiers = stack_id_stack.back()->get();
- current_stack_size = stack_identifiers.size() + current_temporaries;
stack_id_stack.pop_back();
+#ifdef DEBUG_ENABLED
+ if (current_temporaries != 0) {
+ ERR_PRINT("Leaving block with non-zero temporary variables: " + itos(current_temporaries));
+ }
+#endif
+ current_stack_size = current_locals;
if (debug_stack) {
for (Map<StringName, int>::Element *E = block_identifiers.front(); E; E = E->next()) {
@@ -134,22 +170,123 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
return pos;
}
+ int get_operation_pos(const Variant::ValidatedOperatorEvaluator p_operation) {
+ if (operator_func_map.has(p_operation))
+ return operator_func_map[p_operation];
+ int pos = operator_func_map.size();
+ operator_func_map[p_operation] = pos;
+ return pos;
+ }
+
+ int get_setter_pos(const Variant::ValidatedSetter p_setter) {
+ if (setters_map.has(p_setter))
+ return setters_map[p_setter];
+ int pos = setters_map.size();
+ setters_map[p_setter] = pos;
+ return pos;
+ }
+
+ int get_getter_pos(const Variant::ValidatedGetter p_getter) {
+ if (getters_map.has(p_getter))
+ return getters_map[p_getter];
+ int pos = getters_map.size();
+ getters_map[p_getter] = pos;
+ return pos;
+ }
+
+ int get_keyed_setter_pos(const Variant::ValidatedKeyedSetter p_keyed_setter) {
+ if (keyed_setters_map.has(p_keyed_setter))
+ return keyed_setters_map[p_keyed_setter];
+ int pos = keyed_setters_map.size();
+ keyed_setters_map[p_keyed_setter] = pos;
+ return pos;
+ }
+
+ int get_keyed_getter_pos(const Variant::ValidatedKeyedGetter p_keyed_getter) {
+ if (keyed_getters_map.has(p_keyed_getter))
+ return keyed_getters_map[p_keyed_getter];
+ int pos = keyed_getters_map.size();
+ keyed_getters_map[p_keyed_getter] = pos;
+ return pos;
+ }
+
+ int get_indexed_setter_pos(const Variant::ValidatedIndexedSetter p_indexed_setter) {
+ if (indexed_setters_map.has(p_indexed_setter))
+ return indexed_setters_map[p_indexed_setter];
+ int pos = indexed_setters_map.size();
+ indexed_setters_map[p_indexed_setter] = pos;
+ return pos;
+ }
+
+ int get_indexed_getter_pos(const Variant::ValidatedIndexedGetter p_indexed_getter) {
+ if (indexed_getters_map.has(p_indexed_getter))
+ return indexed_getters_map[p_indexed_getter];
+ int pos = indexed_getters_map.size();
+ indexed_getters_map[p_indexed_getter] = pos;
+ return pos;
+ }
+
+ int get_builtin_method_pos(const Variant::ValidatedBuiltInMethod p_method) {
+ if (builtin_method_map.has(p_method)) {
+ return builtin_method_map[p_method];
+ }
+ int pos = builtin_method_map.size();
+ builtin_method_map[p_method] = pos;
+ return pos;
+ }
+
+ int get_constructor_pos(const Variant::ValidatedConstructor p_constructor) {
+ if (constructors_map.has(p_constructor)) {
+ return constructors_map[p_constructor];
+ }
+ int pos = constructors_map.size();
+ constructors_map[p_constructor] = pos;
+ return pos;
+ }
+
+ int get_utility_pos(const Variant::ValidatedUtilityFunction p_utility) {
+ if (utilities_map.has(p_utility)) {
+ return utilities_map[p_utility];
+ }
+ int pos = utilities_map.size();
+ utilities_map[p_utility] = pos;
+ return pos;
+ }
+
+ int get_gds_utility_pos(const GDScriptUtilityFunctions::FunctionPtr p_gds_utility) {
+ if (gds_utilities_map.has(p_gds_utility)) {
+ return gds_utilities_map[p_gds_utility];
+ }
+ int pos = gds_utilities_map.size();
+ gds_utilities_map[p_gds_utility] = pos;
+ return pos;
+ }
+
+ int get_method_bind_pos(MethodBind *p_method) {
+ if (method_bind_map.has(p_method)) {
+ return method_bind_map[p_method];
+ }
+ int pos = method_bind_map.size();
+ method_bind_map[p_method] = pos;
+ return pos;
+ }
+
void alloc_stack(int p_level) {
if (p_level >= stack_max)
stack_max = p_level + 1;
}
- void alloc_call(int p_params) {
- if (p_params >= call_max)
- call_max = p_params;
- }
-
int increase_stack() {
int top = current_stack_size++;
alloc_stack(current_stack_size);
return top;
}
+ void alloc_ptrcall(int p_params) {
+ if (p_params >= ptrcall_max)
+ ptrcall_max = p_params;
+ }
+
int address_of(const Address &p_address) {
switch (p_address.mode) {
case Address::SELF:
@@ -177,8 +314,13 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
return -1; // Unreachable.
}
- void append(int code) {
- opcodes.push_back(code);
+ void append(GDScriptFunction::Opcode p_code, int p_argument_count) {
+ opcodes.push_back((p_code & GDScriptFunction::INSTR_MASK) | (p_argument_count << GDScriptFunction::INSTR_BITS));
+ instr_args_max = MAX(instr_args_max, p_argument_count);
+ }
+
+ void append(int p_code) {
+ opcodes.push_back(p_code);
}
void append(const Address &p_address) {
@@ -189,6 +331,54 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
opcodes.push_back(get_name_map_pos(p_name));
}
+ void append(const Variant::ValidatedOperatorEvaluator p_operation) {
+ opcodes.push_back(get_operation_pos(p_operation));
+ }
+
+ void append(const Variant::ValidatedSetter p_setter) {
+ opcodes.push_back(get_setter_pos(p_setter));
+ }
+
+ void append(const Variant::ValidatedGetter p_getter) {
+ opcodes.push_back(get_getter_pos(p_getter));
+ }
+
+ void append(const Variant::ValidatedKeyedSetter p_keyed_setter) {
+ opcodes.push_back(get_keyed_setter_pos(p_keyed_setter));
+ }
+
+ void append(const Variant::ValidatedKeyedGetter p_keyed_getter) {
+ opcodes.push_back(get_keyed_getter_pos(p_keyed_getter));
+ }
+
+ void append(const Variant::ValidatedIndexedSetter p_indexed_setter) {
+ opcodes.push_back(get_indexed_setter_pos(p_indexed_setter));
+ }
+
+ void append(const Variant::ValidatedIndexedGetter p_indexed_getter) {
+ opcodes.push_back(get_indexed_getter_pos(p_indexed_getter));
+ }
+
+ void append(const Variant::ValidatedBuiltInMethod p_method) {
+ opcodes.push_back(get_builtin_method_pos(p_method));
+ }
+
+ void append(const Variant::ValidatedConstructor p_constructor) {
+ opcodes.push_back(get_constructor_pos(p_constructor));
+ }
+
+ void append(const Variant::ValidatedUtilityFunction p_utility) {
+ opcodes.push_back(get_utility_pos(p_utility));
+ }
+
+ void append(const GDScriptUtilityFunctions::FunctionPtr p_gds_utility) {
+ opcodes.push_back(get_gds_utility_pos(p_gds_utility));
+ }
+
+ void append(MethodBind *p_method) {
+ opcodes.push_back(get_method_bind_pos(p_method));
+ }
+
void patch_jump(int p_address) {
opcodes.write[p_address] = opcodes.size();
}
@@ -216,7 +406,8 @@ public:
#endif
virtual void set_initial_line(int p_line) override;
- virtual void write_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) override;
+ virtual void write_unary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand) override;
+ virtual void write_binary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) override;
virtual void write_type_test(const Address &p_target, const Address &p_source, const Address &p_type) override;
virtual void write_type_test_builtin(const Address &p_target, const Address &p_source, Variant::Type p_type) override;
virtual void write_and_left_operand(const Address &p_left_operand) override;
@@ -239,14 +430,18 @@ public:
virtual void write_assign(const Address &p_target, const Address &p_source) override;
virtual void write_assign_true(const Address &p_target) override;
virtual void write_assign_false(const Address &p_target) override;
+ virtual void write_assign_default_parameter(const Address &p_dst, const Address &p_src) override;
virtual void write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) override;
virtual void write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_call_async(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
- virtual void write_call_builtin(const Address &p_target, GDScriptFunctions::Function p_function, const Vector<Address> &p_arguments) override;
- virtual void write_call_method_bind(const Address &p_target, const Address &p_base, const MethodBind *p_method, const Vector<Address> &p_arguments) override;
- virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, const MethodBind *p_method, const Vector<Address> &p_arguments) override;
+ virtual void write_call_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) override;
+ virtual void write_call_gdscript_utility(const Address &p_target, GDScriptUtilityFunctions::FunctionPtr p_function, const Vector<Address> &p_arguments) override;
+ virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override;
+ virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override;
+ virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override;
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_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;
@@ -255,7 +450,9 @@ public:
virtual void write_if(const Address &p_condition) override;
virtual void write_else() override;
virtual void write_endif() override;
- virtual void write_for(const Address &p_variable, const Address &p_list) override;
+ virtual void start_for(const GDScriptDataType &p_iterator_type, const GDScriptDataType &p_list_type) override;
+ virtual void write_for_assignment(const Address &p_variable, const Address &p_list) override;
+ virtual void write_for() override;
virtual void write_endfor() override;
virtual void start_while_condition() override;
virtual void write_while(const Address &p_condition) override;
diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp
index 57b95f5b21..113d36be98 100644
--- a/modules/gdscript/gdscript_cache.cpp
+++ b/modules/gdscript/gdscript_cache.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,7 +31,7 @@
#include "gdscript_cache.h"
#include "core/os/file_access.h"
-#include "core/vector.h"
+#include "core/templates/vector.h"
#include "gdscript.h"
#include "gdscript_analyzer.h"
#include "gdscript_parser.h"
diff --git a/modules/gdscript/gdscript_cache.h b/modules/gdscript/gdscript_cache.h
index 865df34051..d1d2a2abbf 100644
--- a/modules/gdscript/gdscript_cache.h
+++ b/modules/gdscript/gdscript_cache.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,10 +31,10 @@
#ifndef GDSCRIPT_CACHE_H
#define GDSCRIPT_CACHE_H
-#include "core/hash_map.h"
+#include "core/object/reference.h"
#include "core/os/mutex.h"
-#include "core/reference.h"
-#include "core/set.h"
+#include "core/templates/hash_map.h"
+#include "core/templates/set.h"
#include "gdscript.h"
class GDScriptAnalyzer;
diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h
index 31e1e6ba23..d72bd12033 100644
--- a/modules/gdscript/gdscript_codegen.h
+++ b/modules/gdscript/gdscript_codegen.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,10 +32,10 @@
#define GDSCRIPT_CODEGEN
#include "core/io/multiplayer_api.h"
-#include "core/string_name.h"
-#include "core/variant.h"
+#include "core/string/string_name.h"
+#include "core/variant/variant.h"
#include "gdscript_function.h"
-#include "gdscript_functions.h"
+#include "gdscript_utility_functions.h"
class GDScriptCodeGenerator {
public:
@@ -98,7 +98,8 @@ public:
// virtual void alloc_stack(int p_level) = 0; // Is this needed?
// virtual void alloc_call(int p_arg_count) = 0; // This might be automatic from other functions.
- virtual void write_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) = 0;
+ virtual void write_unary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand) = 0;
+ virtual void write_binary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) = 0;
virtual void write_type_test(const Address &p_target, const Address &p_source, const Address &p_type) = 0;
virtual void write_type_test_builtin(const Address &p_target, const Address &p_source, Variant::Type p_type) = 0;
virtual void write_and_left_operand(const Address &p_left_operand) = 0;
@@ -121,14 +122,18 @@ public:
virtual void write_assign(const Address &p_target, const Address &p_source) = 0;
virtual void write_assign_true(const Address &p_target) = 0;
virtual void write_assign_false(const Address &p_target) = 0;
+ virtual void write_assign_default_parameter(const Address &dst, const Address &src) = 0;
virtual void write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) = 0;
virtual void write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_call_async(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
- virtual void write_call_builtin(const Address &p_target, GDScriptFunctions::Function p_function, const Vector<Address> &p_arguments) = 0;
- virtual void write_call_method_bind(const Address &p_target, const Address &p_base, const MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
- virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, const MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
+ virtual void write_call_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) = 0;
+ virtual void write_call_gdscript_utility(const Address &p_target, GDScriptUtilityFunctions::FunctionPtr p_function, const Vector<Address> &p_arguments) = 0;
+ virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) = 0;
+ virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
+ virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
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_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;
@@ -138,7 +143,9 @@ public:
// virtual void write_elseif(const Address &p_condition) = 0; This kind of makes things more difficult for no real benefit.
virtual void write_else() = 0;
virtual void write_endif() = 0;
- virtual void write_for(const Address &p_variable, const Address &p_list) = 0;
+ virtual void start_for(const GDScriptDataType &p_iterator_type, const GDScriptDataType &p_list_type) = 0;
+ virtual void write_for_assignment(const Address &p_variable, const Address &p_list) = 0;
+ virtual void write_for() = 0;
virtual void write_endfor() = 0;
virtual void start_while_condition() = 0; // Used to allow a jump to the expression evaluation.
virtual void write_while(const Address &p_condition) = 0;
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index bad450c9f9..b491440d4c 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,6 +33,7 @@
#include "gdscript.h"
#include "gdscript_byte_codegen.h"
#include "gdscript_cache.h"
+#include "gdscript_utility_functions.h"
bool GDScriptCompiler::_is_class_member_property(CodeGen &codegen, const StringName &p_name) {
if (codegen.function_node && codegen.function_node->is_static) {
@@ -98,14 +99,15 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
} break;
case GDScriptParser::DataType::SCRIPT: {
result.kind = GDScriptDataType::SCRIPT;
- result.script_type = Ref<Script>(p_datatype.script_type).ptr();
+ result.script_type_ref = Ref<Script>(p_datatype.script_type);
+ result.script_type = result.script_type_ref.ptr();
result.native_type = result.script_type->get_instance_base_type();
} break;
case GDScriptParser::DataType::CLASS: {
// Locate class by constructing the path to it and following that path
GDScriptParser::ClassNode *class_type = p_datatype.class_type;
if (class_type) {
- if (class_type->fqcn.begins_with(main_script->path) || (!main_script->name.empty() && class_type->fqcn.begins_with(main_script->name))) {
+ if (class_type->fqcn.begins_with(main_script->path) || (!main_script->name.is_empty() && class_type->fqcn.begins_with(main_script->name))) {
// Local class.
List<StringName> names;
while (class_type->outer) {
@@ -124,11 +126,13 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
names.pop_back();
}
result.kind = GDScriptDataType::GDSCRIPT;
- result.script_type = script.ptr();
+ result.script_type_ref = script;
+ result.script_type = result.script_type_ref.ptr();
result.native_type = script->get_instance_base_type();
} else {
result.kind = GDScriptDataType::GDSCRIPT;
- result.script_type = GDScriptCache::get_shallow_script(p_datatype.script_path, main_script->path).ptr();
+ result.script_type_ref = GDScriptCache::get_shallow_script(p_datatype.script_path, main_script->path);
+ result.script_type = result.script_type_ref.ptr();
result.native_type = p_datatype.native_type;
}
}
@@ -151,13 +155,55 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
// Only hold strong reference to the script if it's not the owner of the
// element qualified with this type, to avoid cyclic references (leaks).
- if (result.script_type && result.script_type != p_owner) {
- result.script_type_ref = Ref<Script>(result.script_type);
+ if (result.script_type && result.script_type == p_owner) {
+ result.script_type_ref = Ref<Script>();
}
return result;
}
+static bool _is_exact_type(const PropertyInfo &p_par_type, const GDScriptDataType &p_arg_type) {
+ if (!p_arg_type.has_type) {
+ return false;
+ }
+ if (p_par_type.type == Variant::NIL) {
+ return false;
+ }
+ if (p_par_type.type == Variant::OBJECT) {
+ if (p_arg_type.kind == GDScriptDataType::BUILTIN) {
+ return false;
+ }
+ StringName class_name;
+ if (p_arg_type.kind == GDScriptDataType::NATIVE) {
+ class_name = p_arg_type.native_type;
+ } else {
+ class_name = p_arg_type.native_type == StringName() ? p_arg_type.script_type->get_instance_base_type() : p_arg_type.native_type;
+ }
+ return p_par_type.class_name == class_name || ClassDB::is_parent_class(class_name, p_par_type.class_name);
+ } else {
+ if (p_arg_type.kind != GDScriptDataType::BUILTIN) {
+ return false;
+ }
+ return p_par_type.type == p_arg_type.builtin_type;
+ }
+}
+
+static bool _have_exact_arguments(const MethodBind *p_method, const Vector<GDScriptCodeGenerator::Address> &p_arguments) {
+ if (p_method->get_argument_count() != p_arguments.size()) {
+ // ptrcall won't work with default arguments.
+ return false;
+ }
+ MethodInfo info;
+ ClassDB::get_method_info(p_method->get_instance_class(), p_method->get_name(), &info);
+ for (int i = 0; i < p_arguments.size(); i++) {
+ const PropertyInfo &prop = info.arguments[i];
+ if (!_is_exact_type(prop, p_arguments[i].type)) {
+ return false;
+ }
+ }
+ return true;
+}
+
GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &codegen, Error &r_error, const GDScriptParser::ExpressionNode *p_expression, bool p_root, bool p_initializer, const GDScriptCodeGenerator::Address &p_index_addr) {
if (p_expression->is_constant) {
return codegen.add_constant(p_expression->reduced_value);
@@ -395,7 +441,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
gen->pop_temporary();
}
- return source;
+ return result;
} break;
case GDScriptParser::Node::CALL: {
const GDScriptParser::CallNode *call = static_cast<const GDScriptParser::CallNode *>(p_expression);
@@ -411,15 +457,17 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
arguments.push_back(arg);
}
- if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name) != Variant::VARIANT_MAX) {
+ if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(call->function_name) != Variant::VARIANT_MAX) {
// Construct a built-in type.
Variant::Type vtype = GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name);
gen->write_construct(result, vtype, arguments);
- } else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_function(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name) != GDScriptFunctions::FUNC_MAX) {
- // Built-in function.
- GDScriptFunctions::Function func = GDScriptParser::get_builtin_function(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name);
- gen->write_call_builtin(result, func, arguments);
+ } else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && Variant::has_utility_function(call->function_name)) {
+ // Variant utility function.
+ gen->write_call_utility(result, call->function_name, arguments);
+ } else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptUtilityFunctions::function_exists(call->function_name)) {
+ // GDScript utility function.
+ gen->write_call_gdscript_utility(result, GDScriptUtilityFunctions::get_function(call->function_name), arguments);
} else {
// Regular function.
const GDScriptParser::ExpressionNode *callee = call->callee;
@@ -430,12 +478,33 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
} else {
if (callee->type == GDScriptParser::Node::IDENTIFIER) {
// Self function call.
- if ((codegen.function_node && codegen.function_node->is_static) || call->function_name == "new") {
+ if (ClassDB::has_method(codegen.script->native->get_name(), call->function_name)) {
+ // Native method, use faster path.
+ GDScriptCodeGenerator::Address self;
+ self.mode = GDScriptCodeGenerator::Address::SELF;
+ MethodBind *method = ClassDB::get_method(codegen.script->native->get_name(), call->function_name);
+
+ if (_have_exact_arguments(method, arguments)) {
+ // Exact arguments, use ptrcall.
+ gen->write_call_ptrcall(result, self, method, arguments);
+ } else {
+ // Not exact arguments, but still can use method bind call.
+ gen->write_call_method_bind(result, self, method, arguments);
+ }
+ } else if ((codegen.function_node && codegen.function_node->is_static) || call->function_name == "new") {
GDScriptCodeGenerator::Address self;
self.mode = GDScriptCodeGenerator::Address::CLASS;
- gen->write_call(result, self, call->function_name, arguments);
+ if (within_await) {
+ gen->write_call_async(result, self, call->function_name, arguments);
+ } else {
+ gen->write_call(result, self, call->function_name, arguments);
+ }
} else {
- gen->write_call_self(result, call->function_name, arguments);
+ if (within_await) {
+ gen->write_call_self_async(result, call->function_name, arguments);
+ } else {
+ gen->write_call_self(result, call->function_name, arguments);
+ }
}
} else if (callee->type == GDScriptParser::Node::SUBSCRIPT) {
const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(call->callee);
@@ -447,6 +516,28 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
}
if (within_await) {
gen->write_call_async(result, base, call->function_name, arguments);
+ } else if (base.type.has_type && base.type.kind != GDScriptDataType::BUILTIN) {
+ // Native method, use faster path.
+ StringName class_name;
+ if (base.type.kind == GDScriptDataType::NATIVE) {
+ class_name = base.type.native_type;
+ } else {
+ class_name = base.type.native_type == StringName() ? base.type.script_type->get_instance_base_type() : base.type.native_type;
+ }
+ if (ClassDB::class_exists(class_name) && ClassDB::has_method(class_name, call->function_name)) {
+ MethodBind *method = ClassDB::get_method(class_name, call->function_name);
+ if (_have_exact_arguments(method, arguments)) {
+ // Exact arguments, use ptrcall.
+ gen->write_call_ptrcall(result, base, method, arguments);
+ } else {
+ // Not exact arguments, but still can use method bind call.
+ gen->write_call_method_bind(result, base, method, arguments);
+ }
+ } else {
+ gen->write_call(result, base, call->function_name, arguments);
+ }
+ } else if (base.type.has_type && base.type.kind == GDScriptDataType::BUILTIN) {
+ gen->write_call_builtin_type(result, base, base.type.builtin_type, call->function_name, arguments);
} else {
gen->write_call(result, base, call->function_name, arguments);
}
@@ -493,7 +584,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(get_node->get_datatype()));
MethodBind *get_node_method = ClassDB::get_method("Node", "get_node");
- gen->write_call_method_bind(result, GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF), get_node_method, args);
+ gen->write_call_ptrcall(result, GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF), get_node_method, args);
return result;
} break;
@@ -600,7 +691,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
return GDScriptCodeGenerator::Address();
}
- gen->write_operator(result, unary->variant_op, operand, GDScriptCodeGenerator::Address());
+ gen->write_unary_operator(result, unary->variant_op, operand);
if (operand.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
gen->pop_temporary();
@@ -668,7 +759,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
GDScriptCodeGenerator::Address left_operand = _parse_expression(codegen, r_error, binary->left_operand);
GDScriptCodeGenerator::Address right_operand = _parse_expression(codegen, r_error, binary->right_operand);
- gen->write_operator(result, binary->variant_op, left_operand, right_operand);
+ gen->write_binary_operator(result, binary->variant_op, left_operand, right_operand);
if (right_operand.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
gen->pop_temporary();
@@ -831,7 +922,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
} else {
gen->write_get(value, key, prev_base);
}
- gen->write_operator(value, assignment->variant_op, value, assigned);
+ gen->write_binary_operator(value, assignment->variant_op, value, assigned);
if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
gen->pop_temporary();
}
@@ -889,7 +980,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
if (assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) {
GDScriptCodeGenerator::Address member = codegen.add_temporary();
gen->write_get_member(member, name);
- gen->write_operator(assigned, assignment->variant_op, member, assigned);
+ gen->write_binary_operator(assigned, assignment->variant_op, member, assigned);
gen->pop_temporary();
}
@@ -939,7 +1030,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
if (assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) {
// Perform operation.
op_result = codegen.add_temporary();
- gen->write_operator(op_result, assignment->variant_op, target, assigned);
+ gen->write_binary_operator(op_result, assignment->variant_op, target, assigned);
} else {
op_result = assigned;
assigned = GDScriptCodeGenerator::Address();
@@ -995,7 +1086,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
// Check type equality.
GDScriptCodeGenerator::Address type_equality_addr = codegen.add_temporary(equality_type);
- codegen.generator->write_operator(type_equality_addr, Variant::OP_EQUAL, p_type_addr, literal_type_addr);
+ codegen.generator->write_binary_operator(type_equality_addr, Variant::OP_EQUAL, p_type_addr, literal_type_addr);
codegen.generator->write_and_left_operand(type_equality_addr);
// Get literal.
@@ -1006,7 +1097,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
// Check value equality.
GDScriptCodeGenerator::Address equality_addr = codegen.add_temporary(equality_type);
- codegen.generator->write_operator(equality_addr, Variant::OP_EQUAL, p_value_addr, literal_addr);
+ codegen.generator->write_binary_operator(equality_addr, Variant::OP_EQUAL, p_value_addr, literal_addr);
codegen.generator->write_and_right_operand(equality_addr);
// AND both together (reuse temporary location).
@@ -1055,14 +1146,14 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
// Evaluate expression type.
Vector<GDScriptCodeGenerator::Address> typeof_args;
typeof_args.push_back(expr_addr);
- codegen.generator->write_call_builtin(result_addr, GDScriptFunctions::TYPE_OF, typeof_args);
+ codegen.generator->write_call_utility(result_addr, "typeof", typeof_args);
// Check type equality.
- codegen.generator->write_operator(result_addr, Variant::OP_EQUAL, p_type_addr, result_addr);
+ codegen.generator->write_binary_operator(result_addr, Variant::OP_EQUAL, p_type_addr, result_addr);
codegen.generator->write_and_left_operand(result_addr);
// Check value equality.
- codegen.generator->write_operator(result_addr, Variant::OP_EQUAL, p_value_addr, expr_addr);
+ codegen.generator->write_binary_operator(result_addr, Variant::OP_EQUAL, p_value_addr, expr_addr);
codegen.generator->write_and_right_operand(equality_test_addr);
// AND both type and value equality.
@@ -1108,7 +1199,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
// Check type equality.
GDScriptCodeGenerator::Address result_addr = codegen.add_temporary(temp_type);
- codegen.generator->write_operator(result_addr, Variant::OP_EQUAL, p_type_addr, array_type_addr);
+ codegen.generator->write_binary_operator(result_addr, Variant::OP_EQUAL, p_type_addr, array_type_addr);
codegen.generator->write_and_left_operand(result_addr);
// Store pattern length in constant map.
@@ -1119,12 +1210,12 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
GDScriptCodeGenerator::Address value_length_addr = codegen.add_temporary(temp_type);
Vector<GDScriptCodeGenerator::Address> len_args;
len_args.push_back(p_value_addr);
- codegen.generator->write_call_builtin(value_length_addr, GDScriptFunctions::LEN, len_args);
+ codegen.generator->write_call_gdscript_utility(value_length_addr, GDScriptUtilityFunctions::get_function("len"), len_args);
// Test length compatibility.
temp_type.builtin_type = Variant::BOOL;
GDScriptCodeGenerator::Address length_compat_addr = codegen.add_temporary(temp_type);
- codegen.generator->write_operator(length_compat_addr, p_pattern->rest_used ? Variant::OP_GREATER_EQUAL : Variant::OP_EQUAL, value_length_addr, array_length_addr);
+ codegen.generator->write_binary_operator(length_compat_addr, p_pattern->rest_used ? Variant::OP_GREATER_EQUAL : Variant::OP_EQUAL, value_length_addr, array_length_addr);
codegen.generator->write_and_right_operand(length_compat_addr);
// AND type and length check.
@@ -1173,7 +1264,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
// Also get type of element.
Vector<GDScriptCodeGenerator::Address> typeof_args;
typeof_args.push_back(element_addr);
- codegen.generator->write_call_builtin(element_type_addr, GDScriptFunctions::TYPE_OF, typeof_args);
+ codegen.generator->write_call_utility(element_type_addr, "typeof", typeof_args);
// Try the pattern inside the element.
test_addr = _parse_match_pattern(codegen, r_error, p_pattern->array[i], element_addr, element_type_addr, p_previous_test, false, true);
@@ -1207,7 +1298,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
// Check type equality.
GDScriptCodeGenerator::Address result_addr = codegen.add_temporary(temp_type);
- codegen.generator->write_operator(result_addr, Variant::OP_EQUAL, p_type_addr, dict_type_addr);
+ codegen.generator->write_binary_operator(result_addr, Variant::OP_EQUAL, p_type_addr, dict_type_addr);
codegen.generator->write_and_left_operand(result_addr);
// Store pattern length in constant map.
@@ -1218,12 +1309,12 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
GDScriptCodeGenerator::Address value_length_addr = codegen.add_temporary(temp_type);
Vector<GDScriptCodeGenerator::Address> func_args;
func_args.push_back(p_value_addr);
- codegen.generator->write_call_builtin(value_length_addr, GDScriptFunctions::LEN, func_args);
+ codegen.generator->write_call_gdscript_utility(value_length_addr, GDScriptUtilityFunctions::get_function("len"), func_args);
// Test length compatibility.
temp_type.builtin_type = Variant::BOOL;
GDScriptCodeGenerator::Address length_compat_addr = codegen.add_temporary(temp_type);
- codegen.generator->write_operator(length_compat_addr, p_pattern->rest_used ? Variant::OP_GREATER_EQUAL : Variant::OP_EQUAL, value_length_addr, dict_length_addr);
+ codegen.generator->write_binary_operator(length_compat_addr, p_pattern->rest_used ? Variant::OP_GREATER_EQUAL : Variant::OP_EQUAL, value_length_addr, dict_length_addr);
codegen.generator->write_and_right_operand(length_compat_addr);
// AND type and length check.
@@ -1287,7 +1378,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
// Also get type of value.
func_args.clear();
func_args.push_back(element_addr);
- codegen.generator->write_call_builtin(element_type_addr, GDScriptFunctions::TYPE_OF, func_args);
+ codegen.generator->write_call_utility(element_type_addr, "typeof", func_args);
// Try the pattern inside the value.
test_addr = _parse_match_pattern(codegen, r_error, element.value_pattern, element_addr, element_type_addr, test_addr, false, true);
@@ -1397,16 +1488,30 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
codegen.start_block();
// Evaluate the match expression.
+ GDScriptCodeGenerator::Address value_local = codegen.add_local("@match_value", _gdtype_from_datatype(match->test->get_datatype()));
GDScriptCodeGenerator::Address value = _parse_expression(codegen, error, match->test);
if (error) {
return error;
}
+ // Assign to local.
+ // TODO: This can be improved by passing the target to parse_expression().
+ gen->write_assign(value_local, value);
+
+ if (value.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ codegen.generator->pop_temporary();
+ }
+
// Then, let's save the type of the value in the stack too, so we can reuse for later comparisons.
- GDScriptCodeGenerator::Address type = codegen.add_temporary();
+ GDScriptDataType typeof_type;
+ typeof_type.has_type = true;
+ typeof_type.kind = GDScriptDataType::BUILTIN;
+ typeof_type.builtin_type = Variant::INT;
+ GDScriptCodeGenerator::Address type = codegen.add_local("@match_type", typeof_type);
+
Vector<GDScriptCodeGenerator::Address> typeof_args;
typeof_args.push_back(value);
- gen->write_call_builtin(type, GDScriptFunctions::TYPE_OF, typeof_args);
+ gen->write_call_utility(type, "typeof", typeof_args);
// Now we can actually start testing.
// For each branch.
@@ -1457,12 +1562,6 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
gen->write_endif();
}
- gen->pop_temporary();
-
- if (value.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
- codegen.generator->pop_temporary();
- }
-
gen->end_match();
} break;
case GDScriptParser::Node::IF: {
@@ -1500,12 +1599,20 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
codegen.start_block();
GDScriptCodeGenerator::Address iterator = codegen.add_local(for_n->variable->name, _gdtype_from_datatype(for_n->variable->get_datatype()));
+ gen->start_for(iterator.type, _gdtype_from_datatype(for_n->list->get_datatype()));
+
GDScriptCodeGenerator::Address list = _parse_expression(codegen, error, for_n->list);
if (error) {
return error;
}
- gen->write_for(iterator, list);
+ gen->write_for_assignment(iterator, list);
+
+ if (list.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ codegen.generator->pop_temporary();
+ }
+
+ gen->write_for();
error = _parse_block(codegen, for_n->loop);
if (error) {
@@ -1514,10 +1621,6 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
gen->write_endfor();
- if (list.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
- codegen.generator->pop_temporary();
- }
-
codegen.end_block();
} break;
case GDScriptParser::Node::WHILE: {
@@ -1749,7 +1852,7 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
return error;
}
GDScriptCodeGenerator::Address dst_addr = codegen.parameters[parameter->identifier->name];
- codegen.generator->write_assign(dst_addr, src_addr);
+ codegen.generator->write_assign_default_parameter(dst_addr, src_addr);
if (src_addr.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
codegen.generator->pop_temporary();
}
@@ -1794,6 +1897,7 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
codegen.generator->set_initial_line(p_func->start_line);
#ifdef TOOLS_ENABLED
p_script->member_lines[func_name] = p_func->start_line;
+ p_script->doc_functions[func_name] = p_func->doc_description;
#endif
} else {
codegen.generator->set_initial_line(0);
@@ -1807,6 +1911,21 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
p_script->implicit_initializer = gd_function;
}
+ if (p_func) {
+ // if no return statement -> return type is void not unresolved Variant
+ if (p_func->body->has_return) {
+ gd_function->return_type = _gdtype_from_datatype(p_func->get_datatype());
+ } else {
+ gd_function->return_type = GDScriptDataType();
+ gd_function->return_type.has_type = true;
+ gd_function->return_type.kind = GDScriptDataType::BUILTIN;
+ gd_function->return_type.builtin_type = Variant::NIL;
+ }
+#ifdef TOOLS_ENABLED
+ gd_function->default_arg_values = p_func->default_arg_values;
+#endif
+ }
+
p_script->member_functions[func_name] = gd_function;
memdelete(codegen.generator);
@@ -1904,6 +2023,24 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
}
}
+#ifdef TOOLS_ENABLED
+ p_script->doc_functions.clear();
+ p_script->doc_variables.clear();
+ p_script->doc_constants.clear();
+ p_script->doc_enums.clear();
+ p_script->doc_signals.clear();
+ p_script->doc_tutorials.clear();
+
+ p_script->doc_brief_description = p_class->doc_brief_description;
+ p_script->doc_description = p_class->doc_description;
+ for (int i = 0; i < p_class->doc_tutorials.size(); i++) {
+ DocData::TutorialDoc td;
+ td.title = p_class->doc_tutorials[i].first;
+ td.link = p_class->doc_tutorials[i].second;
+ p_script->doc_tutorials.append(td);
+ }
+#endif
+
p_script->native = Ref<GDScriptNativeClass>();
p_script->base = Ref<GDScript>();
p_script->_base = nullptr;
@@ -1963,6 +2100,8 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
}
p_script->member_indices = base->member_indices;
+ native = base->native;
+ p_script->native = native;
} break;
default: {
_set_error("Parser bug: invalid inheritance.", p_class);
@@ -2014,20 +2153,23 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
prop_info.hint = export_info.hint;
prop_info.hint_string = export_info.hint_string;
prop_info.usage = export_info.usage;
-#ifdef TOOLS_ENABLED
- if (variable->initializer != nullptr && variable->initializer->type == GDScriptParser::Node::LITERAL) {
- p_script->member_default_values[name] = static_cast<const GDScriptParser::LiteralNode *>(variable->initializer)->value;
- }
-#endif
} else {
prop_info.usage = PROPERTY_USAGE_SCRIPT_VARIABLE;
}
+#ifdef TOOLS_ENABLED
+ p_script->doc_variables[name] = variable->doc_description;
+#endif
p_script->member_info[name] = prop_info;
p_script->member_indices[name] = minfo;
p_script->members.insert(name);
#ifdef TOOLS_ENABLED
+ if (variable->initializer != nullptr && variable->initializer->is_constant) {
+ p_script->member_default_values[name] = variable->initializer->reduced_value;
+ } else {
+ p_script->member_default_values.erase(name);
+ }
p_script->member_lines[name] = variable->start_line;
#endif
} break;
@@ -2038,8 +2180,10 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
p_script->constants.insert(name, constant->initializer->reduced_value);
#ifdef TOOLS_ENABLED
-
p_script->member_lines[name] = constant->start_line;
+ if (constant->doc_description != String()) {
+ p_script->doc_constants[name] = constant->doc_description;
+ }
#endif
} break;
@@ -2050,6 +2194,15 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
p_script->constants.insert(name, enum_value.value);
#ifdef TOOLS_ENABLED
p_script->member_lines[name] = enum_value.identifier->start_line;
+ if (!p_script->doc_enums.has("@unnamed_enums")) {
+ p_script->doc_enums["@unnamed_enums"] = DocData::EnumDoc();
+ p_script->doc_enums["@unnamed_enums"].name = "@unnamed_enums";
+ }
+ DocData::ConstantDoc const_doc;
+ const_doc.name = enum_value.identifier->name;
+ const_doc.value = Variant(enum_value.value).operator String(); // TODO-DOC: enum value currently is int.
+ const_doc.description = enum_value.doc_description;
+ p_script->doc_enums["@unnamed_enums"].values.push_back(const_doc);
#endif
} break;
@@ -2085,6 +2238,11 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
parameters_names.write[j] = signal->parameters[j]->identifier->name;
}
p_script->_signals[name] = parameters_names;
+#ifdef TOOLS_ENABLED
+ if (!signal->doc_description.is_empty()) {
+ p_script->doc_signals[name] = signal->doc_description;
+ }
+#endif
} break;
case GDScriptParser::ClassNode::Member::ENUM: {
@@ -2101,6 +2259,16 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
p_script->constants.insert(enum_n->identifier->name, new_enum);
#ifdef TOOLS_ENABLED
p_script->member_lines[enum_n->identifier->name] = enum_n->start_line;
+ p_script->doc_enums[enum_n->identifier->name] = DocData::EnumDoc();
+ p_script->doc_enums[enum_n->identifier->name].name = enum_n->identifier->name;
+ p_script->doc_enums[enum_n->identifier->name].description = enum_n->doc_description;
+ for (int j = 0; j < enum_n->values.size(); j++) {
+ DocData::ConstantDoc const_doc;
+ const_doc.name = enum_n->values[j].identifier->name;
+ const_doc.value = Variant(enum_n->values[j].value).operator String();
+ const_doc.description = enum_n->values[j].doc_description;
+ p_script->doc_enums[enum_n->identifier->name].values.push_back(const_doc);
+ }
#endif
} break;
default:
diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h
index db02079d26..00953ad752 100644
--- a/modules/gdscript/gdscript_compiler.h
+++ b/modules/gdscript/gdscript_compiler.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,7 +31,7 @@
#ifndef GDSCRIPT_COMPILER_H
#define GDSCRIPT_COMPILER_H
-#include "core/set.h"
+#include "core/templates/set.h"
#include "gdscript.h"
#include "gdscript_codegen.h"
#include "gdscript_function.h"
@@ -51,12 +51,11 @@ class GDScriptCompiler {
GDScriptCodeGenerator *generator = nullptr;
Map<StringName, GDScriptCodeGenerator::Address> parameters;
Map<StringName, GDScriptCodeGenerator::Address> locals;
- List<Set<StringName>> locals_in_scope;
+ List<Map<StringName, GDScriptCodeGenerator::Address>> locals_stack;
GDScriptCodeGenerator::Address add_local(const StringName &p_name, const GDScriptDataType &p_type) {
uint32_t addr = generator->add_local(p_name, p_type);
locals[p_name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::LOCAL_VARIABLE, addr, p_type);
- locals_in_scope.back()->get().insert(p_name);
return locals[p_name];
}
@@ -102,17 +101,14 @@ class GDScriptCompiler {
}
void start_block() {
- Set<StringName> scope;
- locals_in_scope.push_back(scope);
+ Map<StringName, GDScriptCodeGenerator::Address> old_locals = locals;
+ locals_stack.push_back(old_locals);
generator->start_block();
}
void end_block() {
- Set<StringName> &scope = locals_in_scope.back()->get();
- for (Set<StringName>::Element *E = scope.front(); E; E = E->next()) {
- locals.erase(E->get());
- }
- locals_in_scope.pop_back();
+ locals = locals_stack.back()->get();
+ locals_stack.pop_back();
generator->end_block();
}
};
diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp
new file mode 100644
index 0000000000..17cb5e3c96
--- /dev/null
+++ b/modules/gdscript/gdscript_disassembler.cpp
@@ -0,0 +1,842 @@
+/*************************************************************************/
+/* gdscript_disassembler.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifdef DEBUG_ENABLED
+
+#include "gdscript_function.h"
+
+#include "core/string/string_builder.h"
+#include "gdscript.h"
+
+static String _get_variant_string(const Variant &p_variant) {
+ String txt;
+ if (p_variant.get_type() == Variant::STRING) {
+ txt = "\"" + String(p_variant) + "\"";
+ } else if (p_variant.get_type() == Variant::STRING_NAME) {
+ txt = "&\"" + String(p_variant) + "\"";
+ } else if (p_variant.get_type() == Variant::NODE_PATH) {
+ txt = "^\"" + String(p_variant) + "\"";
+ } else if (p_variant.get_type() == Variant::OBJECT) {
+ Object *obj = p_variant;
+ if (!obj) {
+ txt = "null";
+ } else {
+ GDScriptNativeClass *cls = Object::cast_to<GDScriptNativeClass>(obj);
+ if (cls) {
+ txt += cls->get_name();
+ txt += " (class)";
+ } else {
+ txt = obj->get_class();
+ if (obj->get_script_instance()) {
+ txt += "(" + obj->get_script_instance()->get_script()->get_path() + ")";
+ }
+ }
+ }
+ } else {
+ txt = p_variant;
+ }
+ return txt;
+}
+
+static String _disassemble_address(const GDScript *p_script, const GDScriptFunction &p_function, int p_address) {
+ int addr = p_address & GDScriptFunction::ADDR_MASK;
+
+ switch (p_address >> GDScriptFunction::ADDR_BITS) {
+ case GDScriptFunction::ADDR_TYPE_SELF: {
+ return "self";
+ } break;
+ case GDScriptFunction::ADDR_TYPE_CLASS: {
+ return "class";
+ } break;
+ case GDScriptFunction::ADDR_TYPE_MEMBER: {
+ return "member(" + p_script->debug_get_member_by_index(addr) + ")";
+ } break;
+ case GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT: {
+ return "class_const(" + p_function.get_global_name(addr) + ")";
+ } break;
+ case GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT: {
+ return "const(" + _get_variant_string(p_function.get_constant(addr)) + ")";
+ } break;
+ case GDScriptFunction::ADDR_TYPE_STACK: {
+ return "stack(" + itos(addr) + ")";
+ } break;
+ case GDScriptFunction::ADDR_TYPE_STACK_VARIABLE: {
+ return "var_stack(" + itos(addr) + ")";
+ } break;
+ case GDScriptFunction::ADDR_TYPE_GLOBAL: {
+ return "global(" + _get_variant_string(GDScriptLanguage::get_singleton()->get_global_array()[addr]) + ")";
+ } break;
+ case GDScriptFunction::ADDR_TYPE_NAMED_GLOBAL: {
+ return "named_global(" + p_function.get_global_name(addr) + ")";
+ } break;
+ case GDScriptFunction::ADDR_TYPE_NIL: {
+ return "nil";
+ } break;
+ }
+
+ return "<err>";
+}
+
+void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
+#define DADDR(m_ip) (_disassemble_address(_script, *this, _code_ptr[ip + m_ip]))
+
+ for (int ip = 0; ip < _code_size;) {
+ StringBuilder text;
+ int incr = 0;
+
+ text += " ";
+ text += itos(ip);
+ text += ": ";
+
+ // This makes the compiler complain if some opcode is unchecked in the switch.
+ Opcode code = Opcode(_code_ptr[ip] & INSTR_MASK);
+ int instr_var_args = (_code_ptr[ip] & INSTR_ARGS_MASK) >> INSTR_BITS;
+
+ switch (code) {
+ case OPCODE_OPERATOR: {
+ int operation = _code_ptr[ip + 4];
+
+ text += "operator ";
+
+ text += DADDR(3);
+ text += " = ";
+ text += DADDR(1);
+ text += " ";
+ text += Variant::get_operator_name(Variant::Operator(operation));
+ text += " ";
+ text += DADDR(2);
+
+ incr += 5;
+ } break;
+ case OPCODE_OPERATOR_VALIDATED: {
+ text += "validated operator ";
+
+ text += DADDR(3);
+ text += " = ";
+ text += DADDR(1);
+ text += " <operator function> ";
+ text += DADDR(2);
+
+ incr += 5;
+ } break;
+ case OPCODE_EXTENDS_TEST: {
+ text += "is object ";
+ text += DADDR(3);
+ text += " = ";
+ text += DADDR(1);
+ text += " is ";
+ text += DADDR(2);
+
+ incr += 4;
+ } break;
+ case OPCODE_IS_BUILTIN: {
+ text += "is builtin ";
+ text += DADDR(2);
+ text += " = ";
+ text += DADDR(1);
+ text += " is ";
+ text += Variant::get_type_name(Variant::Type(_code_ptr[ip + 3]));
+
+ incr += 4;
+ } break;
+ case OPCODE_SET_KEYED: {
+ text += "set keyed ";
+ text += DADDR(1);
+ text += "[";
+ text += DADDR(2);
+ text += "] = ";
+ text += DADDR(3);
+
+ incr += 4;
+ } break;
+ case OPCODE_SET_KEYED_VALIDATED: {
+ text += "set keyed validated ";
+ text += DADDR(1);
+ text += "[";
+ text += DADDR(2);
+ text += "] = ";
+ text += DADDR(3);
+
+ incr += 5;
+ } break;
+ case OPCODE_SET_INDEXED_VALIDATED: {
+ text += "set indexed validated ";
+ text += DADDR(1);
+ text += "[";
+ text += DADDR(2);
+ text += "] = ";
+ text += DADDR(3);
+
+ incr += 5;
+ } break;
+ case OPCODE_GET_KEYED: {
+ text += "get keyed ";
+ text += DADDR(3);
+ text += " = ";
+ text += DADDR(1);
+ text += "[";
+ text += DADDR(2);
+ text += "]";
+
+ incr += 4;
+ } break;
+ case OPCODE_GET_KEYED_VALIDATED: {
+ text += "get keyed validated ";
+ text += DADDR(3);
+ text += " = ";
+ text += DADDR(1);
+ text += "[";
+ text += DADDR(2);
+ text += "]";
+
+ incr += 5;
+ } break;
+ case OPCODE_GET_INDEXED_VALIDATED: {
+ text += "get indexed validated ";
+ text += DADDR(3);
+ text += " = ";
+ text += DADDR(1);
+ text += "[";
+ text += DADDR(2);
+ text += "]";
+
+ incr += 5;
+ } break;
+ case OPCODE_SET_NAMED: {
+ text += "set_named ";
+ text += DADDR(1);
+ text += "[\"";
+ text += _global_names_ptr[_code_ptr[ip + 3]];
+ text += "\"] = ";
+ text += DADDR(2);
+
+ incr += 4;
+ } break;
+ case OPCODE_SET_NAMED_VALIDATED: {
+ text += "set_named validated ";
+ text += DADDR(1);
+ text += "[\"";
+ text += "<unknown name>";
+ text += "\"] = ";
+ text += DADDR(2);
+
+ incr += 4;
+ } break;
+ case OPCODE_GET_NAMED: {
+ text += "get_named ";
+ text += DADDR(2);
+ text += " = ";
+ text += DADDR(1);
+ text += "[\"";
+ text += _global_names_ptr[_code_ptr[ip + 3]];
+ text += "\"]";
+
+ incr += 4;
+ } break;
+ case OPCODE_GET_NAMED_VALIDATED: {
+ text += "get_named validated ";
+ text += DADDR(2);
+ text += " = ";
+ text += DADDR(1);
+ text += "[\"";
+ text += "<unknown name>";
+ text += "\"]";
+
+ incr += 4;
+ } break;
+ case OPCODE_SET_MEMBER: {
+ text += "set_member ";
+ text += "[\"";
+ text += _global_names_ptr[_code_ptr[ip + 2]];
+ text += "\"] = ";
+ text += DADDR(1);
+
+ incr += 3;
+ } break;
+ case OPCODE_GET_MEMBER: {
+ text += "get_member ";
+ text += DADDR(1);
+ text += " = ";
+ text += "[\"";
+ text += _global_names_ptr[_code_ptr[ip + 2]];
+ text += "\"]";
+
+ incr += 3;
+ } break;
+ case OPCODE_ASSIGN: {
+ text += "assign ";
+ text += DADDR(1);
+ text += " = ";
+ text += DADDR(2);
+
+ incr += 3;
+ } break;
+ case OPCODE_ASSIGN_TRUE: {
+ text += "assign ";
+ text += DADDR(1);
+ text += " = true";
+
+ incr += 2;
+ } break;
+ case OPCODE_ASSIGN_FALSE: {
+ text += "assign ";
+ text += DADDR(1);
+ text += " = false";
+
+ incr += 2;
+ } break;
+ case OPCODE_ASSIGN_TYPED_BUILTIN: {
+ text += "assign typed builtin (";
+ text += Variant::get_type_name((Variant::Type)_code_ptr[ip + 3]);
+ text += ") ";
+ text += DADDR(1);
+ text += " = ";
+ text += DADDR(2);
+
+ incr += 4;
+ } break;
+ case OPCODE_ASSIGN_TYPED_NATIVE: {
+ text += "assign typed native (";
+ text += DADDR(3);
+ text += ") ";
+ text += DADDR(1);
+ text += " = ";
+ text += DADDR(2);
+
+ incr += 4;
+ } break;
+ case OPCODE_ASSIGN_TYPED_SCRIPT: {
+ Variant script = _constants_ptr[_code_ptr[ip + 3]];
+ Script *sc = Object::cast_to<Script>(script.operator Object *());
+
+ text += "assign typed script (";
+ text += sc->get_path();
+ text += ") ";
+ text += DADDR(1);
+ text += " = ";
+ text += DADDR(2);
+
+ incr += 4;
+ } break;
+ case OPCODE_CAST_TO_BUILTIN: {
+ text += "cast builtin ";
+ text += DADDR(2);
+ text += " = ";
+ text += DADDR(1);
+ text += " as ";
+ text += Variant::get_type_name(Variant::Type(_code_ptr[ip + 1]));
+
+ incr += 4;
+ } break;
+ case OPCODE_CAST_TO_NATIVE: {
+ text += "cast native ";
+ text += DADDR(2);
+ text += " = ";
+ text += DADDR(1);
+ text += " as ";
+ text += DADDR(3);
+
+ incr += 4;
+ } break;
+ case OPCODE_CAST_TO_SCRIPT: {
+ text += "cast ";
+ text += DADDR(2);
+ text += " = ";
+ text += DADDR(1);
+ text += " as ";
+ text += DADDR(3);
+
+ incr += 4;
+ } break;
+ case OPCODE_CONSTRUCT: {
+ Variant::Type t = Variant::Type(_code_ptr[ip + 3 + instr_var_args]);
+ int argc = _code_ptr[ip + 1 + instr_var_args];
+
+ text += "construct ";
+ text += DADDR(1 + argc);
+ text += " = ";
+
+ text += Variant::get_type_name(t) + "(";
+ for (int i = 0; i < argc; i++) {
+ if (i > 0)
+ text += ", ";
+ text += DADDR(i + 1);
+ }
+ text += ")";
+
+ incr = 3 + instr_var_args;
+ } break;
+ case OPCODE_CONSTRUCT_VALIDATED: {
+ int argc = _code_ptr[ip + 1 + instr_var_args];
+
+ text += "construct validated ";
+ text += DADDR(1 + argc);
+ text += " = ";
+
+ text += "<unkown type>(";
+ for (int i = 0; i < argc; i++) {
+ if (i > 0)
+ text += ", ";
+ text += DADDR(i + 1);
+ }
+ text += ")";
+
+ incr = 3 + instr_var_args;
+ } break;
+ case OPCODE_CONSTRUCT_ARRAY: {
+ int argc = _code_ptr[ip + 1 + instr_var_args];
+ text += " make_array ";
+ text += DADDR(1 + argc);
+ text += " = [";
+
+ for (int i = 0; i < argc; i++) {
+ if (i > 0)
+ text += ", ";
+ text += DADDR(1 + i);
+ }
+
+ text += "]";
+
+ incr += 3 + argc;
+ } break;
+ case OPCODE_CONSTRUCT_DICTIONARY: {
+ int argc = _code_ptr[ip + 1 + instr_var_args];
+ text += "make_dict ";
+ text += DADDR(1 + argc * 2);
+ text += " = {";
+
+ for (int i = 0; i < argc; i++) {
+ if (i > 0)
+ text += ", ";
+ text += DADDR(1 + i * 2 + 0);
+ text += ": ";
+ text += DADDR(1 + i * 2 + 1);
+ }
+
+ text += "}";
+
+ incr += 3 + argc * 2;
+ } break;
+ case OPCODE_CALL:
+ case OPCODE_CALL_RETURN:
+ case OPCODE_CALL_ASYNC: {
+ bool ret = (_code_ptr[ip] & INSTR_MASK) == OPCODE_CALL_RETURN;
+ bool async = (_code_ptr[ip] & INSTR_MASK) == OPCODE_CALL_ASYNC;
+
+ if (ret) {
+ text += "call-ret ";
+ } else if (async) {
+ text += "call-async ";
+ } else {
+ text += "call ";
+ }
+
+ int argc = _code_ptr[ip + 1 + instr_var_args];
+ if (ret || async) {
+ text += DADDR(2 + argc) + " = ";
+ }
+
+ text += DADDR(1 + argc) + ".";
+ text += String(_global_names_ptr[_code_ptr[ip + 2 + instr_var_args]]);
+ text += "(";
+
+ for (int i = 0; i < argc; i++) {
+ if (i > 0)
+ text += ", ";
+ text += DADDR(1 + i);
+ }
+ text += ")";
+
+ incr = 5 + argc;
+ } break;
+ case OPCODE_CALL_METHOD_BIND:
+ case OPCODE_CALL_METHOD_BIND_RET: {
+ bool ret = (_code_ptr[ip] & INSTR_MASK) == OPCODE_CALL_METHOD_BIND_RET;
+
+ if (ret) {
+ text += "call-method_bind-ret ";
+ } else {
+ text += "call-method_bind ";
+ }
+
+ MethodBind *method = _methods_ptr[_code_ptr[ip + 2 + instr_var_args]];
+
+ int argc = _code_ptr[ip + 1 + instr_var_args];
+ if (ret) {
+ text += DADDR(2 + argc) + " = ";
+ }
+
+ text += DADDR(1 + argc) + ".";
+ text += method->get_name();
+ text += "(";
+
+ for (int i = 0; i < argc; i++) {
+ if (i > 0)
+ text += ", ";
+ text += DADDR(1 + i);
+ }
+ text += ")";
+
+ incr = 5 + argc;
+ } break;
+ case OPCODE_CALL_PTRCALL_NO_RETURN: {
+ text += "call-ptrcall (no return) ";
+
+ MethodBind *method = _methods_ptr[_code_ptr[ip + 2 + instr_var_args]];
+
+ int argc = _code_ptr[ip + 1 + instr_var_args];
+
+ text += DADDR(1 + argc) + ".";
+ text += method->get_name();
+ text += "(";
+
+ for (int i = 0; i < argc; i++) {
+ if (i > 0)
+ text += ", ";
+ text += DADDR(1 + i);
+ }
+ text += ")";
+
+ incr = 5 + argc;
+ } break;
+
+#define DISASSEMBLE_PTRCALL(m_type) \
+ case OPCODE_CALL_PTRCALL_##m_type: { \
+ text += "call-ptrcall (return "; \
+ text += #m_type; \
+ text += ") "; \
+ MethodBind *method = _methods_ptr[_code_ptr[ip + 2 + instr_var_args]]; \
+ int argc = _code_ptr[ip + 1 + instr_var_args]; \
+ text += DADDR(2 + argc) + " = "; \
+ text += DADDR(1 + argc) + "."; \
+ text += method->get_name(); \
+ text += "("; \
+ for (int i = 0; i < argc; i++) { \
+ if (i > 0) \
+ text += ", "; \
+ text += DADDR(1 + i); \
+ } \
+ text += ")"; \
+ incr = 5 + argc; \
+ } break
+
+ DISASSEMBLE_PTRCALL(BOOL);
+ DISASSEMBLE_PTRCALL(INT);
+ DISASSEMBLE_PTRCALL(FLOAT);
+ DISASSEMBLE_PTRCALL(STRING);
+ DISASSEMBLE_PTRCALL(VECTOR2);
+ DISASSEMBLE_PTRCALL(VECTOR2I);
+ DISASSEMBLE_PTRCALL(RECT2);
+ DISASSEMBLE_PTRCALL(RECT2I);
+ DISASSEMBLE_PTRCALL(VECTOR3);
+ DISASSEMBLE_PTRCALL(VECTOR3I);
+ DISASSEMBLE_PTRCALL(TRANSFORM2D);
+ DISASSEMBLE_PTRCALL(PLANE);
+ DISASSEMBLE_PTRCALL(AABB);
+ DISASSEMBLE_PTRCALL(BASIS);
+ DISASSEMBLE_PTRCALL(TRANSFORM);
+ DISASSEMBLE_PTRCALL(COLOR);
+ DISASSEMBLE_PTRCALL(STRING_NAME);
+ DISASSEMBLE_PTRCALL(NODE_PATH);
+ DISASSEMBLE_PTRCALL(RID);
+ DISASSEMBLE_PTRCALL(QUAT);
+ DISASSEMBLE_PTRCALL(OBJECT);
+ DISASSEMBLE_PTRCALL(CALLABLE);
+ DISASSEMBLE_PTRCALL(SIGNAL);
+ DISASSEMBLE_PTRCALL(DICTIONARY);
+ DISASSEMBLE_PTRCALL(ARRAY);
+ DISASSEMBLE_PTRCALL(PACKED_BYTE_ARRAY);
+ DISASSEMBLE_PTRCALL(PACKED_INT32_ARRAY);
+ DISASSEMBLE_PTRCALL(PACKED_INT64_ARRAY);
+ DISASSEMBLE_PTRCALL(PACKED_FLOAT32_ARRAY);
+ DISASSEMBLE_PTRCALL(PACKED_FLOAT64_ARRAY);
+ DISASSEMBLE_PTRCALL(PACKED_STRING_ARRAY);
+ DISASSEMBLE_PTRCALL(PACKED_VECTOR2_ARRAY);
+ DISASSEMBLE_PTRCALL(PACKED_VECTOR3_ARRAY);
+ DISASSEMBLE_PTRCALL(PACKED_COLOR_ARRAY);
+
+ case OPCODE_CALL_BUILTIN_TYPE_VALIDATED: {
+ int argc = _code_ptr[ip + 1 + instr_var_args];
+
+ text += "call-builtin-method validated ";
+
+ text += DADDR(2 + argc) + " = ";
+
+ text += DADDR(1) + ".";
+ text += "<unknown method>";
+
+ text += "(";
+
+ for (int i = 0; i < argc; i++) {
+ if (i > 0)
+ text += ", ";
+ text += DADDR(1 + i);
+ }
+ text += ")";
+
+ incr = 5 + argc;
+ } break;
+ case OPCODE_CALL_UTILITY: {
+ text += "call-utility ";
+
+ int argc = _code_ptr[ip + 1 + instr_var_args];
+ text += DADDR(1 + argc) + " = ";
+
+ text += _global_names_ptr[_code_ptr[ip + 2 + instr_var_args]];
+ text += "(";
+
+ for (int i = 0; i < argc; i++) {
+ if (i > 0)
+ text += ", ";
+ text += DADDR(1 + i);
+ }
+ text += ")";
+
+ incr = 4 + argc;
+ } break;
+ case OPCODE_CALL_UTILITY_VALIDATED: {
+ text += "call-utility ";
+
+ int argc = _code_ptr[ip + 1 + instr_var_args];
+ text += DADDR(1 + argc) + " = ";
+
+ text += "<unkown function>";
+ text += "(";
+
+ for (int i = 0; i < argc; i++) {
+ if (i > 0)
+ text += ", ";
+ text += DADDR(1 + i);
+ }
+ text += ")";
+
+ incr = 4 + argc;
+ } break;
+ case OPCODE_CALL_GDSCRIPT_UTILITY: {
+ text += "call-gscript-utility ";
+
+ int argc = _code_ptr[ip + 1 + instr_var_args];
+ text += DADDR(1 + argc) + " = ";
+
+ text += "<unknown function>";
+ text += "(";
+
+ for (int i = 0; i < argc; i++) {
+ if (i > 0)
+ text += ", ";
+ text += DADDR(1 + i);
+ }
+ text += ")";
+
+ incr = 4 + argc;
+ } break;
+ case OPCODE_CALL_SELF_BASE: {
+ text += "call-self-base ";
+
+ int argc = _code_ptr[ip + 1 + instr_var_args];
+ text += DADDR(2 + argc) + " = ";
+
+ text += _global_names_ptr[_code_ptr[ip + 2 + instr_var_args]];
+ text += "(";
+
+ for (int i = 0; i < argc; i++) {
+ if (i > 0)
+ text += ", ";
+ text += DADDR(1 + i);
+ }
+ text += ")";
+
+ incr = 4 + argc;
+ } break;
+ case OPCODE_AWAIT: {
+ text += "await ";
+ text += DADDR(1);
+
+ incr += 2;
+ } break;
+ case OPCODE_AWAIT_RESUME: {
+ text += "await resume ";
+ text += DADDR(1);
+
+ incr = 2;
+ } break;
+ case OPCODE_JUMP: {
+ text += "jump ";
+ text += itos(_code_ptr[ip + 1]);
+
+ incr = 2;
+ } break;
+ case OPCODE_JUMP_IF: {
+ text += "jump-if ";
+ text += DADDR(1);
+ text += " to ";
+ text += itos(_code_ptr[ip + 2]);
+
+ incr = 3;
+ } break;
+ case OPCODE_JUMP_IF_NOT: {
+ text += "jump-if-not ";
+ text += DADDR(1);
+ text += " to ";
+ text += itos(_code_ptr[ip + 2]);
+
+ incr = 3;
+ } break;
+ case OPCODE_JUMP_TO_DEF_ARGUMENT: {
+ text += "jump-to-default-argument ";
+
+ incr = 1;
+ } break;
+ case OPCODE_RETURN: {
+ text += "return ";
+ text += DADDR(1);
+
+ incr = 2;
+ } break;
+
+#define DISASSEMBLE_ITERATE(m_type) \
+ case OPCODE_ITERATE_##m_type: { \
+ text += "for-loop (typed "; \
+ text += #m_type; \
+ text += ") "; \
+ text += DADDR(3); \
+ text += " in "; \
+ text += DADDR(2); \
+ text += " counter "; \
+ text += DADDR(1); \
+ text += " end "; \
+ text += itos(_code_ptr[ip + 4]); \
+ incr += 5; \
+ } break
+
+#define DISASSEMBLE_ITERATE_BEGIN(m_type) \
+ case OPCODE_ITERATE_BEGIN_##m_type: { \
+ text += "for-init (typed "; \
+ text += #m_type; \
+ text += ") "; \
+ text += DADDR(3); \
+ text += " in "; \
+ text += DADDR(2); \
+ text += " counter "; \
+ text += DADDR(1); \
+ text += " end "; \
+ text += itos(_code_ptr[ip + 4]); \
+ incr += 5; \
+ } break
+
+#define DISASSEMBLE_ITERATE_TYPES(m_macro) \
+ m_macro(INT); \
+ m_macro(FLOAT); \
+ m_macro(VECTOR2); \
+ m_macro(VECTOR2I); \
+ m_macro(VECTOR3); \
+ m_macro(VECTOR3I); \
+ m_macro(STRING); \
+ m_macro(DICTIONARY); \
+ m_macro(ARRAY); \
+ m_macro(PACKED_BYTE_ARRAY); \
+ m_macro(PACKED_INT32_ARRAY); \
+ m_macro(PACKED_INT64_ARRAY); \
+ m_macro(PACKED_FLOAT32_ARRAY); \
+ m_macro(PACKED_FLOAT64_ARRAY); \
+ m_macro(PACKED_STRING_ARRAY); \
+ m_macro(PACKED_VECTOR2_ARRAY); \
+ m_macro(PACKED_VECTOR3_ARRAY); \
+ m_macro(PACKED_COLOR_ARRAY); \
+ m_macro(OBJECT)
+
+ case OPCODE_ITERATE_BEGIN: {
+ text += "for-init ";
+ text += DADDR(3);
+ text += " in ";
+ text += DADDR(2);
+ text += " counter ";
+ text += DADDR(1);
+ text += " end ";
+ text += itos(_code_ptr[ip + 4]);
+
+ incr += 5;
+ } break;
+ DISASSEMBLE_ITERATE_TYPES(DISASSEMBLE_ITERATE_BEGIN);
+ case OPCODE_ITERATE: {
+ text += "for-loop ";
+ text += DADDR(2);
+ text += " in ";
+ text += DADDR(2);
+ text += " counter ";
+ text += DADDR(1);
+ text += " end ";
+ text += itos(_code_ptr[ip + 4]);
+
+ incr += 5;
+ } break;
+ DISASSEMBLE_ITERATE_TYPES(DISASSEMBLE_ITERATE);
+ case OPCODE_LINE: {
+ int line = _code_ptr[ip + 1] - 1;
+ if (line >= 0 && line < p_code_lines.size()) {
+ text += "line ";
+ text += itos(line + 1);
+ text += ": ";
+ text += p_code_lines[line];
+ } else {
+ text += "";
+ }
+
+ incr += 2;
+ } break;
+ case OPCODE_ASSERT: {
+ text += "assert (";
+ text += DADDR(1);
+ text += ", ";
+ text += DADDR(2);
+ text += ")";
+
+ incr += 3;
+ } break;
+ case OPCODE_BREAKPOINT: {
+ text += "breakpoint";
+
+ incr += 1;
+ } break;
+ case OPCODE_END: {
+ text += "== END ==";
+
+ incr += 1;
+ } break;
+ }
+
+ ip += incr;
+ if (text.get_string_length() > 0) {
+ print_line(text.as_string());
+ }
+ }
+}
+
+#endif
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 2e372575da..b17971cf93 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,16 +30,17 @@
#include "gdscript.h"
-#include "core/engine.h"
-#include "core/global_constants.h"
+#include "core/config/engine.h"
+#include "core/core_constants.h"
#include "core/os/file_access.h"
#include "gdscript_analyzer.h"
#include "gdscript_compiler.h"
#include "gdscript_parser.h"
#include "gdscript_tokenizer.h"
+#include "gdscript_utility_functions.h"
#ifdef TOOLS_ENABLED
-#include "core/project_settings.h"
+#include "core/config/project_settings.h"
#include "editor/editor_file_system.h"
#include "editor/editor_settings.h"
#endif
@@ -122,10 +123,10 @@ static void get_function_names_recursively(const GDScriptParser::ClassNode *p_cl
for (int i = 0; i < p_class->members.size(); i++) {
if (p_class->members[i].type == GDScriptParser::ClassNode::Member::FUNCTION) {
const GDScriptParser::FunctionNode *function = p_class->members[i].function;
- r_funcs[function->start_line] = p_prefix.empty() ? String(function->identifier->name) : p_prefix + "." + String(function->identifier->name);
+ r_funcs[function->start_line] = p_prefix.is_empty() ? String(function->identifier->name) : p_prefix + "." + String(function->identifier->name);
} else if (p_class->members[i].type == GDScriptParser::ClassNode::Member::CLASS) {
String new_prefix = p_class->members[i].m_class->identifier->name;
- get_function_names_recursively(p_class->members[i].m_class, p_prefix.empty() ? new_prefix : p_prefix + "." + new_prefix, r_funcs);
+ get_function_names_recursively(p_class->members[i].m_class, p_prefix.is_empty() ? new_prefix : p_prefix + "." + new_prefix, r_funcs);
}
}
}
@@ -193,6 +194,10 @@ bool GDScriptLanguage::supports_builtin_mode() const {
return true;
}
+bool GDScriptLanguage::supports_documentation() const {
+ return true;
+}
+
int GDScriptLanguage::find_function(const String &p_function, const String &p_code) const {
GDScriptTokenizer tokenizer;
tokenizer.set_source_code(p_code);
@@ -383,8 +388,8 @@ void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant>
}
bool skip = false;
- for (int i = 0; i < GlobalConstants::get_global_constant_count(); i++) {
- if (E->key() == GlobalConstants::get_global_constant_name(i)) {
+ for (int i = 0; i < CoreConstants::get_global_constant_count(); i++) {
+ if (E->key() == CoreConstants::get_global_constant_name(i)) {
skip = true;
break;
}
@@ -407,11 +412,14 @@ void GDScriptLanguage::get_recognized_extensions(List<String> *p_extensions) con
}
void GDScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const {
- for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) {
- p_functions->push_back(GDScriptFunctions::get_info(GDScriptFunctions::Function(i)));
+ List<StringName> functions;
+ GDScriptUtilityFunctions::get_function_list(&functions);
+
+ for (const List<StringName>::Element *E = functions.front(); E; E = E->next()) {
+ p_functions->push_back(GDScriptUtilityFunctions::get_function_info(E->get()));
}
- //not really "functions", but..
+ // Not really "functions", but show in documentation.
{
MethodInfo mi;
mi.name = "preload";
@@ -468,7 +476,7 @@ String GDScriptLanguage::make_function(const String &p_class, const String &p_na
s += p_args[i].get_slice(":", 0);
if (th) {
String type = p_args[i].get_slice(":", 1);
- if (!type.empty() && type != "var") {
+ if (!type.is_empty() && type != "var") {
s += ": " + type;
}
}
@@ -792,6 +800,9 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,
continue;
}
option = ScriptCodeCompletionOption(member.constant->identifier->name, ScriptCodeCompletionOption::KIND_CONSTANT);
+ if (member.constant->initializer) {
+ option.default_value = member.constant->initializer->reduced_value;
+ }
break;
case GDScriptParser::ClassNode::Member::CLASS:
if (p_only_functions) {
@@ -970,7 +981,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
} break;
case GDScriptParser::DataType::BUILTIN: {
Callable::CallError err;
- Variant tmp = Variant::construct(base_type.builtin_type, nullptr, 0, err);
+ Variant tmp;
+ Variant::construct(base_type.builtin_type, tmp, nullptr, 0, err);
if (err.error != Callable::CallError::CALL_OK) {
return;
}
@@ -1022,9 +1034,12 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
_find_identifiers_in_class(p_context.current_class, p_only_functions, (!p_context.current_function || p_context.current_function->is_static), false, r_result, p_recursion_depth + 1);
}
- for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) {
- MethodInfo function = GDScriptFunctions::get_info(GDScriptFunctions::Function(i));
- ScriptCodeCompletionOption option(String(GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i))), ScriptCodeCompletionOption::KIND_FUNCTION);
+ List<StringName> functions;
+ GDScriptUtilityFunctions::get_function_list(&functions);
+
+ for (const List<StringName>::Element *E = functions.front(); E; E = E->next()) {
+ MethodInfo function = GDScriptUtilityFunctions::get_function_info(E->get());
+ ScriptCodeCompletionOption option(String(E->get()), ScriptCodeCompletionOption::KIND_FUNCTION);
if (function.arguments.size() || (function.flags & METHOD_FLAG_VARARG)) {
option.insert_text += "(";
} else {
@@ -1050,10 +1065,8 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
}
static const char *_keywords[] = {
- "and", "in", "not", "or", "false", "PI", "TAU", "INF", "NAN", "self", "true", "as", "assert",
- "breakpoint", "class", "extends", "is", "func", "preload", "signal", "tool", "await",
- "const", "enum", "static", "super", "var", "break", "continue", "if", "elif",
- "else", "for", "pass", "return", "match", "while",
+ "false", "PI", "TAU", "INF", "NAN", "self", "true", "breakpoint", "tool", "super",
+ "break", "continue", "pass", "return",
0
};
@@ -1064,6 +1077,33 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
kw++;
}
+ static const char *_keywords_with_space[] = {
+ "and", "in", "not", "or", "as", "class", "extends", "is", "func", "signal", "await",
+ "const", "enum", "static", "var", "if", "elif", "else", "for", "match", "while",
+ 0
+ };
+
+ const char **kws = _keywords_with_space;
+ while (*kws) {
+ ScriptCodeCompletionOption option(*kws, ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
+ option.insert_text += " ";
+ r_result.insert(option.display, option);
+ kws++;
+ }
+
+ static const char *_keywords_with_args[] = {
+ "assert", "preload",
+ 0
+ };
+
+ const char **kwa = _keywords_with_args;
+ while (*kwa) {
+ ScriptCodeCompletionOption option(*kwa, ScriptCodeCompletionOption::KIND_FUNCTION);
+ option.insert_text += "(";
+ r_result.insert(option.display, option);
+ kwa++;
+ }
+
Map<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
for (const Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E != nullptr; E = E->next()) {
if (!E->value().is_singleton) {
@@ -1255,8 +1295,8 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context,
r_type.type.builtin_type = GDScriptParser::get_builtin_type(call->function_name);
found = true;
break;
- } else if (GDScriptParser::get_builtin_function(call->function_name) < GDScriptFunctions::FUNC_MAX) {
- MethodInfo mi = GDScriptFunctions::get_info(GDScriptParser::get_builtin_function(call->function_name));
+ } else if (GDScriptUtilityFunctions::function_exists(call->function_name)) {
+ MethodInfo mi = GDScriptUtilityFunctions::get_function_info(call->function_name);
r_type = _type_from_property(mi.return_val);
found = true;
break;
@@ -1520,7 +1560,8 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context,
found = _guess_identifier_type_from_base(c, base, id, r_type);
} else if (!found && index.type.kind == GDScriptParser::DataType::BUILTIN) {
Callable::CallError err;
- Variant base_val = Variant::construct(base.type.builtin_type, nullptr, 0, err);
+ Variant base_val;
+ Variant::construct(base.type.builtin_type, base_val, nullptr, 0, err);
bool valid = false;
Variant res = base_val.get(index.value, &valid);
if (valid) {
@@ -1557,9 +1598,14 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context,
Callable::CallError ce;
bool v1_use_value = p1.value.get_type() != Variant::NIL && p1.value.get_type() != Variant::OBJECT;
- Variant v1 = (v1_use_value) ? p1.value : Variant::construct(p1.type.builtin_type, nullptr, 0, ce);
+ Variant d1;
+ Variant::construct(p1.type.builtin_type, d1, nullptr, 0, ce);
+ Variant d2;
+ Variant::construct(p2.type.builtin_type, d2, nullptr, 0, ce);
+
+ Variant v1 = (v1_use_value) ? p1.value : d1;
bool v2_use_value = p2.value.get_type() != Variant::NIL && p2.value.get_type() != Variant::OBJECT;
- Variant v2 = (v2_use_value) ? p2.value : Variant::construct(p2.type.builtin_type, nullptr, 0, ce);
+ Variant v2 = (v2_use_value) ? p2.value : d2;
// avoid potential invalid ops
if ((op->variant_op == Variant::OP_DIVIDE || op->variant_op == Variant::OP_MODULE) && v2.get_type() == Variant::INT) {
v2 = 1;
@@ -1949,7 +1995,8 @@ static bool _guess_identifier_type_from_base(GDScriptParser::CompletionContext &
} break;
case GDScriptParser::DataType::BUILTIN: {
Callable::CallError err;
- Variant tmp = Variant::construct(base_type.builtin_type, nullptr, 0, err);
+ Variant tmp;
+ Variant::construct(base_type.builtin_type, tmp, nullptr, 0, err);
if (err.error != Callable::CallError::CALL_OK) {
return false;
@@ -2099,7 +2146,8 @@ static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContex
} break;
case GDScriptParser::DataType::BUILTIN: {
Callable::CallError err;
- Variant tmp = Variant::construct(base_type.builtin_type, nullptr, 0, err);
+ Variant tmp;
+ Variant::construct(base_type.builtin_type, tmp, nullptr, 0, err);
if (err.error != Callable::CallError::CALL_OK) {
return false;
}
@@ -2136,9 +2184,9 @@ static void _find_enumeration_candidates(GDScriptParser::CompletionContext &p_co
r_result.insert(option.display, option);
}
} else {
- for (int i = 0; i < GlobalConstants::get_global_constant_count(); i++) {
- if (GlobalConstants::get_global_constant_enum(i) == current_enum) {
- ScriptCodeCompletionOption option(GlobalConstants::get_global_constant_name(i), ScriptCodeCompletionOption::KIND_ENUM);
+ 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);
r_result.insert(option.display, option);
}
}
@@ -2254,7 +2302,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
case GDScriptParser::DataType::BUILTIN: {
if (base.get_type() == Variant::NIL) {
Callable::CallError err;
- base = Variant::construct(base_type.builtin_type, nullptr, 0, err);
+ Variant::construct(base_type.builtin_type, base, nullptr, 0, err);
if (err.error != Callable::CallError::CALL_OK) {
return;
}
@@ -2297,17 +2345,12 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
GDScriptParser::DataType base_type;
bool _static = false;
const GDScriptParser::CallNode *call = static_cast<const GDScriptParser::CallNode *>(p_call);
- GDScriptParser::Node::Type callee_type = GDScriptParser::Node::NONE;
+ GDScriptParser::Node::Type callee_type = call->get_callee_type();
GDScriptCompletionIdentifier connect_base;
- if (GDScriptParser::get_builtin_function(call->function_name) < GDScriptFunctions::FUNC_MAX) {
- MethodInfo info = GDScriptFunctions::get_info(GDScriptParser::get_builtin_function(call->function_name));
-
- if ((info.name == "load" || info.name == "preload") && bool(EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths"))) {
- _get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), r_result);
- }
-
+ if (GDScriptUtilityFunctions::function_exists(call->function_name)) {
+ MethodInfo info = GDScriptUtilityFunctions::get_function_info(call->function_name);
r_arghint = _make_arguments_hint(info, p_argidx);
return;
} else if (GDScriptParser::get_builtin_type(call->function_name) < Variant::VARIANT_MAX) {
@@ -2404,6 +2447,11 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
Variant::get_constants_for_type(completion_context.builtin_type, &constants);
for (const List<StringName>::Element *E = constants.front(); E != nullptr; E = E->next()) {
ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_CONSTANT);
+ bool valid = false;
+ Variant default_value = Variant::get_constant_value(completion_context.builtin_type, E->get(), &valid);
+ if (valid) {
+ option.default_value = default_value;
+ }
options.insert(option.display, option);
}
} break;
@@ -2463,7 +2511,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
break;
}
- if (!type.enumeration.empty()) {
+ if (!type.enumeration.is_empty()) {
_find_enumeration_candidates(completion_context, type.enumeration, options);
r_forced = options.size() > 0;
} else {
@@ -2875,7 +2923,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
v = v_ref;
} else {
Callable::CallError err;
- v = Variant::construct(base_type.builtin_type, NULL, 0, err);
+ Variant::construct(base_type.builtin_type, v, NULL, 0, err);
if (err.error != Callable::CallError::CALL_OK) {
break;
}
@@ -2930,13 +2978,11 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol
}
}
- for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) {
- if (GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i)) == p_symbol) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD;
- r_result.class_name = "@GDScript";
- r_result.class_member = p_symbol;
- return OK;
- }
+ if (GDScriptUtilityFunctions::function_exists(p_symbol)) {
+ r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD;
+ r_result.class_name = "@GDScript";
+ r_result.class_member = p_symbol;
+ return OK;
}
if ("PI" == p_symbol || "TAU" == p_symbol || "INF" == p_symbol || "NAN" == p_symbol) {
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp
index e59f99fc56..2171426e6f 100644
--- a/modules/gdscript/gdscript_function.cpp
+++ b/modules/gdscript/gdscript_function.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,1565 +30,7 @@
#include "gdscript_function.h"
-#include "core/os/os.h"
#include "gdscript.h"
-#include "gdscript_functions.h"
-
-#ifdef DEBUG_ENABLED
-#include "core/string_builder.h"
-#endif
-
-Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_instance, GDScript *p_script, Variant &self, Variant &static_ref, Variant *p_stack, String &r_error) const {
- int address = p_address & ADDR_MASK;
-
- //sequential table (jump table generated by compiler)
- switch ((p_address & ADDR_TYPE_MASK) >> ADDR_BITS) {
- case ADDR_TYPE_SELF: {
-#ifdef DEBUG_ENABLED
- if (unlikely(!p_instance)) {
- r_error = "Cannot access self without instance.";
- return nullptr;
- }
-#endif
- return &self;
- } break;
- case ADDR_TYPE_CLASS: {
- return &static_ref;
- } break;
- case ADDR_TYPE_MEMBER: {
-#ifdef DEBUG_ENABLED
- if (unlikely(!p_instance)) {
- r_error = "Cannot access member without instance.";
- return nullptr;
- }
-#endif
- //member indexing is O(1)
- return &p_instance->members.write[address];
- } break;
- case ADDR_TYPE_CLASS_CONSTANT: {
- //todo change to index!
- GDScript *s = p_script;
-#ifdef DEBUG_ENABLED
- ERR_FAIL_INDEX_V(address, _global_names_count, nullptr);
-#endif
- const StringName *sn = &_global_names_ptr[address];
-
- while (s) {
- GDScript *o = s;
- while (o) {
- Map<StringName, Variant>::Element *E = o->constants.find(*sn);
- if (E) {
- return &E->get();
- }
- o = o->_owner;
- }
- s = s->_base;
- }
-
- ERR_FAIL_V_MSG(nullptr, "GDScriptCompiler bug.");
- } break;
- case ADDR_TYPE_LOCAL_CONSTANT: {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_INDEX_V(address, _constant_count, nullptr);
-#endif
- return &_constants_ptr[address];
- } break;
- case ADDR_TYPE_STACK:
- case ADDR_TYPE_STACK_VARIABLE: {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_INDEX_V(address, _stack_size, nullptr);
-#endif
- return &p_stack[address];
- } break;
- case ADDR_TYPE_GLOBAL: {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_INDEX_V(address, GDScriptLanguage::get_singleton()->get_global_array_size(), nullptr);
-#endif
- return &GDScriptLanguage::get_singleton()->get_global_array()[address];
- } break;
-#ifdef TOOLS_ENABLED
- case ADDR_TYPE_NAMED_GLOBAL: {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_INDEX_V(address, _global_names_count, nullptr);
-#endif
- StringName id = _global_names_ptr[address];
-
- if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(id)) {
- return (Variant *)&GDScriptLanguage::get_singleton()->get_named_globals_map()[id];
- } else {
- r_error = "Autoload singleton '" + String(id) + "' has been removed.";
- return nullptr;
- }
- } break;
-#endif
- case ADDR_TYPE_NIL: {
- return &nil;
- } break;
- }
-
- ERR_FAIL_V_MSG(nullptr, "Bad code! (unknown addressing mode).");
- return nullptr;
-}
-
-#ifdef DEBUG_ENABLED
-static String _get_var_type(const Variant *p_var) {
- String basestr;
-
- if (p_var->get_type() == Variant::OBJECT) {
- bool was_freed;
- Object *bobj = p_var->get_validated_object_with_check(was_freed);
- if (!bobj) {
- if (was_freed) {
- basestr = "null instance";
- } else {
- basestr = "previously freed";
- }
- } else {
- if (bobj->get_script_instance()) {
- basestr = bobj->get_class() + " (" + bobj->get_script_instance()->get_script()->get_path().get_file() + ")";
- } else {
- basestr = bobj->get_class();
- }
- }
-
- } else {
- basestr = Variant::get_type_name(p_var->get_type());
- }
-
- return basestr;
-}
-#endif // DEBUG_ENABLED
-
-String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const String &p_where, const Variant **argptrs) const {
- String err_text;
-
- if (p_err.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) {
- int errorarg = p_err.argument;
- // Handle the Object to Object case separately as we don't have further class details.
-#ifdef DEBUG_ENABLED
- if (p_err.expected == Variant::OBJECT && argptrs[errorarg]->get_type() == p_err.expected) {
- err_text = "Invalid type in " + p_where + ". The Object-derived class of argument " + itos(errorarg + 1) + " (" + _get_var_type(argptrs[errorarg]) + ") is not a subclass of the expected argument class.";
- } else
-#endif // DEBUG_ENABLED
- {
- err_text = "Invalid type in " + p_where + ". Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(Variant::Type(p_err.expected)) + ".";
- }
- } else if (p_err.error == Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) {
- err_text = "Invalid call to " + p_where + ". Expected " + itos(p_err.argument) + " arguments.";
- } else if (p_err.error == Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) {
- err_text = "Invalid call to " + p_where + ". Expected " + itos(p_err.argument) + " arguments.";
- } else if (p_err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
- err_text = "Invalid call. Nonexistent " + p_where + ".";
- } else if (p_err.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
- err_text = "Attempt to call " + p_where + " on a null instance.";
- } else {
- err_text = "Bug, call error: #" + itos(p_err.error);
- }
-
- return err_text;
-}
-
-#if defined(__GNUC__)
-#define OPCODES_TABLE \
- static const void *switch_table_ops[] = { \
- &&OPCODE_OPERATOR, \
- &&OPCODE_EXTENDS_TEST, \
- &&OPCODE_IS_BUILTIN, \
- &&OPCODE_SET, \
- &&OPCODE_GET, \
- &&OPCODE_SET_NAMED, \
- &&OPCODE_GET_NAMED, \
- &&OPCODE_SET_MEMBER, \
- &&OPCODE_GET_MEMBER, \
- &&OPCODE_ASSIGN, \
- &&OPCODE_ASSIGN_TRUE, \
- &&OPCODE_ASSIGN_FALSE, \
- &&OPCODE_ASSIGN_TYPED_BUILTIN, \
- &&OPCODE_ASSIGN_TYPED_NATIVE, \
- &&OPCODE_ASSIGN_TYPED_SCRIPT, \
- &&OPCODE_CAST_TO_BUILTIN, \
- &&OPCODE_CAST_TO_NATIVE, \
- &&OPCODE_CAST_TO_SCRIPT, \
- &&OPCODE_CONSTRUCT, \
- &&OPCODE_CONSTRUCT_ARRAY, \
- &&OPCODE_CONSTRUCT_DICTIONARY, \
- &&OPCODE_CALL, \
- &&OPCODE_CALL_RETURN, \
- &&OPCODE_CALL_ASYNC, \
- &&OPCODE_CALL_BUILT_IN, \
- &&OPCODE_CALL_SELF_BASE, \
- &&OPCODE_AWAIT, \
- &&OPCODE_AWAIT_RESUME, \
- &&OPCODE_JUMP, \
- &&OPCODE_JUMP_IF, \
- &&OPCODE_JUMP_IF_NOT, \
- &&OPCODE_JUMP_TO_DEF_ARGUMENT, \
- &&OPCODE_RETURN, \
- &&OPCODE_ITERATE_BEGIN, \
- &&OPCODE_ITERATE, \
- &&OPCODE_ASSERT, \
- &&OPCODE_BREAKPOINT, \
- &&OPCODE_LINE, \
- &&OPCODE_END \
- }; \
- static_assert((sizeof(switch_table_ops) / sizeof(switch_table_ops[0]) == (OPCODE_END + 1)), "Opcodes in jump table aren't the same as opcodes in enum.");
-
-#define OPCODE(m_op) \
- m_op:
-#define OPCODE_WHILE(m_test)
-#define OPCODES_END \
- OPSEXIT:
-#define OPCODES_OUT \
- OPSOUT:
-#define DISPATCH_OPCODE goto *switch_table_ops[_code_ptr[ip]]
-#define OPCODE_SWITCH(m_test) DISPATCH_OPCODE;
-#define OPCODE_BREAK goto OPSEXIT
-#define OPCODE_OUT goto OPSOUT
-#else
-#define OPCODES_TABLE
-#define OPCODE(m_op) case m_op:
-#define OPCODE_WHILE(m_test) while (m_test)
-#define OPCODES_END
-#define OPCODES_OUT
-#define DISPATCH_OPCODE continue
-#define OPCODE_SWITCH(m_test) switch (m_test)
-#define OPCODE_BREAK break
-#define OPCODE_OUT break
-#endif
-
-Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_args, int p_argcount, Callable::CallError &r_err, CallState *p_state) {
- OPCODES_TABLE;
-
- if (!_code_ptr) {
- return Variant();
- }
-
- r_err.error = Callable::CallError::CALL_OK;
-
- Variant self;
- Variant static_ref;
- Variant retvalue;
- Variant *stack = nullptr;
- Variant **call_args;
- int defarg = 0;
-
-#ifdef DEBUG_ENABLED
-
- //GDScriptLanguage::get_singleton()->calls++;
-
-#endif
-
- uint32_t alloca_size = 0;
- GDScript *script;
- int ip = 0;
- int line = _initial_line;
-
- if (p_state) {
- //use existing (supplied) state (awaited)
- stack = (Variant *)p_state->stack.ptr();
- call_args = (Variant **)&p_state->stack.ptr()[sizeof(Variant) * p_state->stack_size]; //ptr() to avoid bounds check
- line = p_state->line;
- ip = p_state->ip;
- alloca_size = p_state->stack.size();
- script = p_state->script;
- p_instance = p_state->instance;
- defarg = p_state->defarg;
- self = p_state->self;
-
- } else {
- if (p_argcount != _argument_count) {
- if (p_argcount > _argument_count) {
- r_err.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_err.argument = _argument_count;
-
- return Variant();
- } else if (p_argcount < _argument_count - _default_arg_count) {
- r_err.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_err.argument = _argument_count - _default_arg_count;
- return Variant();
- } else {
- defarg = _argument_count - p_argcount;
- }
- }
-
- alloca_size = sizeof(Variant *) * _call_size + sizeof(Variant) * _stack_size;
-
- if (alloca_size) {
- uint8_t *aptr = (uint8_t *)alloca(alloca_size);
-
- if (_stack_size) {
- stack = (Variant *)aptr;
- for (int i = 0; i < p_argcount; i++) {
- if (!argument_types[i].has_type) {
- memnew_placement(&stack[i], Variant(*p_args[i]));
- continue;
- }
-
- if (!argument_types[i].is_type(*p_args[i], true)) {
- r_err.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_err.argument = i;
- r_err.expected = argument_types[i].kind == GDScriptDataType::BUILTIN ? argument_types[i].builtin_type : Variant::OBJECT;
- return Variant();
- }
- if (argument_types[i].kind == GDScriptDataType::BUILTIN) {
- Variant arg = Variant::construct(argument_types[i].builtin_type, &p_args[i], 1, r_err);
- memnew_placement(&stack[i], Variant(arg));
- } else {
- memnew_placement(&stack[i], Variant(*p_args[i]));
- }
- }
- for (int i = p_argcount; i < _stack_size; i++) {
- memnew_placement(&stack[i], Variant);
- }
- } else {
- stack = nullptr;
- }
-
- if (_call_size) {
- call_args = (Variant **)&aptr[sizeof(Variant) * _stack_size];
- } else {
- call_args = nullptr;
- }
-
- } else {
- stack = nullptr;
- call_args = nullptr;
- }
-
- if (p_instance) {
- if (p_instance->base_ref && static_cast<Reference *>(p_instance->owner)->is_referenced()) {
- self = REF(static_cast<Reference *>(p_instance->owner));
- } else {
- self = p_instance->owner;
- }
- script = p_instance->script.ptr();
- } else {
- script = _script;
- }
- }
-
- static_ref = script;
-
- String err_text;
-
-#ifdef DEBUG_ENABLED
-
- if (EngineDebugger::is_active()) {
- GDScriptLanguage::get_singleton()->enter_function(p_instance, this, stack, &ip, &line);
- }
-
-#define GD_ERR_BREAK(m_cond) \
- { \
- if (unlikely(m_cond)) { \
- _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true. Breaking..:"); \
- OPCODE_BREAK; \
- } \
- }
-
-#define CHECK_SPACE(m_space) \
- GD_ERR_BREAK((ip + m_space) > _code_size)
-
-#define GET_VARIANT_PTR(m_v, m_code_ofs) \
- Variant *m_v; \
- m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, script, self, static_ref, stack, err_text); \
- if (unlikely(!m_v)) \
- OPCODE_BREAK;
-
-#else
-#define GD_ERR_BREAK(m_cond)
-#define CHECK_SPACE(m_space)
-#define GET_VARIANT_PTR(m_v, m_code_ofs) \
- Variant *m_v; \
- m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, script, self, static_ref, stack, err_text);
-
-#endif
-
-#ifdef DEBUG_ENABLED
-
- uint64_t function_start_time = 0;
- uint64_t function_call_time = 0;
-
- if (GDScriptLanguage::get_singleton()->profiling) {
- function_start_time = OS::get_singleton()->get_ticks_usec();
- function_call_time = 0;
- profile.call_count++;
- profile.frame_call_count++;
- }
- bool exit_ok = false;
- bool awaited = false;
-#endif
-
-#ifdef DEBUG_ENABLED
- OPCODE_WHILE(ip < _code_size) {
- int last_opcode = _code_ptr[ip];
-#else
- OPCODE_WHILE(true) {
-#endif
-
- OPCODE_SWITCH(_code_ptr[ip]) {
- OPCODE(OPCODE_OPERATOR) {
- CHECK_SPACE(5);
-
- bool valid;
- Variant::Operator op = (Variant::Operator)_code_ptr[ip + 1];
- GD_ERR_BREAK(op >= Variant::OP_MAX);
-
- GET_VARIANT_PTR(a, 2);
- GET_VARIANT_PTR(b, 3);
- GET_VARIANT_PTR(dst, 4);
-
-#ifdef DEBUG_ENABLED
-
- Variant ret;
- Variant::evaluate(op, *a, *b, ret, valid);
-#else
- Variant::evaluate(op, *a, *b, *dst, valid);
-#endif
-#ifdef DEBUG_ENABLED
- if (!valid) {
- if (ret.get_type() == Variant::STRING) {
- //return a string when invalid with the error
- err_text = ret;
- err_text += " in operator '" + Variant::get_operator_name(op) + "'.";
- } else {
- err_text = "Invalid operands '" + Variant::get_type_name(a->get_type()) + "' and '" + Variant::get_type_name(b->get_type()) + "' in operator '" + Variant::get_operator_name(op) + "'.";
- }
- OPCODE_BREAK;
- }
- *dst = ret;
-#endif
- ip += 5;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_EXTENDS_TEST) {
- CHECK_SPACE(4);
-
- GET_VARIANT_PTR(a, 1);
- GET_VARIANT_PTR(b, 2);
- GET_VARIANT_PTR(dst, 3);
-
-#ifdef DEBUG_ENABLED
- if (b->get_type() != Variant::OBJECT || b->operator Object *() == nullptr) {
- err_text = "Right operand of 'is' is not a class.";
- OPCODE_BREAK;
- }
-#endif
-
- bool extends_ok = false;
- if (a->get_type() == Variant::OBJECT && a->operator Object *() != nullptr) {
-#ifdef DEBUG_ENABLED
- bool was_freed;
- Object *obj_A = a->get_validated_object_with_check(was_freed);
-
- if (was_freed) {
- err_text = "Left operand of 'is' is a previously freed instance.";
- OPCODE_BREAK;
- }
-
- Object *obj_B = b->get_validated_object_with_check(was_freed);
-
- if (was_freed) {
- err_text = "Right operand of 'is' is a previously freed instance.";
- OPCODE_BREAK;
- }
-#else
-
- Object *obj_A = *a;
- Object *obj_B = *b;
-#endif // DEBUG_ENABLED
-
- GDScript *scr_B = Object::cast_to<GDScript>(obj_B);
-
- if (scr_B) {
- //if B is a script, the only valid condition is that A has an instance which inherits from the script
- //in other situation, this shoul return false.
-
- if (obj_A->get_script_instance() && obj_A->get_script_instance()->get_language() == GDScriptLanguage::get_singleton()) {
- GDScript *cmp = static_cast<GDScript *>(obj_A->get_script_instance()->get_script().ptr());
- //bool found=false;
- while (cmp) {
- if (cmp == scr_B) {
- //inherits from script, all ok
- extends_ok = true;
- break;
- }
-
- cmp = cmp->_base;
- }
- }
-
- } else {
- GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(obj_B);
-
-#ifdef DEBUG_ENABLED
- if (!nc) {
- err_text = "Right operand of 'is' is not a class (type: '" + obj_B->get_class() + "').";
- OPCODE_BREAK;
- }
-#endif
- extends_ok = ClassDB::is_parent_class(obj_A->get_class_name(), nc->get_name());
- }
- }
-
- *dst = extends_ok;
- ip += 4;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_IS_BUILTIN) {
- CHECK_SPACE(4);
-
- GET_VARIANT_PTR(value, 1);
- Variant::Type var_type = (Variant::Type)_code_ptr[ip + 2];
- GET_VARIANT_PTR(dst, 3);
-
- GD_ERR_BREAK(var_type < 0 || var_type >= Variant::VARIANT_MAX);
-
- *dst = value->get_type() == var_type;
- ip += 4;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_SET) {
- CHECK_SPACE(3);
-
- GET_VARIANT_PTR(dst, 1);
- GET_VARIANT_PTR(index, 2);
- GET_VARIANT_PTR(value, 3);
-
- bool valid;
- dst->set(*index, *value, &valid);
-
-#ifdef DEBUG_ENABLED
- if (!valid) {
- String v = index->operator String();
- if (v != "") {
- v = "'" + v + "'";
- } else {
- v = "of type '" + _get_var_type(index) + "'";
- }
- err_text = "Invalid set index " + v + " (on base: '" + _get_var_type(dst) + "') with value of type '" + _get_var_type(value) + "'";
- OPCODE_BREAK;
- }
-#endif
- ip += 4;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_GET) {
- CHECK_SPACE(3);
-
- GET_VARIANT_PTR(src, 1);
- GET_VARIANT_PTR(index, 2);
- GET_VARIANT_PTR(dst, 3);
-
- bool valid;
-#ifdef DEBUG_ENABLED
- //allow better error message in cases where src and dst are the same stack position
- Variant ret = src->get(*index, &valid);
-#else
- *dst = src->get(*index, &valid);
-
-#endif
-#ifdef DEBUG_ENABLED
- if (!valid) {
- String v = index->operator String();
- if (v != "") {
- v = "'" + v + "'";
- } else {
- v = "of type '" + _get_var_type(index) + "'";
- }
- err_text = "Invalid get index " + v + " (on base: '" + _get_var_type(src) + "').";
- OPCODE_BREAK;
- }
- *dst = ret;
-#endif
- ip += 4;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_SET_NAMED) {
- CHECK_SPACE(3);
-
- GET_VARIANT_PTR(dst, 1);
- GET_VARIANT_PTR(value, 3);
-
- int indexname = _code_ptr[ip + 2];
-
- GD_ERR_BREAK(indexname < 0 || indexname >= _global_names_count);
- const StringName *index = &_global_names_ptr[indexname];
-
- bool valid;
- dst->set_named(*index, *value, &valid);
-
-#ifdef DEBUG_ENABLED
- if (!valid) {
- String err_type;
- err_text = "Invalid set index '" + String(*index) + "' (on base: '" + _get_var_type(dst) + "') with value of type '" + _get_var_type(value) + "'.";
- OPCODE_BREAK;
- }
-#endif
- ip += 4;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_GET_NAMED) {
- CHECK_SPACE(4);
-
- GET_VARIANT_PTR(src, 1);
- GET_VARIANT_PTR(dst, 3);
-
- int indexname = _code_ptr[ip + 2];
-
- GD_ERR_BREAK(indexname < 0 || indexname >= _global_names_count);
- const StringName *index = &_global_names_ptr[indexname];
-
- bool valid;
-#ifdef DEBUG_ENABLED
- //allow better error message in cases where src and dst are the same stack position
- Variant ret = src->get_named(*index, &valid);
-
-#else
- *dst = src->get_named(*index, &valid);
-#endif
-#ifdef DEBUG_ENABLED
- if (!valid) {
- if (src->has_method(*index)) {
- err_text = "Invalid get index '" + index->operator String() + "' (on base: '" + _get_var_type(src) + "'). Did you mean '." + index->operator String() + "()' or funcref(obj, \"" + index->operator String() + "\") ?";
- } else {
- err_text = "Invalid get index '" + index->operator String() + "' (on base: '" + _get_var_type(src) + "').";
- }
- OPCODE_BREAK;
- }
- *dst = ret;
-#endif
- ip += 4;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_SET_MEMBER) {
- CHECK_SPACE(3);
- int indexname = _code_ptr[ip + 1];
- GD_ERR_BREAK(indexname < 0 || indexname >= _global_names_count);
- const StringName *index = &_global_names_ptr[indexname];
- GET_VARIANT_PTR(src, 2);
-
- bool valid;
-#ifndef DEBUG_ENABLED
- ClassDB::set_property(p_instance->owner, *index, *src, &valid);
-#else
- bool ok = ClassDB::set_property(p_instance->owner, *index, *src, &valid);
- if (!ok) {
- err_text = "Internal error setting property: " + String(*index);
- OPCODE_BREAK;
- } else if (!valid) {
- err_text = "Error setting property '" + String(*index) + "' with value of type " + Variant::get_type_name(src->get_type()) + ".";
- OPCODE_BREAK;
- }
-#endif
- ip += 3;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_GET_MEMBER) {
- CHECK_SPACE(3);
- int indexname = _code_ptr[ip + 1];
- GD_ERR_BREAK(indexname < 0 || indexname >= _global_names_count);
- const StringName *index = &_global_names_ptr[indexname];
- GET_VARIANT_PTR(dst, 2);
-
-#ifndef DEBUG_ENABLED
- ClassDB::get_property(p_instance->owner, *index, *dst);
-#else
- bool ok = ClassDB::get_property(p_instance->owner, *index, *dst);
- if (!ok) {
- err_text = "Internal error getting property: " + String(*index);
- OPCODE_BREAK;
- }
-#endif
- ip += 3;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_ASSIGN) {
- CHECK_SPACE(3);
- GET_VARIANT_PTR(dst, 1);
- GET_VARIANT_PTR(src, 2);
-
- *dst = *src;
-
- ip += 3;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_ASSIGN_TRUE) {
- CHECK_SPACE(2);
- GET_VARIANT_PTR(dst, 1);
-
- *dst = true;
-
- ip += 2;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_ASSIGN_FALSE) {
- CHECK_SPACE(2);
- GET_VARIANT_PTR(dst, 1);
-
- *dst = false;
-
- ip += 2;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_ASSIGN_TYPED_BUILTIN) {
- CHECK_SPACE(4);
- GET_VARIANT_PTR(dst, 2);
- GET_VARIANT_PTR(src, 3);
-
- Variant::Type var_type = (Variant::Type)_code_ptr[ip + 1];
- GD_ERR_BREAK(var_type < 0 || var_type >= Variant::VARIANT_MAX);
-
- if (src->get_type() != var_type) {
-#ifdef DEBUG_ENABLED
- if (Variant::can_convert_strict(src->get_type(), var_type)) {
-#endif // DEBUG_ENABLED
- Callable::CallError ce;
- *dst = Variant::construct(var_type, const_cast<const Variant **>(&src), 1, ce);
- } else {
-#ifdef DEBUG_ENABLED
- err_text = "Trying to assign value of type '" + Variant::get_type_name(src->get_type()) +
- "' to a variable of type '" + Variant::get_type_name(var_type) + "'.";
- OPCODE_BREAK;
- }
- } else {
-#endif // DEBUG_ENABLED
- *dst = *src;
- }
-
- ip += 4;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_ASSIGN_TYPED_NATIVE) {
- CHECK_SPACE(4);
- GET_VARIANT_PTR(dst, 2);
- GET_VARIANT_PTR(src, 3);
-
-#ifdef DEBUG_ENABLED
- GET_VARIANT_PTR(type, 1);
- GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(type->operator Object *());
- GD_ERR_BREAK(!nc);
- if (src->get_type() != Variant::OBJECT && src->get_type() != Variant::NIL) {
- err_text = "Trying to assign value of type '" + Variant::get_type_name(src->get_type()) +
- "' to a variable of type '" + nc->get_name() + "'.";
- OPCODE_BREAK;
- }
- Object *src_obj = src->operator Object *();
-
- if (src_obj && !ClassDB::is_parent_class(src_obj->get_class_name(), nc->get_name())) {
- err_text = "Trying to assign value of type '" + src_obj->get_class_name() +
- "' to a variable of type '" + nc->get_name() + "'.";
- OPCODE_BREAK;
- }
-#endif // DEBUG_ENABLED
- *dst = *src;
-
- ip += 4;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_ASSIGN_TYPED_SCRIPT) {
- CHECK_SPACE(4);
- GET_VARIANT_PTR(dst, 2);
- GET_VARIANT_PTR(src, 3);
-
-#ifdef DEBUG_ENABLED
- GET_VARIANT_PTR(type, 1);
- Script *base_type = Object::cast_to<Script>(type->operator Object *());
-
- GD_ERR_BREAK(!base_type);
-
- if (src->get_type() != Variant::OBJECT && src->get_type() != Variant::NIL) {
- err_text = "Trying to assign a non-object value to a variable of type '" + base_type->get_path().get_file() + "'.";
- OPCODE_BREAK;
- }
-
- if (src->get_type() != Variant::NIL && src->operator Object *() != nullptr) {
- ScriptInstance *scr_inst = src->operator Object *()->get_script_instance();
- if (!scr_inst) {
- err_text = "Trying to assign value of type '" + src->operator Object *()->get_class_name() +
- "' to a variable of type '" + base_type->get_path().get_file() + "'.";
- OPCODE_BREAK;
- }
-
- Script *src_type = src->operator Object *()->get_script_instance()->get_script().ptr();
- bool valid = false;
-
- while (src_type) {
- if (src_type == base_type) {
- valid = true;
- break;
- }
- src_type = src_type->get_base_script().ptr();
- }
-
- if (!valid) {
- err_text = "Trying to assign value of type '" + src->operator Object *()->get_script_instance()->get_script()->get_path().get_file() +
- "' to a variable of type '" + base_type->get_path().get_file() + "'.";
- OPCODE_BREAK;
- }
- }
-#endif // DEBUG_ENABLED
-
- *dst = *src;
-
- ip += 4;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_CAST_TO_BUILTIN) {
- CHECK_SPACE(4);
- Variant::Type to_type = (Variant::Type)_code_ptr[ip + 1];
- GET_VARIANT_PTR(src, 2);
- GET_VARIANT_PTR(dst, 3);
-
- GD_ERR_BREAK(to_type < 0 || to_type >= Variant::VARIANT_MAX);
-
- Callable::CallError err;
- *dst = Variant::construct(to_type, (const Variant **)&src, 1, err);
-
-#ifdef DEBUG_ENABLED
- if (err.error != Callable::CallError::CALL_OK) {
- err_text = "Invalid cast: could not convert value to '" + Variant::get_type_name(to_type) + "'.";
- OPCODE_BREAK;
- }
-#endif
-
- ip += 4;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_CAST_TO_NATIVE) {
- CHECK_SPACE(4);
- GET_VARIANT_PTR(to_type, 1);
- GET_VARIANT_PTR(src, 2);
- GET_VARIANT_PTR(dst, 3);
-
- GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(to_type->operator Object *());
- GD_ERR_BREAK(!nc);
-
-#ifdef DEBUG_ENABLED
- if (src->get_type() != Variant::OBJECT && src->get_type() != Variant::NIL) {
- err_text = "Invalid cast: can't convert a non-object value to an object type.";
- OPCODE_BREAK;
- }
-#endif
- Object *src_obj = src->operator Object *();
-
- if (src_obj && !ClassDB::is_parent_class(src_obj->get_class_name(), nc->get_name())) {
- *dst = Variant(); // invalid cast, assign NULL
- } else {
- *dst = *src;
- }
-
- ip += 4;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_CAST_TO_SCRIPT) {
- CHECK_SPACE(4);
- GET_VARIANT_PTR(to_type, 1);
- GET_VARIANT_PTR(src, 2);
- GET_VARIANT_PTR(dst, 3);
-
- Script *base_type = Object::cast_to<Script>(to_type->operator Object *());
-
- GD_ERR_BREAK(!base_type);
-
-#ifdef DEBUG_ENABLED
- if (src->get_type() != Variant::OBJECT && src->get_type() != Variant::NIL) {
- err_text = "Trying to assign a non-object value to a variable of type '" + base_type->get_path().get_file() + "'.";
- OPCODE_BREAK;
- }
-#endif
-
- bool valid = false;
-
- if (src->get_type() != Variant::NIL && src->operator Object *() != nullptr) {
- ScriptInstance *scr_inst = src->operator Object *()->get_script_instance();
-
- if (scr_inst) {
- Script *src_type = src->operator Object *()->get_script_instance()->get_script().ptr();
-
- while (src_type) {
- if (src_type == base_type) {
- valid = true;
- break;
- }
- src_type = src_type->get_base_script().ptr();
- }
- }
- }
-
- if (valid) {
- *dst = *src; // Valid cast, copy the source object
- } else {
- *dst = Variant(); // invalid cast, assign NULL
- }
-
- ip += 4;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_CONSTRUCT) {
- CHECK_SPACE(2);
- Variant::Type t = Variant::Type(_code_ptr[ip + 1]);
- int argc = _code_ptr[ip + 2];
- CHECK_SPACE(argc + 2);
- Variant **argptrs = call_args;
- for (int i = 0; i < argc; i++) {
- GET_VARIANT_PTR(v, 3 + i);
- argptrs[i] = v;
- }
-
- GET_VARIANT_PTR(dst, 3 + argc);
- Callable::CallError err;
- *dst = Variant::construct(t, (const Variant **)argptrs, argc, err);
-
-#ifdef DEBUG_ENABLED
- if (err.error != Callable::CallError::CALL_OK) {
- err_text = _get_call_error(err, "'" + Variant::get_type_name(t) + "' constructor", (const Variant **)argptrs);
- OPCODE_BREAK;
- }
-#endif
-
- ip += 4 + argc;
- //construct a basic type
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_CONSTRUCT_ARRAY) {
- CHECK_SPACE(1);
- int argc = _code_ptr[ip + 1];
- Array array; //arrays are always shared
- array.resize(argc);
- CHECK_SPACE(argc + 2);
-
- for (int i = 0; i < argc; i++) {
- GET_VARIANT_PTR(v, 2 + i);
- array[i] = *v;
- }
-
- GET_VARIANT_PTR(dst, 2 + argc);
-
- *dst = array;
-
- ip += 3 + argc;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_CONSTRUCT_DICTIONARY) {
- CHECK_SPACE(1);
- int argc = _code_ptr[ip + 1];
- Dictionary dict; //arrays are always shared
-
- CHECK_SPACE(argc * 2 + 2);
-
- for (int i = 0; i < argc; i++) {
- GET_VARIANT_PTR(k, 2 + i * 2 + 0);
- GET_VARIANT_PTR(v, 2 + i * 2 + 1);
- dict[*k] = *v;
- }
-
- GET_VARIANT_PTR(dst, 2 + argc * 2);
-
- *dst = dict;
-
- ip += 3 + argc * 2;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_CALL_ASYNC)
- OPCODE(OPCODE_CALL_RETURN)
- OPCODE(OPCODE_CALL) {
- CHECK_SPACE(4);
- bool call_ret = _code_ptr[ip] != OPCODE_CALL;
-#ifdef DEBUG_ENABLED
- bool call_async = _code_ptr[ip] == OPCODE_CALL_ASYNC;
-#endif
-
- int argc = _code_ptr[ip + 1];
- GET_VARIANT_PTR(base, 2);
- int nameg = _code_ptr[ip + 3];
-
- GD_ERR_BREAK(nameg < 0 || nameg >= _global_names_count);
- const StringName *methodname = &_global_names_ptr[nameg];
-
- GD_ERR_BREAK(argc < 0);
- ip += 4;
- CHECK_SPACE(argc + 1);
- Variant **argptrs = call_args;
-
- for (int i = 0; i < argc; i++) {
- GET_VARIANT_PTR(v, i);
- argptrs[i] = v;
- }
-
-#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;
- if (call_ret) {
- GET_VARIANT_PTR(ret, argc);
- base->call_ptr(*methodname, (const Variant **)argptrs, argc, ret, err);
-#ifdef DEBUG_ENABLED
- if (!call_async && ret->get_type() == Variant::OBJECT) {
- // Check if getting a function state without await.
- bool was_freed = false;
- Object *obj = ret->get_validated_object_with_check(was_freed);
-
- if (was_freed) {
- err_text = "Got a freed object as a result of the call.";
- OPCODE_BREAK;
- }
- if (obj && obj->is_class_ptr(GDScriptFunctionState::get_class_ptr_static())) {
- err_text = R"(Trying to call an async function without "await".)";
- OPCODE_BREAK;
- }
- }
-#endif
- } else {
- base->call_ptr(*methodname, (const Variant **)argptrs, argc, nullptr, 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) {
- String methodstr = *methodname;
- String basestr = _get_var_type(base);
-
- if (methodstr == "call") {
- if (argc >= 1) {
- methodstr = String(*argptrs[0]) + " (via call)";
- if (err.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) {
- err.argument += 1;
- }
- }
- } else if (methodstr == "free") {
- if (err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
- if (base->is_ref()) {
- err_text = "Attempted to free a reference.";
- OPCODE_BREAK;
- } else if (base->get_type() == Variant::OBJECT) {
- err_text = "Attempted to free a locked object (calling or emitting).";
- OPCODE_BREAK;
- }
- }
- }
- err_text = _get_call_error(err, "function '" + methodstr + "' in base '" + basestr + "'", (const Variant **)argptrs);
- OPCODE_BREAK;
- }
-#endif
-
- //_call_func(nullptr,base,*methodname,ip,argc,p_instance,stack);
- ip += argc + 1;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_CALL_BUILT_IN) {
- CHECK_SPACE(4);
-
- GDScriptFunctions::Function func = GDScriptFunctions::Function(_code_ptr[ip + 1]);
- int argc = _code_ptr[ip + 2];
- GD_ERR_BREAK(argc < 0);
-
- ip += 3;
- CHECK_SPACE(argc + 1);
- Variant **argptrs = call_args;
-
- for (int i = 0; i < argc; i++) {
- GET_VARIANT_PTR(v, i);
- argptrs[i] = v;
- }
-
- GET_VARIANT_PTR(dst, argc);
-
- Callable::CallError err;
-
- GDScriptFunctions::call(func, (const Variant **)argptrs, argc, *dst, err);
-
-#ifdef DEBUG_ENABLED
- if (err.error != Callable::CallError::CALL_OK) {
- String methodstr = GDScriptFunctions::get_func_name(func);
- if (dst->get_type() == Variant::STRING) {
- //call provided error string
- err_text = "Error calling built-in function '" + methodstr + "': " + String(*dst);
- } else {
- err_text = _get_call_error(err, "built-in function '" + methodstr + "'", (const Variant **)argptrs);
- }
- OPCODE_BREAK;
- }
-#endif
- ip += argc + 1;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_CALL_SELF_BASE) {
- CHECK_SPACE(2);
- int self_fun = _code_ptr[ip + 1];
-
-#ifdef DEBUG_ENABLED
- if (self_fun < 0 || self_fun >= _global_names_count) {
- err_text = "compiler bug, function name not found";
- OPCODE_BREAK;
- }
-#endif
- const StringName *methodname = &_global_names_ptr[self_fun];
-
- int argc = _code_ptr[ip + 2];
-
- CHECK_SPACE(2 + argc + 1);
-
- Variant **argptrs = call_args;
-
- for (int i = 0; i < argc; i++) {
- GET_VARIANT_PTR(v, i + 3);
- argptrs[i] = v;
- }
-
- GET_VARIANT_PTR(dst, argc + 3);
-
- const GDScript *gds = _script;
-
- const Map<StringName, GDScriptFunction *>::Element *E = nullptr;
- while (gds->base.ptr()) {
- gds = gds->base.ptr();
- E = gds->member_functions.find(*methodname);
- if (E) {
- break;
- }
- }
-
- Callable::CallError err;
-
- if (E) {
- *dst = E->get()->call(p_instance, (const Variant **)argptrs, argc, err);
- } else if (gds->native.ptr()) {
- if (*methodname != GDScriptLanguage::get_singleton()->strings._init) {
- MethodBind *mb = ClassDB::get_method(gds->native->get_name(), *methodname);
- if (!mb) {
- err.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- } else {
- *dst = mb->call(p_instance->owner, (const Variant **)argptrs, argc, err);
- }
- } else {
- err.error = Callable::CallError::CALL_OK;
- }
- } else {
- if (*methodname != GDScriptLanguage::get_singleton()->strings._init) {
- err.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- } else {
- err.error = Callable::CallError::CALL_OK;
- }
- }
-
- if (err.error != Callable::CallError::CALL_OK) {
- String methodstr = *methodname;
- err_text = _get_call_error(err, "function '" + methodstr + "'", (const Variant **)argptrs);
-
- OPCODE_BREAK;
- }
-
- ip += 4 + argc;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_AWAIT) {
- CHECK_SPACE(2);
-
- //do the oneshot connect
- GET_VARIANT_PTR(argobj, 1);
-
- Signal sig;
- bool is_signal = true;
-
- {
- Variant result = *argobj;
-
- if (argobj->get_type() == Variant::OBJECT) {
- bool was_freed = false;
- Object *obj = argobj->get_validated_object_with_check(was_freed);
-
- if (was_freed) {
- err_text = "Trying to await on a freed object.";
- OPCODE_BREAK;
- }
-
- // Is this even possible to be null at this point?
- if (obj) {
- if (obj->is_class_ptr(GDScriptFunctionState::get_class_ptr_static())) {
- static StringName completed = _scs_create("completed");
- result = Signal(obj, completed);
- }
- }
- }
-
- if (result.get_type() != Variant::SIGNAL) {
- ip += 4; // Skip OPCODE_AWAIT_RESUME and its data.
- // The stack pointer should be the same, so we don't need to set a return value.
- is_signal = false;
- } else {
- sig = result;
- }
- }
-
- if (is_signal) {
- Ref<GDScriptFunctionState> gdfs = memnew(GDScriptFunctionState);
- gdfs->function = this;
-
- gdfs->state.stack.resize(alloca_size);
- //copy variant stack
- for (int i = 0; i < _stack_size; i++) {
- memnew_placement(&gdfs->state.stack.write[sizeof(Variant) * i], Variant(stack[i]));
- }
- gdfs->state.stack_size = _stack_size;
- gdfs->state.self = self;
- gdfs->state.alloca_size = alloca_size;
- gdfs->state.ip = ip + 2;
- gdfs->state.line = line;
- gdfs->state.script = _script;
- {
- MutexLock lock(GDScriptLanguage::get_singleton()->lock);
- _script->pending_func_states.add(&gdfs->scripts_list);
- if (p_instance) {
- gdfs->state.instance = p_instance;
- p_instance->pending_func_states.add(&gdfs->instances_list);
- } else {
- gdfs->state.instance = nullptr;
- }
- }
-#ifdef DEBUG_ENABLED
- gdfs->state.function_name = name;
- gdfs->state.script_path = _script->get_path();
-#endif
- gdfs->state.defarg = defarg;
- gdfs->function = this;
-
- retvalue = gdfs;
-
- Error err = sig.connect(Callable(gdfs.ptr(), "_signal_callback"), varray(gdfs), Object::CONNECT_ONESHOT);
- if (err != OK) {
- err_text = "Error connecting to signal: " + sig.get_name() + " during await.";
- OPCODE_BREAK;
- }
-
-#ifdef DEBUG_ENABLED
- exit_ok = true;
- awaited = true;
-#endif
- OPCODE_BREAK;
- }
- }
- DISPATCH_OPCODE; // Needed for synchronous calls (when result is immediately available).
-
- OPCODE(OPCODE_AWAIT_RESUME) {
- CHECK_SPACE(2);
-#ifdef DEBUG_ENABLED
- if (!p_state) {
- err_text = ("Invalid Resume (bug?)");
- OPCODE_BREAK;
- }
-#endif
- GET_VARIANT_PTR(result, 1);
- *result = p_state->result;
- ip += 2;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_JUMP) {
- CHECK_SPACE(2);
- int to = _code_ptr[ip + 1];
-
- GD_ERR_BREAK(to < 0 || to > _code_size);
- ip = to;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_JUMP_IF) {
- CHECK_SPACE(3);
-
- GET_VARIANT_PTR(test, 1);
-
- bool result = test->booleanize();
-
- if (result) {
- int to = _code_ptr[ip + 2];
- GD_ERR_BREAK(to < 0 || to > _code_size);
- ip = to;
- } else {
- ip += 3;
- }
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_JUMP_IF_NOT) {
- CHECK_SPACE(3);
-
- GET_VARIANT_PTR(test, 1);
-
- bool result = test->booleanize();
-
- if (!result) {
- int to = _code_ptr[ip + 2];
- GD_ERR_BREAK(to < 0 || to > _code_size);
- ip = to;
- } else {
- ip += 3;
- }
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_JUMP_TO_DEF_ARGUMENT) {
- CHECK_SPACE(2);
- ip = _default_arg_ptr[defarg];
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_RETURN) {
- CHECK_SPACE(2);
- GET_VARIANT_PTR(r, 1);
- retvalue = *r;
-#ifdef DEBUG_ENABLED
- exit_ok = true;
-#endif
- OPCODE_BREAK;
- }
-
- OPCODE(OPCODE_ITERATE_BEGIN) {
- CHECK_SPACE(8); //space for this a regular iterate
-
- GET_VARIANT_PTR(counter, 1);
- GET_VARIANT_PTR(container, 2);
-
- bool valid;
- if (!container->iter_init(*counter, valid)) {
-#ifdef DEBUG_ENABLED
- if (!valid) {
- err_text = "Unable to iterate on object of type '" + Variant::get_type_name(container->get_type()) + "'.";
- OPCODE_BREAK;
- }
-#endif
- int jumpto = _code_ptr[ip + 3];
- GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
- ip = jumpto;
- } else {
- GET_VARIANT_PTR(iterator, 4);
-
- *iterator = container->iter_get(*counter, valid);
-#ifdef DEBUG_ENABLED
- if (!valid) {
- err_text = "Unable to obtain iterator object of type '" + Variant::get_type_name(container->get_type()) + "'.";
- OPCODE_BREAK;
- }
-#endif
- ip += 5; //skip regular iterate which is always next
- }
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_ITERATE) {
- CHECK_SPACE(4);
-
- GET_VARIANT_PTR(counter, 1);
- GET_VARIANT_PTR(container, 2);
-
- bool valid;
- if (!container->iter_next(*counter, valid)) {
-#ifdef DEBUG_ENABLED
- if (!valid) {
- err_text = "Unable to iterate on object of type '" + Variant::get_type_name(container->get_type()) + "' (type changed since first iteration?).";
- OPCODE_BREAK;
- }
-#endif
- int jumpto = _code_ptr[ip + 3];
- GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
- ip = jumpto;
- } else {
- GET_VARIANT_PTR(iterator, 4);
-
- *iterator = container->iter_get(*counter, valid);
-#ifdef DEBUG_ENABLED
- if (!valid) {
- err_text = "Unable to obtain iterator object of type '" + Variant::get_type_name(container->get_type()) + "' (but was obtained on first iteration?).";
- OPCODE_BREAK;
- }
-#endif
- ip += 5; //loop again
- }
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_ASSERT) {
- CHECK_SPACE(3);
-
-#ifdef DEBUG_ENABLED
- GET_VARIANT_PTR(test, 1);
- bool result = test->booleanize();
-
- if (!result) {
- String message_str;
- if (_code_ptr[ip + 2] != 0) {
- GET_VARIANT_PTR(message, 2);
- message_str = *message;
- }
- if (message_str.empty()) {
- err_text = "Assertion failed.";
- } else {
- err_text = "Assertion failed: " + message_str;
- }
- OPCODE_BREAK;
- }
-
-#endif
- ip += 3;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_BREAKPOINT) {
-#ifdef DEBUG_ENABLED
- if (EngineDebugger::is_active()) {
- GDScriptLanguage::get_singleton()->debug_break("Breakpoint Statement", true);
- }
-#endif
- ip += 1;
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_LINE) {
- CHECK_SPACE(2);
-
- line = _code_ptr[ip + 1];
- ip += 2;
-
- if (EngineDebugger::is_active()) {
- // line
- bool do_break = false;
-
- if (EngineDebugger::get_script_debugger()->get_lines_left() > 0) {
- if (EngineDebugger::get_script_debugger()->get_depth() <= 0) {
- EngineDebugger::get_script_debugger()->set_lines_left(EngineDebugger::get_script_debugger()->get_lines_left() - 1);
- }
- if (EngineDebugger::get_script_debugger()->get_lines_left() <= 0) {
- do_break = true;
- }
- }
-
- if (EngineDebugger::get_script_debugger()->is_breakpoint(line, source)) {
- do_break = true;
- }
-
- if (do_break) {
- GDScriptLanguage::get_singleton()->debug_break("Breakpoint", true);
- }
-
- EngineDebugger::get_singleton()->line_poll();
- }
- }
- DISPATCH_OPCODE;
-
- OPCODE(OPCODE_END) {
-#ifdef DEBUG_ENABLED
- exit_ok = true;
-#endif
- OPCODE_BREAK;
- }
-
-#if 0 // Enable for debugging.
- default: {
- err_text = "Illegal opcode " + itos(_code_ptr[ip]) + " at address " + itos(ip);
- OPCODE_BREAK;
- }
-#endif
- }
-
- OPCODES_END
-#ifdef DEBUG_ENABLED
- if (exit_ok) {
- OPCODE_OUT;
- }
- //error
- // function, file, line, error, explanation
- String err_file;
- if (p_instance && ObjectDB::get_instance(p_instance->owner_id) != nullptr && p_instance->script->is_valid() && p_instance->script->path != "") {
- err_file = p_instance->script->path;
- } else if (script) {
- err_file = script->path;
- }
- if (err_file == "") {
- err_file = "<built-in>";
- }
- String err_func = name;
- if (p_instance && ObjectDB::get_instance(p_instance->owner_id) != nullptr && p_instance->script->is_valid() && p_instance->script->name != "") {
- err_func = p_instance->script->name + "." + err_func;
- }
- int err_line = line;
- if (err_text == "") {
- err_text = "Internal Script Error! - opcode #" + itos(last_opcode) + " (report please).";
- }
-
- if (!GDScriptLanguage::get_singleton()->debug_break(err_text, false)) {
- // debugger break did not happen
-
- _err_print_error(err_func.utf8().get_data(), err_file.utf8().get_data(), err_line, err_text.utf8().get_data(), ERR_HANDLER_SCRIPT);
- }
-
-#endif
- OPCODE_OUT;
- }
-
- OPCODES_OUT
-#ifdef DEBUG_ENABLED
- if (GDScriptLanguage::get_singleton()->profiling) {
- uint64_t time_taken = OS::get_singleton()->get_ticks_usec() - function_start_time;
- profile.total_time += time_taken;
- profile.self_time += time_taken - function_call_time;
- profile.frame_total_time += time_taken;
- profile.frame_self_time += time_taken - function_call_time;
- GDScriptLanguage::get_singleton()->script_frame_time += time_taken - function_call_time;
- }
-
- // Check if this is the last time the function is resuming from await
- // Will be true if never awaited as well
- // When it's the last resume it will postpone the exit from stack,
- // so the debugger knows which function triggered the resume of the next function (if any)
- if (!p_state || awaited) {
- if (EngineDebugger::is_active()) {
- GDScriptLanguage::get_singleton()->exit_function();
- }
-#endif
-
- if (_stack_size) {
- //free stack
- for (int i = 0; i < _stack_size; i++) {
- stack[i].~Variant();
- }
- }
-
-#ifdef DEBUG_ENABLED
- }
-#endif
-
- return retvalue;
-}
const int *GDScriptFunction::get_code() const {
return _code_ptr;
@@ -1672,7 +114,7 @@ void GDScriptFunction::debug_get_stack_member_state(int p_line, List<Pair<String
ERR_CONTINUE(!sdmap.has(sd.identifier));
sdmap[sd.identifier].pos.pop_back();
- if (sdmap[sd.identifier].pos.empty()) {
+ if (sdmap[sd.identifier].pos.is_empty()) {
sdmap.erase(sd.identifier);
}
}
@@ -1697,31 +139,13 @@ void GDScriptFunction::debug_get_stack_member_state(int p_line, List<Pair<String
}
}
-GDScriptFunction::GDScriptFunction() :
- function_list(this) {
- _stack_size = 0;
- _call_size = 0;
- rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
+GDScriptFunction::GDScriptFunction() {
name = "<anonymous>";
#ifdef DEBUG_ENABLED
- _func_cname = nullptr;
-
{
MutexLock lock(GDScriptLanguage::get_singleton()->lock);
-
GDScriptLanguage::get_singleton()->function_list.add(&function_list);
}
-
- profile.call_count = 0;
- profile.self_time = 0;
- profile.total_time = 0;
- profile.frame_call_count = 0;
- profile.frame_self_time = 0;
- profile.frame_total_time = 0;
- profile.last_frame_call_count = 0;
- profile.last_frame_self_time = 0;
- profile.last_frame_total_time = 0;
-
#endif
}
@@ -1882,506 +306,3 @@ GDScriptFunctionState::~GDScriptFunctionState() {
instances_list.remove_from_list();
}
}
-
-#ifdef DEBUG_ENABLED
-static String _get_variant_string(const Variant &p_variant) {
- String txt;
- if (p_variant.get_type() == Variant::STRING) {
- txt = "\"" + String(p_variant) + "\"";
- } else if (p_variant.get_type() == Variant::STRING_NAME) {
- txt = "&\"" + String(p_variant) + "\"";
- } else if (p_variant.get_type() == Variant::NODE_PATH) {
- txt = "^\"" + String(p_variant) + "\"";
- } else if (p_variant.get_type() == Variant::OBJECT) {
- Object *obj = p_variant;
- if (!obj) {
- txt = "null";
- } else {
- GDScriptNativeClass *cls = Object::cast_to<GDScriptNativeClass>(obj);
- if (cls) {
- txt += cls->get_name();
- txt += " (class)";
- } else {
- txt = obj->get_class();
- if (obj->get_script_instance()) {
- txt += "(" + obj->get_script_instance()->get_script()->get_path() + ")";
- }
- }
- }
- } else {
- txt = p_variant;
- }
- return txt;
-}
-
-static String _disassemble_address(const GDScript *p_script, const GDScriptFunction &p_function, int p_address) {
- int addr = p_address & GDScriptFunction::ADDR_MASK;
-
- switch (p_address >> GDScriptFunction::ADDR_BITS) {
- case GDScriptFunction::ADDR_TYPE_SELF: {
- return "self";
- } break;
- case GDScriptFunction::ADDR_TYPE_CLASS: {
- return "class";
- } break;
- case GDScriptFunction::ADDR_TYPE_MEMBER: {
- return "member(" + p_script->debug_get_member_by_index(addr) + ")";
- } break;
- case GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT: {
- return "class_const(" + p_function.get_global_name(addr) + ")";
- } break;
- case GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT: {
- return "const(" + _get_variant_string(p_function.get_constant(addr)) + ")";
- } break;
- case GDScriptFunction::ADDR_TYPE_STACK: {
- return "stack(" + itos(addr) + ")";
- } break;
- case GDScriptFunction::ADDR_TYPE_STACK_VARIABLE: {
- return "var_stack(" + itos(addr) + ")";
- } break;
- case GDScriptFunction::ADDR_TYPE_GLOBAL: {
- return "global(" + _get_variant_string(GDScriptLanguage::get_singleton()->get_global_array()[addr]) + ")";
- } break;
- case GDScriptFunction::ADDR_TYPE_NAMED_GLOBAL: {
- return "named_global(" + p_function.get_global_name(addr) + ")";
- } break;
- case GDScriptFunction::ADDR_TYPE_NIL: {
- return "nil";
- } break;
- }
-
- return "<err>";
-}
-
-void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
-#define DADDR(m_ip) (_disassemble_address(_script, *this, _code_ptr[ip + m_ip]))
-
- for (int ip = 0; ip < _code_size;) {
- StringBuilder text;
- int incr = 0;
-
- text += " ";
- text += itos(ip);
- text += ": ";
-
- // This makes the compiler complain if some opcode is unchecked in the switch.
- Opcode code = Opcode(_code_ptr[ip]);
-
- switch (code) {
- case OPCODE_OPERATOR: {
- int operation = _code_ptr[ip + 1];
-
- text += "operator ";
-
- text += DADDR(4);
- text += " = ";
- text += DADDR(2);
- text += " ";
- text += Variant::get_operator_name(Variant::Operator(operation));
- text += " ";
- text += DADDR(3);
-
- incr += 5;
- } break;
- case OPCODE_EXTENDS_TEST: {
- text += "is object ";
- text += DADDR(3);
- text += " = ";
- text += DADDR(1);
- text += " is ";
- text += DADDR(2);
-
- incr += 4;
- } break;
- case OPCODE_IS_BUILTIN: {
- text += "is builtin ";
- text += DADDR(3);
- text += " = ";
- text += DADDR(1);
- text += " is ";
- text += Variant::get_type_name(Variant::Type(_code_ptr[ip + 2]));
-
- incr += 4;
- } break;
- case OPCODE_SET: {
- text += "set ";
- text += DADDR(1);
- text += "[";
- text += DADDR(2);
- text += "] = ";
- text += DADDR(3);
-
- incr += 4;
- } break;
- case OPCODE_GET: {
- text += "get ";
- text += DADDR(3);
- text += " = ";
- text += DADDR(1);
- text += "[";
- text += DADDR(2);
- text += "]";
-
- incr += 4;
- } break;
- case OPCODE_SET_NAMED: {
- text += "set_named ";
- text += DADDR(1);
- text += "[\"";
- text += _global_names_ptr[_code_ptr[ip + 2]];
- text += "\"] = ";
- text += DADDR(3);
-
- incr += 4;
- } break;
- case OPCODE_GET_NAMED: {
- text += "get_named ";
- text += DADDR(3);
- text += " = ";
- text += DADDR(1);
- text += "[\"";
- text += _global_names_ptr[_code_ptr[ip + 2]];
- text += "\"]";
-
- incr += 4;
- } break;
- case OPCODE_SET_MEMBER: {
- text += "set_member ";
- text += "[\"";
- text += _global_names_ptr[_code_ptr[ip + 1]];
- text += "\"] = ";
- text += DADDR(2);
-
- incr += 3;
- } break;
- case OPCODE_GET_MEMBER: {
- text += "get_member ";
- text += DADDR(2);
- text += " = ";
- text += "[\"";
- text += _global_names_ptr[_code_ptr[ip + 1]];
- text += "\"]";
-
- incr += 3;
- } break;
- case OPCODE_ASSIGN: {
- text += "assign ";
- text += DADDR(1);
- text += " = ";
- text += DADDR(2);
-
- incr += 3;
- } break;
- case OPCODE_ASSIGN_TRUE: {
- text += "assign ";
- text += DADDR(1);
- text += " = true";
-
- incr += 2;
- } break;
- case OPCODE_ASSIGN_FALSE: {
- text += "assign ";
- text += DADDR(1);
- text += " = false";
-
- incr += 2;
- } break;
- case OPCODE_ASSIGN_TYPED_BUILTIN: {
- text += "assign typed builtin (";
- text += Variant::get_type_name((Variant::Type)_code_ptr[ip + 1]);
- text += ") ";
- text += DADDR(2);
- text += " = ";
- text += DADDR(3);
-
- incr += 4;
- } break;
- case OPCODE_ASSIGN_TYPED_NATIVE: {
- Variant class_name = _constants_ptr[_code_ptr[ip + 1]];
- GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(class_name.operator Object *());
-
- text += "assign typed native (";
- text += nc->get_name().operator String();
- text += ") ";
- text += DADDR(2);
- text += " = ";
- text += DADDR(3);
-
- incr += 4;
- } break;
- case OPCODE_ASSIGN_TYPED_SCRIPT: {
- Variant script = _constants_ptr[_code_ptr[ip + 1]];
- Script *sc = Object::cast_to<Script>(script.operator Object *());
-
- text += "assign typed script (";
- text += sc->get_path();
- text += ") ";
- text += DADDR(2);
- text += " = ";
- text += DADDR(3);
-
- incr += 4;
- } break;
- case OPCODE_CAST_TO_BUILTIN: {
- text += "cast builtin ";
- text += DADDR(3);
- text += " = ";
- text += DADDR(2);
- text += " as ";
- text += Variant::get_type_name(Variant::Type(_code_ptr[ip + 1]));
-
- incr += 4;
- } break;
- case OPCODE_CAST_TO_NATIVE: {
- Variant class_name = _constants_ptr[_code_ptr[ip + 1]];
- GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(class_name.operator Object *());
-
- text += "cast native ";
- text += DADDR(3);
- text += " = ";
- text += DADDR(2);
- text += " as ";
- text += nc->get_name();
-
- incr += 4;
- } break;
- case OPCODE_CAST_TO_SCRIPT: {
- text += "cast ";
- text += DADDR(3);
- text += " = ";
- text += DADDR(2);
- text += " as ";
- text += DADDR(1);
-
- incr += 4;
- } break;
- case OPCODE_CONSTRUCT: {
- Variant::Type t = Variant::Type(_code_ptr[ip + 1]);
- int argc = _code_ptr[ip + 2];
-
- text += "construct ";
- text += DADDR(3 + argc);
- text += " = ";
-
- text += Variant::get_type_name(t) + "(";
- for (int i = 0; i < argc; i++) {
- if (i > 0)
- text += ", ";
- text += DADDR(i + 3);
- }
- text += ")";
-
- incr = 4 + argc;
- } break;
- case OPCODE_CONSTRUCT_ARRAY: {
- int argc = _code_ptr[ip + 1];
- text += " make_array ";
- text += DADDR(2 + argc);
- text += " = [";
-
- for (int i = 0; i < argc; i++) {
- if (i > 0)
- text += ", ";
- text += DADDR(2 + i);
- }
-
- text += "]";
-
- incr += 3 + argc;
- } break;
- case OPCODE_CONSTRUCT_DICTIONARY: {
- int argc = _code_ptr[ip + 1];
- text += "make_dict ";
- text += DADDR(2 + argc * 2);
- text += " = {";
-
- for (int i = 0; i < argc; i++) {
- if (i > 0)
- text += ", ";
- text += DADDR(2 + i * 2 + 0);
- text += ": ";
- text += DADDR(2 + i * 2 + 1);
- }
-
- text += "}";
-
- incr += 3 + argc * 2;
- } break;
- case OPCODE_CALL:
- case OPCODE_CALL_RETURN:
- case OPCODE_CALL_ASYNC: {
- bool ret = _code_ptr[ip] == OPCODE_CALL_RETURN;
- bool async = _code_ptr[ip] == OPCODE_CALL_ASYNC;
-
- if (ret) {
- text += "call-ret ";
- } else if (async) {
- text += "call-async ";
- } else {
- text += "call ";
- }
-
- int argc = _code_ptr[ip + 1];
- if (ret || async) {
- text += DADDR(4 + argc) + " = ";
- }
-
- text += DADDR(2) + ".";
- text += String(_global_names_ptr[_code_ptr[ip + 3]]);
- text += "(";
-
- for (int i = 0; i < argc; i++) {
- if (i > 0)
- text += ", ";
- text += DADDR(4 + i);
- }
- text += ")";
-
- incr = 5 + argc;
- } break;
- case OPCODE_CALL_BUILT_IN: {
- text += "call-built-in ";
-
- int argc = _code_ptr[ip + 2];
- text += DADDR(3 + argc) + " = ";
-
- text += GDScriptFunctions::get_func_name(GDScriptFunctions::Function(_code_ptr[ip + 1]));
- text += "(";
-
- for (int i = 0; i < argc; i++) {
- if (i > 0)
- text += ", ";
- text += DADDR(3 + i);
- }
- text += ")";
-
- incr = 4 + argc;
- } break;
- case OPCODE_CALL_SELF_BASE: {
- text += "call-self-base ";
-
- int argc = _code_ptr[ip + 2];
- text += DADDR(3 + argc) + " = ";
-
- text += _global_names_ptr[_code_ptr[ip + 1]];
- text += "(";
-
- for (int i = 0; i < argc; i++) {
- if (i > 0)
- text += ", ";
- text += DADDR(3 + i);
- }
- text += ")";
-
- incr = 4 + argc;
- } break;
- case OPCODE_AWAIT: {
- text += "await ";
- text += DADDR(1);
-
- incr += 2;
- } break;
- case OPCODE_AWAIT_RESUME: {
- text += "await resume ";
- text += DADDR(1);
-
- incr = 2;
- } break;
- case OPCODE_JUMP: {
- text += "jump ";
- text += itos(_code_ptr[ip + 1]);
-
- incr = 2;
- } break;
- case OPCODE_JUMP_IF: {
- text += "jump-if ";
- text += DADDR(1);
- text += " to ";
- text += itos(_code_ptr[ip + 2]);
-
- incr = 3;
- } break;
- case OPCODE_JUMP_IF_NOT: {
- text += "jump-if-not ";
- text += DADDR(1);
- text += " to ";
- text += itos(_code_ptr[ip + 2]);
-
- incr = 3;
- } break;
- case OPCODE_JUMP_TO_DEF_ARGUMENT: {
- text += "jump-to-default-argument ";
-
- incr = 1;
- } break;
- case OPCODE_RETURN: {
- text += "return ";
- text += DADDR(1);
-
- incr = 2;
- } break;
- case OPCODE_ITERATE_BEGIN: {
- text += "for-init ";
- text += DADDR(4);
- text += " in ";
- text += DADDR(2);
- text += " counter ";
- text += DADDR(1);
- text += " end ";
- text += itos(_code_ptr[ip + 3]);
-
- incr += 5;
- } break;
- case OPCODE_ITERATE: {
- text += "for-loop ";
- text += DADDR(4);
- text += " in ";
- text += DADDR(2);
- text += " counter ";
- text += DADDR(1);
- text += " end ";
- text += itos(_code_ptr[ip + 3]);
-
- incr += 5;
- } break;
- case OPCODE_LINE: {
- int line = _code_ptr[ip + 1] - 1;
- if (line >= 0 && line < p_code_lines.size()) {
- text += "line ";
- text += itos(line + 1);
- text += ": ";
- text += p_code_lines[line];
- } else {
- text += "";
- }
-
- incr += 2;
- } break;
- case OPCODE_ASSERT: {
- text += "assert (";
- text += DADDR(1);
- text += ", ";
- text += DADDR(2);
- text += ")";
-
- incr += 3;
- } break;
- case OPCODE_BREAKPOINT: {
- text += "breakpoint";
-
- incr += 1;
- } break;
- case OPCODE_END: {
- text += "== END ==";
-
- incr += 1;
- } break;
- }
-
- ip += incr;
- if (text.get_string_length() > 0) {
- print_line(text.as_string());
- }
- }
-}
-#endif
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index c98ac09310..6c791836b9 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,13 +31,14 @@
#ifndef GDSCRIPT_FUNCTION_H
#define GDSCRIPT_FUNCTION_H
+#include "core/object/reference.h"
+#include "core/object/script_language.h"
#include "core/os/thread.h"
-#include "core/pair.h"
-#include "core/reference.h"
-#include "core/script_language.h"
-#include "core/self_list.h"
-#include "core/string_name.h"
-#include "core/variant.h"
+#include "core/string/string_name.h"
+#include "core/templates/pair.h"
+#include "core/templates/self_list.h"
+#include "core/variant/variant.h"
+#include "gdscript_utility_functions.h"
class GDScriptInstance;
class GDScript;
@@ -159,12 +160,19 @@ class GDScriptFunction {
public:
enum Opcode {
OPCODE_OPERATOR,
+ OPCODE_OPERATOR_VALIDATED,
OPCODE_EXTENDS_TEST,
OPCODE_IS_BUILTIN,
- OPCODE_SET,
- OPCODE_GET,
+ OPCODE_SET_KEYED,
+ OPCODE_SET_KEYED_VALIDATED,
+ OPCODE_SET_INDEXED_VALIDATED,
+ OPCODE_GET_KEYED,
+ OPCODE_GET_KEYED_VALIDATED,
+ OPCODE_GET_INDEXED_VALIDATED,
OPCODE_SET_NAMED,
+ OPCODE_SET_NAMED_VALIDATED,
OPCODE_GET_NAMED,
+ OPCODE_GET_NAMED_VALIDATED,
OPCODE_SET_MEMBER,
OPCODE_GET_MEMBER,
OPCODE_ASSIGN,
@@ -176,14 +184,56 @@ public:
OPCODE_CAST_TO_BUILTIN,
OPCODE_CAST_TO_NATIVE,
OPCODE_CAST_TO_SCRIPT,
- OPCODE_CONSTRUCT, //only for basic types!!
+ OPCODE_CONSTRUCT, // Only for basic types!
+ OPCODE_CONSTRUCT_VALIDATED, // Only for basic types!
OPCODE_CONSTRUCT_ARRAY,
OPCODE_CONSTRUCT_DICTIONARY,
OPCODE_CALL,
OPCODE_CALL_RETURN,
OPCODE_CALL_ASYNC,
- OPCODE_CALL_BUILT_IN,
+ OPCODE_CALL_UTILITY,
+ OPCODE_CALL_UTILITY_VALIDATED,
+ OPCODE_CALL_GDSCRIPT_UTILITY,
+ OPCODE_CALL_BUILTIN_TYPE_VALIDATED,
OPCODE_CALL_SELF_BASE,
+ OPCODE_CALL_METHOD_BIND,
+ OPCODE_CALL_METHOD_BIND_RET,
+ // ptrcall have one instruction per return type.
+ OPCODE_CALL_PTRCALL_NO_RETURN,
+ OPCODE_CALL_PTRCALL_BOOL,
+ OPCODE_CALL_PTRCALL_INT,
+ OPCODE_CALL_PTRCALL_FLOAT,
+ OPCODE_CALL_PTRCALL_STRING,
+ OPCODE_CALL_PTRCALL_VECTOR2,
+ OPCODE_CALL_PTRCALL_VECTOR2I,
+ OPCODE_CALL_PTRCALL_RECT2,
+ OPCODE_CALL_PTRCALL_RECT2I,
+ OPCODE_CALL_PTRCALL_VECTOR3,
+ OPCODE_CALL_PTRCALL_VECTOR3I,
+ OPCODE_CALL_PTRCALL_TRANSFORM2D,
+ OPCODE_CALL_PTRCALL_PLANE,
+ OPCODE_CALL_PTRCALL_QUAT,
+ OPCODE_CALL_PTRCALL_AABB,
+ OPCODE_CALL_PTRCALL_BASIS,
+ OPCODE_CALL_PTRCALL_TRANSFORM,
+ OPCODE_CALL_PTRCALL_COLOR,
+ OPCODE_CALL_PTRCALL_STRING_NAME,
+ OPCODE_CALL_PTRCALL_NODE_PATH,
+ OPCODE_CALL_PTRCALL_RID,
+ OPCODE_CALL_PTRCALL_OBJECT,
+ OPCODE_CALL_PTRCALL_CALLABLE,
+ OPCODE_CALL_PTRCALL_SIGNAL,
+ OPCODE_CALL_PTRCALL_DICTIONARY,
+ OPCODE_CALL_PTRCALL_ARRAY,
+ OPCODE_CALL_PTRCALL_PACKED_BYTE_ARRAY,
+ OPCODE_CALL_PTRCALL_PACKED_INT32_ARRAY,
+ OPCODE_CALL_PTRCALL_PACKED_INT64_ARRAY,
+ OPCODE_CALL_PTRCALL_PACKED_FLOAT32_ARRAY,
+ OPCODE_CALL_PTRCALL_PACKED_FLOAT64_ARRAY,
+ OPCODE_CALL_PTRCALL_PACKED_STRING_ARRAY,
+ OPCODE_CALL_PTRCALL_PACKED_VECTOR2_ARRAY,
+ OPCODE_CALL_PTRCALL_PACKED_VECTOR3_ARRAY,
+ OPCODE_CALL_PTRCALL_PACKED_COLOR_ARRAY,
OPCODE_AWAIT,
OPCODE_AWAIT_RESUME,
OPCODE_JUMP,
@@ -192,7 +242,45 @@ public:
OPCODE_JUMP_TO_DEF_ARGUMENT,
OPCODE_RETURN,
OPCODE_ITERATE_BEGIN,
+ OPCODE_ITERATE_BEGIN_INT,
+ OPCODE_ITERATE_BEGIN_FLOAT,
+ OPCODE_ITERATE_BEGIN_VECTOR2,
+ OPCODE_ITERATE_BEGIN_VECTOR2I,
+ OPCODE_ITERATE_BEGIN_VECTOR3,
+ OPCODE_ITERATE_BEGIN_VECTOR3I,
+ OPCODE_ITERATE_BEGIN_STRING,
+ OPCODE_ITERATE_BEGIN_DICTIONARY,
+ OPCODE_ITERATE_BEGIN_ARRAY,
+ OPCODE_ITERATE_BEGIN_PACKED_BYTE_ARRAY,
+ OPCODE_ITERATE_BEGIN_PACKED_INT32_ARRAY,
+ OPCODE_ITERATE_BEGIN_PACKED_INT64_ARRAY,
+ OPCODE_ITERATE_BEGIN_PACKED_FLOAT32_ARRAY,
+ OPCODE_ITERATE_BEGIN_PACKED_FLOAT64_ARRAY,
+ OPCODE_ITERATE_BEGIN_PACKED_STRING_ARRAY,
+ OPCODE_ITERATE_BEGIN_PACKED_VECTOR2_ARRAY,
+ OPCODE_ITERATE_BEGIN_PACKED_VECTOR3_ARRAY,
+ OPCODE_ITERATE_BEGIN_PACKED_COLOR_ARRAY,
+ OPCODE_ITERATE_BEGIN_OBJECT,
OPCODE_ITERATE,
+ OPCODE_ITERATE_INT,
+ OPCODE_ITERATE_FLOAT,
+ OPCODE_ITERATE_VECTOR2,
+ OPCODE_ITERATE_VECTOR2I,
+ OPCODE_ITERATE_VECTOR3,
+ OPCODE_ITERATE_VECTOR3I,
+ OPCODE_ITERATE_STRING,
+ OPCODE_ITERATE_DICTIONARY,
+ OPCODE_ITERATE_ARRAY,
+ OPCODE_ITERATE_PACKED_BYTE_ARRAY,
+ OPCODE_ITERATE_PACKED_INT32_ARRAY,
+ OPCODE_ITERATE_PACKED_INT64_ARRAY,
+ OPCODE_ITERATE_PACKED_FLOAT32_ARRAY,
+ OPCODE_ITERATE_PACKED_FLOAT64_ARRAY,
+ OPCODE_ITERATE_PACKED_STRING_ARRAY,
+ OPCODE_ITERATE_PACKED_VECTOR2_ARRAY,
+ OPCODE_ITERATE_PACKED_VECTOR3_ARRAY,
+ OPCODE_ITERATE_PACKED_COLOR_ARRAY,
+ OPCODE_ITERATE_OBJECT,
OPCODE_ASSERT,
OPCODE_BREAKPOINT,
OPCODE_LINE,
@@ -215,6 +303,12 @@ public:
ADDR_TYPE_NIL = 9
};
+ enum Instruction {
+ INSTR_BITS = 20,
+ INSTR_MASK = ((1 << INSTR_BITS) - 1),
+ INSTR_ARGS_MASK = ~INSTR_MASK,
+ };
+
struct StackDebug {
int line;
int pos;
@@ -229,33 +323,72 @@ private:
StringName source;
mutable Variant nil;
- mutable Variant *_constants_ptr;
- int _constant_count;
- const StringName *_global_names_ptr;
- int _global_names_count;
- const int *_default_arg_ptr;
- int _default_arg_count;
- const int *_code_ptr;
- int _code_size;
- int _argument_count;
- int _stack_size;
- int _call_size;
- int _initial_line;
- bool _static;
- MultiplayerAPI::RPCMode rpc_mode;
-
- GDScript *_script;
+ mutable Variant *_constants_ptr = nullptr;
+ int _constant_count = 0;
+ const StringName *_global_names_ptr = nullptr;
+ int _global_names_count = 0;
+ const int *_default_arg_ptr = nullptr;
+ int _default_arg_count = 0;
+ int _operator_funcs_count = 0;
+ const Variant::ValidatedOperatorEvaluator *_operator_funcs_ptr = nullptr;
+ int _setters_count = 0;
+ const Variant::ValidatedSetter *_setters_ptr = nullptr;
+ int _getters_count = 0;
+ const Variant::ValidatedGetter *_getters_ptr = nullptr;
+ int _keyed_setters_count = 0;
+ const Variant::ValidatedKeyedSetter *_keyed_setters_ptr = nullptr;
+ int _keyed_getters_count = 0;
+ const Variant::ValidatedKeyedGetter *_keyed_getters_ptr = nullptr;
+ int _indexed_setters_count = 0;
+ const Variant::ValidatedIndexedSetter *_indexed_setters_ptr = nullptr;
+ int _indexed_getters_count = 0;
+ const Variant::ValidatedIndexedGetter *_indexed_getters_ptr = nullptr;
+ int _builtin_methods_count = 0;
+ const Variant::ValidatedBuiltInMethod *_builtin_methods_ptr = nullptr;
+ int _constructors_count = 0;
+ const Variant::ValidatedConstructor *_constructors_ptr = nullptr;
+ int _utilities_count = 0;
+ const Variant::ValidatedUtilityFunction *_utilities_ptr = nullptr;
+ int _gds_utilities_count = 0;
+ const GDScriptUtilityFunctions::FunctionPtr *_gds_utilities_ptr = nullptr;
+ int _methods_count = 0;
+ MethodBind **_methods_ptr = nullptr;
+ const int *_code_ptr = nullptr;
+ int _code_size = 0;
+ int _argument_count = 0;
+ int _stack_size = 0;
+ int _instruction_args_size = 0;
+ int _ptrcall_args_size = 0;
+
+ int _initial_line = 0;
+ bool _static = false;
+ MultiplayerAPI::RPCMode rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
+
+ GDScript *_script = nullptr;
StringName name;
Vector<Variant> constants;
Vector<StringName> global_names;
Vector<int> default_arguments;
+ Vector<Variant::ValidatedOperatorEvaluator> operator_funcs;
+ Vector<Variant::ValidatedSetter> setters;
+ Vector<Variant::ValidatedGetter> getters;
+ Vector<Variant::ValidatedKeyedSetter> keyed_setters;
+ Vector<Variant::ValidatedKeyedGetter> keyed_getters;
+ Vector<Variant::ValidatedIndexedSetter> indexed_setters;
+ Vector<Variant::ValidatedIndexedGetter> indexed_getters;
+ Vector<Variant::ValidatedBuiltInMethod> builtin_methods;
+ Vector<Variant::ValidatedConstructor> constructors;
+ Vector<Variant::ValidatedUtilityFunction> utilities;
+ Vector<GDScriptUtilityFunctions::FunctionPtr> gds_utilities;
+ Vector<MethodBind *> methods;
Vector<int> code;
Vector<GDScriptDataType> argument_types;
GDScriptDataType return_type;
#ifdef TOOLS_ENABLED
Vector<StringName> arg_names;
+ Vector<Variant> default_arg_values;
#endif
List<StackDebug> stack_debug;
@@ -265,22 +398,22 @@ private:
friend class GDScriptLanguage;
- SelfList<GDScriptFunction> function_list;
+ SelfList<GDScriptFunction> function_list{ this };
#ifdef DEBUG_ENABLED
CharString func_cname;
- const char *_func_cname;
+ const char *_func_cname = nullptr;
struct Profile {
StringName signature;
- uint64_t call_count;
- uint64_t self_time;
- uint64_t total_time;
- uint64_t frame_call_count;
- uint64_t frame_self_time;
- uint64_t frame_total_time;
- uint64_t last_frame_call_count;
- uint64_t last_frame_self_time;
- uint64_t last_frame_total_time;
+ uint64_t call_count = 0;
+ uint64_t self_time = 0;
+ uint64_t total_time = 0;
+ uint64_t frame_call_count = 0;
+ uint64_t frame_self_time = 0;
+ uint64_t frame_total_time = 0;
+ uint64_t last_frame_call_count = 0;
+ uint64_t last_frame_self_time = 0;
+ uint64_t last_frame_total_time = 0;
} profile;
#endif
@@ -335,6 +468,11 @@ public:
ERR_FAIL_INDEX_V(p_idx, default_arguments.size(), Variant());
return default_arguments[p_idx];
}
+#ifdef TOOLS_ENABLED
+ const Vector<Variant> &get_default_arg_values() const {
+ return default_arg_values;
+ }
+#endif // TOOLS_ENABLED
Variant call(GDScriptInstance *p_instance, const Variant **p_args, int p_argcount, Callable::CallError &r_err, CallState *p_state = nullptr);
diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp
deleted file mode 100644
index 31ce63bc6e..0000000000
--- a/modules/gdscript/gdscript_functions.cpp
+++ /dev/null
@@ -1,1964 +0,0 @@
-/*************************************************************************/
-/* gdscript_functions.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "gdscript_functions.h"
-
-#include "core/class_db.h"
-#include "core/func_ref.h"
-#include "core/io/json.h"
-#include "core/io/marshalls.h"
-#include "core/math/math_funcs.h"
-#include "core/os/os.h"
-#include "core/reference.h"
-#include "core/variant_parser.h"
-#include "gdscript.h"
-
-const char *GDScriptFunctions::get_func_name(Function p_func) {
- ERR_FAIL_INDEX_V(p_func, FUNC_MAX, "");
-
- static const char *_names[FUNC_MAX] = {
- "sin",
- "cos",
- "tan",
- "sinh",
- "cosh",
- "tanh",
- "asin",
- "acos",
- "atan",
- "atan2",
- "sqrt",
- "fmod",
- "fposmod",
- "posmod",
- "floor",
- "ceil",
- "round",
- "abs",
- "sign",
- "pow",
- "log",
- "exp",
- "is_nan",
- "is_inf",
- "is_equal_approx",
- "is_zero_approx",
- "ease",
- "step_decimals",
- "stepify",
- "lerp",
- "lerp_angle",
- "inverse_lerp",
- "range_lerp",
- "smoothstep",
- "move_toward",
- "dectime",
- "randomize",
- "randi",
- "randf",
- "rand_range",
- "seed",
- "rand_seed",
- "deg2rad",
- "rad2deg",
- "linear2db",
- "db2linear",
- "polar2cartesian",
- "cartesian2polar",
- "wrapi",
- "wrapf",
- "max",
- "min",
- "clamp",
- "nearest_po2",
- "weakref",
- "funcref",
- "convert",
- "typeof",
- "type_exists",
- "char",
- "ord",
- "str",
- "print",
- "printt",
- "prints",
- "printerr",
- "printraw",
- "print_debug",
- "push_error",
- "push_warning",
- "var2str",
- "str2var",
- "var2bytes",
- "bytes2var",
- "range",
- "load",
- "inst2dict",
- "dict2inst",
- "validate_json",
- "parse_json",
- "to_json",
- "hash",
- "Color8",
- "ColorN",
- "print_stack",
- "get_stack",
- "instance_from_id",
- "len",
- "is_instance_valid",
- };
-
- return _names[p_func];
-}
-
-void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_count, Variant &r_ret, Callable::CallError &r_error) {
- r_error.error = Callable::CallError::CALL_OK;
-#ifdef DEBUG_ENABLED
-
-#define VALIDATE_ARG_COUNT(m_count) \
- if (p_arg_count < m_count) { \
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; \
- r_error.argument = m_count; \
- r_error.expected = m_count; \
- r_ret = Variant(); \
- return; \
- } \
- if (p_arg_count > m_count) { \
- r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; \
- r_error.argument = m_count; \
- r_error.expected = m_count; \
- r_ret = Variant(); \
- return; \
- }
-
-#define VALIDATE_ARG_NUM(m_arg) \
- if (!p_args[m_arg]->is_num()) { \
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; \
- r_error.argument = m_arg; \
- r_error.expected = Variant::FLOAT; \
- r_ret = Variant(); \
- return; \
- }
-
-#else
-
-#define VALIDATE_ARG_COUNT(m_count)
-#define VALIDATE_ARG_NUM(m_arg)
-#endif
-
- //using a switch, so the compiler generates a jumptable
-
- switch (p_func) {
- case MATH_SIN: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::sin((double)*p_args[0]);
- } break;
- case MATH_COS: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::cos((double)*p_args[0]);
- } break;
- case MATH_TAN: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::tan((double)*p_args[0]);
- } break;
- case MATH_SINH: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::sinh((double)*p_args[0]);
- } break;
- case MATH_COSH: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::cosh((double)*p_args[0]);
- } break;
- case MATH_TANH: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::tanh((double)*p_args[0]);
- } break;
- case MATH_ASIN: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::asin((double)*p_args[0]);
- } break;
- case MATH_ACOS: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::acos((double)*p_args[0]);
- } break;
- case MATH_ATAN: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::atan((double)*p_args[0]);
- } break;
- case MATH_ATAN2: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::atan2((double)*p_args[0], (double)*p_args[1]);
- } break;
- case MATH_SQRT: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::sqrt((double)*p_args[0]);
- } break;
- case MATH_FMOD: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::fmod((double)*p_args[0], (double)*p_args[1]);
- } break;
- case MATH_FPOSMOD: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::fposmod((double)*p_args[0], (double)*p_args[1]);
- } break;
- case MATH_POSMOD: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::posmod((int)*p_args[0], (int)*p_args[1]);
- } break;
- case MATH_FLOOR: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::floor((double)*p_args[0]);
- } break;
- case MATH_CEIL: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::ceil((double)*p_args[0]);
- } break;
- case MATH_ROUND: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::round((double)*p_args[0]);
- } break;
- case MATH_ABS: {
- VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type() == Variant::INT) {
- int64_t i = *p_args[0];
- r_ret = ABS(i);
- } else if (p_args[0]->get_type() == Variant::FLOAT) {
- double r = *p_args[0];
- r_ret = Math::abs(r);
- } else {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::FLOAT;
- r_ret = Variant();
- }
- } break;
- case MATH_SIGN: {
- VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type() == Variant::INT) {
- int64_t i = *p_args[0];
- r_ret = i < 0 ? -1 : (i > 0 ? +1 : 0);
- } else if (p_args[0]->get_type() == Variant::FLOAT) {
- real_t r = *p_args[0];
- r_ret = r < 0.0 ? -1.0 : (r > 0.0 ? +1.0 : 0.0);
- } else {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::FLOAT;
- r_ret = Variant();
- }
- } break;
- case MATH_POW: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::pow((double)*p_args[0], (double)*p_args[1]);
- } break;
- case MATH_LOG: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::log((double)*p_args[0]);
- } break;
- case MATH_EXP: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::exp((double)*p_args[0]);
- } break;
- case MATH_ISNAN: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::is_nan((double)*p_args[0]);
- } break;
- case MATH_ISINF: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::is_inf((double)*p_args[0]);
- } break;
- case MATH_ISEQUALAPPROX: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::is_equal_approx((real_t)*p_args[0], (real_t)*p_args[1]);
- } break;
- case MATH_ISZEROAPPROX: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::is_zero_approx((real_t)*p_args[0]);
- } break;
- case MATH_EASE: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::ease((double)*p_args[0], (double)*p_args[1]);
- } break;
- case MATH_STEP_DECIMALS: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::step_decimals((double)*p_args[0]);
- } break;
- case MATH_STEPIFY: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::stepify((double)*p_args[0], (double)*p_args[1]);
- } break;
- case MATH_LERP: {
- VALIDATE_ARG_COUNT(3);
- VALIDATE_ARG_NUM(2);
- const double t = (double)*p_args[2];
- switch (p_args[0]->get_type() == p_args[1]->get_type() ? p_args[0]->get_type() : Variant::FLOAT) {
- case Variant::VECTOR2: {
- r_ret = ((Vector2)*p_args[0]).lerp((Vector2)*p_args[1], t);
- } break;
- case Variant::VECTOR3: {
- r_ret = (p_args[0]->operator Vector3()).lerp(p_args[1]->operator Vector3(), t);
- } break;
- case Variant::COLOR: {
- r_ret = ((Color)*p_args[0]).lerp((Color)*p_args[1], t);
- } break;
- default: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::lerp((double)*p_args[0], (double)*p_args[1], t);
- } break;
- }
- } break;
- case MATH_LERP_ANGLE: {
- VALIDATE_ARG_COUNT(3);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- r_ret = Math::lerp_angle((double)*p_args[0], (double)*p_args[1], (double)*p_args[2]);
- } break;
- case MATH_INVERSE_LERP: {
- VALIDATE_ARG_COUNT(3);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- r_ret = Math::inverse_lerp((double)*p_args[0], (double)*p_args[1], (double)*p_args[2]);
- } break;
- case MATH_RANGE_LERP: {
- VALIDATE_ARG_COUNT(5);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- VALIDATE_ARG_NUM(3);
- VALIDATE_ARG_NUM(4);
- r_ret = Math::range_lerp((double)*p_args[0], (double)*p_args[1], (double)*p_args[2], (double)*p_args[3], (double)*p_args[4]);
- } break;
- case MATH_SMOOTHSTEP: {
- VALIDATE_ARG_COUNT(3);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- r_ret = Math::smoothstep((double)*p_args[0], (double)*p_args[1], (double)*p_args[2]);
- } break;
- case MATH_MOVE_TOWARD: {
- VALIDATE_ARG_COUNT(3);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- r_ret = Math::move_toward((double)*p_args[0], (double)*p_args[1], (double)*p_args[2]);
- } break;
- case MATH_DECTIME: {
- VALIDATE_ARG_COUNT(3);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- r_ret = Math::dectime((double)*p_args[0], (double)*p_args[1], (double)*p_args[2]);
- } break;
- case MATH_RANDOMIZE: {
- VALIDATE_ARG_COUNT(0);
- Math::randomize();
- r_ret = Variant();
- } break;
- case MATH_RAND: {
- VALIDATE_ARG_COUNT(0);
- r_ret = Math::rand();
- } break;
- case MATH_RANDF: {
- VALIDATE_ARG_COUNT(0);
- r_ret = Math::randf();
- } break;
- case MATH_RANDOM: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- r_ret = Math::random((double)*p_args[0], (double)*p_args[1]);
- } break;
- case MATH_SEED: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- uint64_t seed = *p_args[0];
- Math::seed(seed);
- r_ret = Variant();
- } break;
- case MATH_RANDSEED: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- uint64_t seed = *p_args[0];
- int ret = Math::rand_from_seed(&seed);
- Array reta;
- reta.push_back(ret);
- reta.push_back(seed);
- r_ret = reta;
-
- } break;
- case MATH_DEG2RAD: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::deg2rad((double)*p_args[0]);
- } break;
- case MATH_RAD2DEG: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::rad2deg((double)*p_args[0]);
- } break;
- case MATH_LINEAR2DB: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::linear2db((double)*p_args[0]);
- } break;
- case MATH_DB2LINEAR: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- r_ret = Math::db2linear((double)*p_args[0]);
- } break;
- case MATH_POLAR2CARTESIAN: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- double r = *p_args[0];
- double th = *p_args[1];
- r_ret = Vector2(r * Math::cos(th), r * Math::sin(th));
- } break;
- case MATH_CARTESIAN2POLAR: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- double x = *p_args[0];
- double y = *p_args[1];
- r_ret = Vector2(Math::sqrt(x * x + y * y), Math::atan2(y, x));
- } break;
- case MATH_WRAP: {
- VALIDATE_ARG_COUNT(3);
- r_ret = Math::wrapi((int64_t)*p_args[0], (int64_t)*p_args[1], (int64_t)*p_args[2]);
- } break;
- case MATH_WRAPF: {
- VALIDATE_ARG_COUNT(3);
- r_ret = Math::wrapf((double)*p_args[0], (double)*p_args[1], (double)*p_args[2]);
- } break;
- case LOGIC_MAX: {
- VALIDATE_ARG_COUNT(2);
- if (p_args[0]->get_type() == Variant::INT && p_args[1]->get_type() == Variant::INT) {
- int64_t a = *p_args[0];
- int64_t b = *p_args[1];
- r_ret = MAX(a, b);
- } else {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
-
- real_t a = *p_args[0];
- real_t b = *p_args[1];
-
- r_ret = MAX(a, b);
- }
-
- } break;
- case LOGIC_MIN: {
- VALIDATE_ARG_COUNT(2);
- if (p_args[0]->get_type() == Variant::INT && p_args[1]->get_type() == Variant::INT) {
- int64_t a = *p_args[0];
- int64_t b = *p_args[1];
- r_ret = MIN(a, b);
- } else {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
-
- real_t a = *p_args[0];
- real_t b = *p_args[1];
-
- r_ret = MIN(a, b);
- }
- } break;
- case LOGIC_CLAMP: {
- VALIDATE_ARG_COUNT(3);
- if (p_args[0]->get_type() == Variant::INT && p_args[1]->get_type() == Variant::INT && p_args[2]->get_type() == Variant::INT) {
- int64_t a = *p_args[0];
- int64_t b = *p_args[1];
- int64_t c = *p_args[2];
- r_ret = CLAMP(a, b, c);
- } else {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
-
- real_t a = *p_args[0];
- real_t b = *p_args[1];
- real_t c = *p_args[2];
-
- r_ret = CLAMP(a, b, c);
- }
- } break;
- case LOGIC_NEAREST_PO2: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- int64_t num = *p_args[0];
- r_ret = next_power_of_2(num);
- } break;
- case OBJ_WEAKREF: {
- VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type() == Variant::OBJECT) {
- if (p_args[0]->is_ref()) {
- Ref<WeakRef> wref = memnew(WeakRef);
- REF r = *p_args[0];
- if (r.is_valid()) {
- wref->set_ref(r);
- }
- r_ret = wref;
- } else {
- Ref<WeakRef> wref = memnew(WeakRef);
- Object *obj = *p_args[0];
- if (obj) {
- wref->set_obj(obj);
- }
- r_ret = wref;
- }
- } else if (p_args[0]->get_type() == Variant::NIL) {
- Ref<WeakRef> wref = memnew(WeakRef);
- r_ret = wref;
- } else {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- r_ret = Variant();
- return;
- }
- } break;
- case FUNC_FUNCREF: {
- VALIDATE_ARG_COUNT(2);
- if (p_args[0]->get_type() != Variant::OBJECT) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- r_ret = Variant();
- return;
- }
- if (p_args[1]->get_type() != Variant::STRING && p_args[1]->get_type() != Variant::NODE_PATH) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 1;
- r_error.expected = Variant::STRING;
- r_ret = Variant();
- return;
- }
-
- Ref<FuncRef> fr = memnew(FuncRef);
-
- fr->set_instance(*p_args[0]);
- fr->set_function(*p_args[1]);
-
- r_ret = fr;
-
- } break;
- case TYPE_CONVERT: {
- VALIDATE_ARG_COUNT(2);
- VALIDATE_ARG_NUM(1);
- int type = *p_args[1];
- if (type < 0 || type >= Variant::VARIANT_MAX) {
- r_ret = RTR("Invalid type argument to convert(), use TYPE_* constants.");
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::INT;
- return;
-
- } else {
- r_ret = Variant::construct(Variant::Type(type), p_args, 1, r_error);
- }
- } break;
- case TYPE_OF: {
- VALIDATE_ARG_COUNT(1);
- r_ret = p_args[0]->get_type();
-
- } break;
- case TYPE_EXISTS: {
- VALIDATE_ARG_COUNT(1);
- r_ret = ClassDB::class_exists(*p_args[0]);
-
- } break;
- case TEXT_CHAR: {
- VALIDATE_ARG_COUNT(1);
- VALIDATE_ARG_NUM(0);
- char32_t result[2] = { *p_args[0], 0 };
- r_ret = String(result);
- } break;
- case TEXT_ORD: {
- VALIDATE_ARG_COUNT(1);
-
- if (p_args[0]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
- r_ret = Variant();
- return;
- }
-
- String str = p_args[0]->operator String();
-
- if (str.length() != 1) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
- r_ret = RTR("Expected a string of length 1 (a character).");
- return;
- }
-
- r_ret = str.get(0);
-
- } break;
- case TEXT_STR: {
- if (p_arg_count < 1) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 1;
- r_ret = Variant();
-
- return;
- }
- String str;
- for (int i = 0; i < p_arg_count; i++) {
- String os = p_args[i]->operator String();
-
- if (i == 0) {
- str = os;
- } else {
- str += os;
- }
- }
-
- r_ret = str;
-
- } break;
- case TEXT_PRINT: {
- String str;
- for (int i = 0; i < p_arg_count; i++) {
- str += p_args[i]->operator String();
- }
-
- print_line(str);
- r_ret = Variant();
-
- } break;
- case TEXT_PRINT_TABBED: {
- String str;
- for (int i = 0; i < p_arg_count; i++) {
- if (i) {
- str += "\t";
- }
- str += p_args[i]->operator String();
- }
-
- print_line(str);
- r_ret = Variant();
-
- } break;
- case TEXT_PRINT_SPACED: {
- String str;
- for (int i = 0; i < p_arg_count; i++) {
- if (i) {
- str += " ";
- }
- str += p_args[i]->operator String();
- }
-
- print_line(str);
- r_ret = Variant();
-
- } break;
-
- case TEXT_PRINTERR: {
- String str;
- for (int i = 0; i < p_arg_count; i++) {
- str += p_args[i]->operator String();
- }
-
- print_error(str);
- r_ret = Variant();
-
- } break;
- case TEXT_PRINTRAW: {
- String str;
- for (int i = 0; i < p_arg_count; i++) {
- str += p_args[i]->operator String();
- }
-
- OS::get_singleton()->print("%s", str.utf8().get_data());
- r_ret = Variant();
-
- } break;
- case TEXT_PRINT_DEBUG: {
- String str;
- for (int i = 0; i < p_arg_count; i++) {
- str += p_args[i]->operator String();
- }
-
- ScriptLanguage *script = GDScriptLanguage::get_singleton();
- if (script->debug_get_stack_level_count() > 0) {
- str += "\n At: " + script->debug_get_stack_level_source(0) + ":" + itos(script->debug_get_stack_level_line(0)) + ":" + script->debug_get_stack_level_function(0) + "()";
- }
-
- print_line(str);
- r_ret = Variant();
- } break;
- case PUSH_ERROR: {
- VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
- r_ret = Variant();
- break;
- }
-
- String message = *p_args[0];
- ERR_PRINT(message);
- r_ret = Variant();
- } break;
- case PUSH_WARNING: {
- VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
- r_ret = Variant();
- break;
- }
-
- String message = *p_args[0];
- WARN_PRINT(message);
- r_ret = Variant();
- } break;
- case VAR_TO_STR: {
- VALIDATE_ARG_COUNT(1);
- String vars;
- VariantWriter::write_to_string(*p_args[0], vars);
- r_ret = vars;
- } break;
- case STR_TO_VAR: {
- VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
- r_ret = Variant();
- return;
- }
- r_ret = *p_args[0];
-
- VariantParser::StreamString ss;
- ss.s = *p_args[0];
-
- String errs;
- int line;
- (void)VariantParser::parse(&ss, r_ret, errs, line);
- } break;
- case VAR_TO_BYTES: {
- bool full_objects = false;
- if (p_arg_count < 1) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 1;
- r_ret = Variant();
- return;
- } else if (p_arg_count > 2) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = 2;
- r_ret = Variant();
- } else if (p_arg_count == 2) {
- if (p_args[1]->get_type() != Variant::BOOL) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 1;
- r_error.expected = Variant::BOOL;
- r_ret = Variant();
- return;
- }
- full_objects = *p_args[1];
- }
-
- PackedByteArray barr;
- int len;
- Error err = encode_variant(*p_args[0], nullptr, len, full_objects);
- if (err) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::NIL;
- r_ret = "Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID).";
- return;
- }
-
- barr.resize(len);
- {
- uint8_t *w = barr.ptrw();
- encode_variant(*p_args[0], w, len, full_objects);
- }
- r_ret = barr;
- } break;
- case BYTES_TO_VAR: {
- bool allow_objects = false;
- if (p_arg_count < 1) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 1;
- r_ret = Variant();
- return;
- } else if (p_arg_count > 2) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = 2;
- r_ret = Variant();
- } else if (p_arg_count == 2) {
- if (p_args[1]->get_type() != Variant::BOOL) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 1;
- r_error.expected = Variant::BOOL;
- r_ret = Variant();
- return;
- }
- allow_objects = *p_args[1];
- }
-
- if (p_args[0]->get_type() != Variant::PACKED_BYTE_ARRAY) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 1;
- r_error.expected = Variant::PACKED_BYTE_ARRAY;
- r_ret = Variant();
- return;
- }
-
- PackedByteArray varr = *p_args[0];
- Variant ret;
- {
- const uint8_t *r = varr.ptr();
- Error err = decode_variant(ret, r, varr.size(), nullptr, allow_objects);
- if (err != OK) {
- r_ret = RTR("Not enough bytes for decoding bytes, or invalid format.");
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::PACKED_BYTE_ARRAY;
- return;
- }
- }
-
- r_ret = ret;
-
- } break;
- case GEN_RANGE: {
- switch (p_arg_count) {
- case 0: {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 1;
- r_error.expected = 1;
- r_ret = Variant();
-
- } break;
- case 1: {
- VALIDATE_ARG_NUM(0);
- int count = *p_args[0];
- Array arr;
- if (count <= 0) {
- r_ret = arr;
- return;
- }
- Error err = arr.resize(count);
- if (err != OK) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_ret = Variant();
- return;
- }
-
- for (int i = 0; i < count; i++) {
- arr[i] = i;
- }
-
- r_ret = arr;
- } break;
- case 2: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
-
- int from = *p_args[0];
- int to = *p_args[1];
-
- Array arr;
- if (from >= to) {
- r_ret = arr;
- return;
- }
- Error err = arr.resize(to - from);
- if (err != OK) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_ret = Variant();
- return;
- }
- for (int i = from; i < to; i++) {
- arr[i - from] = i;
- }
- r_ret = arr;
- } break;
- case 3: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
-
- int from = *p_args[0];
- int to = *p_args[1];
- int incr = *p_args[2];
- if (incr == 0) {
- r_ret = RTR("Step argument is zero!");
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return;
- }
-
- Array arr;
- if (from >= to && incr > 0) {
- r_ret = arr;
- return;
- }
- if (from <= to && incr < 0) {
- r_ret = arr;
- return;
- }
-
- //calculate how many
- int count = 0;
- if (incr > 0) {
- count = ((to - from - 1) / incr) + 1;
- } else {
- count = ((from - to - 1) / -incr) + 1;
- }
-
- Error err = arr.resize(count);
-
- if (err != OK) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_ret = Variant();
- return;
- }
-
- if (incr > 0) {
- int idx = 0;
- for (int i = from; i < to; i += incr) {
- arr[idx++] = i;
- }
- } else {
- int idx = 0;
- for (int i = from; i > to; i += incr) {
- arr[idx++] = i;
- }
- }
-
- r_ret = arr;
- } break;
- default: {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = 3;
- r_error.expected = 3;
- r_ret = Variant();
-
- } break;
- }
-
- } break;
- case RESOURCE_LOAD: {
- VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
- r_ret = Variant();
- } else {
- r_ret = ResourceLoader::load(*p_args[0]);
- }
-
- } break;
- case INST2DICT: {
- VALIDATE_ARG_COUNT(1);
-
- if (p_args[0]->get_type() == Variant::NIL) {
- r_ret = Variant();
- } else if (p_args[0]->get_type() != Variant::OBJECT) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_ret = Variant();
- } else {
- Object *obj = *p_args[0];
- if (!obj) {
- r_ret = Variant();
-
- } else if (!obj->get_script_instance() || obj->get_script_instance()->get_language() != GDScriptLanguage::get_singleton()) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::DICTIONARY;
- r_ret = RTR("Not a script with an instance");
- return;
- } else {
- GDScriptInstance *ins = static_cast<GDScriptInstance *>(obj->get_script_instance());
- Ref<GDScript> base = ins->get_script();
- if (base.is_null()) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::DICTIONARY;
- r_ret = RTR("Not based on a script");
- return;
- }
-
- GDScript *p = base.ptr();
- Vector<StringName> sname;
-
- while (p->_owner) {
- sname.push_back(p->name);
- p = p->_owner;
- }
- sname.invert();
-
- if (!p->path.is_resource_file()) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::DICTIONARY;
- r_ret = Variant();
-
- r_ret = RTR("Not based on a resource file");
-
- return;
- }
-
- NodePath cp(sname, Vector<StringName>(), false);
-
- Dictionary d;
- d["@subpath"] = cp;
- d["@path"] = p->get_path();
-
- for (Map<StringName, GDScript::MemberInfo>::Element *E = base->member_indices.front(); E; E = E->next()) {
- if (!d.has(E->key())) {
- d[E->key()] = ins->members[E->get().index];
- }
- }
- r_ret = d;
- }
- }
-
- } break;
- case DICT2INST: {
- VALIDATE_ARG_COUNT(1);
-
- if (p_args[0]->get_type() != Variant::DICTIONARY) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::DICTIONARY;
- r_ret = Variant();
-
- return;
- }
-
- Dictionary d = *p_args[0];
-
- if (!d.has("@path")) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- r_ret = RTR("Invalid instance dictionary format (missing @path)");
-
- return;
- }
-
- Ref<Script> scr = ResourceLoader::load(d["@path"]);
- if (!scr.is_valid()) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- r_ret = RTR("Invalid instance dictionary format (can't load script at @path)");
- return;
- }
-
- Ref<GDScript> gdscr = scr;
-
- if (!gdscr.is_valid()) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- r_ret = Variant();
- r_ret = RTR("Invalid instance dictionary format (invalid script at @path)");
- return;
- }
-
- NodePath sub;
- if (d.has("@subpath")) {
- sub = d["@subpath"];
- }
-
- for (int i = 0; i < sub.get_name_count(); i++) {
- gdscr = gdscr->subclasses[sub.get_name(i)];
- if (!gdscr.is_valid()) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- r_ret = Variant();
- r_ret = RTR("Invalid instance dictionary (invalid subclasses)");
- return;
- }
- }
- r_ret = gdscr->_new(nullptr, -1 /*skip initializer*/, r_error);
-
- if (r_error.error != Callable::CallError::CALL_OK) {
- r_ret = Variant();
- return;
- }
-
- GDScriptInstance *ins = static_cast<GDScriptInstance *>(static_cast<Object *>(r_ret)->get_script_instance());
- Ref<GDScript> gd_ref = ins->get_script();
-
- for (Map<StringName, GDScript::MemberInfo>::Element *E = gd_ref->member_indices.front(); E; E = E->next()) {
- if (d.has(E->key())) {
- ins->members.write[E->get().index] = d[E->key()];
- }
- }
-
- } break;
- case VALIDATE_JSON: {
- VALIDATE_ARG_COUNT(1);
-
- if (p_args[0]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
- r_ret = Variant();
- return;
- }
-
- String errs;
- int errl;
-
- Error err = JSON::parse(*p_args[0], r_ret, errs, errl);
-
- if (err != OK) {
- r_ret = itos(errl) + ":" + errs;
- } else {
- r_ret = "";
- }
-
- } break;
- case PARSE_JSON: {
- VALIDATE_ARG_COUNT(1);
-
- if (p_args[0]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
- r_ret = Variant();
- return;
- }
-
- String errs;
- int errl;
-
- Error err = JSON::parse(*p_args[0], r_ret, errs, errl);
-
- if (err != OK) {
- r_ret = Variant();
- ERR_PRINT(vformat("Error parsing JSON at line %s: %s", errl, errs));
- }
-
- } break;
- case TO_JSON: {
- VALIDATE_ARG_COUNT(1);
-
- r_ret = JSON::print(*p_args[0]);
- } break;
- case HASH: {
- VALIDATE_ARG_COUNT(1);
- r_ret = p_args[0]->hash();
-
- } break;
- case COLOR8: {
- if (p_arg_count < 3) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 3;
- r_ret = Variant();
-
- return;
- }
- if (p_arg_count > 4) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = 4;
- r_ret = Variant();
-
- return;
- }
-
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
-
- Color color((float)*p_args[0] / 255.0f, (float)*p_args[1] / 255.0f, (float)*p_args[2] / 255.0f);
-
- if (p_arg_count == 4) {
- VALIDATE_ARG_NUM(3);
- color.a = (float)*p_args[3] / 255.0f;
- }
-
- r_ret = color;
-
- } break;
- case COLORN: {
- if (p_arg_count < 1) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 1;
- r_ret = Variant();
- return;
- }
-
- if (p_arg_count > 2) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = 2;
- r_ret = Variant();
- return;
- }
-
- if (p_args[0]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_ret = Variant();
- } else {
- Color color = Color::named(*p_args[0]);
- if (p_arg_count == 2) {
- VALIDATE_ARG_NUM(1);
- color.a = *p_args[1];
- }
- r_ret = color;
- }
-
- } break;
-
- case PRINT_STACK: {
- VALIDATE_ARG_COUNT(0);
-
- ScriptLanguage *script = GDScriptLanguage::get_singleton();
- for (int i = 0; i < script->debug_get_stack_level_count(); i++) {
- print_line("Frame " + itos(i) + " - " + script->debug_get_stack_level_source(i) + ":" + itos(script->debug_get_stack_level_line(i)) + " in function '" + script->debug_get_stack_level_function(i) + "'");
- };
- } break;
-
- case GET_STACK: {
- VALIDATE_ARG_COUNT(0);
-
- ScriptLanguage *script = GDScriptLanguage::get_singleton();
- Array ret;
- for (int i = 0; i < script->debug_get_stack_level_count(); i++) {
- Dictionary frame;
- frame["source"] = script->debug_get_stack_level_source(i);
- frame["function"] = script->debug_get_stack_level_function(i);
- frame["line"] = script->debug_get_stack_level_line(i);
- ret.push_back(frame);
- };
- r_ret = ret;
- } break;
-
- case INSTANCE_FROM_ID: {
- VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type() != Variant::INT && p_args[0]->get_type() != Variant::FLOAT) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::INT;
- r_ret = Variant();
- break;
- }
-
- ObjectID id = *p_args[0];
- r_ret = ObjectDB::get_instance(id);
-
- } break;
- case LEN: {
- VALIDATE_ARG_COUNT(1);
- switch (p_args[0]->get_type()) {
- case Variant::STRING: {
- String d = *p_args[0];
- r_ret = d.length();
- } break;
- case Variant::DICTIONARY: {
- Dictionary d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::ARRAY: {
- Array d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_BYTE_ARRAY: {
- Vector<uint8_t> d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_INT32_ARRAY: {
- Vector<int32_t> d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_INT64_ARRAY: {
- Vector<int64_t> d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_FLOAT32_ARRAY: {
- Vector<float> d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_FLOAT64_ARRAY: {
- Vector<double> d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_STRING_ARRAY: {
- Vector<String> d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_VECTOR2_ARRAY: {
- Vector<Vector2> d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_VECTOR3_ARRAY: {
- Vector<Vector3> d = *p_args[0];
- r_ret = d.size();
- } break;
- case Variant::PACKED_COLOR_ARRAY: {
- Vector<Color> d = *p_args[0];
- r_ret = d.size();
- } break;
- default: {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- r_ret = Variant();
- r_ret = RTR("Object can't provide a length.");
- }
- }
-
- } break;
- case IS_INSTANCE_VALID: {
- VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type() != Variant::OBJECT) {
- r_ret = false;
- } else {
- Object *obj = p_args[0]->get_validated_object();
- r_ret = obj != nullptr;
- }
-
- } break;
- case FUNC_MAX: {
- ERR_FAIL();
- } break;
- }
-}
-
-bool GDScriptFunctions::is_deterministic(Function p_func) {
- //man i couldn't have chosen a worse function name,
- //way too controversial..
-
- switch (p_func) {
- case MATH_SIN:
- case MATH_COS:
- case MATH_TAN:
- case MATH_SINH:
- case MATH_COSH:
- case MATH_TANH:
- case MATH_ASIN:
- case MATH_ACOS:
- case MATH_ATAN:
- case MATH_ATAN2:
- case MATH_SQRT:
- case MATH_FMOD:
- case MATH_FPOSMOD:
- case MATH_POSMOD:
- case MATH_FLOOR:
- case MATH_CEIL:
- case MATH_ROUND:
- case MATH_ABS:
- case MATH_SIGN:
- case MATH_POW:
- case MATH_LOG:
- case MATH_EXP:
- case MATH_ISNAN:
- case MATH_ISINF:
- case MATH_EASE:
- case MATH_STEP_DECIMALS:
- case MATH_STEPIFY:
- case MATH_LERP:
- case MATH_INVERSE_LERP:
- case MATH_RANGE_LERP:
- case MATH_SMOOTHSTEP:
- case MATH_MOVE_TOWARD:
- case MATH_DECTIME:
- case MATH_DEG2RAD:
- case MATH_RAD2DEG:
- case MATH_LINEAR2DB:
- case MATH_DB2LINEAR:
- case MATH_POLAR2CARTESIAN:
- case MATH_CARTESIAN2POLAR:
- case MATH_WRAP:
- case MATH_WRAPF:
- case LOGIC_MAX:
- case LOGIC_MIN:
- case LOGIC_CLAMP:
- case LOGIC_NEAREST_PO2:
- case TYPE_CONVERT:
- case TYPE_OF:
- case TYPE_EXISTS:
- case TEXT_CHAR:
- case TEXT_ORD:
- case TEXT_STR:
- case COLOR8:
- case LEN:
- // enable for debug only, otherwise not desirable - case GEN_RANGE:
- return true;
- default:
- return false;
- }
-
- return false;
-}
-
-MethodInfo GDScriptFunctions::get_info(Function p_func) {
-#ifdef DEBUG_ENABLED
- //using a switch, so the compiler generates a jumptable
-
- switch (p_func) {
- case MATH_SIN: {
- MethodInfo mi("sin", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
-
- } break;
- case MATH_COS: {
- MethodInfo mi("cos", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_TAN: {
- MethodInfo mi("tan", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_SINH: {
- MethodInfo mi("sinh", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_COSH: {
- MethodInfo mi("cosh", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_TANH: {
- MethodInfo mi("tanh", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_ASIN: {
- MethodInfo mi("asin", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_ACOS: {
- MethodInfo mi("acos", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_ATAN: {
- MethodInfo mi("atan", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_ATAN2: {
- MethodInfo mi("atan2", PropertyInfo(Variant::FLOAT, "y"), PropertyInfo(Variant::FLOAT, "x"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_SQRT: {
- MethodInfo mi("sqrt", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_FMOD: {
- MethodInfo mi("fmod", PropertyInfo(Variant::FLOAT, "a"), PropertyInfo(Variant::FLOAT, "b"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_FPOSMOD: {
- MethodInfo mi("fposmod", PropertyInfo(Variant::FLOAT, "a"), PropertyInfo(Variant::FLOAT, "b"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_POSMOD: {
- MethodInfo mi("posmod", PropertyInfo(Variant::INT, "a"), PropertyInfo(Variant::INT, "b"));
- mi.return_val.type = Variant::INT;
- return mi;
- } break;
- case MATH_FLOOR: {
- MethodInfo mi("floor", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_CEIL: {
- MethodInfo mi("ceil", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_ROUND: {
- MethodInfo mi("round", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_ABS: {
- MethodInfo mi("abs", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_SIGN: {
- MethodInfo mi("sign", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_POW: {
- MethodInfo mi("pow", PropertyInfo(Variant::FLOAT, "base"), PropertyInfo(Variant::FLOAT, "exp"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_LOG: {
- MethodInfo mi("log", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_EXP: {
- MethodInfo mi("exp", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_ISNAN: {
- MethodInfo mi("is_nan", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::BOOL;
- return mi;
- } break;
- case MATH_ISINF: {
- MethodInfo mi("is_inf", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::BOOL;
- return mi;
- } break;
- case MATH_ISEQUALAPPROX: {
- MethodInfo mi("is_equal_approx", PropertyInfo(Variant::FLOAT, "a"), PropertyInfo(Variant::FLOAT, "b"));
- mi.return_val.type = Variant::BOOL;
- return mi;
- } break;
- case MATH_ISZEROAPPROX: {
- MethodInfo mi("is_zero_approx", PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::BOOL;
- return mi;
- } break;
- case MATH_EASE: {
- MethodInfo mi("ease", PropertyInfo(Variant::FLOAT, "s"), PropertyInfo(Variant::FLOAT, "curve"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_STEP_DECIMALS: {
- MethodInfo mi("step_decimals", PropertyInfo(Variant::FLOAT, "step"));
- mi.return_val.type = Variant::INT;
- return mi;
- } break;
- case MATH_STEPIFY: {
- MethodInfo mi("stepify", PropertyInfo(Variant::FLOAT, "s"), PropertyInfo(Variant::FLOAT, "step"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_LERP: {
- MethodInfo mi("lerp", PropertyInfo(Variant::NIL, "from"), PropertyInfo(Variant::NIL, "to"), PropertyInfo(Variant::FLOAT, "weight"));
- mi.return_val.type = Variant::NIL;
- mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- return mi;
- } break;
- case MATH_LERP_ANGLE: {
- MethodInfo mi("lerp_angle", PropertyInfo(Variant::FLOAT, "from"), PropertyInfo(Variant::FLOAT, "to"), PropertyInfo(Variant::FLOAT, "weight"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_INVERSE_LERP: {
- MethodInfo mi("inverse_lerp", PropertyInfo(Variant::FLOAT, "from"), PropertyInfo(Variant::FLOAT, "to"), PropertyInfo(Variant::FLOAT, "weight"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_RANGE_LERP: {
- MethodInfo mi("range_lerp", PropertyInfo(Variant::FLOAT, "value"), PropertyInfo(Variant::FLOAT, "istart"), PropertyInfo(Variant::FLOAT, "istop"), PropertyInfo(Variant::FLOAT, "ostart"), PropertyInfo(Variant::FLOAT, "ostop"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_SMOOTHSTEP: {
- MethodInfo mi("smoothstep", PropertyInfo(Variant::FLOAT, "from"), PropertyInfo(Variant::FLOAT, "to"), PropertyInfo(Variant::FLOAT, "s"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_MOVE_TOWARD: {
- MethodInfo mi("move_toward", PropertyInfo(Variant::FLOAT, "from"), PropertyInfo(Variant::FLOAT, "to"), PropertyInfo(Variant::FLOAT, "delta"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_DECTIME: {
- MethodInfo mi("dectime", PropertyInfo(Variant::FLOAT, "value"), PropertyInfo(Variant::FLOAT, "amount"), PropertyInfo(Variant::FLOAT, "step"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_RANDOMIZE: {
- MethodInfo mi("randomize");
- mi.return_val.type = Variant::NIL;
- return mi;
- } break;
- case MATH_RAND: {
- MethodInfo mi("randi");
- mi.return_val.type = Variant::INT;
- return mi;
- } break;
- case MATH_RANDF: {
- MethodInfo mi("randf");
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_RANDOM: {
- MethodInfo mi("rand_range", PropertyInfo(Variant::FLOAT, "from"), PropertyInfo(Variant::FLOAT, "to"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_SEED: {
- MethodInfo mi("seed", PropertyInfo(Variant::INT, "seed"));
- mi.return_val.type = Variant::NIL;
- return mi;
- } break;
- case MATH_RANDSEED: {
- MethodInfo mi("rand_seed", PropertyInfo(Variant::INT, "seed"));
- mi.return_val.type = Variant::ARRAY;
- return mi;
- } break;
- case MATH_DEG2RAD: {
- MethodInfo mi("deg2rad", PropertyInfo(Variant::FLOAT, "deg"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_RAD2DEG: {
- MethodInfo mi("rad2deg", PropertyInfo(Variant::FLOAT, "rad"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_LINEAR2DB: {
- MethodInfo mi("linear2db", PropertyInfo(Variant::FLOAT, "nrg"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_DB2LINEAR: {
- MethodInfo mi("db2linear", PropertyInfo(Variant::FLOAT, "db"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case MATH_POLAR2CARTESIAN: {
- MethodInfo mi("polar2cartesian", PropertyInfo(Variant::FLOAT, "r"), PropertyInfo(Variant::FLOAT, "th"));
- mi.return_val.type = Variant::VECTOR2;
- return mi;
- } break;
- case MATH_CARTESIAN2POLAR: {
- MethodInfo mi("cartesian2polar", PropertyInfo(Variant::FLOAT, "x"), PropertyInfo(Variant::FLOAT, "y"));
- mi.return_val.type = Variant::VECTOR2;
- return mi;
- } break;
- case MATH_WRAP: {
- MethodInfo mi("wrapi", PropertyInfo(Variant::INT, "value"), PropertyInfo(Variant::INT, "min"), PropertyInfo(Variant::INT, "max"));
- mi.return_val.type = Variant::INT;
- return mi;
- } break;
- case MATH_WRAPF: {
- MethodInfo mi("wrapf", PropertyInfo(Variant::FLOAT, "value"), PropertyInfo(Variant::FLOAT, "min"), PropertyInfo(Variant::FLOAT, "max"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case LOGIC_MAX: {
- MethodInfo mi("max", PropertyInfo(Variant::FLOAT, "a"), PropertyInfo(Variant::FLOAT, "b"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
-
- } break;
- case LOGIC_MIN: {
- MethodInfo mi("min", PropertyInfo(Variant::FLOAT, "a"), PropertyInfo(Variant::FLOAT, "b"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case LOGIC_CLAMP: {
- MethodInfo mi("clamp", PropertyInfo(Variant::FLOAT, "value"), PropertyInfo(Variant::FLOAT, "min"), PropertyInfo(Variant::FLOAT, "max"));
- mi.return_val.type = Variant::FLOAT;
- return mi;
- } break;
- case LOGIC_NEAREST_PO2: {
- MethodInfo mi("nearest_po2", PropertyInfo(Variant::INT, "value"));
- mi.return_val.type = Variant::INT;
- return mi;
- } break;
- case OBJ_WEAKREF: {
- MethodInfo mi("weakref", PropertyInfo(Variant::OBJECT, "obj"));
- mi.return_val.type = Variant::OBJECT;
- mi.return_val.class_name = "WeakRef";
-
- return mi;
-
- } break;
- case FUNC_FUNCREF: {
- MethodInfo mi("funcref", PropertyInfo(Variant::OBJECT, "instance"), PropertyInfo(Variant::STRING, "funcname"));
- mi.return_val.type = Variant::OBJECT;
- mi.return_val.class_name = "FuncRef";
- return mi;
-
- } break;
- case TYPE_CONVERT: {
- MethodInfo mi("convert", PropertyInfo(Variant::NIL, "what", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT), PropertyInfo(Variant::INT, "type"));
- mi.return_val.type = Variant::NIL;
- mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- return mi;
- } break;
- case TYPE_OF: {
- MethodInfo mi("typeof", PropertyInfo(Variant::NIL, "what", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT));
- mi.return_val.type = Variant::INT;
- return mi;
-
- } break;
- case TYPE_EXISTS: {
- MethodInfo mi("type_exists", PropertyInfo(Variant::STRING, "type"));
- mi.return_val.type = Variant::BOOL;
- return mi;
-
- } break;
- case TEXT_CHAR: {
- MethodInfo mi("char", PropertyInfo(Variant::INT, "code"));
- mi.return_val.type = Variant::STRING;
- return mi;
-
- } break;
- case TEXT_ORD: {
- MethodInfo mi("ord", PropertyInfo(Variant::STRING, "char"));
- mi.return_val.type = Variant::INT;
- return mi;
-
- } break;
- case TEXT_STR: {
- MethodInfo mi("str");
- mi.return_val.type = Variant::STRING;
- mi.flags |= METHOD_FLAG_VARARG;
- return mi;
-
- } break;
- case TEXT_PRINT: {
- MethodInfo mi("print");
- mi.return_val.type = Variant::NIL;
- mi.flags |= METHOD_FLAG_VARARG;
- return mi;
-
- } break;
- case TEXT_PRINT_TABBED: {
- MethodInfo mi("printt");
- mi.return_val.type = Variant::NIL;
- mi.flags |= METHOD_FLAG_VARARG;
- return mi;
-
- } break;
- case TEXT_PRINT_SPACED: {
- MethodInfo mi("prints");
- mi.return_val.type = Variant::NIL;
- mi.flags |= METHOD_FLAG_VARARG;
- return mi;
-
- } break;
- case TEXT_PRINTERR: {
- MethodInfo mi("printerr");
- mi.return_val.type = Variant::NIL;
- mi.flags |= METHOD_FLAG_VARARG;
- return mi;
-
- } break;
- case TEXT_PRINTRAW: {
- MethodInfo mi("printraw");
- mi.return_val.type = Variant::NIL;
- mi.flags |= METHOD_FLAG_VARARG;
- return mi;
-
- } break;
- case TEXT_PRINT_DEBUG: {
- MethodInfo mi("print_debug");
- mi.return_val.type = Variant::NIL;
- mi.flags |= METHOD_FLAG_VARARG;
- return mi;
-
- } break;
- case PUSH_ERROR: {
- MethodInfo mi(Variant::NIL, "push_error", PropertyInfo(Variant::STRING, "message"));
- mi.return_val.type = Variant::NIL;
- return mi;
-
- } break;
- case PUSH_WARNING: {
- MethodInfo mi(Variant::NIL, "push_warning", PropertyInfo(Variant::STRING, "message"));
- mi.return_val.type = Variant::NIL;
- return mi;
-
- } break;
- case VAR_TO_STR: {
- MethodInfo mi("var2str", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT));
- mi.return_val.type = Variant::STRING;
- return mi;
- } break;
- case STR_TO_VAR: {
- MethodInfo mi(Variant::NIL, "str2var", PropertyInfo(Variant::STRING, "string"));
- mi.return_val.type = Variant::NIL;
- mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- return mi;
- } break;
- case VAR_TO_BYTES: {
- MethodInfo mi("var2bytes", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT), PropertyInfo(Variant::BOOL, "full_objects"));
- mi.default_arguments.push_back(false);
- mi.return_val.type = Variant::PACKED_BYTE_ARRAY;
- return mi;
- } break;
- case BYTES_TO_VAR: {
- MethodInfo mi(Variant::NIL, "bytes2var", PropertyInfo(Variant::PACKED_BYTE_ARRAY, "bytes"), PropertyInfo(Variant::BOOL, "allow_objects"));
- mi.default_arguments.push_back(false);
- mi.return_val.type = Variant::NIL;
- mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- return mi;
- } break;
- case GEN_RANGE: {
- MethodInfo mi("range");
- mi.return_val.type = Variant::ARRAY;
- mi.flags |= METHOD_FLAG_VARARG;
- return mi;
- } break;
- case RESOURCE_LOAD: {
- MethodInfo mi("load", PropertyInfo(Variant::STRING, "path"));
- mi.return_val.type = Variant::OBJECT;
- mi.return_val.class_name = "Resource";
- return mi;
- } break;
- case INST2DICT: {
- MethodInfo mi("inst2dict", PropertyInfo(Variant::OBJECT, "inst"));
- mi.return_val.type = Variant::DICTIONARY;
- return mi;
- } break;
- case DICT2INST: {
- MethodInfo mi("dict2inst", PropertyInfo(Variant::DICTIONARY, "dict"));
- mi.return_val.type = Variant::OBJECT;
- return mi;
- } break;
- case VALIDATE_JSON: {
- MethodInfo mi("validate_json", PropertyInfo(Variant::STRING, "json"));
- mi.return_val.type = Variant::STRING;
- return mi;
- } break;
- case PARSE_JSON: {
- MethodInfo mi(Variant::NIL, "parse_json", PropertyInfo(Variant::STRING, "json"));
- mi.return_val.type = Variant::NIL;
- mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- return mi;
- } break;
- case TO_JSON: {
- MethodInfo mi("to_json", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT));
- mi.return_val.type = Variant::STRING;
- return mi;
- } break;
- case HASH: {
- MethodInfo mi("hash", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT));
- mi.return_val.type = Variant::INT;
- return mi;
- } break;
- case COLOR8: {
- MethodInfo mi("Color8", PropertyInfo(Variant::INT, "r8"), PropertyInfo(Variant::INT, "g8"), PropertyInfo(Variant::INT, "b8"), PropertyInfo(Variant::INT, "a8"));
- mi.default_arguments.push_back(255);
- mi.return_val.type = Variant::COLOR;
- return mi;
- } break;
- case COLORN: {
- MethodInfo mi("ColorN", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::FLOAT, "alpha"));
- mi.default_arguments.push_back(1.0f);
- mi.return_val.type = Variant::COLOR;
- return mi;
- } break;
-
- case PRINT_STACK: {
- MethodInfo mi("print_stack");
- mi.return_val.type = Variant::NIL;
- return mi;
- } break;
- case GET_STACK: {
- MethodInfo mi("get_stack");
- mi.return_val.type = Variant::ARRAY;
- return mi;
- } break;
-
- case INSTANCE_FROM_ID: {
- MethodInfo mi("instance_from_id", PropertyInfo(Variant::INT, "instance_id"));
- mi.return_val.type = Variant::OBJECT;
- return mi;
- } break;
- case LEN: {
- MethodInfo mi("len", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT));
- mi.return_val.type = Variant::INT;
- return mi;
- } break;
- case IS_INSTANCE_VALID: {
- MethodInfo mi("is_instance_valid", PropertyInfo(Variant::OBJECT, "instance"));
- mi.return_val.type = Variant::BOOL;
- return mi;
- } break;
- default: {
- ERR_FAIL_V(MethodInfo());
- } break;
- }
-#endif
- MethodInfo mi;
- mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- return mi;
-}
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 2a69db130b..a77fb14064 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,15 +30,15 @@
#include "gdscript_parser.h"
+#include "core/config/project_settings.h"
#include "core/io/resource_loader.h"
#include "core/math/math_defs.h"
#include "core/os/file_access.h"
-#include "core/project_settings.h"
#include "gdscript.h"
#ifdef DEBUG_ENABLED
#include "core/os/os.h"
-#include "core/string_builder.h"
+#include "core/string/string_builder.h"
#endif // DEBUG_ENABLED
#ifdef TOOLS_ENABLED
@@ -47,7 +47,7 @@
static HashMap<StringName, Variant::Type> builtin_types;
Variant::Type GDScriptParser::get_builtin_type(const StringName &p_type) {
- if (builtin_types.empty()) {
+ if (builtin_types.is_empty()) {
builtin_types["bool"] = Variant::BOOL;
builtin_types["int"] = Variant::INT;
builtin_types["float"] = Variant::FLOAT;
@@ -65,7 +65,7 @@ Variant::Type GDScriptParser::get_builtin_type(const StringName &p_type) {
builtin_types["Basis"] = Variant::BASIS;
builtin_types["Transform"] = Variant::TRANSFORM;
builtin_types["Color"] = Variant::COLOR;
- builtin_types["RID"] = Variant::_RID;
+ builtin_types["RID"] = Variant::RID;
builtin_types["Object"] = Variant::OBJECT;
builtin_types["StringName"] = Variant::STRING_NAME;
builtin_types["NodePath"] = Variant::NODE_PATH;
@@ -98,15 +98,6 @@ void GDScriptParser::cleanup() {
builtin_types.clear();
}
-GDScriptFunctions::Function GDScriptParser::get_builtin_function(const StringName &p_name) {
- for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) {
- if (p_name == GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i))) {
- return GDScriptFunctions::Function(i);
- }
- }
- return GDScriptFunctions::FUNC_MAX;
-}
-
void GDScriptParser::get_annotation_list(List<MethodInfo> *r_annotations) const {
List<StringName> keys;
valid_annotations.get_key_list(&keys);
@@ -184,23 +175,25 @@ void GDScriptParser::push_error(const String &p_message, const Node *p_origin) {
#ifdef DEBUG_ENABLED
void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_code, const String &p_symbol1, const String &p_symbol2, const String &p_symbol3, const String &p_symbol4) {
+ ERR_FAIL_COND(p_source == nullptr);
Vector<String> symbols;
- if (!p_symbol1.empty()) {
+ if (!p_symbol1.is_empty()) {
symbols.push_back(p_symbol1);
}
- if (!p_symbol2.empty()) {
+ if (!p_symbol2.is_empty()) {
symbols.push_back(p_symbol2);
}
- if (!p_symbol3.empty()) {
+ if (!p_symbol3.is_empty()) {
symbols.push_back(p_symbol3);
}
- if (!p_symbol4.empty()) {
+ if (!p_symbol4.is_empty()) {
symbols.push_back(p_symbol4);
}
push_warning(p_source, p_code, symbols);
}
void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_code, const Vector<String> &p_symbols) {
+ ERR_FAIL_COND(p_source == nullptr);
if (is_ignoring_warnings) {
return;
}
@@ -291,7 +284,7 @@ void GDScriptParser::pop_completion_call() {
if (!for_completion) {
return;
}
- ERR_FAIL_COND_MSG(completion_call_stack.empty(), "Trying to pop empty completion call stack");
+ ERR_FAIL_COND_MSG(completion_call_stack.is_empty(), "Trying to pop empty completion call stack");
completion_call_stack.pop_back();
}
@@ -299,7 +292,7 @@ void GDScriptParser::set_last_completion_call_arg(int p_argument) {
if (!for_completion || passed_cursor) {
return;
}
- ERR_FAIL_COND_MSG(completion_call_stack.empty(), "Trying to set argument on empty completion call stack");
+ ERR_FAIL_COND_MSG(completion_call_stack.is_empty(), "Trying to set argument on empty completion call stack");
completion_call_stack.back()->get().argument = p_argument;
}
@@ -365,7 +358,7 @@ Error GDScriptParser::parse(const String &p_source_code, const String &p_script_
}
#endif
- if (errors.empty()) {
+ if (errors.is_empty()) {
return OK;
} else {
return ERR_PARSE_ERROR;
@@ -376,7 +369,7 @@ GDScriptTokenizer::Token GDScriptParser::advance() {
if (current.type == GDScriptTokenizer::Token::TK_EOF) {
ERR_FAIL_COND_V_MSG(current.type == GDScriptTokenizer::Token::TK_EOF, current, "GDScript parser bug: Trying to advance past the end of stream.");
}
- if (for_completion && !completion_call_stack.empty()) {
+ if (for_completion && !completion_call_stack.is_empty()) {
if (completion_call.call == nullptr && tokenizer.is_past_cursor()) {
completion_call = completion_call_stack.back()->get();
passed_cursor = true;
@@ -507,7 +500,7 @@ void GDScriptParser::parse_program() {
// Order here doesn't matter, but there should be only one of each at most.
switch (current.type) {
case GDScriptTokenizer::Token::CLASS_NAME:
- if (!annotation_stack.empty()) {
+ if (!annotation_stack.is_empty()) {
push_error(R"("class_name" should be used before annotations.)");
}
advance();
@@ -518,7 +511,7 @@ void GDScriptParser::parse_program() {
}
break;
case GDScriptTokenizer::Token::EXTENDS:
- if (!annotation_stack.empty()) {
+ if (!annotation_stack.is_empty()) {
push_error(R"("extends" should be used before annotations.)");
}
advance();
@@ -556,6 +549,17 @@ void GDScriptParser::parse_program() {
parse_class_body();
+#ifdef TOOLS_ENABLED
+ for (Map<int, GDScriptTokenizer::CommentData>::Element *E = tokenizer.get_comments().front(); E; E = E->next()) {
+ if (E->get().new_line && E->get().comment.begins_with("##")) {
+ class_doc_line = MIN(class_doc_line, E->key());
+ }
+ }
+ if (has_comment(class_doc_line)) {
+ get_class_doc_comment(class_doc_line, head->doc_brief_description, head->doc_description, head->doc_tutorials, false);
+ }
+#endif // TOOLS_ENABLED
+
if (!check(GDScriptTokenizer::Token::TK_EOF)) {
push_error("Expected end of file.");
}
@@ -666,8 +670,12 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)()
if (member == nullptr) {
return;
}
+#ifdef TOOLS_ENABLED
+ int doc_comment_line = member->start_line - 1;
+#endif // TOOLS_ENABLED
+
// Consume annotations.
- while (!annotation_stack.empty()) {
+ while (!annotation_stack.is_empty()) {
AnnotationNode *last_annotation = annotation_stack.back()->get();
if (last_annotation->applies_to(p_target)) {
last_annotation->apply(this, member);
@@ -678,7 +686,25 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)()
clear_unused_annotations();
return;
}
+#ifdef TOOLS_ENABLED
+ if (last_annotation->start_line == doc_comment_line) {
+ doc_comment_line--;
+ }
+#endif // TOOLS_ENABLED
}
+
+#ifdef TOOLS_ENABLED
+ // Consume doc comments.
+ class_doc_line = MIN(class_doc_line, doc_comment_line - 1);
+ if (has_comment(doc_comment_line)) {
+ if constexpr (std::is_same_v<T, ClassNode>) {
+ get_class_doc_comment(doc_comment_line, member->doc_brief_description, member->doc_description, member->doc_tutorials, true);
+ } else {
+ member->doc_description = get_doc_comment(doc_comment_line);
+ }
+ }
+#endif // TOOLS_ENABLED
+
if (member->identifier != nullptr) {
// Enums may be unnamed.
// TODO: Consider names in outer scope too, for constants and classes (and static functions?)
@@ -950,6 +976,8 @@ GDScriptParser::ConstantNode *GDScriptParser::parse_constant() {
push_error(R"(Expected initializer expression for constant.)");
return nullptr;
}
+ } else {
+ return nullptr;
}
end_statement("constant declaration");
@@ -1048,6 +1076,7 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum() {
item.parent_enum = enum_node;
item.line = previous.start_line;
item.leftmost_column = previous.leftmost_column;
+ item.rightmost_column = previous.rightmost_column;
if (elements.has(item.identifier->name)) {
push_error(vformat(R"(Name "%s" was already in this enum (at line %d).)", item.identifier->name, elements[item.identifier->name]), item.identifier);
@@ -1086,6 +1115,31 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum() {
pop_multiline();
consume(GDScriptTokenizer::Token::BRACE_CLOSE, R"(Expected closing "}" for enum.)");
+#ifdef TOOLS_ENABLED
+ // Enum values documentaion.
+ for (int i = 0; i < enum_node->values.size(); i++) {
+ if (i == enum_node->values.size() - 1) {
+ // If close bracket is same line as last value.
+ if (enum_node->values[i].line != previous.start_line && has_comment(enum_node->values[i].line)) {
+ if (named) {
+ enum_node->values.write[i].doc_description = get_doc_comment(enum_node->values[i].line, true);
+ } else {
+ current_class->set_enum_value_doc(enum_node->values[i].identifier->name, get_doc_comment(enum_node->values[i].line, true));
+ }
+ }
+ } else {
+ // If two values are same line.
+ if (enum_node->values[i].line != enum_node->values[i + 1].line && has_comment(enum_node->values[i].line)) {
+ if (named) {
+ enum_node->values.write[i].doc_description = get_doc_comment(enum_node->values[i].line, true);
+ } else {
+ current_class->set_enum_value_doc(enum_node->values[i].identifier->name, get_doc_comment(enum_node->values[i].line, true));
+ }
+ }
+ }
+ }
+#endif // TOOLS_ENABLED
+
end_statement("enum");
return enum_node;
@@ -1419,9 +1473,13 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {
}
#ifdef DEBUG_ENABLED
- if (unreachable) {
+ if (unreachable && result != nullptr) {
current_suite->has_unreachable_code = true;
- push_warning(result, GDScriptWarning::UNREACHABLE_CODE, current_function->identifier->name);
+ if (current_function) {
+ push_warning(result, GDScriptWarning::UNREACHABLE_CODE, current_function->identifier->name);
+ } else {
+ // TODO: Properties setters and getters with unreachable code are not being warned
+ }
}
#endif
@@ -1445,12 +1503,9 @@ GDScriptParser::AssertNode *GDScriptParser::parse_assert() {
if (match(GDScriptTokenizer::Token::COMMA)) {
// Error message.
- if (consume(GDScriptTokenizer::Token::LITERAL, R"(Expected error message for assert after ",".)")) {
- assert->message = parse_literal();
- if (assert->message->value.get_type() != Variant::STRING) {
- push_error(R"(Expected string for assert error message.)");
- }
- } else {
+ assert->message = parse_expression(false);
+ if (assert->message == nullptr) {
+ push_error(R"(Expected error message for assert after ",".)");
return nullptr;
}
}
@@ -1642,7 +1697,7 @@ GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() {
branch->patterns.push_back(pattern);
} while (match(GDScriptTokenizer::Token::COMMA));
- if (branch->patterns.empty()) {
+ if (branch->patterns.is_empty()) {
push_error(R"(No pattern found for "match" branch.)");
}
@@ -2486,26 +2541,28 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_call(ExpressionNode *p_pre
}
}
- if (!check(GDScriptTokenizer::Token::PARENTHESIS_CLOSE)) {
- // Arguments.
- push_completion_call(call);
- make_completion_context(COMPLETION_CALL_ARGUMENTS, call, 0, true);
- int argument_index = 0;
- do {
- make_completion_context(COMPLETION_CALL_ARGUMENTS, call, argument_index++, true);
- if (check(GDScriptTokenizer::Token::PARENTHESIS_CLOSE)) {
- // Allow for trailing comma.
- break;
- }
- ExpressionNode *argument = parse_expression(false);
- if (argument == nullptr) {
- push_error(R"(Expected expression as the function argument.)");
- } else {
- call->arguments.push_back(argument);
- }
- } while (match(GDScriptTokenizer::Token::COMMA));
- pop_completion_call();
+ // Arguments.
+ CompletionType ct = COMPLETION_CALL_ARGUMENTS;
+ if (call->function_name == "load") {
+ ct = COMPLETION_RESOURCE_PATH;
}
+ push_completion_call(call);
+ int argument_index = 0;
+ do {
+ make_completion_context(ct, call, argument_index++, true);
+ if (check(GDScriptTokenizer::Token::PARENTHESIS_CLOSE)) {
+ // Allow for trailing comma.
+ break;
+ }
+ ExpressionNode *argument = parse_expression(false);
+ if (argument == nullptr) {
+ push_error(R"(Expected expression as the function argument.)");
+ } else {
+ call->arguments.push_back(argument);
+ }
+ ct = COMPLETION_CALL_ARGUMENTS;
+ } while (match(GDScriptTokenizer::Token::COMMA));
+ pop_completion_call();
pop_multiline();
consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected closing ")" after call arguments.)*");
@@ -2616,6 +2673,218 @@ GDScriptParser::TypeNode *GDScriptParser::parse_type(bool p_allow_void) {
return type;
}
+#ifdef TOOLS_ENABLED
+static bool _in_codeblock(String p_line, bool p_already_in, int *r_block_begins = nullptr) {
+ int start_block = p_line.rfind("[codeblock]");
+ int end_block = p_line.rfind("[/codeblock]");
+
+ if (start_block != -1 && r_block_begins) {
+ *r_block_begins = start_block;
+ }
+
+ if (p_already_in) {
+ if (end_block == -1) {
+ return true;
+ } else if (start_block == -1) {
+ return false;
+ } else {
+ return start_block > end_block;
+ }
+ } else {
+ if (start_block == -1) {
+ return false;
+ } else if (end_block == -1) {
+ return true;
+ } else {
+ return start_block > end_block;
+ }
+ }
+}
+
+bool GDScriptParser::has_comment(int p_line) {
+ return tokenizer.get_comments().has(p_line);
+}
+
+String GDScriptParser::get_doc_comment(int p_line, bool p_single_line) {
+ const Map<int, GDScriptTokenizer::CommentData> &comments = tokenizer.get_comments();
+ ERR_FAIL_COND_V(!comments.has(p_line), String());
+
+ if (p_single_line) {
+ if (comments[p_line].comment.begins_with("##")) {
+ return comments[p_line].comment.trim_prefix("##").strip_edges();
+ }
+ return "";
+ }
+
+ String doc;
+
+ int line = p_line;
+ bool in_codeblock = false;
+
+ while (comments.has(line - 1)) {
+ if (!comments[line - 1].new_line || !comments[line - 1].comment.begins_with("##")) {
+ break;
+ }
+ line--;
+ }
+
+ int codeblock_begins = 0;
+ while (comments.has(line)) {
+ if (!comments[line].new_line || !comments[line].comment.begins_with("##")) {
+ break;
+ }
+ String doc_line = comments[line].comment.trim_prefix("##");
+
+ in_codeblock = _in_codeblock(doc_line, in_codeblock, &codeblock_begins);
+
+ if (in_codeblock) {
+ int i = 0;
+ for (; i < codeblock_begins; i++) {
+ if (doc_line[i] != ' ') {
+ break;
+ }
+ }
+ doc_line = doc_line.substr(i);
+ } else {
+ doc_line = doc_line.strip_edges();
+ }
+ String line_join = (in_codeblock) ? "\n" : " ";
+
+ doc = (doc.is_empty()) ? doc_line : doc + line_join + doc_line;
+ line++;
+ }
+
+ return doc;
+}
+
+void GDScriptParser::get_class_doc_comment(int p_line, String &p_brief, String &p_desc, Vector<Pair<String, String>> &p_tutorials, bool p_inner_class) {
+ const Map<int, GDScriptTokenizer::CommentData> &comments = tokenizer.get_comments();
+ if (!comments.has(p_line)) {
+ return;
+ }
+ ERR_FAIL_COND(p_brief != "" || p_desc != "" || p_tutorials.size() != 0);
+
+ int line = p_line;
+ bool in_codeblock = false;
+ enum Mode {
+ BRIEF,
+ DESC,
+ TUTORIALS,
+ DONE,
+ };
+ Mode mode = BRIEF;
+
+ if (p_inner_class) {
+ while (comments.has(line - 1)) {
+ if (!comments[line - 1].new_line || !comments[line - 1].comment.begins_with("##")) {
+ break;
+ }
+ line--;
+ }
+ }
+
+ int codeblock_begins = 0;
+ while (comments.has(line)) {
+ if (!comments[line].new_line || !comments[line].comment.begins_with("##")) {
+ break;
+ }
+
+ String title, link; // For tutorials.
+ String doc_line = comments[line++].comment.trim_prefix("##");
+ String striped_line = doc_line.strip_edges();
+
+ // Set the read mode.
+ if (striped_line.begins_with("@desc:") && p_desc == "") {
+ mode = DESC;
+ striped_line = striped_line.trim_prefix("@desc:");
+ in_codeblock = _in_codeblock(doc_line, in_codeblock);
+
+ } else if (striped_line.begins_with("@tutorial")) {
+ int begin_scan = String("@tutorial").length();
+ if (begin_scan >= striped_line.length()) {
+ continue; // invalid syntax.
+ }
+
+ if (striped_line[begin_scan] == ':') { // No title.
+ // Syntax: ## @tutorial: https://godotengine.org/ // The title argument is optional.
+ title = "";
+ link = striped_line.trim_prefix("@tutorial:").strip_edges();
+
+ } else {
+ /* Syntax:
+ @tutorial ( The Title Here ) : http://the.url/
+ ^ open ^ close ^ colon ^ url
+ */
+ int open_bracket_pos = begin_scan, close_bracket_pos = 0;
+ while (open_bracket_pos < striped_line.length() && (striped_line[open_bracket_pos] == ' ' || striped_line[open_bracket_pos] == '\t')) {
+ open_bracket_pos++;
+ }
+ if (open_bracket_pos == striped_line.length() || striped_line[open_bracket_pos++] != '(') {
+ continue; // invalid syntax.
+ }
+ close_bracket_pos = open_bracket_pos;
+ while (close_bracket_pos < striped_line.length() && striped_line[close_bracket_pos] != ')') {
+ close_bracket_pos++;
+ }
+ if (close_bracket_pos == striped_line.length()) {
+ continue; // invalid syntax.
+ }
+
+ int colon_pos = close_bracket_pos + 1;
+ while (colon_pos < striped_line.length() && (striped_line[colon_pos] == ' ' || striped_line[colon_pos] == '\t')) {
+ colon_pos++;
+ }
+ if (colon_pos == striped_line.length() || striped_line[colon_pos++] != ':') {
+ continue; // invalid syntax.
+ }
+
+ title = striped_line.substr(open_bracket_pos, close_bracket_pos - open_bracket_pos).strip_edges();
+ link = striped_line.substr(colon_pos).strip_edges();
+ }
+
+ mode = TUTORIALS;
+ in_codeblock = false;
+ } else if (striped_line.is_empty()) {
+ continue;
+ } else {
+ // Tutorial docs are single line, we need a @tag after it.
+ if (mode == TUTORIALS) {
+ mode = DONE;
+ }
+
+ in_codeblock = _in_codeblock(doc_line, in_codeblock, &codeblock_begins);
+ }
+
+ if (in_codeblock) {
+ int i = 0;
+ for (; i < codeblock_begins; i++) {
+ if (doc_line[i] != ' ') {
+ break;
+ }
+ }
+ doc_line = doc_line.substr(i);
+ } else {
+ doc_line = striped_line;
+ }
+ String line_join = (in_codeblock) ? "\n" : " ";
+
+ switch (mode) {
+ case BRIEF:
+ p_brief = (p_brief.length() == 0) ? doc_line : p_brief + line_join + doc_line;
+ break;
+ case DESC:
+ p_desc = (p_desc.length() == 0) ? doc_line : p_desc + line_join + doc_line;
+ break;
+ case TUTORIALS:
+ p_tutorials.append(Pair<String, String>(title, link));
+ break;
+ case DONE:
+ return;
+ }
+ }
+}
+#endif // TOOLS_ENABLED
+
GDScriptParser::ParseRule *GDScriptParser::get_rule(GDScriptTokenizer::Token::Type p_token_type) {
// Function table for expression parsing.
// clang-format destroys the alignment here, so turn off for the table.
@@ -2649,8 +2918,8 @@ GDScriptParser::ParseRule *GDScriptParser::get_rule(GDScriptTokenizer::Token::Ty
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_BIT_SHIFT }, // LESS_LESS,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_BIT_SHIFT }, // GREATER_GREATER,
// Math
- { &GDScriptParser::parse_unary_operator, &GDScriptParser::parse_binary_operator, PREC_ADDITION }, // PLUS,
- { &GDScriptParser::parse_unary_operator, &GDScriptParser::parse_binary_operator, PREC_SUBTRACTION }, // MINUS,
+ { &GDScriptParser::parse_unary_operator, &GDScriptParser::parse_binary_operator, PREC_ADDITION_SUBTRACTION }, // PLUS,
+ { &GDScriptParser::parse_unary_operator, &GDScriptParser::parse_binary_operator, PREC_ADDITION_SUBTRACTION }, // MINUS,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_FACTOR }, // STAR,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_FACTOR }, // SLASH,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_FACTOR }, // PERCENT,
@@ -2802,7 +3071,9 @@ bool GDScriptParser::validate_annotation_arguments(AnnotationNode *p_annotation)
Callable::CallError error;
Vector<Variant> args = varray(string->name);
const Variant *name = args.ptr();
- p_annotation->resolved_arguments.push_back(Variant::construct(parameter.type, &(name), 1, error));
+ Variant r;
+ Variant::construct(parameter.type, r, &(name), 1, error);
+ p_annotation->resolved_arguments.push_back(r);
if (error.error != Callable::CallError::CALL_OK) {
push_error(vformat(R"(Expected %s as argument %d of annotation "%s").)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name));
p_annotation->resolved_arguments.remove(p_annotation->resolved_arguments.size() - 1);
@@ -2824,7 +3095,9 @@ bool GDScriptParser::validate_annotation_arguments(AnnotationNode *p_annotation)
}
Callable::CallError error;
const Variant *args = &value;
- p_annotation->resolved_arguments.push_back(Variant::construct(parameter.type, &(args), 1, error));
+ Variant r;
+ Variant::construct(parameter.type, r, &(args), 1, error);
+ p_annotation->resolved_arguments.push_back(r);
if (error.error != Callable::CallError::CALL_OK) {
push_error(vformat(R"(Expected %s as argument %d of annotation "%s").)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name));
p_annotation->resolved_arguments.remove(p_annotation->resolved_arguments.size() - 1);
@@ -3006,11 +3279,11 @@ String GDScriptParser::DataType::to_string() const {
return script_type->get_class_name().operator String();
}
String name = script_type->get_name();
- if (!name.empty()) {
+ if (!name.is_empty()) {
return name;
}
name = script_path;
- if (!name.empty()) {
+ if (!name.is_empty()) {
return name;
}
return native_type.operator String();
@@ -3055,7 +3328,7 @@ void GDScriptParser::TreePrinter::decrease_indent() {
}
void GDScriptParser::TreePrinter::push_line(const String &p_line) {
- if (!p_line.empty()) {
+ if (!p_line.is_empty()) {
push_text(p_line);
}
printed += "\n";
@@ -3264,7 +3537,7 @@ void GDScriptParser::TreePrinter::print_class(ClassNode *p_class) {
if (p_class->extends_used) {
bool first = true;
push_text(" Extends ");
- if (!p_class->extends_path.empty()) {
+ if (!p_class->extends_path.is_empty()) {
push_text(vformat(R"("%s")", p_class->extends_path));
first = false;
}
@@ -3726,7 +3999,7 @@ void GDScriptParser::TreePrinter::print_ternary_op(TernaryOpNode *p_ternary_op)
}
void GDScriptParser::TreePrinter::print_type(TypeNode *p_type) {
- if (p_type->type_chain.empty()) {
+ if (p_type->type_chain.is_empty()) {
push_text("Void");
} else {
for (int i = 0; i < p_type->type_chain.size(); i++) {
@@ -3846,7 +4119,7 @@ void GDScriptParser::TreePrinter::print_tree(const GDScriptParser &p_parser) {
if (p_parser.is_tool()) {
push_line("@tool");
}
- if (!p_parser.get_tree()->icon_path.empty()) {
+ if (!p_parser.get_tree()->icon_path.is_empty()) {
push_text(R"(@icon (")");
push_text(p_parser.get_tree()->icon_path);
push_line("\")");
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 4c9473c7bd..f43708b81f 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,23 +31,22 @@
#ifndef GDSCRIPT_PARSER_H
#define GDSCRIPT_PARSER_H
-#include "core/hash_map.h"
#include "core/io/multiplayer_api.h"
-#include "core/list.h"
-#include "core/map.h"
-#include "core/reference.h"
-#include "core/resource.h"
-#include "core/script_language.h"
-#include "core/string_name.h"
-#include "core/ustring.h"
-#include "core/variant.h"
-#include "core/vector.h"
+#include "core/io/resource.h"
+#include "core/object/reference.h"
+#include "core/object/script_language.h"
+#include "core/string/string_name.h"
+#include "core/string/ustring.h"
+#include "core/templates/hash_map.h"
+#include "core/templates/list.h"
+#include "core/templates/map.h"
+#include "core/templates/vector.h"
+#include "core/variant/variant.h"
#include "gdscript_cache.h"
-#include "gdscript_functions.h"
#include "gdscript_tokenizer.h"
#ifdef DEBUG_ENABLED
-#include "core/string_builder.h"
+#include "core/string/string_builder.h"
#include "gdscript_warning.h"
#endif // DEBUG_ENABLED
@@ -287,7 +286,7 @@ public:
struct AssertNode : public Node {
ExpressionNode *condition = nullptr;
- LiteralNode *message = nullptr;
+ ExpressionNode *message = nullptr;
AssertNode() {
type = ASSERT;
@@ -413,9 +412,16 @@ public:
int line = 0;
int leftmost_column = 0;
int rightmost_column = 0;
+#ifdef TOOLS_ENABLED
+ String doc_description;
+#endif // TOOLS_ENABLED
};
+
IdentifierNode *identifier = nullptr;
Vector<Value> values;
+#ifdef TOOLS_ENABLED
+ String doc_description;
+#endif // TOOLS_ENABLED
EnumNode() {
type = ENUM;
@@ -568,6 +574,17 @@ public:
Vector<StringName> extends; // List for indexing: extends A.B.C
DataType base_type;
String fqcn; // Fully-qualified class name. Identifies uniquely any class in the project.
+#ifdef TOOLS_ENABLED
+ String doc_description;
+ String doc_brief_description;
+ Vector<Pair<String, String>> doc_tutorials;
+
+ // EnumValue docs are parsed after itself, so we need a method to add/modify the doc property later.
+ void set_enum_value_doc(const StringName &p_name, const String &p_doc_description) {
+ ERR_FAIL_INDEX(members_indices[p_name], members.size());
+ members.write[members_indices[p_name]].enum_value.doc_description = p_doc_description;
+ }
+#endif // TOOLS_ENABLED
bool resolved_interface = false;
bool resolved_body = false;
@@ -602,6 +619,9 @@ public:
TypeNode *datatype_specifier = nullptr;
bool infer_datatype = false;
int usages = 0;
+#ifdef TOOLS_ENABLED
+ String doc_description;
+#endif // TOOLS_ENABLED
ConstantNode() {
type = CONSTANT;
@@ -653,6 +673,10 @@ public:
bool is_coroutine = false;
MultiplayerAPI::RPCMode rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
MethodInfo info;
+#ifdef TOOLS_ENABLED
+ Vector<Variant> default_arg_values;
+ String doc_description;
+#endif // TOOLS_ENABLED
bool resolved_signature = false;
bool resolved_body = false;
@@ -820,6 +844,9 @@ public:
IdentifierNode *identifier = nullptr;
Vector<ParameterNode *> parameters;
HashMap<StringName, int> parameters_indices;
+#ifdef TOOLS_ENABLED
+ String doc_description;
+#endif // TOOLS_ENABLED
SignalNode() {
type = SIGNAL;
@@ -1012,6 +1039,9 @@ public:
MultiplayerAPI::RPCMode rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
int assignments = 0;
int usages = 0;
+#ifdef TOOLS_ENABLED
+ String doc_description;
+#endif // TOOLS_ENABLED
VariableNode() {
type = VARIABLE;
@@ -1142,8 +1172,7 @@ private:
PREC_BIT_XOR,
PREC_BIT_AND,
PREC_BIT_SHIFT,
- PREC_SUBTRACTION,
- PREC_ADDITION,
+ PREC_ADDITION_SUBTRACTION,
PREC_FACTOR,
PREC_SIGN,
PREC_BIT_NOT,
@@ -1270,13 +1299,19 @@ private:
ExpressionNode *parse_subscript(ExpressionNode *p_previous_operand, bool p_can_assign);
ExpressionNode *parse_invalid_token(ExpressionNode *p_previous_operand, bool p_can_assign);
TypeNode *parse_type(bool p_allow_void = false);
+#ifdef TOOLS_ENABLED
+ // Doc comments.
+ int class_doc_line = 0x7FFFFFFF;
+ bool has_comment(int p_line);
+ String get_doc_comment(int p_line, bool p_single_line = false);
+ void get_class_doc_comment(int p_line, String &p_brief, String &p_desc, Vector<Pair<String, String>> &p_tutorials, bool p_inner_class);
+#endif // TOOLS_ENABLED
public:
Error parse(const String &p_source_code, const String &p_script_path, bool p_for_completion);
ClassNode *get_tree() const { return head; }
bool is_tool() const { return _is_tool; }
static Variant::Type get_builtin_type(const StringName &p_type);
- static GDScriptFunctions::Function get_builtin_function(const StringName &p_name);
CompletionContext get_completion_context() const { return completion_context; }
CompletionCall get_completion_call() const { return completion_call; }
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index 9a40aa50ac..315b8ee3b4 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,7 +30,7 @@
#include "gdscript_tokenizer.h"
-#include "core/error_macros.h"
+#include "core/error/error_macros.h"
#ifdef TOOLS_ENABLED
#include "editor/editor_settings.h"
@@ -221,7 +221,7 @@ String GDScriptTokenizer::get_token_name(Token::Type p_token_type) {
void GDScriptTokenizer::set_source_code(const String &p_source_code) {
source = p_source_code;
- if (source.empty()) {
+ if (source.is_empty()) {
_source = U"";
} else {
_source = source.ptr();
@@ -287,7 +287,7 @@ void GDScriptTokenizer::push_paren(char32_t p_char) {
}
bool GDScriptTokenizer::pop_paren(char32_t p_expected) {
- if (paren_stack.empty()) {
+ if (paren_stack.is_empty()) {
return false;
}
char32_t actual = paren_stack.back()->get();
@@ -405,7 +405,7 @@ void GDScriptTokenizer::push_error(const Token &p_error) {
}
GDScriptTokenizer::Token GDScriptTokenizer::make_paren_error(char32_t p_paren) {
- if (paren_stack.empty()) {
+ if (paren_stack.is_empty()) {
return make_error(vformat("Closing \"%c\" doesn't have an opening counterpart.", p_paren));
}
Token error = make_error(vformat("Closing \"%c\" doesn't match the opening \"%c\".", p_paren, paren_stack.back()->get()));
@@ -1014,9 +1014,17 @@ void GDScriptTokenizer::check_indent() {
}
if (_peek() == '#') {
// Comment. Advance to the next line.
+#ifdef TOOLS_ENABLED
+ String comment;
+ while (_peek() != '\n' && !_is_at_end()) {
+ comment += _advance();
+ }
+ comments[line] = CommentData(comment, true);
+#else
while (_peek() != '\n' && !_is_at_end()) {
_advance();
}
+#endif // TOOLS_ENABLED
if (_is_at_end()) {
// Reached the end with an empty line, so just dedent as much as needed.
pending_indents -= indent_level();
@@ -1125,18 +1133,26 @@ void GDScriptTokenizer::_skip_whitespace() {
newline(!is_bol); // Don't create new line token if line is empty.
check_indent();
break;
- case '#':
+ case '#': {
// Comment.
+#ifdef TOOLS_ENABLED
+ String comment;
+ while (_peek() != '\n' && !_is_at_end()) {
+ comment += _advance();
+ }
+ comments[line] = CommentData(comment, is_bol);
+#else
while (_peek() != '\n' && !_is_at_end()) {
_advance();
}
+#endif // TOOLS_ENABLED
if (_is_at_end()) {
return;
}
_advance(); // Consume '\n'
newline(!is_bol);
check_indent();
- break;
+ } break;
default:
return;
}
diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h
index 4453982d08..cdb0072294 100644
--- a/modules/gdscript/gdscript_tokenizer.h
+++ b/modules/gdscript/gdscript_tokenizer.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,10 +31,11 @@
#ifndef GDSCRIPT_TOKENIZER_H
#define GDSCRIPT_TOKENIZER_H
-#include "core/list.h"
-#include "core/set.h"
-#include "core/variant.h"
-#include "core/vector.h"
+#include "core/templates/list.h"
+#include "core/templates/map.h"
+#include "core/templates/set.h"
+#include "core/templates/vector.h"
+#include "core/variant/variant.h"
class GDScriptTokenizer {
public:
@@ -181,6 +182,21 @@ public:
}
};
+#ifdef TOOLS_ENABLED
+ struct CommentData {
+ String comment;
+ bool new_line = false;
+ CommentData() {}
+ CommentData(const String &p_comment, bool p_new_line) {
+ comment = p_comment;
+ new_line = p_new_line;
+ }
+ };
+ const Map<int, CommentData> &get_comments() const {
+ return comments;
+ }
+#endif // TOOLS_ENABLED
+
private:
String source;
const char32_t *_source = nullptr;
@@ -207,10 +223,14 @@ private:
int position = 0;
int length = 0;
+#ifdef TOOLS_ENABLED
+ Map<int, CommentData> comments;
+#endif // TOOLS_ENABLED
+
_FORCE_INLINE_ bool _is_at_end() { return position >= length; }
_FORCE_INLINE_ char32_t _peek(int p_offset = 0) { return position + p_offset >= 0 && position + p_offset < length ? _current[p_offset] : '\0'; }
int indent_level() const { return indent_stack.size(); }
- bool has_error() const { return !error_stack.empty(); }
+ bool has_error() const { return !error_stack.is_empty(); }
Token pop_error();
char32_t _advance();
void _skip_whitespace();
diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp
new file mode 100644
index 0000000000..348d221352
--- /dev/null
+++ b/modules/gdscript/gdscript_utility_functions.cpp
@@ -0,0 +1,718 @@
+/*************************************************************************/
+/* gdscript_utility_functions.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gdscript_utility_functions.h"
+
+#include "core/io/resource_loader.h"
+#include "core/object/class_db.h"
+#include "core/object/method_bind.h"
+#include "core/object/object.h"
+#include "core/templates/oa_hash_map.h"
+#include "core/templates/vector.h"
+#include "gdscript.h"
+
+#ifdef DEBUG_ENABLED
+
+#define VALIDATE_ARG_COUNT(m_count) \
+ if (p_arg_count < m_count) { \
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; \
+ r_error.argument = m_count; \
+ r_error.expected = m_count; \
+ *r_ret = Variant(); \
+ return; \
+ } \
+ if (p_arg_count > m_count) { \
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; \
+ r_error.argument = m_count; \
+ r_error.expected = m_count; \
+ *r_ret = Variant(); \
+ return; \
+ }
+
+#define VALIDATE_ARG_INT(m_arg) \
+ if (p_args[m_arg]->get_type() != Variant::INT) { \
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; \
+ r_error.argument = m_arg; \
+ r_error.expected = Variant::INT; \
+ *r_ret = Variant(); \
+ return; \
+ }
+
+#define VALIDATE_ARG_NUM(m_arg) \
+ if (!p_args[m_arg]->is_num()) { \
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; \
+ r_error.argument = m_arg; \
+ r_error.expected = Variant::FLOAT; \
+ *r_ret = Variant(); \
+ return; \
+ }
+
+#else
+
+#define VALIDATE_ARG_COUNT(m_count)
+#define VALIDATE_ARG_INT(m_arg)
+#define VALIDATE_ARG_NUM(m_arg)
+
+#endif
+
+struct GDScriptUtilityFunctionsDefinitions {
+ static inline void convert(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(2);
+ VALIDATE_ARG_INT(1);
+ int type = *p_args[1];
+ if (type < 0 || type >= Variant::VARIANT_MAX) {
+ *r_ret = RTR("Invalid type argument to convert(), use TYPE_* constants.");
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::INT;
+ return;
+
+ } else {
+ Variant::construct(Variant::Type(type), *r_ret, p_args, 1, r_error);
+ }
+ }
+
+ static inline void type_exists(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(1);
+ *r_ret = ClassDB::class_exists(*p_args[0]);
+ }
+
+ static inline void _char(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(1);
+ VALIDATE_ARG_INT(0);
+ char32_t result[2] = { *p_args[0], 0 };
+ *r_ret = String(result);
+ }
+
+ static inline void str(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ if (p_arg_count < 1) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 1;
+ *r_ret = Variant();
+ return;
+ }
+
+ String str;
+ for (int i = 0; i < p_arg_count; i++) {
+ String os = p_args[i]->operator String();
+
+ if (i == 0) {
+ str = os;
+ } else {
+ str += os;
+ }
+ }
+ *r_ret = str;
+ }
+
+ static inline void range(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ switch (p_arg_count) {
+ case 0: {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 1;
+ r_error.expected = 1;
+ *r_ret = Variant();
+ } break;
+ case 1: {
+ VALIDATE_ARG_NUM(0);
+ int count = *p_args[0];
+ Array arr;
+ if (count <= 0) {
+ *r_ret = arr;
+ return;
+ }
+ Error err = arr.resize(count);
+ if (err != OK) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ *r_ret = Variant();
+ return;
+ }
+
+ for (int i = 0; i < count; i++) {
+ arr[i] = i;
+ }
+
+ *r_ret = arr;
+ } break;
+ case 2: {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+
+ int from = *p_args[0];
+ int to = *p_args[1];
+
+ Array arr;
+ if (from >= to) {
+ *r_ret = arr;
+ return;
+ }
+ Error err = arr.resize(to - from);
+ if (err != OK) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ *r_ret = Variant();
+ return;
+ }
+ for (int i = from; i < to; i++) {
+ arr[i - from] = i;
+ }
+ *r_ret = arr;
+ } break;
+ case 3: {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+
+ int from = *p_args[0];
+ int to = *p_args[1];
+ int incr = *p_args[2];
+ if (incr == 0) {
+ *r_ret = RTR("Step argument is zero!");
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return;
+ }
+
+ Array arr;
+ if (from >= to && incr > 0) {
+ *r_ret = arr;
+ return;
+ }
+ if (from <= to && incr < 0) {
+ *r_ret = arr;
+ return;
+ }
+
+ // Calculate how many.
+ int count = 0;
+ if (incr > 0) {
+ count = ((to - from - 1) / incr) + 1;
+ } else {
+ count = ((from - to - 1) / -incr) + 1;
+ }
+
+ Error err = arr.resize(count);
+
+ if (err != OK) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ *r_ret = Variant();
+ return;
+ }
+
+ if (incr > 0) {
+ int idx = 0;
+ for (int i = from; i < to; i += incr) {
+ arr[idx++] = i;
+ }
+ } else {
+ int idx = 0;
+ for (int i = from; i > to; i += incr) {
+ arr[idx++] = i;
+ }
+ }
+
+ *r_ret = arr;
+ } break;
+ default: {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = 3;
+ r_error.expected = 3;
+ *r_ret = Variant();
+
+ } break;
+ }
+ }
+
+ static inline void load(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(1);
+ if (p_args[0]->get_type() != Variant::STRING) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::STRING;
+ *r_ret = Variant();
+ } else {
+ *r_ret = ResourceLoader::load(*p_args[0]);
+ }
+ }
+
+ static inline void inst2dict(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(1);
+
+ if (p_args[0]->get_type() == Variant::NIL) {
+ *r_ret = Variant();
+ } else if (p_args[0]->get_type() != Variant::OBJECT) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ *r_ret = Variant();
+ } else {
+ Object *obj = *p_args[0];
+ if (!obj) {
+ *r_ret = Variant();
+
+ } else if (!obj->get_script_instance() || obj->get_script_instance()->get_language() != GDScriptLanguage::get_singleton()) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::DICTIONARY;
+ *r_ret = RTR("Not a script with an instance");
+ return;
+ } else {
+ GDScriptInstance *ins = static_cast<GDScriptInstance *>(obj->get_script_instance());
+ Ref<GDScript> base = ins->get_script();
+ if (base.is_null()) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::DICTIONARY;
+ *r_ret = RTR("Not based on a script");
+ return;
+ }
+
+ GDScript *p = base.ptr();
+ Vector<StringName> sname;
+
+ while (p->_owner) {
+ sname.push_back(p->name);
+ p = p->_owner;
+ }
+ sname.invert();
+
+ if (!p->path.is_resource_file()) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::DICTIONARY;
+ *r_ret = Variant();
+
+ *r_ret = RTR("Not based on a resource file");
+
+ return;
+ }
+
+ NodePath cp(sname, Vector<StringName>(), false);
+
+ Dictionary d;
+ d["@subpath"] = cp;
+ d["@path"] = p->get_path();
+
+ for (Map<StringName, GDScript::MemberInfo>::Element *E = base->member_indices.front(); E; E = E->next()) {
+ if (!d.has(E->key())) {
+ d[E->key()] = ins->members[E->get().index];
+ }
+ }
+ *r_ret = d;
+ }
+ }
+ }
+
+ static inline void dict2inst(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(1);
+
+ if (p_args[0]->get_type() != Variant::DICTIONARY) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::DICTIONARY;
+ *r_ret = Variant();
+
+ return;
+ }
+
+ Dictionary d = *p_args[0];
+
+ if (!d.has("@path")) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::OBJECT;
+ *r_ret = RTR("Invalid instance dictionary format (missing @path)");
+
+ return;
+ }
+
+ Ref<Script> scr = ResourceLoader::load(d["@path"]);
+ if (!scr.is_valid()) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::OBJECT;
+ *r_ret = RTR("Invalid instance dictionary format (can't load script at @path)");
+ return;
+ }
+
+ Ref<GDScript> gdscr = scr;
+
+ if (!gdscr.is_valid()) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::OBJECT;
+ *r_ret = Variant();
+ *r_ret = RTR("Invalid instance dictionary format (invalid script at @path)");
+ return;
+ }
+
+ NodePath sub;
+ if (d.has("@subpath")) {
+ sub = d["@subpath"];
+ }
+
+ for (int i = 0; i < sub.get_name_count(); i++) {
+ gdscr = gdscr->subclasses[sub.get_name(i)];
+ if (!gdscr.is_valid()) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::OBJECT;
+ *r_ret = Variant();
+ *r_ret = RTR("Invalid instance dictionary (invalid subclasses)");
+ return;
+ }
+ }
+ *r_ret = gdscr->_new(nullptr, -1 /*skip initializer*/, r_error);
+
+ if (r_error.error != Callable::CallError::CALL_OK) {
+ *r_ret = Variant();
+ return;
+ }
+
+ GDScriptInstance *ins = static_cast<GDScriptInstance *>(static_cast<Object *>(*r_ret)->get_script_instance());
+ Ref<GDScript> gd_ref = ins->get_script();
+
+ for (Map<StringName, GDScript::MemberInfo>::Element *E = gd_ref->member_indices.front(); E; E = E->next()) {
+ if (d.has(E->key())) {
+ ins->members.write[E->get().index] = d[E->key()];
+ }
+ }
+ }
+
+ static inline void Color8(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ if (p_arg_count < 3) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 3;
+ *r_ret = Variant();
+ return;
+ }
+ if (p_arg_count > 4) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = 4;
+ *r_ret = Variant();
+ return;
+ }
+
+ VALIDATE_ARG_INT(0);
+ VALIDATE_ARG_INT(1);
+ VALIDATE_ARG_INT(2);
+
+ Color color((int64_t)*p_args[0] / 255.0f, (int64_t)*p_args[1] / 255.0f, (int64_t)*p_args[2] / 255.0f);
+
+ if (p_arg_count == 4) {
+ VALIDATE_ARG_INT(3);
+ color.a = (int64_t)*p_args[3] / 255.0f;
+ }
+
+ *r_ret = color;
+ }
+
+ static inline void print_debug(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ String str;
+ for (int i = 0; i < p_arg_count; i++) {
+ str += p_args[i]->operator String();
+ }
+
+ ScriptLanguage *script = GDScriptLanguage::get_singleton();
+ if (script->debug_get_stack_level_count() > 0) {
+ str += "\n At: " + script->debug_get_stack_level_source(0) + ":" + itos(script->debug_get_stack_level_line(0)) + ":" + script->debug_get_stack_level_function(0) + "()";
+ }
+
+ print_line(str);
+ *r_ret = Variant();
+ }
+
+ static inline void print_stack(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(0);
+
+ ScriptLanguage *script = GDScriptLanguage::get_singleton();
+ for (int i = 0; i < script->debug_get_stack_level_count(); i++) {
+ print_line("Frame " + itos(i) + " - " + script->debug_get_stack_level_source(i) + ":" + itos(script->debug_get_stack_level_line(i)) + " in function '" + script->debug_get_stack_level_function(i) + "'");
+ };
+ }
+
+ static inline void get_stack(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(0);
+
+ ScriptLanguage *script = GDScriptLanguage::get_singleton();
+ Array ret;
+ for (int i = 0; i < script->debug_get_stack_level_count(); i++) {
+ Dictionary frame;
+ frame["source"] = script->debug_get_stack_level_source(i);
+ frame["function"] = script->debug_get_stack_level_function(i);
+ frame["line"] = script->debug_get_stack_level_line(i);
+ ret.push_back(frame);
+ };
+ *r_ret = ret;
+ }
+
+ static inline void len(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ VALIDATE_ARG_COUNT(1);
+ switch (p_args[0]->get_type()) {
+ case Variant::STRING: {
+ String d = *p_args[0];
+ *r_ret = d.length();
+ } break;
+ case Variant::DICTIONARY: {
+ Dictionary d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::ARRAY: {
+ Array d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_BYTE_ARRAY: {
+ Vector<uint8_t> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_INT32_ARRAY: {
+ Vector<int32_t> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_INT64_ARRAY: {
+ Vector<int64_t> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_FLOAT32_ARRAY: {
+ Vector<float> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_FLOAT64_ARRAY: {
+ Vector<double> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_STRING_ARRAY: {
+ Vector<String> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_VECTOR2_ARRAY: {
+ Vector<Vector2> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_VECTOR3_ARRAY: {
+ Vector<Vector3> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ case Variant::PACKED_COLOR_ARRAY: {
+ Vector<Color> d = *p_args[0];
+ *r_ret = d.size();
+ } break;
+ default: {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::NIL;
+ *r_ret = vformat(RTR("Value of type '%s' can't provide a length."), Variant::get_type_name(p_args[0]->get_type()));
+ }
+ }
+ }
+};
+
+struct GDScriptUtilityFunctionInfo {
+ GDScriptUtilityFunctions::FunctionPtr function;
+ MethodInfo info;
+ bool is_constant = false;
+};
+
+static OAHashMap<StringName, GDScriptUtilityFunctionInfo> utility_function_table;
+static List<StringName> utility_function_name_table;
+
+static void _register_function(const String &p_name, const MethodInfo &p_method_info, GDScriptUtilityFunctions::FunctionPtr p_function, bool p_is_const) {
+ StringName sname(p_name);
+
+ ERR_FAIL_COND(utility_function_table.has(sname));
+
+ GDScriptUtilityFunctionInfo function;
+ function.function = p_function;
+ function.info = p_method_info;
+ function.is_constant = p_is_const;
+
+ utility_function_table.insert(sname, function);
+ utility_function_name_table.push_back(sname);
+}
+
+#define REGISTER_FUNC(m_func, m_is_const, m_return_type, ...) \
+ { \
+ String name(#m_func); \
+ if (name.begins_with("_")) { \
+ name = name.substr(1, name.length() - 1); \
+ } \
+ MethodInfo info = MethodInfo(name, __VA_ARGS__); \
+ info.return_val.type = m_return_type; \
+ _register_function(name, info, GDScriptUtilityFunctionsDefinitions::m_func, m_is_const); \
+ }
+
+#define REGISTER_FUNC_NO_ARGS(m_func, m_is_const, m_return_type) \
+ { \
+ String name(#m_func); \
+ if (name.begins_with("_")) { \
+ name = name.substr(1, name.length() - 1); \
+ } \
+ MethodInfo info = MethodInfo(name); \
+ info.return_val.type = m_return_type; \
+ _register_function(name, info, GDScriptUtilityFunctionsDefinitions::m_func, m_is_const); \
+ }
+
+#define REGISTER_VARARG_FUNC(m_func, m_is_const, m_return_type) \
+ { \
+ String name(#m_func); \
+ if (name.begins_with("_")) { \
+ name = name.substr(1, name.length() - 1); \
+ } \
+ MethodInfo info = MethodInfo(name); \
+ info.return_val.type = m_return_type; \
+ info.flags |= METHOD_FLAG_VARARG; \
+ _register_function(name, info, GDScriptUtilityFunctionsDefinitions::m_func, m_is_const); \
+ }
+
+#define REGISTER_VARIANT_FUNC(m_func, m_is_const, ...) \
+ { \
+ String name(#m_func); \
+ if (name.begins_with("_")) { \
+ name = name.substr(1, name.length() - 1); \
+ } \
+ MethodInfo info = MethodInfo(name, __VA_ARGS__); \
+ info.return_val.type = Variant::NIL; \
+ info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; \
+ _register_function(name, info, GDScriptUtilityFunctionsDefinitions::m_func, m_is_const); \
+ }
+
+#define REGISTER_CLASS_FUNC(m_func, m_is_const, m_return_type, ...) \
+ { \
+ String name(#m_func); \
+ if (name.begins_with("_")) { \
+ name = name.substr(1, name.length() - 1); \
+ } \
+ MethodInfo info = MethodInfo(name, __VA_ARGS__); \
+ info.return_val.type = Variant::OBJECT; \
+ info.return_val.hint = PROPERTY_HINT_RESOURCE_TYPE; \
+ info.return_val.class_name = m_return_type; \
+ _register_function(name, info, GDScriptUtilityFunctionsDefinitions::m_func, m_is_const); \
+ }
+
+#define REGISTER_FUNC_DEF(m_func, m_is_const, m_default, m_return_type, ...) \
+ { \
+ String name(#m_func); \
+ if (name.begins_with("_")) { \
+ name = name.substr(1, name.length() - 1); \
+ } \
+ MethodInfo info = MethodInfo(name, __VA_ARGS__); \
+ info.return_val.type = m_return_type; \
+ info.default_arguments.push_back(m_default); \
+ _register_function(name, info, GDScriptUtilityFunctionsDefinitions::m_func, m_is_const); \
+ }
+
+#define ARG(m_name, m_type) \
+ PropertyInfo(m_type, m_name)
+
+#define VARARG(m_name) \
+ PropertyInfo(Variant::NIL, m_name, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT)
+
+void GDScriptUtilityFunctions::register_functions() {
+ REGISTER_VARIANT_FUNC(convert, true, VARARG("what"), ARG("type", Variant::INT));
+ REGISTER_FUNC(type_exists, true, Variant::BOOL, ARG("type", Variant::STRING_NAME));
+ REGISTER_FUNC(_char, true, Variant::STRING, ARG("char", Variant::INT));
+ REGISTER_VARARG_FUNC(str, true, Variant::STRING);
+ REGISTER_VARARG_FUNC(range, false, Variant::ARRAY);
+ REGISTER_CLASS_FUNC(load, false, "Resource", ARG("path", Variant::STRING));
+ REGISTER_FUNC(inst2dict, false, Variant::DICTIONARY, ARG("instance", Variant::OBJECT));
+ REGISTER_FUNC(dict2inst, false, Variant::OBJECT, ARG("dictionary", Variant::DICTIONARY));
+ REGISTER_FUNC_DEF(Color8, true, 255, Variant::COLOR, ARG("r8", Variant::INT), ARG("g8", Variant::INT), ARG("b8", Variant::INT), ARG("a8", Variant::INT));
+ REGISTER_VARARG_FUNC(print_debug, false, Variant::NIL);
+ REGISTER_FUNC_NO_ARGS(print_stack, false, Variant::NIL);
+ REGISTER_FUNC_NO_ARGS(get_stack, false, Variant::ARRAY);
+ REGISTER_FUNC(len, true, Variant::INT, VARARG("var"));
+}
+
+void GDScriptUtilityFunctions::unregister_functions() {
+ utility_function_name_table.clear();
+ utility_function_table.clear();
+}
+
+GDScriptUtilityFunctions::FunctionPtr GDScriptUtilityFunctions::get_function(const StringName &p_function) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, nullptr);
+ return info->function;
+}
+
+bool GDScriptUtilityFunctions::has_function_return_value(const StringName &p_function) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, false);
+ return info->info.return_val.type != Variant::NIL || bool(info->info.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT);
+}
+
+Variant::Type GDScriptUtilityFunctions::get_function_return_type(const StringName &p_function) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, Variant::NIL);
+ return info->info.return_val.type;
+}
+
+StringName GDScriptUtilityFunctions::get_function_return_class(const StringName &p_function) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, StringName());
+ return info->info.return_val.class_name;
+}
+
+Variant::Type GDScriptUtilityFunctions::get_function_argument_type(const StringName &p_function, int p_arg) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, Variant::NIL);
+ ERR_FAIL_COND_V(p_arg >= info->info.arguments.size(), Variant::NIL);
+ return info->info.arguments[p_arg].type;
+}
+
+int GDScriptUtilityFunctions::get_function_argument_count(const StringName &p_function, int p_arg) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, 0);
+ return info->info.arguments.size();
+}
+
+bool GDScriptUtilityFunctions::is_function_vararg(const StringName &p_function) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, false);
+ return (bool)(info->info.flags & METHOD_FLAG_VARARG);
+}
+
+bool GDScriptUtilityFunctions::is_function_constant(const StringName &p_function) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, false);
+ return info->is_constant;
+}
+
+bool GDScriptUtilityFunctions::function_exists(const StringName &p_function) {
+ return utility_function_table.has(p_function);
+}
+
+void GDScriptUtilityFunctions::get_function_list(List<StringName> *r_functions) {
+ for (const List<StringName>::Element *E = utility_function_name_table.front(); E; E = E->next()) {
+ r_functions->push_back(E->get());
+ }
+}
+
+MethodInfo GDScriptUtilityFunctions::get_function_info(const StringName &p_function) {
+ GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
+ ERR_FAIL_COND_V(!info, MethodInfo());
+ return info->info;
+}
diff --git a/modules/gdscript/gdscript_utility_functions.h b/modules/gdscript/gdscript_utility_functions.h
new file mode 100644
index 0000000000..c6d3718844
--- /dev/null
+++ b/modules/gdscript/gdscript_utility_functions.h
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* gdscript_utility_functions.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GDSCRIPT_UTILITY_FUNCTIONS_H
+#define GDSCRIPT_UTILITY_FUNCTIONS_H
+
+#include "core/string/string_name.h"
+#include "core/variant/variant.h"
+
+class GDScriptUtilityFunctions {
+public:
+ typedef void (*FunctionPtr)(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
+
+ static FunctionPtr get_function(const StringName &p_function);
+ static bool has_function_return_value(const StringName &p_function);
+ static Variant::Type get_function_return_type(const StringName &p_function);
+ static StringName get_function_return_class(const StringName &p_function);
+ static Variant::Type get_function_argument_type(const StringName &p_function, int p_arg);
+ static int get_function_argument_count(const StringName &p_function, int p_arg);
+ static bool is_function_vararg(const StringName &p_function);
+ static bool is_function_constant(const StringName &p_function);
+
+ static bool function_exists(const StringName &p_function);
+ static void get_function_list(List<StringName> *r_functions);
+ static MethodInfo get_function_info(const StringName &p_function);
+
+ static void register_functions();
+ static void unregister_functions();
+};
+
+#endif // GDSCRIPT_UTILITY_FUNCTIONS_H
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
new file mode 100644
index 0000000000..4e098d7a6d
--- /dev/null
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -0,0 +1,2918 @@
+/*************************************************************************/
+/* gdscript_vm.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gdscript_function.h"
+
+#include "core/core_string_names.h"
+#include "core/os/os.h"
+#include "gdscript.h"
+
+Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_instance, GDScript *p_script, Variant &self, Variant &static_ref, Variant *p_stack, String &r_error) const {
+ int address = p_address & ADDR_MASK;
+
+ //sequential table (jump table generated by compiler)
+ switch ((p_address & ADDR_TYPE_MASK) >> ADDR_BITS) {
+ case ADDR_TYPE_SELF: {
+#ifdef DEBUG_ENABLED
+ if (unlikely(!p_instance)) {
+ r_error = "Cannot access self without instance.";
+ return nullptr;
+ }
+#endif
+ return &self;
+ } break;
+ case ADDR_TYPE_CLASS: {
+ return &static_ref;
+ } break;
+ case ADDR_TYPE_MEMBER: {
+#ifdef DEBUG_ENABLED
+ if (unlikely(!p_instance)) {
+ r_error = "Cannot access member without instance.";
+ return nullptr;
+ }
+#endif
+ //member indexing is O(1)
+ return &p_instance->members.write[address];
+ } break;
+ case ADDR_TYPE_CLASS_CONSTANT: {
+ //todo change to index!
+ GDScript *s = p_script;
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_INDEX_V(address, _global_names_count, nullptr);
+#endif
+ const StringName *sn = &_global_names_ptr[address];
+
+ while (s) {
+ GDScript *o = s;
+ while (o) {
+ Map<StringName, Variant>::Element *E = o->constants.find(*sn);
+ if (E) {
+ return &E->get();
+ }
+ o = o->_owner;
+ }
+ s = s->_base;
+ }
+
+ ERR_FAIL_V_MSG(nullptr, "GDScriptCompiler bug.");
+ } break;
+ case ADDR_TYPE_LOCAL_CONSTANT: {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_INDEX_V(address, _constant_count, nullptr);
+#endif
+ return &_constants_ptr[address];
+ } break;
+ case ADDR_TYPE_STACK:
+ case ADDR_TYPE_STACK_VARIABLE: {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_INDEX_V(address, _stack_size, nullptr);
+#endif
+ return &p_stack[address];
+ } break;
+ case ADDR_TYPE_GLOBAL: {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_INDEX_V(address, GDScriptLanguage::get_singleton()->get_global_array_size(), nullptr);
+#endif
+ return &GDScriptLanguage::get_singleton()->get_global_array()[address];
+ } break;
+#ifdef TOOLS_ENABLED
+ case ADDR_TYPE_NAMED_GLOBAL: {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_INDEX_V(address, _global_names_count, nullptr);
+#endif
+ StringName id = _global_names_ptr[address];
+
+ if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(id)) {
+ return (Variant *)&GDScriptLanguage::get_singleton()->get_named_globals_map()[id];
+ } else {
+ r_error = "Autoload singleton '" + String(id) + "' has been removed.";
+ return nullptr;
+ }
+ } break;
+#endif
+ case ADDR_TYPE_NIL: {
+ return &nil;
+ } break;
+ }
+
+ ERR_FAIL_V_MSG(nullptr, "Bad code! (unknown addressing mode).");
+ return nullptr;
+}
+
+#ifdef DEBUG_ENABLED
+static String _get_var_type(const Variant *p_var) {
+ String basestr;
+
+ if (p_var->get_type() == Variant::OBJECT) {
+ bool was_freed;
+ Object *bobj = p_var->get_validated_object_with_check(was_freed);
+ if (!bobj) {
+ if (was_freed) {
+ basestr = "null instance";
+ } else {
+ basestr = "previously freed";
+ }
+ } else {
+ if (bobj->get_script_instance()) {
+ basestr = bobj->get_class() + " (" + bobj->get_script_instance()->get_script()->get_path().get_file() + ")";
+ } else {
+ basestr = bobj->get_class();
+ }
+ }
+
+ } else {
+ basestr = Variant::get_type_name(p_var->get_type());
+ }
+
+ return basestr;
+}
+#endif // DEBUG_ENABLED
+
+String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const String &p_where, const Variant **argptrs) const {
+ String err_text;
+
+ if (p_err.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) {
+ int errorarg = p_err.argument;
+ // Handle the Object to Object case separately as we don't have further class details.
+#ifdef DEBUG_ENABLED
+ if (p_err.expected == Variant::OBJECT && argptrs[errorarg]->get_type() == p_err.expected) {
+ err_text = "Invalid type in " + p_where + ". The Object-derived class of argument " + itos(errorarg + 1) + " (" + _get_var_type(argptrs[errorarg]) + ") is not a subclass of the expected argument class.";
+ } else
+#endif // DEBUG_ENABLED
+ {
+ err_text = "Invalid type in " + p_where + ". Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(Variant::Type(p_err.expected)) + ".";
+ }
+ } else if (p_err.error == Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) {
+ err_text = "Invalid call to " + p_where + ". Expected " + itos(p_err.argument) + " arguments.";
+ } else if (p_err.error == Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) {
+ err_text = "Invalid call to " + p_where + ". Expected " + itos(p_err.argument) + " arguments.";
+ } else if (p_err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
+ err_text = "Invalid call. Nonexistent " + p_where + ".";
+ } else if (p_err.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
+ err_text = "Attempt to call " + p_where + " on a null instance.";
+ } else {
+ err_text = "Bug, call error: #" + itos(p_err.error);
+ }
+
+ return err_text;
+}
+
+#if defined(__GNUC__)
+#define OPCODES_TABLE \
+ static const void *switch_table_ops[] = { \
+ &&OPCODE_OPERATOR, \
+ &&OPCODE_OPERATOR_VALIDATED, \
+ &&OPCODE_EXTENDS_TEST, \
+ &&OPCODE_IS_BUILTIN, \
+ &&OPCODE_SET_KEYED, \
+ &&OPCODE_SET_KEYED_VALIDATED, \
+ &&OPCODE_SET_INDEXED_VALIDATED, \
+ &&OPCODE_GET_KEYED, \
+ &&OPCODE_GET_KEYED_VALIDATED, \
+ &&OPCODE_GET_INDEXED_VALIDATED, \
+ &&OPCODE_SET_NAMED, \
+ &&OPCODE_SET_NAMED_VALIDATED, \
+ &&OPCODE_GET_NAMED, \
+ &&OPCODE_GET_NAMED_VALIDATED, \
+ &&OPCODE_SET_MEMBER, \
+ &&OPCODE_GET_MEMBER, \
+ &&OPCODE_ASSIGN, \
+ &&OPCODE_ASSIGN_TRUE, \
+ &&OPCODE_ASSIGN_FALSE, \
+ &&OPCODE_ASSIGN_TYPED_BUILTIN, \
+ &&OPCODE_ASSIGN_TYPED_NATIVE, \
+ &&OPCODE_ASSIGN_TYPED_SCRIPT, \
+ &&OPCODE_CAST_TO_BUILTIN, \
+ &&OPCODE_CAST_TO_NATIVE, \
+ &&OPCODE_CAST_TO_SCRIPT, \
+ &&OPCODE_CONSTRUCT, \
+ &&OPCODE_CONSTRUCT_VALIDATED, \
+ &&OPCODE_CONSTRUCT_ARRAY, \
+ &&OPCODE_CONSTRUCT_DICTIONARY, \
+ &&OPCODE_CALL, \
+ &&OPCODE_CALL_RETURN, \
+ &&OPCODE_CALL_ASYNC, \
+ &&OPCODE_CALL_UTILITY, \
+ &&OPCODE_CALL_UTILITY_VALIDATED, \
+ &&OPCODE_CALL_GDSCRIPT_UTILITY, \
+ &&OPCODE_CALL_BUILTIN_TYPE_VALIDATED, \
+ &&OPCODE_CALL_SELF_BASE, \
+ &&OPCODE_CALL_METHOD_BIND, \
+ &&OPCODE_CALL_METHOD_BIND_RET, \
+ &&OPCODE_CALL_PTRCALL_NO_RETURN, \
+ &&OPCODE_CALL_PTRCALL_BOOL, \
+ &&OPCODE_CALL_PTRCALL_INT, \
+ &&OPCODE_CALL_PTRCALL_FLOAT, \
+ &&OPCODE_CALL_PTRCALL_STRING, \
+ &&OPCODE_CALL_PTRCALL_VECTOR2, \
+ &&OPCODE_CALL_PTRCALL_VECTOR2I, \
+ &&OPCODE_CALL_PTRCALL_RECT2, \
+ &&OPCODE_CALL_PTRCALL_RECT2I, \
+ &&OPCODE_CALL_PTRCALL_VECTOR3, \
+ &&OPCODE_CALL_PTRCALL_VECTOR3I, \
+ &&OPCODE_CALL_PTRCALL_TRANSFORM2D, \
+ &&OPCODE_CALL_PTRCALL_PLANE, \
+ &&OPCODE_CALL_PTRCALL_QUAT, \
+ &&OPCODE_CALL_PTRCALL_AABB, \
+ &&OPCODE_CALL_PTRCALL_BASIS, \
+ &&OPCODE_CALL_PTRCALL_TRANSFORM, \
+ &&OPCODE_CALL_PTRCALL_COLOR, \
+ &&OPCODE_CALL_PTRCALL_STRING_NAME, \
+ &&OPCODE_CALL_PTRCALL_NODE_PATH, \
+ &&OPCODE_CALL_PTRCALL_RID, \
+ &&OPCODE_CALL_PTRCALL_OBJECT, \
+ &&OPCODE_CALL_PTRCALL_CALLABLE, \
+ &&OPCODE_CALL_PTRCALL_SIGNAL, \
+ &&OPCODE_CALL_PTRCALL_DICTIONARY, \
+ &&OPCODE_CALL_PTRCALL_ARRAY, \
+ &&OPCODE_CALL_PTRCALL_PACKED_BYTE_ARRAY, \
+ &&OPCODE_CALL_PTRCALL_PACKED_INT32_ARRAY, \
+ &&OPCODE_CALL_PTRCALL_PACKED_INT64_ARRAY, \
+ &&OPCODE_CALL_PTRCALL_PACKED_FLOAT32_ARRAY, \
+ &&OPCODE_CALL_PTRCALL_PACKED_FLOAT64_ARRAY, \
+ &&OPCODE_CALL_PTRCALL_PACKED_STRING_ARRAY, \
+ &&OPCODE_CALL_PTRCALL_PACKED_VECTOR2_ARRAY, \
+ &&OPCODE_CALL_PTRCALL_PACKED_VECTOR3_ARRAY, \
+ &&OPCODE_CALL_PTRCALL_PACKED_COLOR_ARRAY, \
+ &&OPCODE_AWAIT, \
+ &&OPCODE_AWAIT_RESUME, \
+ &&OPCODE_JUMP, \
+ &&OPCODE_JUMP_IF, \
+ &&OPCODE_JUMP_IF_NOT, \
+ &&OPCODE_JUMP_TO_DEF_ARGUMENT, \
+ &&OPCODE_RETURN, \
+ &&OPCODE_ITERATE_BEGIN, \
+ &&OPCODE_ITERATE_BEGIN_INT, \
+ &&OPCODE_ITERATE_BEGIN_FLOAT, \
+ &&OPCODE_ITERATE_BEGIN_VECTOR2, \
+ &&OPCODE_ITERATE_BEGIN_VECTOR2I, \
+ &&OPCODE_ITERATE_BEGIN_VECTOR3, \
+ &&OPCODE_ITERATE_BEGIN_VECTOR3I, \
+ &&OPCODE_ITERATE_BEGIN_STRING, \
+ &&OPCODE_ITERATE_BEGIN_DICTIONARY, \
+ &&OPCODE_ITERATE_BEGIN_ARRAY, \
+ &&OPCODE_ITERATE_BEGIN_PACKED_BYTE_ARRAY, \
+ &&OPCODE_ITERATE_BEGIN_PACKED_INT32_ARRAY, \
+ &&OPCODE_ITERATE_BEGIN_PACKED_INT64_ARRAY, \
+ &&OPCODE_ITERATE_BEGIN_PACKED_FLOAT32_ARRAY, \
+ &&OPCODE_ITERATE_BEGIN_PACKED_FLOAT64_ARRAY, \
+ &&OPCODE_ITERATE_BEGIN_PACKED_STRING_ARRAY, \
+ &&OPCODE_ITERATE_BEGIN_PACKED_VECTOR2_ARRAY, \
+ &&OPCODE_ITERATE_BEGIN_PACKED_VECTOR3_ARRAY, \
+ &&OPCODE_ITERATE_BEGIN_PACKED_COLOR_ARRAY, \
+ &&OPCODE_ITERATE_BEGIN_OBJECT, \
+ &&OPCODE_ITERATE, \
+ &&OPCODE_ITERATE_INT, \
+ &&OPCODE_ITERATE_FLOAT, \
+ &&OPCODE_ITERATE_VECTOR2, \
+ &&OPCODE_ITERATE_VECTOR2I, \
+ &&OPCODE_ITERATE_VECTOR3, \
+ &&OPCODE_ITERATE_VECTOR3I, \
+ &&OPCODE_ITERATE_STRING, \
+ &&OPCODE_ITERATE_DICTIONARY, \
+ &&OPCODE_ITERATE_ARRAY, \
+ &&OPCODE_ITERATE_PACKED_BYTE_ARRAY, \
+ &&OPCODE_ITERATE_PACKED_INT32_ARRAY, \
+ &&OPCODE_ITERATE_PACKED_INT64_ARRAY, \
+ &&OPCODE_ITERATE_PACKED_FLOAT32_ARRAY, \
+ &&OPCODE_ITERATE_PACKED_FLOAT64_ARRAY, \
+ &&OPCODE_ITERATE_PACKED_STRING_ARRAY, \
+ &&OPCODE_ITERATE_PACKED_VECTOR2_ARRAY, \
+ &&OPCODE_ITERATE_PACKED_VECTOR3_ARRAY, \
+ &&OPCODE_ITERATE_PACKED_COLOR_ARRAY, \
+ &&OPCODE_ITERATE_OBJECT, \
+ &&OPCODE_ASSERT, \
+ &&OPCODE_BREAKPOINT, \
+ &&OPCODE_LINE, \
+ &&OPCODE_END \
+ }; \
+ static_assert((sizeof(switch_table_ops) / sizeof(switch_table_ops[0]) == (OPCODE_END + 1)), "Opcodes in jump table aren't the same as opcodes in enum.");
+
+#define OPCODE(m_op) \
+ m_op:
+#define OPCODE_WHILE(m_test) \
+ OPSWHILE:
+#define OPCODES_END \
+ OPSEXIT:
+#define OPCODES_OUT \
+ OPSOUT:
+#define DISPATCH_OPCODE goto OPSWHILE
+#define OPCODE_SWITCH(m_test) goto *switch_table_ops[m_test];
+#define OPCODE_BREAK goto OPSEXIT
+#define OPCODE_OUT goto OPSOUT
+#else
+#define OPCODES_TABLE
+#define OPCODE(m_op) case m_op:
+#define OPCODE_WHILE(m_test) while (m_test)
+#define OPCODES_END
+#define OPCODES_OUT
+#define DISPATCH_OPCODE continue
+#define OPCODE_SWITCH(m_test) switch (m_test)
+#define OPCODE_BREAK break
+#define OPCODE_OUT break
+#endif
+
+// Helpers for VariantInternal methods in macros.
+#define OP_GET_BOOL get_bool
+#define OP_GET_INT get_int
+#define OP_GET_FLOAT get_float
+#define OP_GET_VECTOR2 get_vector2
+#define OP_GET_VECTOR2I get_vector2i
+#define OP_GET_VECTOR3 get_vector3
+#define OP_GET_VECTOR3I get_vector3i
+#define OP_GET_RECT2 get_rect2
+#define OP_GET_RECT2I get_rect2i
+#define OP_GET_QUAT get_quat
+#define OP_GET_COLOR get_color
+#define OP_GET_STRING get_string
+#define OP_GET_STRING_NAME get_string_name
+#define OP_GET_NODE_PATH get_node_path
+#define OP_GET_CALLABLE get_callable
+#define OP_GET_SIGNAL get_signal
+#define OP_GET_ARRAY get_array
+#define OP_GET_DICTIONARY get_dictionary
+#define OP_GET_PACKED_BYTE_ARRAY get_byte_array
+#define OP_GET_PACKED_INT32_ARRAY get_int32_array
+#define OP_GET_PACKED_INT64_ARRAY get_int64_array
+#define OP_GET_PACKED_FLOAT32_ARRAY get_float32_array
+#define OP_GET_PACKED_FLOAT64_ARRAY get_float64_array
+#define OP_GET_PACKED_STRING_ARRAY get_string_array
+#define OP_GET_PACKED_VECTOR2_ARRAY get_vector2_array
+#define OP_GET_PACKED_VECTOR3_ARRAY get_vector3_array
+#define OP_GET_PACKED_COLOR_ARRAY get_color_array
+#define OP_GET_TRANSFORM get_transform
+#define OP_GET_TRANSFORM2D get_transform2d
+#define OP_GET_PLANE get_plane
+#define OP_GET_AABB get_aabb
+#define OP_GET_BASIS get_basis
+#define OP_GET_RID get_rid
+
+Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_args, int p_argcount, Callable::CallError &r_err, CallState *p_state) {
+ OPCODES_TABLE;
+
+ if (!_code_ptr) {
+ return Variant();
+ }
+
+ r_err.error = Callable::CallError::CALL_OK;
+
+ Variant self;
+ Variant static_ref;
+ Variant retvalue;
+ Variant *stack = nullptr;
+ Variant **instruction_args;
+ const void **call_args_ptr = nullptr;
+ int defarg = 0;
+
+#ifdef DEBUG_ENABLED
+
+ //GDScriptLanguage::get_singleton()->calls++;
+
+#endif
+
+ uint32_t alloca_size = 0;
+ GDScript *script;
+ int ip = 0;
+ int line = _initial_line;
+
+ if (p_state) {
+ //use existing (supplied) state (awaited)
+ stack = (Variant *)p_state->stack.ptr();
+ instruction_args = (Variant **)&p_state->stack.ptr()[sizeof(Variant) * p_state->stack_size]; //ptr() to avoid bounds check
+ line = p_state->line;
+ ip = p_state->ip;
+ alloca_size = p_state->stack.size();
+ script = p_state->script;
+ p_instance = p_state->instance;
+ defarg = p_state->defarg;
+ self = p_state->self;
+
+ } else {
+ if (p_argcount != _argument_count) {
+ if (p_argcount > _argument_count) {
+ r_err.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_err.argument = _argument_count;
+
+ return Variant();
+ } else if (p_argcount < _argument_count - _default_arg_count) {
+ r_err.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_err.argument = _argument_count - _default_arg_count;
+ return Variant();
+ } else {
+ defarg = _argument_count - p_argcount;
+ }
+ }
+
+ alloca_size = sizeof(Variant *) * _instruction_args_size + sizeof(Variant) * _stack_size;
+
+ if (alloca_size) {
+ uint8_t *aptr = (uint8_t *)alloca(alloca_size);
+
+ if (_stack_size) {
+ stack = (Variant *)aptr;
+ for (int i = 0; i < p_argcount; i++) {
+ if (!argument_types[i].has_type) {
+ memnew_placement(&stack[i], Variant(*p_args[i]));
+ continue;
+ }
+
+ if (!argument_types[i].is_type(*p_args[i], true)) {
+ r_err.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_err.argument = i;
+ r_err.expected = argument_types[i].kind == GDScriptDataType::BUILTIN ? argument_types[i].builtin_type : Variant::OBJECT;
+ return Variant();
+ }
+ if (argument_types[i].kind == GDScriptDataType::BUILTIN) {
+ Variant arg;
+ Variant::construct(argument_types[i].builtin_type, arg, &p_args[i], 1, r_err);
+ memnew_placement(&stack[i], Variant(arg));
+ } else {
+ memnew_placement(&stack[i], Variant(*p_args[i]));
+ }
+ }
+ for (int i = p_argcount; i < _stack_size; i++) {
+ memnew_placement(&stack[i], Variant);
+ }
+ } else {
+ stack = nullptr;
+ }
+
+ if (_instruction_args_size) {
+ instruction_args = (Variant **)&aptr[sizeof(Variant) * _stack_size];
+ } else {
+ instruction_args = nullptr;
+ }
+
+ } else {
+ stack = nullptr;
+ instruction_args = nullptr;
+ }
+
+ if (p_instance) {
+ self = p_instance->owner;
+ script = p_instance->script.ptr();
+ } else {
+ script = _script;
+ }
+ }
+ if (_ptrcall_args_size) {
+ call_args_ptr = (const void **)alloca(_ptrcall_args_size * sizeof(void *));
+ } else {
+ call_args_ptr = nullptr;
+ }
+
+ static_ref = script;
+
+ String err_text;
+
+#ifdef DEBUG_ENABLED
+
+ if (EngineDebugger::is_active()) {
+ GDScriptLanguage::get_singleton()->enter_function(p_instance, this, stack, &ip, &line);
+ }
+
+#define GD_ERR_BREAK(m_cond) \
+ { \
+ if (unlikely(m_cond)) { \
+ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true. Breaking..:"); \
+ OPCODE_BREAK; \
+ } \
+ }
+
+#define CHECK_SPACE(m_space) \
+ GD_ERR_BREAK((ip + m_space) > _code_size)
+
+#define GET_VARIANT_PTR(m_v, m_code_ofs) \
+ Variant *m_v; \
+ m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, script, self, static_ref, stack, err_text); \
+ if (unlikely(!m_v)) \
+ OPCODE_BREAK;
+
+#else
+#define GD_ERR_BREAK(m_cond)
+#define CHECK_SPACE(m_space)
+#define GET_VARIANT_PTR(m_v, m_code_ofs) \
+ Variant *m_v; \
+ m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, script, self, static_ref, stack, err_text);
+
+#endif
+
+#define GET_INSTRUCTION_ARG(m_v, m_idx) \
+ Variant *m_v = instruction_args[m_idx]
+
+#ifdef DEBUG_ENABLED
+
+ uint64_t function_start_time = 0;
+ uint64_t function_call_time = 0;
+
+ if (GDScriptLanguage::get_singleton()->profiling) {
+ function_start_time = OS::get_singleton()->get_ticks_usec();
+ function_call_time = 0;
+ profile.call_count++;
+ profile.frame_call_count++;
+ }
+ bool exit_ok = false;
+ bool awaited = false;
+#endif
+
+#ifdef DEBUG_ENABLED
+ OPCODE_WHILE(ip < _code_size) {
+ int last_opcode = _code_ptr[ip];
+#else
+ OPCODE_WHILE(true) {
+#endif
+ // Load arguments for the instruction before each instruction.
+ int instr_arg_count = ((_code_ptr[ip]) & INSTR_ARGS_MASK) >> INSTR_BITS;
+ for (int i = 0; i < instr_arg_count; i++) {
+ GET_VARIANT_PTR(v, i + 1);
+ instruction_args[i] = v;
+ }
+
+ OPCODE_SWITCH(_code_ptr[ip] & INSTR_MASK) {
+ OPCODE(OPCODE_OPERATOR) {
+ CHECK_SPACE(5);
+
+ bool valid;
+ Variant::Operator op = (Variant::Operator)_code_ptr[ip + 4];
+ GD_ERR_BREAK(op >= Variant::OP_MAX);
+
+ GET_INSTRUCTION_ARG(a, 0);
+ GET_INSTRUCTION_ARG(b, 1);
+ GET_INSTRUCTION_ARG(dst, 2);
+
+#ifdef DEBUG_ENABLED
+
+ Variant ret;
+ Variant::evaluate(op, *a, *b, ret, valid);
+#else
+ Variant::evaluate(op, *a, *b, *dst, valid);
+#endif
+#ifdef DEBUG_ENABLED
+ if (!valid) {
+ if (ret.get_type() == Variant::STRING) {
+ //return a string when invalid with the error
+ err_text = ret;
+ err_text += " in operator '" + Variant::get_operator_name(op) + "'.";
+ } else {
+ err_text = "Invalid operands '" + Variant::get_type_name(a->get_type()) + "' and '" + Variant::get_type_name(b->get_type()) + "' in operator '" + Variant::get_operator_name(op) + "'.";
+ }
+ OPCODE_BREAK;
+ }
+ *dst = ret;
+#endif
+ ip += 5;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_OPERATOR_VALIDATED) {
+ CHECK_SPACE(5);
+
+ int operator_idx = _code_ptr[ip + 4];
+ GD_ERR_BREAK(operator_idx < 0 || operator_idx >= _operator_funcs_count);
+ Variant::ValidatedOperatorEvaluator operator_func = _operator_funcs_ptr[operator_idx];
+
+ GET_INSTRUCTION_ARG(a, 0);
+ GET_INSTRUCTION_ARG(b, 1);
+ GET_INSTRUCTION_ARG(dst, 2);
+
+ operator_func(a, b, dst);
+
+ ip += 5;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_EXTENDS_TEST) {
+ CHECK_SPACE(4);
+
+ GET_INSTRUCTION_ARG(a, 0);
+ GET_INSTRUCTION_ARG(b, 1);
+ GET_INSTRUCTION_ARG(dst, 2);
+
+#ifdef DEBUG_ENABLED
+ if (b->get_type() != Variant::OBJECT || b->operator Object *() == nullptr) {
+ err_text = "Right operand of 'is' is not a class.";
+ OPCODE_BREAK;
+ }
+#endif
+
+ bool extends_ok = false;
+ if (a->get_type() == Variant::OBJECT && a->operator Object *() != nullptr) {
+#ifdef DEBUG_ENABLED
+ bool was_freed;
+ Object *obj_A = a->get_validated_object_with_check(was_freed);
+
+ if (was_freed) {
+ err_text = "Left operand of 'is' is a previously freed instance.";
+ OPCODE_BREAK;
+ }
+
+ Object *obj_B = b->get_validated_object_with_check(was_freed);
+
+ if (was_freed) {
+ err_text = "Right operand of 'is' is a previously freed instance.";
+ OPCODE_BREAK;
+ }
+#else
+
+ Object *obj_A = *a;
+ Object *obj_B = *b;
+#endif // DEBUG_ENABLED
+
+ GDScript *scr_B = Object::cast_to<GDScript>(obj_B);
+
+ if (scr_B) {
+ //if B is a script, the only valid condition is that A has an instance which inherits from the script
+ //in other situation, this shoul return false.
+
+ if (obj_A->get_script_instance() && obj_A->get_script_instance()->get_language() == GDScriptLanguage::get_singleton()) {
+ GDScript *cmp = static_cast<GDScript *>(obj_A->get_script_instance()->get_script().ptr());
+ //bool found=false;
+ while (cmp) {
+ if (cmp == scr_B) {
+ //inherits from script, all ok
+ extends_ok = true;
+ break;
+ }
+
+ cmp = cmp->_base;
+ }
+ }
+
+ } else {
+ GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(obj_B);
+
+#ifdef DEBUG_ENABLED
+ if (!nc) {
+ err_text = "Right operand of 'is' is not a class (type: '" + obj_B->get_class() + "').";
+ OPCODE_BREAK;
+ }
+#endif
+ extends_ok = ClassDB::is_parent_class(obj_A->get_class_name(), nc->get_name());
+ }
+ }
+
+ *dst = extends_ok;
+ ip += 4;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_IS_BUILTIN) {
+ CHECK_SPACE(4);
+
+ GET_INSTRUCTION_ARG(value, 0);
+ GET_INSTRUCTION_ARG(dst, 1);
+ Variant::Type var_type = (Variant::Type)_code_ptr[ip + 3];
+
+ GD_ERR_BREAK(var_type < 0 || var_type >= Variant::VARIANT_MAX);
+
+ *dst = value->get_type() == var_type;
+ ip += 4;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_SET_KEYED) {
+ CHECK_SPACE(3);
+
+ GET_INSTRUCTION_ARG(dst, 0);
+ GET_INSTRUCTION_ARG(index, 1);
+ GET_INSTRUCTION_ARG(value, 2);
+
+ bool valid;
+ dst->set(*index, *value, &valid);
+
+#ifdef DEBUG_ENABLED
+ if (!valid) {
+ String v = index->operator String();
+ if (v != "") {
+ v = "'" + v + "'";
+ } else {
+ v = "of type '" + _get_var_type(index) + "'";
+ }
+ err_text = "Invalid set index " + v + " (on base: '" + _get_var_type(dst) + "') with value of type '" + _get_var_type(value) + "'";
+ OPCODE_BREAK;
+ }
+#endif
+ ip += 4;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_SET_KEYED_VALIDATED) {
+ CHECK_SPACE(4);
+
+ GET_INSTRUCTION_ARG(dst, 0);
+ GET_INSTRUCTION_ARG(index, 1);
+ GET_INSTRUCTION_ARG(value, 2);
+
+ int index_setter = _code_ptr[ip + 4];
+ GD_ERR_BREAK(index_setter < 0 || index_setter >= _keyed_setters_count);
+ const Variant::ValidatedKeyedSetter setter = _keyed_setters_ptr[index_setter];
+
+ bool valid;
+ setter(dst, index, value, &valid);
+
+#ifdef DEBUG_ENABLED
+ if (!valid) {
+ String v = index->operator String();
+ if (v != "") {
+ v = "'" + v + "'";
+ } else {
+ v = "of type '" + _get_var_type(index) + "'";
+ }
+ err_text = "Invalid set index " + v + " (on base: '" + _get_var_type(dst) + "') with value of type '" + _get_var_type(value) + "'";
+ OPCODE_BREAK;
+ }
+#endif
+ ip += 5;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_SET_INDEXED_VALIDATED) {
+ CHECK_SPACE(4);
+
+ GET_INSTRUCTION_ARG(dst, 0);
+ GET_INSTRUCTION_ARG(index, 1);
+ GET_INSTRUCTION_ARG(value, 2);
+
+ int index_setter = _code_ptr[ip + 4];
+ GD_ERR_BREAK(index_setter < 0 || index_setter >= _indexed_setters_count);
+ const Variant::ValidatedIndexedSetter setter = _indexed_setters_ptr[index_setter];
+
+ int64_t int_index = *VariantInternal::get_int(index);
+
+ bool oob;
+ setter(dst, int_index, value, &oob);
+
+#ifdef DEBUG_ENABLED
+ if (oob) {
+ String v = index->operator String();
+ if (v != "") {
+ v = "'" + v + "'";
+ } else {
+ v = "of type '" + _get_var_type(index) + "'";
+ }
+ err_text = "Out of bounds set index " + v + " (on base: '" + _get_var_type(dst) + "')";
+ OPCODE_BREAK;
+ }
+#endif
+ ip += 5;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_GET_KEYED) {
+ CHECK_SPACE(3);
+
+ GET_INSTRUCTION_ARG(src, 0);
+ GET_INSTRUCTION_ARG(index, 1);
+ GET_INSTRUCTION_ARG(dst, 2);
+
+ bool valid;
+#ifdef DEBUG_ENABLED
+ // Allow better error message in cases where src and dst are the same stack position.
+ Variant ret = src->get(*index, &valid);
+#else
+ *dst = src->get(*index, &valid);
+
+#endif
+#ifdef DEBUG_ENABLED
+ if (!valid) {
+ String v = index->operator String();
+ if (v != "") {
+ v = "'" + v + "'";
+ } else {
+ v = "of type '" + _get_var_type(index) + "'";
+ }
+ err_text = "Invalid get index " + v + " (on base: '" + _get_var_type(src) + "').";
+ OPCODE_BREAK;
+ }
+ *dst = ret;
+#endif
+ ip += 4;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_GET_KEYED_VALIDATED) {
+ CHECK_SPACE(4);
+
+ GET_INSTRUCTION_ARG(src, 0);
+ GET_INSTRUCTION_ARG(key, 1);
+ GET_INSTRUCTION_ARG(dst, 2);
+
+ int index_getter = _code_ptr[ip + 4];
+ GD_ERR_BREAK(index_getter < 0 || index_getter >= _keyed_getters_count);
+ const Variant::ValidatedKeyedGetter getter = _keyed_getters_ptr[index_getter];
+
+ bool valid;
+#ifdef DEBUG_ENABLED
+ // Allow better error message in cases where src and dst are the same stack position.
+ Variant ret;
+ getter(src, key, &ret, &valid);
+#else
+ getter(src, key, dst, &valid);
+#endif
+#ifdef DEBUG_ENABLED
+ if (!valid) {
+ String v = key->operator String();
+ if (v != "") {
+ v = "'" + v + "'";
+ } else {
+ v = "of type '" + _get_var_type(key) + "'";
+ }
+ err_text = "Invalid get index " + v + " (on base: '" + _get_var_type(src) + "').";
+ OPCODE_BREAK;
+ }
+ *dst = ret;
+#endif
+ ip += 5;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_GET_INDEXED_VALIDATED) {
+ CHECK_SPACE(4);
+
+ GET_INSTRUCTION_ARG(src, 0);
+ GET_INSTRUCTION_ARG(index, 1);
+ GET_INSTRUCTION_ARG(dst, 2);
+
+ int index_getter = _code_ptr[ip + 4];
+ GD_ERR_BREAK(index_getter < 0 || index_getter >= _indexed_getters_count);
+ const Variant::ValidatedIndexedGetter getter = _indexed_getters_ptr[index_getter];
+
+ int64_t int_index = *VariantInternal::get_int(index);
+
+ bool oob;
+ getter(src, int_index, dst, &oob);
+
+#ifdef DEBUG_ENABLED
+ if (oob) {
+ String v = index->operator String();
+ if (v != "") {
+ v = "'" + v + "'";
+ } else {
+ v = "of type '" + _get_var_type(index) + "'";
+ }
+ err_text = "Out of bounds get index " + v + " (on base: '" + _get_var_type(src) + "')";
+ OPCODE_BREAK;
+ }
+#endif
+ ip += 5;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_SET_NAMED) {
+ CHECK_SPACE(3);
+
+ GET_INSTRUCTION_ARG(dst, 0);
+ GET_INSTRUCTION_ARG(value, 1);
+
+ int indexname = _code_ptr[ip + 3];
+
+ GD_ERR_BREAK(indexname < 0 || indexname >= _global_names_count);
+ const StringName *index = &_global_names_ptr[indexname];
+
+ bool valid;
+ dst->set_named(*index, *value, valid);
+
+#ifdef DEBUG_ENABLED
+ if (!valid) {
+ String err_type;
+ err_text = "Invalid set index '" + String(*index) + "' (on base: '" + _get_var_type(dst) + "') with value of type '" + _get_var_type(value) + "'.";
+ OPCODE_BREAK;
+ }
+#endif
+ ip += 4;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_SET_NAMED_VALIDATED) {
+ CHECK_SPACE(3);
+
+ GET_INSTRUCTION_ARG(dst, 0);
+ GET_INSTRUCTION_ARG(value, 1);
+
+ int index_setter = _code_ptr[ip + 3];
+ GD_ERR_BREAK(index_setter < 0 || index_setter >= _setters_count);
+ const Variant::ValidatedSetter setter = _setters_ptr[index_setter];
+
+ setter(dst, value);
+ ip += 4;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_GET_NAMED) {
+ CHECK_SPACE(4);
+
+ GET_INSTRUCTION_ARG(src, 0);
+ GET_INSTRUCTION_ARG(dst, 1);
+
+ int indexname = _code_ptr[ip + 3];
+
+ GD_ERR_BREAK(indexname < 0 || indexname >= _global_names_count);
+ const StringName *index = &_global_names_ptr[indexname];
+
+ bool valid;
+#ifdef DEBUG_ENABLED
+ //allow better error message in cases where src and dst are the same stack position
+ Variant ret = src->get_named(*index, valid);
+
+#else
+ *dst = src->get_named(*index, valid);
+#endif
+#ifdef DEBUG_ENABLED
+ if (!valid) {
+ if (src->has_method(*index)) {
+ err_text = "Invalid get index '" + index->operator String() + "' (on base: '" + _get_var_type(src) + "'). Did you mean '." + index->operator String() + "()' or funcref(obj, \"" + index->operator String() + "\") ?";
+ } else {
+ err_text = "Invalid get index '" + index->operator String() + "' (on base: '" + _get_var_type(src) + "').";
+ }
+ OPCODE_BREAK;
+ }
+ *dst = ret;
+#endif
+ ip += 4;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_GET_NAMED_VALIDATED) {
+ CHECK_SPACE(3);
+
+ GET_INSTRUCTION_ARG(src, 0);
+ GET_INSTRUCTION_ARG(dst, 1);
+
+ int index_getter = _code_ptr[ip + 3];
+ GD_ERR_BREAK(index_getter < 0 || index_getter >= _getters_count);
+ const Variant::ValidatedGetter getter = _getters_ptr[index_getter];
+
+ getter(src, dst);
+ ip += 4;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_SET_MEMBER) {
+ CHECK_SPACE(3);
+ GET_INSTRUCTION_ARG(src, 0);
+ int indexname = _code_ptr[ip + 2];
+ GD_ERR_BREAK(indexname < 0 || indexname >= _global_names_count);
+ const StringName *index = &_global_names_ptr[indexname];
+
+ bool valid;
+#ifndef DEBUG_ENABLED
+ ClassDB::set_property(p_instance->owner, *index, *src, &valid);
+#else
+ bool ok = ClassDB::set_property(p_instance->owner, *index, *src, &valid);
+ if (!ok) {
+ err_text = "Internal error setting property: " + String(*index);
+ OPCODE_BREAK;
+ } else if (!valid) {
+ err_text = "Error setting property '" + String(*index) + "' with value of type " + Variant::get_type_name(src->get_type()) + ".";
+ OPCODE_BREAK;
+ }
+#endif
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_GET_MEMBER) {
+ CHECK_SPACE(3);
+ GET_INSTRUCTION_ARG(dst, 0);
+ int indexname = _code_ptr[ip + 2];
+ GD_ERR_BREAK(indexname < 0 || indexname >= _global_names_count);
+ const StringName *index = &_global_names_ptr[indexname];
+#ifndef DEBUG_ENABLED
+ ClassDB::get_property(p_instance->owner, *index, *dst);
+#else
+ bool ok = ClassDB::get_property(p_instance->owner, *index, *dst);
+ if (!ok) {
+ err_text = "Internal error getting property: " + String(*index);
+ OPCODE_BREAK;
+ }
+#endif
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ASSIGN) {
+ CHECK_SPACE(3);
+ GET_INSTRUCTION_ARG(dst, 0);
+ GET_INSTRUCTION_ARG(src, 1);
+
+ *dst = *src;
+
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ASSIGN_TRUE) {
+ CHECK_SPACE(2);
+ GET_INSTRUCTION_ARG(dst, 0);
+
+ *dst = true;
+
+ ip += 2;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ASSIGN_FALSE) {
+ CHECK_SPACE(2);
+ GET_INSTRUCTION_ARG(dst, 0);
+
+ *dst = false;
+
+ ip += 2;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ASSIGN_TYPED_BUILTIN) {
+ CHECK_SPACE(4);
+ GET_INSTRUCTION_ARG(dst, 0);
+ GET_INSTRUCTION_ARG(src, 1);
+
+ Variant::Type var_type = (Variant::Type)_code_ptr[ip + 3];
+ GD_ERR_BREAK(var_type < 0 || var_type >= Variant::VARIANT_MAX);
+
+ if (src->get_type() != var_type) {
+#ifdef DEBUG_ENABLED
+ if (Variant::can_convert_strict(src->get_type(), var_type)) {
+#endif // DEBUG_ENABLED
+ Callable::CallError ce;
+ Variant::construct(var_type, *dst, const_cast<const Variant **>(&src), 1, ce);
+ } else {
+#ifdef DEBUG_ENABLED
+ err_text = "Trying to assign value of type '" + Variant::get_type_name(src->get_type()) +
+ "' to a variable of type '" + Variant::get_type_name(var_type) + "'.";
+ OPCODE_BREAK;
+ }
+ } else {
+#endif // DEBUG_ENABLED
+ *dst = *src;
+ }
+
+ ip += 4;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ASSIGN_TYPED_NATIVE) {
+ CHECK_SPACE(4);
+ GET_INSTRUCTION_ARG(dst, 0);
+ GET_INSTRUCTION_ARG(src, 1);
+
+#ifdef DEBUG_ENABLED
+ GET_INSTRUCTION_ARG(type, 2);
+ GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(type->operator Object *());
+ GD_ERR_BREAK(!nc);
+ if (src->get_type() != Variant::OBJECT && src->get_type() != Variant::NIL) {
+ err_text = "Trying to assign value of type '" + Variant::get_type_name(src->get_type()) +
+ "' to a variable of type '" + nc->get_name() + "'.";
+ OPCODE_BREAK;
+ }
+ Object *src_obj = src->operator Object *();
+
+ if (src_obj && !ClassDB::is_parent_class(src_obj->get_class_name(), nc->get_name())) {
+ err_text = "Trying to assign value of type '" + src_obj->get_class_name() +
+ "' to a variable of type '" + nc->get_name() + "'.";
+ OPCODE_BREAK;
+ }
+#endif // DEBUG_ENABLED
+ *dst = *src;
+
+ ip += 4;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ASSIGN_TYPED_SCRIPT) {
+ CHECK_SPACE(4);
+ GET_INSTRUCTION_ARG(dst, 0);
+ GET_INSTRUCTION_ARG(src, 1);
+
+#ifdef DEBUG_ENABLED
+ GET_INSTRUCTION_ARG(type, 2);
+ Script *base_type = Object::cast_to<Script>(type->operator Object *());
+
+ GD_ERR_BREAK(!base_type);
+
+ if (src->get_type() != Variant::OBJECT && src->get_type() != Variant::NIL) {
+ err_text = "Trying to assign a non-object value to a variable of type '" + base_type->get_path().get_file() + "'.";
+ OPCODE_BREAK;
+ }
+
+ if (src->get_type() != Variant::NIL && src->operator Object *() != nullptr) {
+ ScriptInstance *scr_inst = src->operator Object *()->get_script_instance();
+ if (!scr_inst) {
+ err_text = "Trying to assign value of type '" + src->operator Object *()->get_class_name() +
+ "' to a variable of type '" + base_type->get_path().get_file() + "'.";
+ OPCODE_BREAK;
+ }
+
+ Script *src_type = src->operator Object *()->get_script_instance()->get_script().ptr();
+ bool valid = false;
+
+ while (src_type) {
+ if (src_type == base_type) {
+ valid = true;
+ break;
+ }
+ src_type = src_type->get_base_script().ptr();
+ }
+
+ if (!valid) {
+ err_text = "Trying to assign value of type '" + src->operator Object *()->get_script_instance()->get_script()->get_path().get_file() +
+ "' to a variable of type '" + base_type->get_path().get_file() + "'.";
+ OPCODE_BREAK;
+ }
+ }
+#endif // DEBUG_ENABLED
+
+ *dst = *src;
+
+ ip += 4;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_CAST_TO_BUILTIN) {
+ CHECK_SPACE(4);
+ GET_INSTRUCTION_ARG(src, 0);
+ GET_INSTRUCTION_ARG(dst, 1);
+ Variant::Type to_type = (Variant::Type)_code_ptr[ip + 3];
+
+ GD_ERR_BREAK(to_type < 0 || to_type >= Variant::VARIANT_MAX);
+
+ Callable::CallError err;
+ Variant::construct(to_type, *dst, (const Variant **)&src, 1, err);
+
+#ifdef DEBUG_ENABLED
+ if (err.error != Callable::CallError::CALL_OK) {
+ err_text = "Invalid cast: could not convert value to '" + Variant::get_type_name(to_type) + "'.";
+ OPCODE_BREAK;
+ }
+#endif
+
+ ip += 4;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_CAST_TO_NATIVE) {
+ CHECK_SPACE(4);
+ GET_INSTRUCTION_ARG(src, 0);
+ GET_INSTRUCTION_ARG(dst, 1);
+ GET_INSTRUCTION_ARG(to_type, 2);
+
+ GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(to_type->operator Object *());
+ GD_ERR_BREAK(!nc);
+
+#ifdef DEBUG_ENABLED
+ if (src->get_type() != Variant::OBJECT && src->get_type() != Variant::NIL) {
+ err_text = "Invalid cast: can't convert a non-object value to an object type.";
+ OPCODE_BREAK;
+ }
+#endif
+ Object *src_obj = src->operator Object *();
+
+ if (src_obj && !ClassDB::is_parent_class(src_obj->get_class_name(), nc->get_name())) {
+ *dst = Variant(); // invalid cast, assign NULL
+ } else {
+ *dst = *src;
+ }
+
+ ip += 4;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_CAST_TO_SCRIPT) {
+ CHECK_SPACE(4);
+ GET_INSTRUCTION_ARG(src, 0);
+ GET_INSTRUCTION_ARG(dst, 1);
+ GET_INSTRUCTION_ARG(to_type, 2);
+
+ Script *base_type = Object::cast_to<Script>(to_type->operator Object *());
+
+ GD_ERR_BREAK(!base_type);
+
+#ifdef DEBUG_ENABLED
+ if (src->get_type() != Variant::OBJECT && src->get_type() != Variant::NIL) {
+ err_text = "Trying to assign a non-object value to a variable of type '" + base_type->get_path().get_file() + "'.";
+ OPCODE_BREAK;
+ }
+#endif
+
+ bool valid = false;
+
+ if (src->get_type() != Variant::NIL && src->operator Object *() != nullptr) {
+ ScriptInstance *scr_inst = src->operator Object *()->get_script_instance();
+
+ if (scr_inst) {
+ Script *src_type = src->operator Object *()->get_script_instance()->get_script().ptr();
+
+ while (src_type) {
+ if (src_type == base_type) {
+ valid = true;
+ break;
+ }
+ src_type = src_type->get_base_script().ptr();
+ }
+ }
+ }
+
+ if (valid) {
+ *dst = *src; // Valid cast, copy the source object
+ } else {
+ *dst = Variant(); // invalid cast, assign NULL
+ }
+
+ ip += 4;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_CONSTRUCT) {
+ CHECK_SPACE(2 + instr_arg_count);
+
+ ip += instr_arg_count;
+
+ int argc = _code_ptr[ip + 1];
+
+ Variant::Type t = Variant::Type(_code_ptr[ip + 2]);
+ Variant **argptrs = instruction_args;
+
+ GET_INSTRUCTION_ARG(dst, argc);
+
+ Callable::CallError err;
+ Variant::construct(t, *dst, (const Variant **)argptrs, argc, err);
+
+#ifdef DEBUG_ENABLED
+ if (err.error != Callable::CallError::CALL_OK) {
+ err_text = _get_call_error(err, "'" + Variant::get_type_name(t) + "' constructor", (const Variant **)argptrs);
+ OPCODE_BREAK;
+ }
+#endif
+
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_CONSTRUCT_VALIDATED) {
+ CHECK_SPACE(2 + instr_arg_count);
+
+ ip += instr_arg_count;
+
+ int argc = _code_ptr[ip + 1];
+
+ int constructor_idx = _code_ptr[ip + 2];
+ GD_ERR_BREAK(constructor_idx < 0 || constructor_idx >= _constructors_count);
+ Variant::ValidatedConstructor constructor = _constructors_ptr[constructor_idx];
+
+ Variant **argptrs = instruction_args;
+
+ GET_INSTRUCTION_ARG(dst, argc);
+
+ constructor(dst, (const Variant **)argptrs);
+
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_CONSTRUCT_ARRAY) {
+ CHECK_SPACE(1 + instr_arg_count);
+ ip += instr_arg_count;
+
+ int argc = _code_ptr[ip + 1];
+ Array array;
+ array.resize(argc);
+
+ for (int i = 0; i < argc; i++) {
+ array[i] = *(instruction_args[i]);
+ }
+
+ GET_INSTRUCTION_ARG(dst, argc);
+
+ *dst = array;
+
+ ip += 2;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_CONSTRUCT_DICTIONARY) {
+ CHECK_SPACE(2 + instr_arg_count);
+
+ ip += instr_arg_count;
+
+ int argc = _code_ptr[ip + 1];
+ Dictionary dict;
+
+ for (int i = 0; i < argc; i++) {
+ GET_INSTRUCTION_ARG(k, i * 2 + 0);
+ GET_INSTRUCTION_ARG(v, i * 2 + 1);
+ dict[*k] = *v;
+ }
+
+ GET_INSTRUCTION_ARG(dst, argc * 2);
+
+ *dst = dict;
+
+ ip += 2;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_CALL_ASYNC)
+ OPCODE(OPCODE_CALL_RETURN)
+ OPCODE(OPCODE_CALL) {
+ CHECK_SPACE(3 + instr_arg_count);
+ bool call_ret = (_code_ptr[ip] & INSTR_MASK) != OPCODE_CALL;
+#ifdef DEBUG_ENABLED
+ bool call_async = (_code_ptr[ip] & INSTR_MASK) == OPCODE_CALL_ASYNC;
+#endif
+
+ ip += instr_arg_count;
+
+ int argc = _code_ptr[ip + 1];
+ GD_ERR_BREAK(argc < 0);
+
+ int methodname_idx = _code_ptr[ip + 2];
+ GD_ERR_BREAK(methodname_idx < 0 || methodname_idx >= _global_names_count);
+ const StringName *methodname = &_global_names_ptr[methodname_idx];
+
+ GET_INSTRUCTION_ARG(base, argc);
+ Variant **argptrs = 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;
+ if (call_ret) {
+ GET_INSTRUCTION_ARG(ret, argc + 1);
+ base->call(*methodname, (const Variant **)argptrs, argc, *ret, err);
+#ifdef DEBUG_ENABLED
+ if (!call_async && ret->get_type() == Variant::OBJECT) {
+ // Check if getting a function state without await.
+ bool was_freed = false;
+ Object *obj = ret->get_validated_object_with_check(was_freed);
+
+ if (was_freed) {
+ err_text = "Got a freed object as a result of the call.";
+ OPCODE_BREAK;
+ }
+ if (obj && obj->is_class_ptr(GDScriptFunctionState::get_class_ptr_static())) {
+ err_text = R"(Trying to call an async function without "await".)";
+ OPCODE_BREAK;
+ }
+ }
+#endif
+ } else {
+ Variant ret;
+ base->call(*methodname, (const Variant **)argptrs, argc, ret, err);
+ }
+#ifdef DEBUG_ENABLED
+ if (GDScriptLanguage::get_singleton()->profiling) {
+ function_call_time += OS::get_singleton()->get_ticks_usec() - call_time;
+ }
+
+ if (err.error != Callable::CallError::CALL_OK) {
+ String methodstr = *methodname;
+ String basestr = _get_var_type(base);
+
+ if (methodstr == "call") {
+ if (argc >= 1) {
+ methodstr = String(*argptrs[0]) + " (via call)";
+ if (err.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) {
+ err.argument += 1;
+ }
+ }
+ } else if (methodstr == "free") {
+ if (err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
+ if (base->is_ref()) {
+ err_text = "Attempted to free a reference.";
+ OPCODE_BREAK;
+ } else if (base->get_type() == Variant::OBJECT) {
+ err_text = "Attempted to free a locked object (calling or emitting).";
+ OPCODE_BREAK;
+ }
+ }
+ } else if (methodstr == "call_recursive" && basestr == "TreeItem") {
+ if (argc >= 1) {
+ methodstr = String(*argptrs[0]) + " (via TreeItem.call_recursive)";
+ if (err.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) {
+ err.argument += 1;
+ }
+ }
+ }
+ err_text = _get_call_error(err, "function '" + methodstr + "' in base '" + basestr + "'", (const Variant **)argptrs);
+ OPCODE_BREAK;
+ }
+#endif
+
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_CALL_METHOD_BIND)
+ OPCODE(OPCODE_CALL_METHOD_BIND_RET) {
+ CHECK_SPACE(3 + instr_arg_count);
+ bool call_ret = (_code_ptr[ip] & INSTR_MASK) == OPCODE_CALL_METHOD_BIND_RET;
+
+ ip += instr_arg_count;
+
+ int argc = _code_ptr[ip + 1];
+ GD_ERR_BREAK(argc < 0);
+ GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _methods_count);
+ MethodBind *method = _methods_ptr[_code_ptr[ip + 2]];
+
+ GET_INSTRUCTION_ARG(base, argc);
+
+#ifdef DEBUG_ENABLED
+ bool freed = false;
+ Object *base_obj = base->get_validated_object_with_check(freed);
+ if (freed) {
+ err_text = "Trying to call a function on a previously freed instance.";
+ OPCODE_BREAK;
+ } else if (!base_obj) {
+ err_text = "Trying to call a function on a null value.";
+ OPCODE_BREAK;
+ }
+#else
+ Object *base_obj = base->operator Object *();
+#endif
+ Variant **argptrs = 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;
+ if (call_ret) {
+ GET_INSTRUCTION_ARG(ret, argc + 1);
+ *ret = method->call(base_obj, (const Variant **)argptrs, argc, err);
+ } else {
+ method->call(base_obj, (const Variant **)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) {
+ String methodstr = method->get_name();
+ String basestr = _get_var_type(base);
+
+ if (methodstr == "call") {
+ if (argc >= 1) {
+ methodstr = String(*argptrs[0]) + " (via call)";
+ if (err.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) {
+ err.argument += 1;
+ }
+ }
+ } else if (methodstr == "free") {
+ if (err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
+ if (base->is_ref()) {
+ err_text = "Attempted to free a reference.";
+ OPCODE_BREAK;
+ } else if (base->get_type() == Variant::OBJECT) {
+ err_text = "Attempted to free a locked object (calling or emitting).";
+ OPCODE_BREAK;
+ }
+ }
+ }
+ err_text = _get_call_error(err, "function '" + methodstr + "' in base '" + basestr + "'", (const Variant **)argptrs);
+ OPCODE_BREAK;
+ }
+#endif
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
+#ifdef DEBUG_ENABLED
+#define OPCODE_CALL_PTR(m_type) \
+ OPCODE(OPCODE_CALL_PTRCALL_##m_type) { \
+ CHECK_SPACE(3 + instr_arg_count); \
+ ip += instr_arg_count; \
+ int argc = _code_ptr[ip + 1]; \
+ GD_ERR_BREAK(argc < 0); \
+ GET_INSTRUCTION_ARG(base, argc); \
+ GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _methods_count); \
+ MethodBind *method = _methods_ptr[_code_ptr[ip + 2]]; \
+ bool freed = false; \
+ Object *base_obj = base->get_validated_object_with_check(freed); \
+ if (freed) { \
+ err_text = "Trying to call a function on a previously freed instance."; \
+ OPCODE_BREAK; \
+ } else if (!base_obj) { \
+ err_text = "Trying to call a function on a null value."; \
+ OPCODE_BREAK; \
+ } \
+ const void **argptrs = call_args_ptr; \
+ for (int i = 0; i < argc; i++) { \
+ GET_INSTRUCTION_ARG(v, i); \
+ argptrs[i] = VariantInternal::get_opaque_pointer((const Variant *)v); \
+ } \
+ uint64_t call_time = 0; \
+ if (GDScriptLanguage::get_singleton()->profiling) { \
+ call_time = OS::get_singleton()->get_ticks_usec(); \
+ } \
+ GET_INSTRUCTION_ARG(ret, argc + 1); \
+ VariantInternal::initialize(ret, Variant::m_type); \
+ void *ret_opaque = VariantInternal::OP_GET_##m_type(ret); \
+ method->ptrcall(base_obj, argptrs, ret_opaque); \
+ if (GDScriptLanguage::get_singleton()->profiling) { \
+ function_call_time += OS::get_singleton()->get_ticks_usec() - call_time; \
+ } \
+ ip += 3; \
+ } \
+ DISPATCH_OPCODE
+#else
+#define OPCODE_CALL_PTR(m_type) \
+ OPCODE(OPCODE_CALL_PTRCALL_##m_type) { \
+ CHECK_SPACE(3 + instr_arg_count); \
+ int argc = _code_ptr[ip + 1]; \
+ GET_INSTRUCTION_ARG(base, argc); \
+ MethodBind *method = _methods_ptr[_code_ptr[ip + 2]]; \
+ Object *base_obj = *VariantInternal::get_object(base); \
+ const void **argptrs = call_args_ptr; \
+ for (int i = 0; i < argc; i++) { \
+ GET_INSTRUCTION_ARG(v, i); \
+ argptrs[i] = VariantInternal::get_opaque_pointer((const Variant *)v); \
+ } \
+ GET_INSTRUCTION_ARG(ret, argc + 1); \
+ VariantInternal::initialize(ret, Variant::m_type); \
+ void *ret_opaque = VariantInternal::OP_GET_##m_type(ret); \
+ method->ptrcall(base_obj, argptrs, ret_opaque); \
+ ip += 3; \
+ } \
+ DISPATCH_OPCODE
+#endif
+
+ OPCODE_CALL_PTR(BOOL);
+ OPCODE_CALL_PTR(INT);
+ OPCODE_CALL_PTR(FLOAT);
+ OPCODE_CALL_PTR(STRING);
+ OPCODE_CALL_PTR(VECTOR2);
+ OPCODE_CALL_PTR(VECTOR2I);
+ OPCODE_CALL_PTR(RECT2);
+ OPCODE_CALL_PTR(RECT2I);
+ OPCODE_CALL_PTR(VECTOR3);
+ OPCODE_CALL_PTR(VECTOR3I);
+ OPCODE_CALL_PTR(TRANSFORM2D);
+ OPCODE_CALL_PTR(PLANE);
+ OPCODE_CALL_PTR(QUAT);
+ OPCODE_CALL_PTR(AABB);
+ OPCODE_CALL_PTR(BASIS);
+ OPCODE_CALL_PTR(TRANSFORM);
+ OPCODE_CALL_PTR(COLOR);
+ OPCODE_CALL_PTR(STRING_NAME);
+ OPCODE_CALL_PTR(NODE_PATH);
+ OPCODE_CALL_PTR(RID);
+ OPCODE_CALL_PTR(CALLABLE);
+ OPCODE_CALL_PTR(SIGNAL);
+ OPCODE_CALL_PTR(DICTIONARY);
+ OPCODE_CALL_PTR(ARRAY);
+ OPCODE_CALL_PTR(PACKED_BYTE_ARRAY);
+ OPCODE_CALL_PTR(PACKED_INT32_ARRAY);
+ OPCODE_CALL_PTR(PACKED_INT64_ARRAY);
+ OPCODE_CALL_PTR(PACKED_FLOAT32_ARRAY);
+ OPCODE_CALL_PTR(PACKED_FLOAT64_ARRAY);
+ OPCODE_CALL_PTR(PACKED_STRING_ARRAY);
+ OPCODE_CALL_PTR(PACKED_VECTOR2_ARRAY);
+ OPCODE_CALL_PTR(PACKED_VECTOR3_ARRAY);
+ OPCODE_CALL_PTR(PACKED_COLOR_ARRAY);
+ OPCODE(OPCODE_CALL_PTRCALL_OBJECT) {
+ CHECK_SPACE(3 + instr_arg_count);
+
+ ip += instr_arg_count;
+
+ int argc = _code_ptr[ip + 1];
+ GD_ERR_BREAK(argc < 0);
+
+ GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _methods_count);
+ MethodBind *method = _methods_ptr[_code_ptr[ip + 2]];
+
+ GET_INSTRUCTION_ARG(base, argc);
+#ifdef DEBUG_ENABLED
+ bool freed = false;
+ Object *base_obj = base->get_validated_object_with_check(freed);
+ if (freed) {
+ err_text = "Trying to call a function on a previously freed instance.";
+ OPCODE_BREAK;
+ } else if (!base_obj) {
+ err_text = "Trying to call a function on a null value.";
+ OPCODE_BREAK;
+ }
+#else
+ Object *base_obj = *VariantInternal::get_object(base);
+#endif
+
+ const void **argptrs = call_args_ptr;
+
+ for (int i = 0; i < argc; i++) {
+ GET_INSTRUCTION_ARG(v, i);
+ argptrs[i] = VariantInternal::get_opaque_pointer((const Variant *)v);
+ }
+#ifdef DEBUG_ENABLED
+ uint64_t call_time = 0;
+
+ if (GDScriptLanguage::get_singleton()->profiling) {
+ call_time = OS::get_singleton()->get_ticks_usec();
+ }
+#endif
+
+ GET_INSTRUCTION_ARG(ret, argc + 1);
+ VariantInternal::initialize(ret, Variant::OBJECT);
+ Object **ret_opaque = VariantInternal::get_object(ret);
+ method->ptrcall(base_obj, argptrs, ret_opaque);
+ VariantInternal::object_assign(ret, *ret_opaque); // Set so ID is correct too.
+
+#ifdef DEBUG_ENABLED
+ if (GDScriptLanguage::get_singleton()->profiling) {
+ function_call_time += OS::get_singleton()->get_ticks_usec() - call_time;
+ }
+#endif
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+ OPCODE(OPCODE_CALL_PTRCALL_NO_RETURN) {
+ CHECK_SPACE(3 + instr_arg_count);
+
+ ip += instr_arg_count;
+
+ int argc = _code_ptr[ip + 1];
+ GD_ERR_BREAK(argc < 0);
+
+ GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _methods_count);
+ MethodBind *method = _methods_ptr[_code_ptr[ip + 2]];
+
+ GET_INSTRUCTION_ARG(base, argc);
+#ifdef DEBUG_ENABLED
+ bool freed = false;
+ Object *base_obj = base->get_validated_object_with_check(freed);
+ if (freed) {
+ err_text = "Trying to call a function on a previously freed instance.";
+ OPCODE_BREAK;
+ } else if (!base_obj) {
+ err_text = "Trying to call a function on a null value.";
+ OPCODE_BREAK;
+ }
+#else
+ Object *base_obj = *VariantInternal::get_object(base);
+#endif
+ const void **argptrs = call_args_ptr;
+
+ for (int i = 0; i < argc; i++) {
+ GET_INSTRUCTION_ARG(v, i);
+ argptrs[i] = VariantInternal::get_opaque_pointer((const Variant *)v);
+ }
+#ifdef DEBUG_ENABLED
+ uint64_t call_time = 0;
+
+ if (GDScriptLanguage::get_singleton()->profiling) {
+ call_time = OS::get_singleton()->get_ticks_usec();
+ }
+#endif
+
+ GET_INSTRUCTION_ARG(ret, argc + 1);
+ VariantInternal::initialize(ret, Variant::NIL);
+ method->ptrcall(base_obj, argptrs, nullptr);
+
+#ifdef DEBUG_ENABLED
+ if (GDScriptLanguage::get_singleton()->profiling) {
+ function_call_time += OS::get_singleton()->get_ticks_usec() - call_time;
+ }
+#endif
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_CALL_BUILTIN_TYPE_VALIDATED) {
+ CHECK_SPACE(3 + instr_arg_count);
+
+ ip += instr_arg_count;
+
+ int argc = _code_ptr[ip + 1];
+ GD_ERR_BREAK(argc < 0);
+
+ GET_INSTRUCTION_ARG(base, argc);
+
+ GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _builtin_methods_count);
+ Variant::ValidatedBuiltInMethod method = _builtin_methods_ptr[_code_ptr[ip + 2]];
+ Variant **argptrs = instruction_args;
+
+#ifdef DEBUG_ENABLED
+ uint64_t call_time = 0;
+ if (GDScriptLanguage::get_singleton()->profiling) {
+ call_time = OS::get_singleton()->get_ticks_usec();
+ }
+#endif
+
+ GET_INSTRUCTION_ARG(ret, argc + 1);
+ method(base, (const Variant **)argptrs, argc, ret);
+
+#ifdef DEBUG_ENABLED
+ if (GDScriptLanguage::get_singleton()->profiling) {
+ function_call_time += OS::get_singleton()->get_ticks_usec() - call_time;
+ }
+#endif
+
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_CALL_UTILITY) {
+ CHECK_SPACE(3 + instr_arg_count);
+
+ ip += instr_arg_count;
+
+ int argc = _code_ptr[ip + 1];
+ GD_ERR_BREAK(argc < 0);
+
+ GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _global_names_count);
+ StringName function = _global_names_ptr[_code_ptr[ip + 2]];
+
+ Variant **argptrs = instruction_args;
+
+ GET_INSTRUCTION_ARG(dst, argc);
+
+ Callable::CallError err;
+ Variant::call_utility_function(function, dst, (const Variant **)argptrs, argc, err);
+
+#ifdef DEBUG_ENABLED
+ if (err.error != Callable::CallError::CALL_OK) {
+ String methodstr = function;
+ if (dst->get_type() == Variant::STRING) {
+ // Call provided error string.
+ err_text = "Error calling utility function '" + methodstr + "': " + String(*dst);
+ } else {
+ err_text = _get_call_error(err, "utility function '" + methodstr + "'", (const Variant **)argptrs);
+ }
+ OPCODE_BREAK;
+ }
+#endif
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_CALL_UTILITY_VALIDATED) {
+ CHECK_SPACE(3 + instr_arg_count);
+
+ ip += instr_arg_count;
+
+ int argc = _code_ptr[ip + 1];
+ GD_ERR_BREAK(argc < 0);
+
+ GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _utilities_count);
+ Variant::ValidatedUtilityFunction function = _utilities_ptr[_code_ptr[ip + 2]];
+
+ Variant **argptrs = instruction_args;
+
+ GET_INSTRUCTION_ARG(dst, argc);
+
+ function(dst, (const Variant **)argptrs, argc);
+
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_CALL_GDSCRIPT_UTILITY) {
+ CHECK_SPACE(3 + instr_arg_count);
+
+ ip += instr_arg_count;
+
+ int argc = _code_ptr[ip + 1];
+ GD_ERR_BREAK(argc < 0);
+
+ GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _gds_utilities_count);
+ GDScriptUtilityFunctions::FunctionPtr function = _gds_utilities_ptr[_code_ptr[ip + 2]];
+
+ Variant **argptrs = instruction_args;
+
+ GET_INSTRUCTION_ARG(dst, argc);
+
+ Callable::CallError err;
+ function(dst, (const Variant **)argptrs, argc, err);
+
+#ifdef DEBUG_ENABLED
+ if (err.error != Callable::CallError::CALL_OK) {
+ // TODO: Add this information in debug.
+ String methodstr = "<unkown function>";
+ if (dst->get_type() == Variant::STRING) {
+ // Call provided error string.
+ err_text = "Error calling GDScript utility function '" + methodstr + "': " + String(*dst);
+ } else {
+ err_text = _get_call_error(err, "GDScript utility function '" + methodstr + "'", (const Variant **)argptrs);
+ }
+ OPCODE_BREAK;
+ }
+#endif
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_CALL_SELF_BASE) {
+ CHECK_SPACE(3 + instr_arg_count);
+
+ ip += instr_arg_count;
+
+ int self_fun = _code_ptr[ip + 1];
+#ifdef DEBUG_ENABLED
+ if (self_fun < 0 || self_fun >= _global_names_count) {
+ err_text = "compiler bug, function name not found";
+ OPCODE_BREAK;
+ }
+#endif
+ const StringName *methodname = &_global_names_ptr[self_fun];
+
+ int argc = _code_ptr[ip + 2];
+ GD_ERR_BREAK(argc < 0);
+
+ Variant **argptrs = instruction_args;
+
+ GET_INSTRUCTION_ARG(dst, argc);
+
+ const GDScript *gds = _script;
+
+ const Map<StringName, GDScriptFunction *>::Element *E = nullptr;
+ while (gds->base.ptr()) {
+ gds = gds->base.ptr();
+ E = gds->member_functions.find(*methodname);
+ if (E) {
+ break;
+ }
+ }
+
+ Callable::CallError err;
+
+ if (E) {
+ *dst = E->get()->call(p_instance, (const Variant **)argptrs, argc, err);
+ } else if (gds->native.ptr()) {
+ if (*methodname != GDScriptLanguage::get_singleton()->strings._init) {
+ MethodBind *mb = ClassDB::get_method(gds->native->get_name(), *methodname);
+ if (!mb) {
+ err.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ } else {
+ *dst = mb->call(p_instance->owner, (const Variant **)argptrs, argc, err);
+ }
+ } else {
+ err.error = Callable::CallError::CALL_OK;
+ }
+ } else {
+ if (*methodname != GDScriptLanguage::get_singleton()->strings._init) {
+ err.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ } else {
+ err.error = Callable::CallError::CALL_OK;
+ }
+ }
+
+ if (err.error != Callable::CallError::CALL_OK) {
+ String methodstr = *methodname;
+ err_text = _get_call_error(err, "function '" + methodstr + "'", (const Variant **)argptrs);
+
+ OPCODE_BREAK;
+ }
+
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_AWAIT) {
+ CHECK_SPACE(2);
+
+ // Do the oneshot connect.
+ GET_INSTRUCTION_ARG(argobj, 0);
+
+ Signal sig;
+ bool is_signal = true;
+
+ {
+ Variant result = *argobj;
+
+ if (argobj->get_type() == Variant::OBJECT) {
+ bool was_freed = false;
+ Object *obj = argobj->get_validated_object_with_check(was_freed);
+
+ if (was_freed) {
+ err_text = "Trying to await on a freed object.";
+ OPCODE_BREAK;
+ }
+
+ // Is this even possible to be null at this point?
+ if (obj) {
+ if (obj->is_class_ptr(GDScriptFunctionState::get_class_ptr_static())) {
+ static StringName completed = _scs_create("completed");
+ result = Signal(obj, completed);
+ }
+ }
+ }
+
+ if (result.get_type() != Variant::SIGNAL) {
+ ip += 4; // Skip OPCODE_AWAIT_RESUME and its data.
+ // The stack pointer should be the same, so we don't need to set a return value.
+ is_signal = false;
+ } else {
+ sig = result;
+ }
+ }
+
+ if (is_signal) {
+ Ref<GDScriptFunctionState> gdfs = memnew(GDScriptFunctionState);
+ gdfs->function = this;
+
+ gdfs->state.stack.resize(alloca_size);
+ //copy variant stack
+ for (int i = 0; i < _stack_size; i++) {
+ memnew_placement(&gdfs->state.stack.write[sizeof(Variant) * i], Variant(stack[i]));
+ }
+ gdfs->state.stack_size = _stack_size;
+ gdfs->state.self = self;
+ gdfs->state.alloca_size = alloca_size;
+ gdfs->state.ip = ip + 2;
+ gdfs->state.line = line;
+ gdfs->state.script = _script;
+ {
+ MutexLock lock(GDScriptLanguage::get_singleton()->lock);
+ _script->pending_func_states.add(&gdfs->scripts_list);
+ if (p_instance) {
+ gdfs->state.instance = p_instance;
+ p_instance->pending_func_states.add(&gdfs->instances_list);
+ } else {
+ gdfs->state.instance = nullptr;
+ }
+ }
+#ifdef DEBUG_ENABLED
+ gdfs->state.function_name = name;
+ gdfs->state.script_path = _script->get_path();
+#endif
+ gdfs->state.defarg = defarg;
+ gdfs->function = this;
+
+ retvalue = gdfs;
+
+ Error err = sig.connect(Callable(gdfs.ptr(), "_signal_callback"), varray(gdfs), Object::CONNECT_ONESHOT);
+ if (err != OK) {
+ err_text = "Error connecting to signal: " + sig.get_name() + " during await.";
+ OPCODE_BREAK;
+ }
+
+#ifdef DEBUG_ENABLED
+ exit_ok = true;
+ awaited = true;
+#endif
+ OPCODE_BREAK;
+ }
+ }
+ DISPATCH_OPCODE; // Needed for synchronous calls (when result is immediately available).
+
+ OPCODE(OPCODE_AWAIT_RESUME) {
+ CHECK_SPACE(2);
+#ifdef DEBUG_ENABLED
+ if (!p_state) {
+ err_text = ("Invalid Resume (bug?)");
+ OPCODE_BREAK;
+ }
+#endif
+ GET_INSTRUCTION_ARG(result, 0);
+ *result = p_state->result;
+ ip += 2;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_JUMP) {
+ CHECK_SPACE(2);
+ int to = _code_ptr[ip + 1];
+
+ GD_ERR_BREAK(to < 0 || to > _code_size);
+ ip = to;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_JUMP_IF) {
+ CHECK_SPACE(3);
+
+ GET_INSTRUCTION_ARG(test, 0);
+
+ bool result = test->booleanize();
+
+ if (result) {
+ int to = _code_ptr[ip + 2];
+ GD_ERR_BREAK(to < 0 || to > _code_size);
+ ip = to;
+ } else {
+ ip += 3;
+ }
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_JUMP_IF_NOT) {
+ CHECK_SPACE(3);
+
+ GET_INSTRUCTION_ARG(test, 0);
+
+ bool result = test->booleanize();
+
+ if (!result) {
+ int to = _code_ptr[ip + 2];
+ GD_ERR_BREAK(to < 0 || to > _code_size);
+ ip = to;
+ } else {
+ ip += 3;
+ }
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_JUMP_TO_DEF_ARGUMENT) {
+ CHECK_SPACE(2);
+ ip = _default_arg_ptr[defarg];
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_RETURN) {
+ CHECK_SPACE(2);
+ GET_INSTRUCTION_ARG(r, 0);
+ retvalue = *r;
+#ifdef DEBUG_ENABLED
+ exit_ok = true;
+#endif
+ OPCODE_BREAK;
+ }
+
+ OPCODE(OPCODE_ITERATE_BEGIN) {
+ CHECK_SPACE(8); // Space for this and a regular iterate.
+
+ GET_INSTRUCTION_ARG(counter, 0);
+ GET_INSTRUCTION_ARG(container, 1);
+
+ bool valid;
+ if (!container->iter_init(*counter, valid)) {
+#ifdef DEBUG_ENABLED
+ if (!valid) {
+ err_text = "Unable to iterate on object of type '" + Variant::get_type_name(container->get_type()) + "'.";
+ OPCODE_BREAK;
+ }
+#endif
+ int jumpto = _code_ptr[ip + 4];
+ GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+ ip = jumpto;
+ } else {
+ GET_INSTRUCTION_ARG(iterator, 2);
+
+ *iterator = container->iter_get(*counter, valid);
+#ifdef DEBUG_ENABLED
+ if (!valid) {
+ err_text = "Unable to obtain iterator object of type '" + Variant::get_type_name(container->get_type()) + "'.";
+ OPCODE_BREAK;
+ }
+#endif
+ ip += 5; // Skip regular iterate which is always next.
+ }
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ITERATE_BEGIN_INT) {
+ CHECK_SPACE(8); // Check space for iterate instruction too.
+
+ GET_INSTRUCTION_ARG(counter, 0);
+ GET_INSTRUCTION_ARG(container, 1);
+
+ int64_t size = *VariantInternal::get_int(container);
+
+ VariantInternal::initialize(counter, Variant::INT);
+ *VariantInternal::get_int(counter) = 0;
+
+ if (size > 0) {
+ GET_INSTRUCTION_ARG(iterator, 2);
+ VariantInternal::initialize(iterator, Variant::INT);
+ *VariantInternal::get_int(iterator) = 0;
+
+ // Skip regular iterate.
+ ip += 5;
+ } else {
+ // Jump to end of loop.
+ int jumpto = _code_ptr[ip + 4];
+ GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+ ip = jumpto;
+ }
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ITERATE_BEGIN_FLOAT) {
+ CHECK_SPACE(8); // Check space for iterate instruction too.
+
+ GET_INSTRUCTION_ARG(counter, 0);
+ GET_INSTRUCTION_ARG(container, 1);
+
+ double size = *VariantInternal::get_float(container);
+
+ VariantInternal::initialize(counter, Variant::FLOAT);
+ *VariantInternal::get_float(counter) = 0.0;
+
+ if (size > 0) {
+ GET_INSTRUCTION_ARG(iterator, 2);
+ VariantInternal::initialize(iterator, Variant::FLOAT);
+ *VariantInternal::get_float(iterator) = 0;
+
+ // Skip regular iterate.
+ ip += 5;
+ } else {
+ // Jump to end of loop.
+ int jumpto = _code_ptr[ip + 4];
+ GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+ ip = jumpto;
+ }
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ITERATE_BEGIN_VECTOR2) {
+ CHECK_SPACE(8); // Check space for iterate instruction too.
+
+ GET_INSTRUCTION_ARG(counter, 0);
+ GET_INSTRUCTION_ARG(container, 1);
+
+ Vector2 *bounds = VariantInternal::get_vector2(container);
+
+ VariantInternal::initialize(counter, Variant::FLOAT);
+ *VariantInternal::get_float(counter) = bounds->x;
+
+ if (bounds->x < bounds->y) {
+ GET_INSTRUCTION_ARG(iterator, 2);
+ VariantInternal::initialize(iterator, Variant::FLOAT);
+ *VariantInternal::get_float(iterator) = bounds->x;
+
+ // Skip regular iterate.
+ ip += 5;
+ } else {
+ // Jump to end of loop.
+ int jumpto = _code_ptr[ip + 4];
+ GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+ ip = jumpto;
+ }
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ITERATE_BEGIN_VECTOR2I) {
+ CHECK_SPACE(8); // Check space for iterate instruction too.
+
+ GET_INSTRUCTION_ARG(counter, 0);
+ GET_INSTRUCTION_ARG(container, 1);
+
+ Vector2i *bounds = VariantInternal::get_vector2i(container);
+
+ VariantInternal::initialize(counter, Variant::FLOAT);
+ *VariantInternal::get_int(counter) = bounds->x;
+
+ if (bounds->x < bounds->y) {
+ GET_INSTRUCTION_ARG(iterator, 2);
+ VariantInternal::initialize(iterator, Variant::INT);
+ *VariantInternal::get_int(iterator) = bounds->x;
+
+ // Skip regular iterate.
+ ip += 5;
+ } else {
+ // Jump to end of loop.
+ int jumpto = _code_ptr[ip + 4];
+ GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+ ip = jumpto;
+ }
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ITERATE_BEGIN_VECTOR3) {
+ CHECK_SPACE(8); // Check space for iterate instruction too.
+
+ GET_INSTRUCTION_ARG(counter, 0);
+ GET_INSTRUCTION_ARG(container, 1);
+
+ Vector3 *bounds = VariantInternal::get_vector3(container);
+ double from = bounds->x;
+ double to = bounds->y;
+ double step = bounds->z;
+
+ VariantInternal::initialize(counter, Variant::FLOAT);
+ *VariantInternal::get_float(counter) = from;
+
+ bool do_continue = from == to ? false : (from < to ? step > 0 : step < 0);
+
+ if (do_continue) {
+ GET_INSTRUCTION_ARG(iterator, 2);
+ VariantInternal::initialize(iterator, Variant::FLOAT);
+ *VariantInternal::get_float(iterator) = from;
+
+ // Skip regular iterate.
+ ip += 5;
+ } else {
+ // Jump to end of loop.
+ int jumpto = _code_ptr[ip + 4];
+ GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+ ip = jumpto;
+ }
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ITERATE_BEGIN_VECTOR3I) {
+ CHECK_SPACE(8); // Check space for iterate instruction too.
+
+ GET_INSTRUCTION_ARG(counter, 0);
+ GET_INSTRUCTION_ARG(container, 1);
+
+ Vector3i *bounds = VariantInternal::get_vector3i(container);
+ int64_t from = bounds->x;
+ int64_t to = bounds->y;
+ int64_t step = bounds->z;
+
+ VariantInternal::initialize(counter, Variant::INT);
+ *VariantInternal::get_int(counter) = from;
+
+ bool do_continue = from == to ? false : (from < to ? step > 0 : step < 0);
+
+ if (do_continue) {
+ GET_INSTRUCTION_ARG(iterator, 2);
+ VariantInternal::initialize(iterator, Variant::INT);
+ *VariantInternal::get_int(iterator) = from;
+
+ // Skip regular iterate.
+ ip += 5;
+ } else {
+ // Jump to end of loop.
+ int jumpto = _code_ptr[ip + 4];
+ GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+ ip = jumpto;
+ }
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ITERATE_BEGIN_STRING) {
+ CHECK_SPACE(8); // Check space for iterate instruction too.
+
+ GET_INSTRUCTION_ARG(counter, 0);
+ GET_INSTRUCTION_ARG(container, 1);
+
+ String *str = VariantInternal::get_string(container);
+
+ VariantInternal::initialize(counter, Variant::INT);
+ *VariantInternal::get_int(counter) = 0;
+
+ if (!str->is_empty()) {
+ GET_INSTRUCTION_ARG(iterator, 2);
+ VariantInternal::initialize(iterator, Variant::STRING);
+ *VariantInternal::get_string(iterator) = str->substr(0, 1);
+
+ // Skip regular iterate.
+ ip += 5;
+ } else {
+ // Jump to end of loop.
+ int jumpto = _code_ptr[ip + 4];
+ GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+ ip = jumpto;
+ }
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ITERATE_BEGIN_DICTIONARY) {
+ CHECK_SPACE(8); // Check space for iterate instruction too.
+
+ GET_INSTRUCTION_ARG(counter, 0);
+ GET_INSTRUCTION_ARG(container, 1);
+
+ Dictionary *dict = VariantInternal::get_dictionary(container);
+ const Variant *next = dict->next(nullptr);
+
+ if (!dict->is_empty()) {
+ GET_INSTRUCTION_ARG(iterator, 2);
+ *counter = *next;
+ *iterator = *next;
+
+ // Skip regular iterate.
+ ip += 5;
+ } else {
+ // Jump to end of loop.
+ int jumpto = _code_ptr[ip + 4];
+ GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+ ip = jumpto;
+ }
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ITERATE_BEGIN_ARRAY) {
+ CHECK_SPACE(8); // Check space for iterate instruction too.
+
+ GET_INSTRUCTION_ARG(counter, 0);
+ GET_INSTRUCTION_ARG(container, 1);
+
+ Array *array = VariantInternal::get_array(container);
+
+ VariantInternal::initialize(counter, Variant::INT);
+ *VariantInternal::get_int(counter) = 0;
+
+ if (!array->is_empty()) {
+ GET_INSTRUCTION_ARG(iterator, 2);
+ *iterator = array->get(0);
+
+ // Skip regular iterate.
+ ip += 5;
+ } else {
+ // Jump to end of loop.
+ int jumpto = _code_ptr[ip + 4];
+ GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+ ip = jumpto;
+ }
+ }
+ DISPATCH_OPCODE;
+
+#define OPCODE_ITERATE_BEGIN_PACKED_ARRAY(m_var_type, m_elem_type, m_get_func, m_var_ret_type, m_ret_type, m_ret_get_func) \
+ OPCODE(OPCODE_ITERATE_BEGIN_PACKED_##m_var_type##_ARRAY) { \
+ CHECK_SPACE(8); \
+ GET_INSTRUCTION_ARG(counter, 0); \
+ GET_INSTRUCTION_ARG(container, 1); \
+ Vector<m_elem_type> *array = VariantInternal::m_get_func(container); \
+ VariantInternal::initialize(counter, Variant::INT); \
+ *VariantInternal::get_int(counter) = 0; \
+ if (!array->is_empty()) { \
+ GET_INSTRUCTION_ARG(iterator, 2); \
+ VariantInternal::initialize(iterator, Variant::m_var_ret_type); \
+ m_ret_type *it = VariantInternal::m_ret_get_func(iterator); \
+ *it = array->get(0); \
+ ip += 5; \
+ } else { \
+ int jumpto = _code_ptr[ip + 4]; \
+ GD_ERR_BREAK(jumpto<0 || jumpto> _code_size); \
+ ip = jumpto; \
+ } \
+ } \
+ DISPATCH_OPCODE
+
+ OPCODE_ITERATE_BEGIN_PACKED_ARRAY(BYTE, uint8_t, get_byte_array, INT, int64_t, get_int);
+ OPCODE_ITERATE_BEGIN_PACKED_ARRAY(INT32, int32_t, get_int32_array, INT, int64_t, get_int);
+ OPCODE_ITERATE_BEGIN_PACKED_ARRAY(INT64, int64_t, get_int64_array, INT, int64_t, get_int);
+ OPCODE_ITERATE_BEGIN_PACKED_ARRAY(FLOAT32, float, get_float32_array, FLOAT, double, get_float);
+ OPCODE_ITERATE_BEGIN_PACKED_ARRAY(FLOAT64, double, get_float64_array, FLOAT, double, get_float);
+ OPCODE_ITERATE_BEGIN_PACKED_ARRAY(STRING, String, get_string_array, STRING, String, get_string);
+ OPCODE_ITERATE_BEGIN_PACKED_ARRAY(VECTOR2, Vector2, get_vector2_array, VECTOR2, Vector2, get_vector2);
+ OPCODE_ITERATE_BEGIN_PACKED_ARRAY(VECTOR3, Vector3, get_vector3_array, VECTOR3, Vector3, get_vector3);
+ OPCODE_ITERATE_BEGIN_PACKED_ARRAY(COLOR, Color, get_color_array, COLOR, Color, get_color);
+
+ OPCODE(OPCODE_ITERATE_BEGIN_OBJECT) {
+ CHECK_SPACE(4);
+
+ GET_INSTRUCTION_ARG(counter, 0);
+ GET_INSTRUCTION_ARG(container, 1);
+
+#ifdef DEBUG_ENABLED
+ bool freed = false;
+ Object *obj = container->get_validated_object_with_check(freed);
+ if (freed) {
+ err_text = "Trying to iterate on a previously freed object.";
+ OPCODE_BREAK;
+ } else if (!obj) {
+ err_text = "Trying to iterate on a null value.";
+ OPCODE_BREAK;
+ }
+#else
+ Object *obj = *VariantInternal::get_object(container);
+#endif
+ Array ref;
+ ref.push_back(*counter);
+ Variant vref;
+ VariantInternal::initialize(&vref, Variant::ARRAY);
+ *VariantInternal::get_array(&vref) = ref;
+
+ Variant **args = instruction_args; // Overriding an instruction argument, but we don't need access to that anymore.
+ args[0] = &vref;
+
+ Callable::CallError ce;
+ Variant has_next = obj->call(CoreStringNames::get_singleton()->_iter_init, (const Variant **)args, 1, ce);
+
+#ifdef DEBUG_ENABLED
+ if (ce.error != Callable::CallError::CALL_OK) {
+ err_text = vformat(R"(There was an error calling "_iter_next" on iterator object of type %s.)", *container);
+ OPCODE_BREAK;
+ }
+#endif
+ if (!has_next.booleanize()) {
+ int jumpto = _code_ptr[ip + 4];
+ GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+ ip = jumpto;
+ } else {
+ GET_INSTRUCTION_ARG(iterator, 2);
+ *iterator = obj->call(CoreStringNames::get_singleton()->_iter_get, (const Variant **)args, 1, ce);
+#ifdef DEBUG_ENABLED
+ if (ce.error != Callable::CallError::CALL_OK) {
+ err_text = vformat(R"(There was an error calling "_iter_get" on iterator object of type %s.)", *container);
+ OPCODE_BREAK;
+ }
+#endif
+
+ ip += 5; // Loop again.
+ }
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ITERATE) {
+ CHECK_SPACE(4);
+
+ GET_INSTRUCTION_ARG(counter, 0);
+ GET_INSTRUCTION_ARG(container, 1);
+
+ bool valid;
+ if (!container->iter_next(*counter, valid)) {
+#ifdef DEBUG_ENABLED
+ if (!valid) {
+ err_text = "Unable to iterate on object of type '" + Variant::get_type_name(container->get_type()) + "' (type changed since first iteration?).";
+ OPCODE_BREAK;
+ }
+#endif
+ int jumpto = _code_ptr[ip + 4];
+ GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+ ip = jumpto;
+ } else {
+ GET_INSTRUCTION_ARG(iterator, 2);
+
+ *iterator = container->iter_get(*counter, valid);
+#ifdef DEBUG_ENABLED
+ if (!valid) {
+ err_text = "Unable to obtain iterator object of type '" + Variant::get_type_name(container->get_type()) + "' (but was obtained on first iteration?).";
+ OPCODE_BREAK;
+ }
+#endif
+ ip += 5; //loop again
+ }
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ITERATE_INT) {
+ CHECK_SPACE(4);
+
+ GET_INSTRUCTION_ARG(counter, 0);
+ GET_INSTRUCTION_ARG(container, 1);
+
+ int64_t size = *VariantInternal::get_int(container);
+ int64_t *count = VariantInternal::get_int(counter);
+
+ (*count)++;
+
+ if (*count >= size) {
+ int jumpto = _code_ptr[ip + 4];
+ GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+ ip = jumpto;
+ } else {
+ GET_INSTRUCTION_ARG(iterator, 2);
+ *VariantInternal::get_int(iterator) = *count;
+
+ ip += 5; // Loop again.
+ }
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ITERATE_FLOAT) {
+ CHECK_SPACE(4);
+
+ GET_INSTRUCTION_ARG(counter, 0);
+ GET_INSTRUCTION_ARG(container, 1);
+
+ double size = *VariantInternal::get_float(container);
+ double *count = VariantInternal::get_float(counter);
+
+ (*count)++;
+
+ if (*count >= size) {
+ int jumpto = _code_ptr[ip + 4];
+ GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+ ip = jumpto;
+ } else {
+ GET_INSTRUCTION_ARG(iterator, 2);
+ *VariantInternal::get_float(iterator) = *count;
+
+ ip += 5; // Loop again.
+ }
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ITERATE_VECTOR2) {
+ CHECK_SPACE(4);
+
+ GET_INSTRUCTION_ARG(counter, 0);
+ GET_INSTRUCTION_ARG(container, 1);
+
+ const Vector2 *bounds = VariantInternal::get_vector2((const Variant *)container);
+ double *count = VariantInternal::get_float(counter);
+
+ (*count)++;
+
+ if (*count >= bounds->y) {
+ int jumpto = _code_ptr[ip + 4];
+ GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+ ip = jumpto;
+ } else {
+ GET_INSTRUCTION_ARG(iterator, 2);
+ *VariantInternal::get_float(iterator) = *count;
+
+ ip += 5; // Loop again.
+ }
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ITERATE_VECTOR2I) {
+ CHECK_SPACE(4);
+
+ GET_INSTRUCTION_ARG(counter, 0);
+ GET_INSTRUCTION_ARG(container, 1);
+
+ const Vector2i *bounds = VariantInternal::get_vector2i((const Variant *)container);
+ int64_t *count = VariantInternal::get_int(counter);
+
+ (*count)++;
+
+ if (*count >= bounds->y) {
+ int jumpto = _code_ptr[ip + 4];
+ GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+ ip = jumpto;
+ } else {
+ GET_INSTRUCTION_ARG(iterator, 2);
+ *VariantInternal::get_int(iterator) = *count;
+
+ ip += 5; // Loop again.
+ }
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ITERATE_VECTOR3) {
+ CHECK_SPACE(4);
+
+ GET_INSTRUCTION_ARG(counter, 0);
+ GET_INSTRUCTION_ARG(container, 1);
+
+ const Vector3 *bounds = VariantInternal::get_vector3((const Variant *)container);
+ double *count = VariantInternal::get_float(counter);
+
+ *count += bounds->z;
+
+ if ((bounds->z < 0 && *count <= bounds->y) || (bounds->z > 0 && *count >= bounds->y)) {
+ int jumpto = _code_ptr[ip + 4];
+ GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+ ip = jumpto;
+ } else {
+ GET_INSTRUCTION_ARG(iterator, 2);
+ *VariantInternal::get_float(iterator) = *count;
+
+ ip += 5; // Loop again.
+ }
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ITERATE_VECTOR3I) {
+ CHECK_SPACE(4);
+
+ GET_INSTRUCTION_ARG(counter, 0);
+ GET_INSTRUCTION_ARG(container, 1);
+
+ const Vector3i *bounds = VariantInternal::get_vector3i((const Variant *)container);
+ int64_t *count = VariantInternal::get_int(counter);
+
+ *count += bounds->z;
+
+ if ((bounds->z < 0 && *count <= bounds->y) || (bounds->z > 0 && *count >= bounds->y)) {
+ int jumpto = _code_ptr[ip + 4];
+ GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+ ip = jumpto;
+ } else {
+ GET_INSTRUCTION_ARG(iterator, 2);
+ *VariantInternal::get_int(iterator) = *count;
+
+ ip += 5; // Loop again.
+ }
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ITERATE_STRING) {
+ CHECK_SPACE(4);
+
+ GET_INSTRUCTION_ARG(counter, 0);
+ GET_INSTRUCTION_ARG(container, 1);
+
+ const String *str = VariantInternal::get_string((const Variant *)container);
+ int64_t *idx = VariantInternal::get_int(counter);
+ (*idx)++;
+
+ if (*idx >= str->length()) {
+ int jumpto = _code_ptr[ip + 4];
+ GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+ ip = jumpto;
+ } else {
+ GET_INSTRUCTION_ARG(iterator, 2);
+ *VariantInternal::get_string(iterator) = str->substr(*idx, 1);
+
+ ip += 5; // Loop again.
+ }
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ITERATE_DICTIONARY) {
+ CHECK_SPACE(4);
+
+ GET_INSTRUCTION_ARG(counter, 0);
+ GET_INSTRUCTION_ARG(container, 1);
+
+ const Dictionary *dict = VariantInternal::get_dictionary((const Variant *)container);
+ const Variant *next = dict->next(counter);
+
+ if (!next) {
+ int jumpto = _code_ptr[ip + 4];
+ GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+ ip = jumpto;
+ } else {
+ GET_INSTRUCTION_ARG(iterator, 2);
+ *counter = *next;
+ *iterator = *next;
+
+ ip += 5; // Loop again.
+ }
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ITERATE_ARRAY) {
+ CHECK_SPACE(4);
+
+ GET_INSTRUCTION_ARG(counter, 0);
+ GET_INSTRUCTION_ARG(container, 1);
+
+ const Array *array = VariantInternal::get_array((const Variant *)container);
+ int64_t *idx = VariantInternal::get_int(counter);
+ (*idx)++;
+
+ if (*idx >= array->size()) {
+ int jumpto = _code_ptr[ip + 4];
+ GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+ ip = jumpto;
+ } else {
+ GET_INSTRUCTION_ARG(iterator, 2);
+ *iterator = array->get(*idx);
+
+ ip += 5; // Loop again.
+ }
+ }
+ DISPATCH_OPCODE;
+
+#define OPCODE_ITERATE_PACKED_ARRAY(m_var_type, m_elem_type, m_get_func, m_ret_get_func) \
+ OPCODE(OPCODE_ITERATE_PACKED_##m_var_type##_ARRAY) { \
+ CHECK_SPACE(4); \
+ GET_INSTRUCTION_ARG(counter, 0); \
+ GET_INSTRUCTION_ARG(container, 1); \
+ const Vector<m_elem_type> *array = VariantInternal::m_get_func((const Variant *)container); \
+ int64_t *idx = VariantInternal::get_int(counter); \
+ (*idx)++; \
+ if (*idx >= array->size()) { \
+ int jumpto = _code_ptr[ip + 4]; \
+ GD_ERR_BREAK(jumpto<0 || jumpto> _code_size); \
+ ip = jumpto; \
+ } else { \
+ GET_INSTRUCTION_ARG(iterator, 2); \
+ *VariantInternal::m_ret_get_func(iterator) = array->get(*idx); \
+ ip += 5; \
+ } \
+ } \
+ DISPATCH_OPCODE
+
+ OPCODE_ITERATE_PACKED_ARRAY(BYTE, uint8_t, get_byte_array, get_int);
+ OPCODE_ITERATE_PACKED_ARRAY(INT32, int32_t, get_int32_array, get_int);
+ OPCODE_ITERATE_PACKED_ARRAY(INT64, int64_t, get_int64_array, get_int);
+ OPCODE_ITERATE_PACKED_ARRAY(FLOAT32, float, get_float32_array, get_float);
+ OPCODE_ITERATE_PACKED_ARRAY(FLOAT64, double, get_float64_array, get_float);
+ OPCODE_ITERATE_PACKED_ARRAY(STRING, String, get_string_array, get_string);
+ OPCODE_ITERATE_PACKED_ARRAY(VECTOR2, Vector2, get_vector2_array, get_vector2);
+ OPCODE_ITERATE_PACKED_ARRAY(VECTOR3, Vector3, get_vector3_array, get_vector3);
+ OPCODE_ITERATE_PACKED_ARRAY(COLOR, Color, get_color_array, get_color);
+
+ OPCODE(OPCODE_ITERATE_OBJECT) {
+ CHECK_SPACE(4);
+
+ GET_INSTRUCTION_ARG(counter, 0);
+ GET_INSTRUCTION_ARG(container, 1);
+
+#ifdef DEBUG_ENABLED
+ bool freed = false;
+ Object *obj = container->get_validated_object_with_check(freed);
+ if (freed) {
+ err_text = "Trying to iterate on a previously freed object.";
+ OPCODE_BREAK;
+ } else if (!obj) {
+ err_text = "Trying to iterate on a null value.";
+ OPCODE_BREAK;
+ }
+#else
+ Object *obj = *VariantInternal::get_object(container);
+#endif
+ Array ref;
+ ref.push_back(*counter);
+ Variant vref;
+ VariantInternal::initialize(&vref, Variant::ARRAY);
+ *VariantInternal::get_array(&vref) = ref;
+
+ Variant **args = instruction_args; // Overriding an instruction argument, but we don't need access to that anymore.
+ args[0] = &vref;
+
+ Callable::CallError ce;
+ Variant has_next = obj->call(CoreStringNames::get_singleton()->_iter_next, (const Variant **)args, 1, ce);
+
+#ifdef DEBUG_ENABLED
+ if (ce.error != Callable::CallError::CALL_OK) {
+ err_text = vformat(R"(There was an error calling "_iter_next" on iterator object of type %s.)", *container);
+ OPCODE_BREAK;
+ }
+#endif
+ if (!has_next.booleanize()) {
+ int jumpto = _code_ptr[ip + 4];
+ GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+ ip = jumpto;
+ } else {
+ GET_INSTRUCTION_ARG(iterator, 2);
+ *iterator = obj->call(CoreStringNames::get_singleton()->_iter_get, (const Variant **)args, 1, ce);
+#ifdef DEBUG_ENABLED
+ if (ce.error != Callable::CallError::CALL_OK) {
+ err_text = vformat(R"(There was an error calling "_iter_get" on iterator object of type %s.)", *container);
+ OPCODE_BREAK;
+ }
+#endif
+
+ ip += 5; // Loop again.
+ }
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_ASSERT) {
+ CHECK_SPACE(3);
+
+#ifdef DEBUG_ENABLED
+ GET_INSTRUCTION_ARG(test, 0);
+ bool result = test->booleanize();
+
+ if (!result) {
+ String message_str;
+ if (_code_ptr[ip + 2] != 0) {
+ GET_INSTRUCTION_ARG(message, 1);
+ message_str = *message;
+ }
+ if (message_str.is_empty()) {
+ err_text = "Assertion failed.";
+ } else {
+ err_text = "Assertion failed: " + message_str;
+ }
+ OPCODE_BREAK;
+ }
+
+#endif
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_BREAKPOINT) {
+#ifdef DEBUG_ENABLED
+ if (EngineDebugger::is_active()) {
+ GDScriptLanguage::get_singleton()->debug_break("Breakpoint Statement", true);
+ }
+#endif
+ ip += 1;
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_LINE) {
+ CHECK_SPACE(2);
+
+ line = _code_ptr[ip + 1];
+ ip += 2;
+
+ if (EngineDebugger::is_active()) {
+ // line
+ bool do_break = false;
+
+ if (EngineDebugger::get_script_debugger()->get_lines_left() > 0) {
+ if (EngineDebugger::get_script_debugger()->get_depth() <= 0) {
+ EngineDebugger::get_script_debugger()->set_lines_left(EngineDebugger::get_script_debugger()->get_lines_left() - 1);
+ }
+ if (EngineDebugger::get_script_debugger()->get_lines_left() <= 0) {
+ do_break = true;
+ }
+ }
+
+ if (EngineDebugger::get_script_debugger()->is_breakpoint(line, source)) {
+ do_break = true;
+ }
+
+ if (do_break) {
+ GDScriptLanguage::get_singleton()->debug_break("Breakpoint", true);
+ }
+
+ EngineDebugger::get_singleton()->line_poll();
+ }
+ }
+ DISPATCH_OPCODE;
+
+ OPCODE(OPCODE_END) {
+#ifdef DEBUG_ENABLED
+ exit_ok = true;
+#endif
+ OPCODE_BREAK;
+ }
+
+#if 0 // Enable for debugging.
+ default: {
+ err_text = "Illegal opcode " + itos(_code_ptr[ip]) + " at address " + itos(ip);
+ OPCODE_BREAK;
+ }
+#endif
+ }
+
+ OPCODES_END
+#ifdef DEBUG_ENABLED
+ if (exit_ok) {
+ OPCODE_OUT;
+ }
+ //error
+ // function, file, line, error, explanation
+ String err_file;
+ if (p_instance && ObjectDB::get_instance(p_instance->owner_id) != nullptr && p_instance->script->is_valid() && p_instance->script->path != "") {
+ err_file = p_instance->script->path;
+ } else if (script) {
+ err_file = script->path;
+ }
+ if (err_file == "") {
+ err_file = "<built-in>";
+ }
+ String err_func = name;
+ if (p_instance && ObjectDB::get_instance(p_instance->owner_id) != nullptr && p_instance->script->is_valid() && p_instance->script->name != "") {
+ err_func = p_instance->script->name + "." + err_func;
+ }
+ int err_line = line;
+ if (err_text == "") {
+ err_text = "Internal Script Error! - opcode #" + itos(last_opcode) + " (report please).";
+ }
+
+ if (!GDScriptLanguage::get_singleton()->debug_break(err_text, false)) {
+ // debugger break did not happen
+
+ _err_print_error(err_func.utf8().get_data(), err_file.utf8().get_data(), err_line, err_text.utf8().get_data(), ERR_HANDLER_SCRIPT);
+ }
+
+#endif
+ OPCODE_OUT;
+ }
+
+ OPCODES_OUT
+#ifdef DEBUG_ENABLED
+ if (GDScriptLanguage::get_singleton()->profiling) {
+ uint64_t time_taken = OS::get_singleton()->get_ticks_usec() - function_start_time;
+ profile.total_time += time_taken;
+ profile.self_time += time_taken - function_call_time;
+ profile.frame_total_time += time_taken;
+ profile.frame_self_time += time_taken - function_call_time;
+ GDScriptLanguage::get_singleton()->script_frame_time += time_taken - function_call_time;
+ }
+
+ // Check if this is the last time the function is resuming from await
+ // Will be true if never awaited as well
+ // When it's the last resume it will postpone the exit from stack,
+ // so the debugger knows which function triggered the resume of the next function (if any)
+ if (!p_state || awaited) {
+ if (EngineDebugger::is_active()) {
+ GDScriptLanguage::get_singleton()->exit_function();
+ }
+#endif
+
+ if (_stack_size) {
+ //free stack
+ for (int i = 0; i < _stack_size; i++) {
+ stack[i].~Variant();
+ }
+ }
+
+#ifdef DEBUG_ENABLED
+ }
+#endif
+
+ return retvalue;
+}
diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp
index 105facd9d0..ad41b60a4e 100644
--- a/modules/gdscript/gdscript_warning.cpp
+++ b/modules/gdscript/gdscript_warning.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,7 +30,7 @@
#include "gdscript_warning.h"
-#include "core/variant.h"
+#include "core/variant/variant.h"
#ifdef DEBUG_ENABLED
diff --git a/modules/gdscript/gdscript_warning.h b/modules/gdscript/gdscript_warning.h
index e183d6f302..4b295b5eb8 100644
--- a/modules/gdscript/gdscript_warning.h
+++ b/modules/gdscript/gdscript_warning.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,8 +33,8 @@
#ifdef DEBUG_ENABLED
-#include "core/ustring.h"
-#include "core/vector.h"
+#include "core/string/ustring.h"
+#include "core/templates/vector.h"
class GDScriptWarning {
public:
diff --git a/modules/gdscript/icons/GDScript.svg b/modules/gdscript/icons/GDScript.svg
index 953bb9ae9e..aa59125ea9 100644
--- a/modules/gdscript/icons/GDScript.svg
+++ b/modules/gdscript/icons/GDScript.svg
@@ -1,5 +1 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1036.4)">
-<path transform="translate(0 1036.4)" d="m7 1l-0.56445 2.2578a5 5 0 0 0 -0.68945 0.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941a5 5 0 0 0 -0.28516 0.68555l-2.2539 0.5625v2l2.2578 0.56445a5 5 0 0 0 0.2793 0.6875l-1.1934 1.9902 1.4141 1.4141 1.9941-1.1953a5 5 0 0 0 0.68555 0.28516l0.5625 2.2539h2l0.56445-2.2578a5 5 0 0 0 0.6875 -0.2793l1.9902 1.1934 1.4141-1.4141-1.1953-1.9941a5 5 0 0 0 0.28516 -0.68555l2.2539-0.5625v-2l-2.2578-0.56445a5 5 0 0 0 -0.2793 -0.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953a5 5 0 0 0 -0.68555 -0.28516l-0.5625-2.2539h-2zm1 5a2 2 0 0 1 2 2 2 2 0 0 1 -2 2 2 2 0 0 1 -2 -2 2 2 0 0 1 2 -2z" fill="#e0e0e0"/>
-</g>
-</svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1-.56445 2.2578a5 5 0 0 0 -.68945.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941a5 5 0 0 0 -.28516.68555l-2.2539.5625v2l2.2578.56445a5 5 0 0 0 .2793.6875l-1.1934 1.9902 1.4141 1.4141 1.9941-1.1953a5 5 0 0 0 .68555.28516l.5625 2.2539h2l.56445-2.2578a5 5 0 0 0 .6875-.2793l1.9902 1.1934 1.4141-1.4141-1.1953-1.9941a5 5 0 0 0 .28516-.68555l2.2539-.5625v-2l-2.2578-.56445a5 5 0 0 0 -.2793-.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953a5 5 0 0 0 -.68555-.28516l-.5625-2.2539h-2zm1 5a2 2 0 0 1 2 2 2 2 0 0 1 -2 2 2 2 0 0 1 -2-2 2 2 0 0 1 2-2z" fill="#e0e0e0"/></svg>
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp
index 668dfd4835..e63b6ab20e 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.cpp
+++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -147,7 +147,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
r_symbol.script_path = path;
r_symbol.children.clear();
r_symbol.name = p_class->identifier != nullptr ? String(p_class->identifier->name) : String();
- if (r_symbol.name.empty()) {
+ if (r_symbol.name.is_empty()) {
r_symbol.name = path.get_file();
}
r_symbol.kind = lsp::SymbolKind::Class;
@@ -215,9 +215,9 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
String value_text;
if (default_value.get_type() == Variant::OBJECT) {
RES res = default_value;
- if (res.is_valid() && !res->get_path().empty()) {
+ if (res.is_valid() && !res->get_path().is_empty()) {
value_text = "preload(\"" + res->get_path() + "\")";
- if (symbol.documentation.empty()) {
+ if (symbol.documentation.is_empty()) {
if (Map<String, ExtendGDScriptParser *>::Element *S = GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts.find(res->get_path())) {
symbol.documentation = S->get()->class_symbol.documentation;
}
@@ -228,7 +228,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
} else {
value_text = JSON::print(default_value);
}
- if (!value_text.empty()) {
+ if (!value_text.is_empty()) {
symbol.detail += " = " + value_text;
}
@@ -453,7 +453,7 @@ String ExtendGDScriptParser::get_text_for_lookup_symbol(const lsp::Position &p_c
String line = lines[i];
String first_part = line.substr(0, p_cursor.character);
String last_part = line.substr(p_cursor.character + 1, lines[i].length());
- if (!p_symbol.empty()) {
+ if (!p_symbol.is_empty()) {
String left_cursor_text;
for (int c = p_cursor.character - 1; c >= 0; c--) {
left_cursor_text = line.substr(c, p_cursor.character - c);
@@ -589,7 +589,7 @@ const lsp::DocumentSymbol *ExtendGDScriptParser::get_symbol_defined_at_line(int
}
const lsp::DocumentSymbol *ExtendGDScriptParser::get_member_symbol(const String &p_name, const String &p_subclass) const {
- if (p_subclass.empty()) {
+ if (p_subclass.is_empty()) {
const lsp::DocumentSymbol *const *ptr = members.getptr(p_name);
if (ptr) {
return *ptr;
@@ -611,7 +611,7 @@ const List<lsp::DocumentLink> &ExtendGDScriptParser::get_document_links() const
}
const Array &ExtendGDScriptParser::get_member_completions() {
- if (member_completions.empty()) {
+ if (member_completions.is_empty()) {
const String *name = members.next(nullptr);
while (name) {
const lsp::DocumentSymbol *symbol = members.get(*name);
@@ -723,8 +723,8 @@ Dictionary ExtendGDScriptParser::dump_class_api(const GDScriptParser::ClassNode
} break;
case ClassNode::Member::ENUM: {
Dictionary enum_dict;
- for (int j = 0; j < m.m_enum->values.size(); i++) {
- enum_dict[m.m_enum->values[i].identifier->name] = m.m_enum->values[i].value;
+ for (int j = 0; j < m.m_enum->values.size(); j++) {
+ enum_dict[m.m_enum->values[j].identifier->name] = m.m_enum->values[j].value;
}
Dictionary api;
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.h b/modules/gdscript/language_server/gdscript_extend_parser.h
index 0c031d7883..28b9b3c82a 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.h
+++ b/modules/gdscript/language_server/gdscript_extend_parser.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,7 +32,7 @@
#define GDSCRIPT_EXTEND_PARSER_H
#include "../gdscript_parser.h"
-#include "core/variant.h"
+#include "core/variant/variant.h"
#include "lsp.hpp"
#ifndef LINE_NUMBER_TO_INDEX
diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp
index 2a67d2ff4f..5e3d6213d3 100644
--- a/modules/gdscript/language_server/gdscript_language_protocol.cpp
+++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,9 +30,10 @@
#include "gdscript_language_protocol.h"
+#include "core/config/project_settings.h"
#include "core/io/json.h"
#include "core/os/copymem.h"
-#include "core/project_settings.h"
+#include "editor/doc_tools.h"
#include "editor/editor_log.h"
#include "editor/editor_node.h"
@@ -95,7 +96,7 @@ Error GDScriptLanguageProtocol::LSPeer::handle_data() {
// Response
String output = GDScriptLanguageProtocol::get_singleton()->process_message(msg);
- if (!output.empty()) {
+ if (!output.is_empty()) {
res_queue.push_back(output.utf8());
}
}
@@ -104,7 +105,7 @@ Error GDScriptLanguageProtocol::LSPeer::handle_data() {
Error GDScriptLanguageProtocol::LSPeer::send_data() {
int sent = 0;
- if (!res_queue.empty()) {
+ if (!res_queue.is_empty()) {
CharString c_res = res_queue[0];
if (res_sent < c_res.size()) {
Error err = connection->put_partial_data((const uint8_t *)c_res.get_data() + res_sent, c_res.size() - res_sent - 1, sent);
@@ -140,7 +141,7 @@ void GDScriptLanguageProtocol::on_client_disconnected(const int &p_client_id) {
String GDScriptLanguageProtocol::process_message(const String &p_text) {
String ret = process_string(p_text);
- if (ret.empty()) {
+ if (ret.is_empty()) {
return ret;
} else {
return format_output(ret);
@@ -212,7 +213,7 @@ Dictionary GDScriptLanguageProtocol::initialize(const Dictionary &p_params) {
void GDScriptLanguageProtocol::initialized(const Variant &p_params) {
lsp::GodotCapabilities capabilities;
- DocData *doc = EditorHelp::get_doc_data();
+ DocTools *doc = EditorHelp::get_doc_data();
for (Map<String, DocData::ClassDoc>::Element *E = doc->class_list.front(); E; E = E->next()) {
lsp::GodotNativeClassInfo gdclass;
gdclass.name = E->get().name;
diff --git a/modules/gdscript/language_server/gdscript_language_protocol.h b/modules/gdscript/language_server/gdscript_language_protocol.h
index cf5242e8c5..8b08ae0655 100644
--- a/modules/gdscript/language_server/gdscript_language_protocol.h
+++ b/modules/gdscript/language_server/gdscript_language_protocol.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/language_server/gdscript_language_server.cpp b/modules/gdscript/language_server/gdscript_language_server.cpp
index 3387d262f8..12ed56a568 100644
--- a/modules/gdscript/language_server/gdscript_language_server.cpp
+++ b/modules/gdscript/language_server/gdscript_language_server.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -36,7 +36,6 @@
#include "editor/editor_node.h"
GDScriptLanguageServer::GDScriptLanguageServer() {
- thread = nullptr;
thread_running = false;
started = false;
@@ -87,9 +86,8 @@ void GDScriptLanguageServer::start() {
if (protocol.start(port, IP_Address("127.0.0.1")) == OK) {
EditorNode::get_log()->add_message("--- GDScript language server started ---", EditorLog::MSG_TYPE_EDITOR);
if (use_thread) {
- ERR_FAIL_COND(thread != nullptr);
thread_running = true;
- thread = Thread::create(GDScriptLanguageServer::thread_main, this);
+ thread.start(GDScriptLanguageServer::thread_main, this);
}
set_process_internal(!use_thread);
started = true;
@@ -98,11 +96,9 @@ void GDScriptLanguageServer::start() {
void GDScriptLanguageServer::stop() {
if (use_thread) {
- ERR_FAIL_COND(nullptr == thread);
+ ERR_FAIL_COND(!thread.is_started());
thread_running = false;
- Thread::wait_to_finish(thread);
- memdelete(thread);
- thread = nullptr;
+ thread.wait_to_finish();
}
protocol.stop();
started = false;
diff --git a/modules/gdscript/language_server/gdscript_language_server.h b/modules/gdscript/language_server/gdscript_language_server.h
index 228d29bf42..7b7837a463 100644
--- a/modules/gdscript/language_server/gdscript_language_server.h
+++ b/modules/gdscript/language_server/gdscript_language_server.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -40,7 +40,7 @@ class GDScriptLanguageServer : public EditorPlugin {
GDScriptLanguageProtocol protocol;
- Thread *thread;
+ Thread thread;
bool thread_running;
bool started;
bool use_thread;
diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp
index c6fe3169dc..9f2373bf56 100644
--- a/modules/gdscript/language_server/gdscript_text_document.cpp
+++ b/modules/gdscript/language_server/gdscript_text_document.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -147,7 +147,7 @@ Array GDScriptTextDocument::completion(const Dictionary &p_params) {
List<ScriptCodeCompletionOption> options;
GDScriptLanguageProtocol::get_singleton()->get_workspace()->completion(params, &options);
- if (!options.empty()) {
+ if (!options.is_empty()) {
int i = 0;
arr.resize(options.size());
@@ -257,7 +257,7 @@ Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) {
if ((item.kind == lsp::CompletionItemKind::Method || item.kind == lsp::CompletionItemKind::Function) && !item.label.ends_with("):")) {
item.insertText = item.label + "(";
- if (symbol && symbol->children.empty()) {
+ if (symbol && symbol->children.is_empty()) {
item.insertText += ")";
}
} else if (item.kind == lsp::CompletionItemKind::Event) {
@@ -341,7 +341,7 @@ Variant GDScriptTextDocument::declaration(const Dictionary &p_params) {
params.load(p_params);
List<const lsp::DocumentSymbol *> symbols;
Array arr = this->find_symbols(params, symbols);
- if (arr.empty() && !symbols.empty() && !symbols.front()->get()->native_class.empty()) { // Find a native symbol
+ if (arr.is_empty() && !symbols.is_empty() && !symbols.front()->get()->native_class.is_empty()) { // Find a native symbol
const lsp::DocumentSymbol *symbol = symbols.front()->get();
if (GDScriptLanguageProtocol::get_singleton()->is_goto_native_symbols_enabled()) {
String id;
@@ -425,7 +425,7 @@ Array GDScriptTextDocument::find_symbols(const lsp::TextDocumentPositionParams &
GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_related_symbols(p_location, list);
for (List<const lsp::DocumentSymbol *>::Element *E = list.front(); E; E = E->next()) {
if (const lsp::DocumentSymbol *s = E->get()) {
- if (!s->uri.empty()) {
+ if (!s->uri.is_empty()) {
lsp::Location location;
location.uri = s->uri;
location.range = s->range;
diff --git a/modules/gdscript/language_server/gdscript_text_document.h b/modules/gdscript/language_server/gdscript_text_document.h
index b2fd0c31f9..792e601bc1 100644
--- a/modules/gdscript/language_server/gdscript_text_document.h
+++ b/modules/gdscript/language_server/gdscript_text_document.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,8 +31,8 @@
#ifndef GDSCRIPT_TEXT_DOCUMENT_H
#define GDSCRIPT_TEXT_DOCUMENT_H
+#include "core/object/reference.h"
#include "core/os/file_access.h"
-#include "core/reference.h"
#include "lsp.hpp"
class GDScriptTextDocument : public Reference {
diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp
index 776193e37c..69cad1a335 100644
--- a/modules/gdscript/language_server/gdscript_workspace.cpp
+++ b/modules/gdscript/language_server/gdscript_workspace.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,8 +32,9 @@
#include "../gdscript.h"
#include "../gdscript_parser.h"
-#include "core/project_settings.h"
-#include "core/script_language.h"
+#include "core/config/project_settings.h"
+#include "core/object/script_language.h"
+#include "editor/doc_tools.h"
#include "editor/editor_file_system.h"
#include "editor/editor_help.h"
#include "editor/editor_node.h"
@@ -79,7 +80,7 @@ const lsp::DocumentSymbol *GDScriptWorkspace::get_native_symbol(const String &p_
if (const Map<StringName, lsp::DocumentSymbol>::Element *E = native_symbols.find(class_name)) {
const lsp::DocumentSymbol &class_symbol = E->value();
- if (p_member.empty()) {
+ if (p_member.is_empty()) {
return &class_symbol;
} else {
for (int i = 0; i < class_symbol.children.size(); i++) {
@@ -170,7 +171,7 @@ ExtendGDScriptParser *GDScriptWorkspace::get_parse_result(const String &p_path)
Array GDScriptWorkspace::symbol(const Dictionary &p_params) {
String query = p_params["query"];
Array arr;
- if (!query.empty()) {
+ if (!query.is_empty()) {
for (Map<String, ExtendGDScriptParser *>::Element *E = scripts.front(); E; E = E->next()) {
Vector<lsp::DocumentedSymbolInformation> script_symbols;
E->get()->get_symbols().symbol_tree_as_list(E->key(), script_symbols);
@@ -189,7 +190,7 @@ Error GDScriptWorkspace::initialize() {
return OK;
}
- DocData *doc = EditorHelp::get_doc_data();
+ DocTools *doc = EditorHelp::get_doc_data();
for (Map<String, DocData::ClassDoc>::Element *E = doc->class_list.front(); E; E = E->next()) {
const DocData::ClassDoc &class_data = E->value();
lsp::DocumentSymbol class_symbol;
@@ -198,7 +199,7 @@ Error GDScriptWorkspace::initialize() {
class_symbol.native_class = class_name;
class_symbol.kind = lsp::SymbolKind::Class;
class_symbol.detail = String("<Native> class ") + class_name;
- if (!class_data.inherits.empty()) {
+ if (!class_data.inherits.is_empty()) {
class_symbol.detail += " extends " + class_data.inherits;
}
class_symbol.documentation = class_data.brief_description + "\n" + class_data.description;
@@ -262,7 +263,7 @@ Error GDScriptWorkspace::initialize() {
symbol_arg.kind = lsp::SymbolKind::Variable;
symbol_arg.detail = arg.type;
- if (!arg_default_value_started && !arg.default_value.empty()) {
+ if (!arg_default_value_started && !arg.default_value.is_empty()) {
arg_default_value_started = true;
}
String arg_str = arg.name + ": " + arg.type;
@@ -277,11 +278,11 @@ Error GDScriptWorkspace::initialize() {
symbol.children.push_back(symbol_arg);
}
if (data.qualifiers.find("vararg") != -1) {
- params += params.empty() ? "..." : ", ...";
+ params += params.is_empty() ? "..." : ", ...";
}
String return_type = data.return_type;
- if (return_type.empty()) {
+ if (return_type.is_empty()) {
return_type = "void";
}
symbol.detail = "func " + class_name + "." + data.name + "(" + params + ") -> " + return_type;
@@ -349,7 +350,7 @@ Error GDScriptWorkspace::parse_local_script(const String &p_path) {
String GDScriptWorkspace::get_file_path(const String &p_uri) const {
String path = p_uri;
path = path.replace(root_uri + "/", "res://");
- path = path.http_unescape();
+ path = path.uri_decode();
return path;
}
@@ -447,13 +448,13 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu
}
lsp::Position pos = p_doc_pos.position;
- if (symbol_identifier.empty()) {
+ if (symbol_identifier.is_empty()) {
Vector2i offset;
symbol_identifier = parser->get_identifier_under_position(p_doc_pos.position, offset);
pos.character += offset.y;
}
- if (!symbol_identifier.empty()) {
+ if (!symbol_identifier.is_empty()) {
if (ScriptServer::is_global_class(symbol_identifier)) {
String class_path = ScriptServer::get_global_class_path(symbol_identifier);
symbol = get_script_symbol(class_path);
@@ -473,7 +474,7 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu
} else {
String member = ret.class_member;
- if (member.empty() && symbol_identifier != ret.class_name) {
+ if (member.is_empty() && symbol_identifier != ret.class_name) {
member = symbol_identifier;
}
symbol = get_native_symbol(ret.class_name, member);
@@ -528,7 +529,7 @@ void GDScriptWorkspace::resolve_related_symbols(const lsp::TextDocumentPositionP
const lsp::DocumentSymbol *GDScriptWorkspace::resolve_native_symbol(const lsp::NativeSymbolInspectParams &p_params) {
if (Map<StringName, lsp::DocumentSymbol>::Element *E = native_symbols.find(p_params.native_class)) {
const lsp::DocumentSymbol &symbol = E->get();
- if (p_params.symbol_name.empty() || p_params.symbol_name == symbol.name) {
+ if (p_params.symbol_name.is_empty() || p_params.symbol_name == symbol.name) {
return &symbol;
}
diff --git a/modules/gdscript/language_server/gdscript_workspace.h b/modules/gdscript/language_server/gdscript_workspace.h
index e45b06747d..7fd8bfcf20 100644
--- a/modules/gdscript/language_server/gdscript_workspace.h
+++ b/modules/gdscript/language_server/gdscript_workspace.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,7 +32,7 @@
#define GDSCRIPT_WORKSPACE_H
#include "../gdscript_parser.h"
-#include "core/variant.h"
+#include "core/variant/variant.h"
#include "editor/editor_file_system.h"
#include "gdscript_extend_parser.h"
#include "lsp.hpp"
diff --git a/modules/gdscript/language_server/lsp.hpp b/modules/gdscript/language_server/lsp.hpp
index cf27a1578c..6a913edbbf 100644
--- a/modules/gdscript/language_server/lsp.hpp
+++ b/modules/gdscript/language_server/lsp.hpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,9 +31,9 @@
#ifndef GODOT_LSP_H
#define GODOT_LSP_H
-#include "core/class_db.h"
-#include "core/list.h"
-#include "editor/doc_data.h"
+#include "core/doc_data.h"
+#include "core/object/class_db.h"
+#include "core/templates/list.h"
namespace lsp {
@@ -687,7 +687,7 @@ struct Diagnostic {
dict["severity"] = severity;
dict["message"] = message;
dict["source"] = source;
- if (!relatedInformation.empty()) {
+ if (!relatedInformation.is_empty()) {
Array arr;
arr.resize(relatedInformation.size());
for (int i = 0; i < relatedInformation.size(); i++) {
@@ -1191,7 +1191,7 @@ struct DocumentSymbol {
void symbol_tree_as_list(const String &p_uri, Vector<DocumentedSymbolInformation> &r_list, const String &p_container = "", bool p_join_name = false) const {
DocumentedSymbolInformation si;
- if (p_join_name && !p_container.empty()) {
+ if (p_join_name && !p_container.is_empty()) {
si.name = p_container + ">" + name;
} else {
si.name = name;
@@ -1781,7 +1781,6 @@ static String marked_documentation(const String &p_bbcode) {
}
return markdown;
}
-
} // namespace lsp
#endif
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index da4cbe34c7..e90475a60e 100644
--- a/modules/gdscript/register_types.cpp
+++ b/modules/gdscript/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -38,6 +38,7 @@
#include "gdscript_analyzer.h"
#include "gdscript_cache.h"
#include "gdscript_tokenizer.h"
+#include "gdscript_utility_functions.h"
#ifdef TESTS_ENABLED
#include "tests/test_gdscript.h"
@@ -59,7 +60,7 @@ GDScriptCache *gdscript_cache = nullptr;
#include "editor/gdscript_translation_parser_plugin.h"
#ifndef GDSCRIPT_NO_LSP
-#include "core/engine.h"
+#include "core/config/engine.h"
#include "language_server/gdscript_language_server.h"
#endif // !GDSCRIPT_NO_LSP
@@ -112,7 +113,6 @@ static void _editor_init() {
void register_gdscript_types() {
ClassDB::register_class<GDScript>();
- ClassDB::register_virtual_class<GDScriptFunctionState>();
script_language_gd = memnew(GDScriptLanguage);
ScriptServer::register_language(script_language_gd);
@@ -131,6 +131,8 @@ void register_gdscript_types() {
gdscript_translation_parser_plugin.instance();
EditorTranslationParser::get_singleton()->add_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD);
#endif // TOOLS_ENABLED
+
+ GDScriptUtilityFunctions::register_functions();
}
void unregister_gdscript_types() {
@@ -157,6 +159,7 @@ void unregister_gdscript_types() {
GDScriptParser::cleanup();
GDScriptAnalyzer::cleanup();
+ GDScriptUtilityFunctions::unregister_functions();
}
#ifdef TESTS_ENABLED
diff --git a/modules/gdscript/register_types.h b/modules/gdscript/register_types.h
index 18e57c1211..ce1c03d1d0 100644
--- a/modules/gdscript/register_types.h
+++ b/modules/gdscript/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp
index 68d9984b43..898ac653f5 100644
--- a/modules/gdscript/tests/test_gdscript.cpp
+++ b/modules/gdscript/tests/test_gdscript.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,10 +30,13 @@
#include "test_gdscript.h"
+#include "core/config/project_settings.h"
+#include "core/io/file_access_pack.h"
#include "core/os/file_access.h"
#include "core/os/main_loop.h"
#include "core/os/os.h"
-#include "core/string_builder.h"
+#include "core/string/string_builder.h"
+#include "scene/resources/packed_scene.h"
#include "modules/gdscript/gdscript_analyzer.h"
#include "modules/gdscript/gdscript_compiler.h"
@@ -179,10 +182,64 @@ static void test_compiler(const String &p_code, const String &p_script_path, con
}
}
+void init_autoloads() {
+ Map<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
+
+ // First pass, add the constants so they exist before any script is loaded.
+ for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) {
+ const ProjectSettings::AutoloadInfo &info = E->get();
+
+ if (info.is_singleton) {
+ for (int i = 0; i < ScriptServer::get_language_count(); i++) {
+ ScriptServer::get_language(i)->add_global_constant(info.name, Variant());
+ }
+ }
+ }
+
+ // Second pass, load into global constants.
+ for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) {
+ const ProjectSettings::AutoloadInfo &info = E->get();
+
+ if (!info.is_singleton) {
+ // Skip non-singletons since we don't have a scene tree here anyway.
+ continue;
+ }
+
+ RES res = ResourceLoader::load(info.path);
+ ERR_CONTINUE_MSG(res.is_null(), "Can't autoload: " + info.path);
+ Node *n = nullptr;
+ if (res->is_class("PackedScene")) {
+ Ref<PackedScene> ps = res;
+ n = ps->instance();
+ } else if (res->is_class("Script")) {
+ Ref<Script> script_res = res;
+ StringName ibt = script_res->get_instance_base_type();
+ bool valid_type = ClassDB::is_parent_class(ibt, "Node");
+ ERR_CONTINUE_MSG(!valid_type, "Script does not inherit a Node: " + info.path);
+
+ Object *obj = ClassDB::instance(ibt);
+
+ ERR_CONTINUE_MSG(obj == nullptr,
+ "Cannot instance script for autoload, expected 'Node' inheritance, got: " +
+ String(ibt));
+
+ n = Object::cast_to<Node>(obj);
+ n->set_script(script_res);
+ }
+
+ ERR_CONTINUE_MSG(!n, "Path in autoload not a node or script: " + info.path);
+ n->set_name(info.name);
+
+ for (int i = 0; i < ScriptServer::get_language_count(); i++) {
+ ScriptServer::get_language(i)->add_global_constant(info.name, n);
+ }
+ }
+}
+
void test(TestType p_type) {
List<String> cmdlargs = OS::get_singleton()->get_cmdline_args();
- if (cmdlargs.empty()) {
+ if (cmdlargs.is_empty()) {
return;
}
@@ -195,6 +252,21 @@ void test(TestType p_type) {
FileAccessRef fa = FileAccess::open(test, FileAccess::READ);
ERR_FAIL_COND_MSG(!fa, "Could not open file: " + test);
+ // Init PackedData since it's used by ProjectSettings.
+ PackedData *packed_data = memnew(PackedData);
+
+ // Setup project settings since it's needed by the languages to get the global scripts.
+ // This also sets up the base resource path.
+ Error err = ProjectSettings::get_singleton()->setup(fa->get_path_absolute().get_base_dir(), String(), true);
+ if (err) {
+ print_line("Could not load project settings.");
+ // Keep going since some scripts still work without this.
+ }
+
+ // Initialize the language for the test routine.
+ ScriptServer::init_languages();
+ init_autoloads();
+
Vector<uint8_t> buf;
int flen = fa->get_len();
buf.resize(fa->get_len() + 1);
@@ -226,6 +298,9 @@ void test(TestType p_type) {
case TEST_BYTECODE:
print_line("Not implemented.");
}
-}
+ // Destroy stuff we set up earlier.
+ ScriptServer::finish_languages();
+ memdelete(packed_data);
+}
} // namespace TestGDScript
diff --git a/modules/gdscript/tests/test_gdscript.h b/modules/gdscript/tests/test_gdscript.h
index 5aa962dcf8..bbda46cdad 100644
--- a/modules/gdscript/tests/test_gdscript.h
+++ b/modules/gdscript/tests/test_gdscript.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -41,7 +41,6 @@ enum TestType {
};
void test(TestType p_type);
-
} // namespace TestGDScript
#endif // TEST_GDSCRIPT_H
diff --git a/modules/glslang/SCsub b/modules/glslang/SCsub
index c1d23a138b..182272ffc7 100644
--- a/modules/glslang/SCsub
+++ b/modules/glslang/SCsub
@@ -6,9 +6,13 @@ Import("env_modules")
env_glslang = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_glslang"]:
thirdparty_dir = "#thirdparty/glslang/"
thirdparty_sources = [
+ "glslang/CInterface/glslang_c_interface.cpp",
"glslang/MachineIndependent/RemoveTree.cpp",
"glslang/MachineIndependent/ParseHelper.cpp",
"glslang/MachineIndependent/iomapper.cpp",
@@ -30,7 +34,6 @@ if env["builtin_glslang"]:
"glslang/MachineIndependent/intermOut.cpp",
"glslang/MachineIndependent/SymbolTable.cpp",
"glslang/MachineIndependent/glslang_tab.cpp",
- "glslang/MachineIndependent/pch.cpp",
"glslang/MachineIndependent/Versions.cpp",
"glslang/MachineIndependent/ShaderLang.cpp",
"glslang/MachineIndependent/parseConst.cpp",
@@ -40,6 +43,7 @@ if env["builtin_glslang"]:
"glslang/GenericCodeGen/Link.cpp",
"glslang/GenericCodeGen/CodeGen.cpp",
"OGLCompilersDLL/InitializeDll.cpp",
+ "SPIRV/CInterface/spirv_c_interface.cpp",
"SPIRV/InReadableOrder.cpp",
"SPIRV/GlslangToSpv.cpp",
"SPIRV/SpvBuilder.cpp",
@@ -49,6 +53,7 @@ if env["builtin_glslang"]:
"SPIRV/SPVRemapper.cpp",
"SPIRV/SpvPostProcess.cpp",
"SPIRV/Logger.cpp",
+ "StandAlone/ResourceLimits.cpp",
]
if env["platform"] == "windows":
@@ -64,9 +69,20 @@ if env["builtin_glslang"]:
else:
env_glslang.Prepend(CPPPATH=[thirdparty_dir])
+ env_glslang.Append(CPPDEFINES=["ENABLE_OPT=0"])
+
env_thirdparty = env_glslang.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
+
+# Godot source files
+
+module_obj = []
+
+env_glslang.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-# Godot's own source files
-env_glslang.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/glslang/register_types.cpp b/modules/glslang/register_types.cpp
index dd28c4ad4a..545aa68747 100644
--- a/modules/glslang/register_types.cpp
+++ b/modules/glslang/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,115 +33,10 @@
#include "servers/rendering/rendering_device.h"
#include <SPIRV/GlslangToSpv.h>
+#include <StandAlone/ResourceLimits.h>
#include <glslang/Include/Types.h>
#include <glslang/Public/ShaderLang.h>
-static const TBuiltInResource default_builtin_resource = {
- /*maxLights*/ 32,
- /*maxClipPlanes*/ 6,
- /*maxTextureUnits*/ 32,
- /*maxTextureCoords*/ 32,
- /*maxVertexAttribs*/ 64,
- /*maxVertexUniformComponents*/ 4096,
- /*maxVaryingFloats*/ 64,
- /*maxVertexTextureImageUnits*/ 32,
- /*maxCombinedTextureImageUnits*/ 80,
- /*maxTextureImageUnits*/ 32,
- /*maxFragmentUniformComponents*/ 4096,
- /*maxDrawBuffers*/ 32,
- /*maxVertexUniformVectors*/ 128,
- /*maxVaryingVectors*/ 8,
- /*maxFragmentUniformVectors*/ 16,
- /*maxVertexOutputVectors*/ 16,
- /*maxFragmentInputVectors*/ 15,
- /*minProgramTexelOffset*/ -8,
- /*maxProgramTexelOffset*/ 7,
- /*maxClipDistances*/ 8,
- /*maxComputeWorkGroupCountX*/ 65535,
- /*maxComputeWorkGroupCountY*/ 65535,
- /*maxComputeWorkGroupCountZ*/ 65535,
- /*maxComputeWorkGroupSizeX*/ 1024,
- /*maxComputeWorkGroupSizeY*/ 1024,
- /*maxComputeWorkGroupSizeZ*/ 64,
- /*maxComputeUniformComponents*/ 1024,
- /*maxComputeTextureImageUnits*/ 16,
- /*maxComputeImageUniforms*/ 8,
- /*maxComputeAtomicCounters*/ 8,
- /*maxComputeAtomicCounterBuffers*/ 1,
- /*maxVaryingComponents*/ 60,
- /*maxVertexOutputComponents*/ 64,
- /*maxGeometryInputComponents*/ 64,
- /*maxGeometryOutputComponents*/ 128,
- /*maxFragmentInputComponents*/ 128,
- /*maxImageUnits*/ 8,
- /*maxCombinedImageUnitsAndFragmentOutputs*/ 8,
- /*maxCombinedShaderOutputResources*/ 8,
- /*maxImageSamples*/ 0,
- /*maxVertexImageUniforms*/ 0,
- /*maxTessControlImageUniforms*/ 0,
- /*maxTessEvaluationImageUniforms*/ 0,
- /*maxGeometryImageUniforms*/ 0,
- /*maxFragmentImageUniforms*/ 8,
- /*maxCombinedImageUniforms*/ 8,
- /*maxGeometryTextureImageUnits*/ 16,
- /*maxGeometryOutputVertices*/ 256,
- /*maxGeometryTotalOutputComponents*/ 1024,
- /*maxGeometryUniformComponents*/ 1024,
- /*maxGeometryVaryingComponents*/ 64,
- /*maxTessControlInputComponents*/ 128,
- /*maxTessControlOutputComponents*/ 128,
- /*maxTessControlTextureImageUnits*/ 16,
- /*maxTessControlUniformComponents*/ 1024,
- /*maxTessControlTotalOutputComponents*/ 4096,
- /*maxTessEvaluationInputComponents*/ 128,
- /*maxTessEvaluationOutputComponents*/ 128,
- /*maxTessEvaluationTextureImageUnits*/ 16,
- /*maxTessEvaluationUniformComponents*/ 1024,
- /*maxTessPatchComponents*/ 120,
- /*maxPatchVertices*/ 32,
- /*maxTessGenLevel*/ 64,
- /*maxViewports*/ 16,
- /*maxVertexAtomicCounters*/ 0,
- /*maxTessControlAtomicCounters*/ 0,
- /*maxTessEvaluationAtomicCounters*/ 0,
- /*maxGeometryAtomicCounters*/ 0,
- /*maxFragmentAtomicCounters*/ 8,
- /*maxCombinedAtomicCounters*/ 8,
- /*maxAtomicCounterBindings*/ 1,
- /*maxVertexAtomicCounterBuffers*/ 0,
- /*maxTessControlAtomicCounterBuffers*/ 0,
- /*maxTessEvaluationAtomicCounterBuffers*/ 0,
- /*maxGeometryAtomicCounterBuffers*/ 0,
- /*maxFragmentAtomicCounterBuffers*/ 1,
- /*maxCombinedAtomicCounterBuffers*/ 1,
- /*maxAtomicCounterBufferSize*/ 16384,
- /*maxTransformFeedbackBuffers*/ 4,
- /*maxTransformFeedbackInterleavedComponents*/ 64,
- /*maxCullDistances*/ 8,
- /*maxCombinedClipAndCullDistances*/ 8,
- /*maxSamples*/ 4,
- /*maxMeshOutputVerticesNV*/ 0,
- /*maxMeshOutputPrimitivesNV*/ 0,
- /*maxMeshWorkGroupSizeX_NV*/ 0,
- /*maxMeshWorkGroupSizeY_NV*/ 0,
- /*maxMeshWorkGroupSizeZ_NV*/ 0,
- /*maxTaskWorkGroupSizeX_NV*/ 0,
- /*maxTaskWorkGroupSizeY_NV*/ 0,
- /*maxTaskWorkGroupSizeZ_NV*/ 0,
- /*maxMeshViewCountNV*/ 0,
- /*limits*/ {
- /*nonInductiveForLoops*/ true,
- /*whileLoops*/ true,
- /*doWhileLoops*/ true,
- /*generalUniformIndexing*/ true,
- /*generalAttributeMatrixVectorIndexing*/ true,
- /*generalVaryingIndexing*/ true,
- /*generalSamplerIndexing*/ true,
- /*generalVariableIndexing*/ true,
- /*generalConstantMatrixVectorIndexing*/ true,
- }
-};
-
static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage, const String &p_source_code, RenderingDevice::ShaderLanguage p_language, String *r_error) {
Vector<uint8_t> ret;
@@ -158,7 +53,7 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage
int ClientInputSemanticsVersion = 100; // maps to, say, #define VULKAN 100
glslang::EShTargetClientVersion VulkanClientVersion = glslang::EShTargetVulkan_1_0;
- glslang::EShTargetLanguageVersion TargetVersion = glslang::EShTargetSpv_1_0;
+ glslang::EShTargetLanguageVersion TargetVersion = glslang::EShTargetSpv_1_3;
glslang::TShader::ForbidIncluder includer;
glslang::TShader shader(stages[p_stage]);
@@ -175,7 +70,7 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage
std::string pre_processed_code;
//preprocess
- if (!shader.preprocess(&default_builtin_resource, DefaultVersion, ENoProfile, false, false, messages, &pre_processed_code, includer)) {
+ if (!shader.preprocess(&glslang::DefaultTBuiltInResource, DefaultVersion, ENoProfile, false, false, messages, &pre_processed_code, includer)) {
if (r_error) {
(*r_error) = "Failed pre-process:\n";
(*r_error) += shader.getInfoLog();
@@ -190,7 +85,7 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage
shader.setStrings(&cs_strings, 1);
//parse
- if (!shader.parse(&default_builtin_resource, DefaultVersion, false, messages)) {
+ if (!shader.parse(&glslang::DefaultTBuiltInResource, DefaultVersion, false, messages)) {
if (r_error) {
(*r_error) = "Failed parse:\n";
(*r_error) += shader.getInfoLog();
diff --git a/modules/glslang/register_types.h b/modules/glslang/register_types.h
index 2437e2b27a..a1264b77c9 100644
--- a/modules/glslang/register_types.h
+++ b/modules/glslang/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gltf/SCsub b/modules/gltf/SCsub
new file mode 100644
index 0000000000..5d03ee8361
--- /dev/null
+++ b/modules/gltf/SCsub
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+
+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")
diff --git a/modules/arkit/config.py b/modules/gltf/config.py
index e68603fc93..1505a456d7 100644
--- a/modules/arkit/config.py
+++ b/modules/gltf/config.py
@@ -1,5 +1,5 @@
def can_build(env, platform):
- return platform == "iphone"
+ return env["tools"] and not env["disable_3d"]
def configure(env):
diff --git a/modules/gltf/editor_scene_exporter_gltf_plugin.cpp b/modules/gltf/editor_scene_exporter_gltf_plugin.cpp
new file mode 100644
index 0000000000..4cdaccde6f
--- /dev/null
+++ b/modules/gltf/editor_scene_exporter_gltf_plugin.cpp
@@ -0,0 +1,90 @@
+/*************************************************************************/
+/* editor_scene_exporter_gltf_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "editor_scene_exporter_gltf_plugin.h"
+#include "core/config/project_settings.h"
+#include "core/object/object.h"
+#include "core/templates/vector.h"
+#include "editor/editor_file_system.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";
+}
+
+bool SceneExporterGLTFPlugin::has_main_screen() const {
+ return false;
+}
+
+SceneExporterGLTFPlugin::SceneExporterGLTFPlugin(EditorNode *p_node) {
+ editor = p_node;
+ convert_gltf2.instance();
+ file_export_lib = memnew(EditorFileDialog);
+ editor->get_gui_base()->add_child(file_export_lib);
+ file_export_lib->connect("file_selected", callable_mp(this, &SceneExporterGLTFPlugin::_gltf2_dialog_action));
+ file_export_lib->set_title(TTR("Export Library"));
+ file_export_lib->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
+ file_export_lib->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
+ 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));
+}
+
+void SceneExporterGLTFPlugin::_gltf2_dialog_action(String p_file) {
+ Node *root = editor->get_tree()->get_edited_scene_root();
+ if (!root) {
+ editor->show_accept(TTR("This operation can't be done without a scene."), TTR("OK"));
+ return;
+ }
+ List<String> deps;
+ convert_gltf2->save_scene(root, p_file, p_file, 0, 1000.0f, &deps);
+ EditorFileSystem::get_singleton()->scan_changes();
+}
+
+void SceneExporterGLTFPlugin::convert_scene_to_gltf2() {
+ Node *root = editor->get_tree()->get_edited_scene_root();
+ if (!root) {
+ editor->show_accept(TTR("This operation can't be done without a scene."), TTR("OK"));
+ return;
+ }
+ String filename = String(root->get_filename().get_file().get_basename());
+ if (filename.is_empty()) {
+ filename = root->get_name();
+ }
+ file_export_lib->set_current_file(filename + String(".gltf"));
+ file_export_lib->popup_centered_ratio();
+}
diff --git a/modules/gltf/editor_scene_exporter_gltf_plugin.h b/modules/gltf/editor_scene_exporter_gltf_plugin.h
new file mode 100644
index 0000000000..d952894c16
--- /dev/null
+++ b/modules/gltf/editor_scene_exporter_gltf_plugin.h
@@ -0,0 +1,52 @@
+/*************************************************************************/
+/* editor_scene_exporter_gltf_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef EDITOR_SCENE_EXPORTER_GLTF_PLUGIN_H
+#define EDITOR_SCENE_EXPORTER_GLTF_PLUGIN_H
+
+#include "editor/editor_plugin.h"
+#include "editor_scene_importer_gltf.h"
+
+class SceneExporterGLTFPlugin : public EditorPlugin {
+ GDCLASS(SceneExporterGLTFPlugin, EditorPlugin);
+
+ Ref<PackedSceneGLTF> convert_gltf2;
+ EditorNode *editor = nullptr;
+ EditorFileDialog *file_export_lib = nullptr;
+ void _gltf2_dialog_action(String p_file);
+ void convert_scene_to_gltf2();
+
+public:
+ virtual String get_name() const override;
+ bool has_main_screen() const override;
+ SceneExporterGLTFPlugin(class EditorNode *p_node);
+};
+
+#endif // EDITOR_SCENE_EXPORTER_GLTF_PLUGIN_H
diff --git a/modules/gltf/editor_scene_importer_gltf.cpp b/modules/gltf/editor_scene_importer_gltf.cpp
new file mode 100644
index 0000000000..6ea722a216
--- /dev/null
+++ b/modules/gltf/editor_scene_importer_gltf.cpp
@@ -0,0 +1,180 @@
+/*************************************************************************/
+/* editor_scene_importer_gltf.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "core/crypto/crypto_core.h"
+#include "core/io/json.h"
+#include "core/math/disjoint_set.h"
+#include "core/math/math_defs.h"
+#include "core/os/file_access.h"
+#include "core/os/os.h"
+#include "editor/import/resource_importer_scene.h"
+#include "modules/gltf/gltf_state.h"
+#include "modules/regex/regex.h"
+#include "scene/3d/bone_attachment_3d.h"
+#include "scene/3d/camera_3d.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/animation/animation_player.h"
+#include "scene/resources/packed_scene.h"
+#include "scene/resources/surface_tool.h"
+
+#include "modules/gltf/editor_scene_importer_gltf.h"
+
+uint32_t EditorSceneImporterGLTF::get_import_flags() const {
+ return ImportFlags::IMPORT_SCENE | ImportFlags::IMPORT_ANIMATION;
+}
+
+void EditorSceneImporterGLTF::get_extensions(List<String> *r_extensions) const {
+ r_extensions->push_back("gltf");
+ r_extensions->push_back("glb");
+}
+
+Node *EditorSceneImporterGLTF::import_scene(const String &p_path,
+ uint32_t p_flags, int p_bake_fps,
+ List<String> *r_missing_deps,
+ Error *r_err) {
+ Ref<PackedSceneGLTF> importer;
+ importer.instance();
+ return importer->import_scene(p_path, p_flags, p_bake_fps, r_missing_deps, r_err, Ref<GLTFState>());
+}
+
+Ref<Animation> EditorSceneImporterGLTF::import_animation(const String &p_path,
+ uint32_t p_flags,
+ int p_bake_fps) {
+ return Ref<Animation>();
+}
+
+void PackedSceneGLTF::_bind_methods() {
+ ClassDB::bind_method(
+ D_METHOD("export_gltf", "node", "path", "flags", "bake_fps"),
+ &PackedSceneGLTF::export_gltf, DEFVAL(0), DEFVAL(1000.0f));
+ ClassDB::bind_method(D_METHOD("pack_gltf", "path", "flags", "bake_fps", "state"),
+ &PackedSceneGLTF::pack_gltf, DEFVAL(0), DEFVAL(1000.0f), DEFVAL(Ref<GLTFState>()));
+ ClassDB::bind_method(D_METHOD("import_gltf_scene", "path", "flags", "bake_fps", "state"),
+ &PackedSceneGLTF::import_gltf_scene, DEFVAL(0), DEFVAL(1000.0f), DEFVAL(Ref<GLTFState>()));
+}
+Node *PackedSceneGLTF::import_gltf_scene(const String &p_path, uint32_t p_flags, float p_bake_fps, Ref<GLTFState> r_state) {
+ Error err = FAILED;
+ List<String> deps;
+ return import_scene(p_path, p_flags, p_bake_fps, &deps, &err, r_state);
+}
+
+Node *PackedSceneGLTF::import_scene(const String &p_path, uint32_t p_flags,
+ int p_bake_fps,
+ List<String> *r_missing_deps,
+ Error *r_err,
+ Ref<GLTFState> r_state) {
+ if (r_state == Ref<GLTFState>()) {
+ r_state.instance();
+ }
+ r_state->use_named_skin_binds =
+ p_flags & EditorSceneImporter::IMPORT_USE_NAMED_SKIN_BINDS;
+
+ Ref<GLTFDocument> gltf_document;
+ gltf_document.instance();
+ Error err = gltf_document->parse(r_state, p_path);
+ *r_err = err;
+ ERR_FAIL_COND_V(err != Error::OK, nullptr);
+
+ Node3D *root = memnew(Node3D);
+ for (int32_t root_i = 0; root_i < r_state->root_nodes.size(); root_i++) {
+ gltf_document->_generate_scene_node(r_state, root, root, r_state->root_nodes[root_i]);
+ }
+ gltf_document->_process_mesh_instances(r_state, root);
+ if (r_state->animations.size()) {
+ AnimationPlayer *ap = memnew(AnimationPlayer);
+ root->add_child(ap);
+ ap->set_owner(root);
+ for (int i = 0; i < r_state->animations.size(); i++) {
+ gltf_document->_import_animation(r_state, ap, i, p_bake_fps);
+ }
+ }
+
+ return cast_to<Node3D>(root);
+}
+
+void PackedSceneGLTF::pack_gltf(String p_path, int32_t p_flags,
+ real_t p_bake_fps, Ref<GLTFState> r_state) {
+ Error err = FAILED;
+ List<String> deps;
+ Node *root = import_scene(p_path, p_flags, p_bake_fps, &deps, &err, r_state);
+ ERR_FAIL_COND(err != OK);
+ pack(root);
+}
+
+void PackedSceneGLTF::save_scene(Node *p_node, const String &p_path,
+ const String &p_src_path, uint32_t p_flags,
+ int p_bake_fps, List<String> *r_missing_deps,
+ Error *r_err) {
+ Error err = FAILED;
+ if (r_err) {
+ *r_err = err;
+ }
+ Ref<GLTFDocument> gltf_document;
+ gltf_document.instance();
+ Ref<GLTFState> state;
+ state.instance();
+ err = gltf_document->serialize(state, p_node, p_path);
+ if (r_err) {
+ *r_err = err;
+ }
+}
+
+void PackedSceneGLTF::_build_parent_hierachy(Ref<GLTFState> state) {
+ // build the hierarchy
+ for (GLTFNodeIndex node_i = 0; node_i < state->nodes.size(); node_i++) {
+ for (int j = 0; j < state->nodes[node_i]->children.size(); j++) {
+ GLTFNodeIndex child_i = state->nodes[node_i]->children[j];
+ ERR_FAIL_INDEX(child_i, state->nodes.size());
+ if (state->nodes.write[child_i]->parent != -1) {
+ continue;
+ }
+ state->nodes.write[child_i]->parent = node_i;
+ }
+ }
+}
+
+Error PackedSceneGLTF::export_gltf(Node *p_root, String p_path,
+ int32_t p_flags,
+ real_t p_bake_fps) {
+ ERR_FAIL_COND_V(!p_root, FAILED);
+ List<String> deps;
+ Error err;
+ String path = p_path;
+ int32_t flags = p_flags;
+ real_t baked_fps = p_bake_fps;
+ Ref<PackedSceneGLTF> exporter;
+ exporter.instance();
+ exporter->save_scene(p_root, path, "", flags, baked_fps, &deps, &err);
+ int32_t error_code = err;
+ if (error_code != 0) {
+ return Error(error_code);
+ }
+ return OK;
+}
diff --git a/modules/gltf/editor_scene_importer_gltf.h b/modules/gltf/editor_scene_importer_gltf.h
new file mode 100644
index 0000000000..db961e591d
--- /dev/null
+++ b/modules/gltf/editor_scene_importer_gltf.h
@@ -0,0 +1,96 @@
+/*************************************************************************/
+/* editor_scene_importer_gltf.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef EDITOR_SCENE_IMPORTER_GLTF_H
+#define EDITOR_SCENE_IMPORTER_GLTF_H
+
+#include "core/config/project_settings.h"
+#include "core/io/json.h"
+#include "core/object/object.h"
+#include "core/templates/vector.h"
+#include "editor/import/resource_importer_scene.h"
+#include "modules/csg/csg_shape.h"
+#include "modules/gridmap/grid_map.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/3d/multimesh_instance_3d.h"
+#include "scene/3d/node_3d.h"
+#include "scene/3d/skeleton_3d.h"
+#include "scene/animation/animation_player.h"
+#include "scene/gui/check_box.h"
+#include "scene/main/node.h"
+#include "scene/resources/packed_scene.h"
+#include "scene/resources/surface_tool.h"
+
+#include "gltf_document.h"
+#include "gltf_state.h"
+
+class AnimationPlayer;
+class BoneAttachment;
+class EditorSceneImporterMeshNode3D;
+
+#ifdef TOOLS_ENABLED
+class EditorSceneImporterGLTF : public EditorSceneImporter {
+ GDCLASS(EditorSceneImporterGLTF, EditorSceneImporter);
+
+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,
+ int p_bake_fps,
+ List<String> *r_missing_deps = NULL,
+ Error *r_err = NULL) override;
+ virtual Ref<Animation> import_animation(const String &p_path,
+ uint32_t p_flags, int p_bake_fps) override;
+};
+#endif
+
+class PackedSceneGLTF : public PackedScene {
+ GDCLASS(PackedSceneGLTF, PackedScene);
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual void save_scene(Node *p_node, const String &p_path, const String &p_src_path,
+ uint32_t p_flags, int p_bake_fps,
+ List<String> *r_missing_deps, Error *r_err = NULL);
+ virtual void _build_parent_hierachy(Ref<GLTFState> state);
+ virtual Error export_gltf(Node *p_root, String p_path, int32_t p_flags = 0,
+ real_t p_bake_fps = 1000.0f);
+ virtual Node *import_scene(const String &p_path, uint32_t p_flags,
+ int p_bake_fps,
+ List<String> *r_missing_deps,
+ Error *r_err,
+ Ref<GLTFState> r_state);
+ virtual Node *import_gltf_scene(const String &p_path, uint32_t p_flags, float p_bake_fps, Ref<GLTFState> r_state = Ref<GLTFState>());
+ virtual void pack_gltf(String p_path, int32_t p_flags = 0,
+ real_t p_bake_fps = 1000.0f, Ref<GLTFState> r_state = Ref<GLTFState>());
+};
+#endif // EDITOR_SCENE_IMPORTER_GLTF_H
diff --git a/modules/gltf/gltf_accessor.cpp b/modules/gltf/gltf_accessor.cpp
new file mode 100644
index 0000000000..daeb084916
--- /dev/null
+++ b/modules/gltf/gltf_accessor.cpp
@@ -0,0 +1,189 @@
+/*************************************************************************/
+/* gltf_accessor.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gltf_accessor.h"
+
+void GLTFAccessor::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_buffer_view"), &GLTFAccessor::get_buffer_view);
+ ClassDB::bind_method(D_METHOD("set_buffer_view", "buffer_view"), &GLTFAccessor::set_buffer_view);
+ ClassDB::bind_method(D_METHOD("get_byte_offset"), &GLTFAccessor::get_byte_offset);
+ ClassDB::bind_method(D_METHOD("set_byte_offset", "byte_offset"), &GLTFAccessor::set_byte_offset);
+ ClassDB::bind_method(D_METHOD("get_component_type"), &GLTFAccessor::get_component_type);
+ ClassDB::bind_method(D_METHOD("set_component_type", "component_type"), &GLTFAccessor::set_component_type);
+ ClassDB::bind_method(D_METHOD("get_normalized"), &GLTFAccessor::get_normalized);
+ ClassDB::bind_method(D_METHOD("set_normalized", "normalized"), &GLTFAccessor::set_normalized);
+ ClassDB::bind_method(D_METHOD("get_count"), &GLTFAccessor::get_count);
+ ClassDB::bind_method(D_METHOD("set_count", "count"), &GLTFAccessor::set_count);
+ ClassDB::bind_method(D_METHOD("get_type"), &GLTFAccessor::get_type);
+ ClassDB::bind_method(D_METHOD("set_type", "type"), &GLTFAccessor::set_type);
+ ClassDB::bind_method(D_METHOD("get_min"), &GLTFAccessor::get_min);
+ ClassDB::bind_method(D_METHOD("set_min", "min"), &GLTFAccessor::set_min);
+ ClassDB::bind_method(D_METHOD("get_max"), &GLTFAccessor::get_max);
+ ClassDB::bind_method(D_METHOD("set_max", "max"), &GLTFAccessor::set_max);
+ ClassDB::bind_method(D_METHOD("get_sparse_count"), &GLTFAccessor::get_sparse_count);
+ ClassDB::bind_method(D_METHOD("set_sparse_count", "sparse_count"), &GLTFAccessor::set_sparse_count);
+ ClassDB::bind_method(D_METHOD("get_sparse_indices_buffer_view"), &GLTFAccessor::get_sparse_indices_buffer_view);
+ ClassDB::bind_method(D_METHOD("set_sparse_indices_buffer_view", "sparse_indices_buffer_view"), &GLTFAccessor::set_sparse_indices_buffer_view);
+ ClassDB::bind_method(D_METHOD("get_sparse_indices_byte_offset"), &GLTFAccessor::get_sparse_indices_byte_offset);
+ ClassDB::bind_method(D_METHOD("set_sparse_indices_byte_offset", "sparse_indices_byte_offset"), &GLTFAccessor::set_sparse_indices_byte_offset);
+ ClassDB::bind_method(D_METHOD("get_sparse_indices_component_type"), &GLTFAccessor::get_sparse_indices_component_type);
+ ClassDB::bind_method(D_METHOD("set_sparse_indices_component_type", "sparse_indices_component_type"), &GLTFAccessor::set_sparse_indices_component_type);
+ ClassDB::bind_method(D_METHOD("get_sparse_values_buffer_view"), &GLTFAccessor::get_sparse_values_buffer_view);
+ ClassDB::bind_method(D_METHOD("set_sparse_values_buffer_view", "sparse_values_buffer_view"), &GLTFAccessor::set_sparse_values_buffer_view);
+ ClassDB::bind_method(D_METHOD("get_sparse_values_byte_offset"), &GLTFAccessor::get_sparse_values_byte_offset);
+ ClassDB::bind_method(D_METHOD("set_sparse_values_byte_offset", "sparse_values_byte_offset"), &GLTFAccessor::set_sparse_values_byte_offset);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "buffer_view"), "set_buffer_view", "get_buffer_view"); // GLTFBufferViewIndex
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "byte_offset"), "set_byte_offset", "get_byte_offset"); // int
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "component_type"), "set_component_type", "get_component_type"); // int
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "normalized"), "set_normalized", "get_normalized"); // bool
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "count"), "set_count", "get_count"); // int
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "type"), "set_type", "get_type"); // GLTFDocument::GLTFType
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT64_ARRAY, "min"), "set_min", "get_min"); // Vector<real_t>
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT64_ARRAY, "max"), "set_max", "get_max"); // Vector<real_t>
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "sparse_count"), "set_sparse_count", "get_sparse_count"); // int
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "sparse_indices_buffer_view"), "set_sparse_indices_buffer_view", "get_sparse_indices_buffer_view"); // int
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "sparse_indices_byte_offset"), "set_sparse_indices_byte_offset", "get_sparse_indices_byte_offset"); // int
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "sparse_indices_component_type"), "set_sparse_indices_component_type", "get_sparse_indices_component_type"); // int
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "sparse_values_buffer_view"), "set_sparse_values_buffer_view", "get_sparse_values_buffer_view"); // int
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "sparse_values_byte_offset"), "set_sparse_values_byte_offset", "get_sparse_values_byte_offset"); // int
+}
+
+GLTFBufferViewIndex GLTFAccessor::get_buffer_view() {
+ return buffer_view;
+}
+
+void GLTFAccessor::set_buffer_view(GLTFBufferViewIndex p_buffer_view) {
+ buffer_view = p_buffer_view;
+}
+
+int GLTFAccessor::get_byte_offset() {
+ return byte_offset;
+}
+
+void GLTFAccessor::set_byte_offset(int p_byte_offset) {
+ byte_offset = p_byte_offset;
+}
+
+int GLTFAccessor::get_component_type() {
+ return component_type;
+}
+
+void GLTFAccessor::set_component_type(int p_component_type) {
+ component_type = p_component_type;
+}
+
+bool GLTFAccessor::get_normalized() {
+ return normalized;
+}
+
+void GLTFAccessor::set_normalized(bool p_normalized) {
+ normalized = p_normalized;
+}
+
+int GLTFAccessor::get_count() {
+ return count;
+}
+
+void GLTFAccessor::set_count(int p_count) {
+ count = p_count;
+}
+
+int GLTFAccessor::get_type() {
+ return (int)type;
+}
+
+void GLTFAccessor::set_type(int p_type) {
+ type = (GLTFDocument::GLTFType)p_type; // TODO: Register enum
+}
+
+Vector<double> GLTFAccessor::get_min() {
+ return min;
+}
+
+void GLTFAccessor::set_min(Vector<double> p_min) {
+ min = p_min;
+}
+
+Vector<double> GLTFAccessor::get_max() {
+ return max;
+}
+
+void GLTFAccessor::set_max(Vector<double> p_max) {
+ max = p_max;
+}
+
+int GLTFAccessor::get_sparse_count() {
+ return sparse_count;
+}
+
+void GLTFAccessor::set_sparse_count(int p_sparse_count) {
+ sparse_count = p_sparse_count;
+}
+
+int GLTFAccessor::get_sparse_indices_buffer_view() {
+ return sparse_indices_buffer_view;
+}
+
+void GLTFAccessor::set_sparse_indices_buffer_view(int p_sparse_indices_buffer_view) {
+ sparse_indices_buffer_view = p_sparse_indices_buffer_view;
+}
+
+int GLTFAccessor::get_sparse_indices_byte_offset() {
+ return sparse_indices_byte_offset;
+}
+
+void GLTFAccessor::set_sparse_indices_byte_offset(int p_sparse_indices_byte_offset) {
+ sparse_indices_byte_offset = p_sparse_indices_byte_offset;
+}
+
+int GLTFAccessor::get_sparse_indices_component_type() {
+ return sparse_indices_component_type;
+}
+
+void GLTFAccessor::set_sparse_indices_component_type(int p_sparse_indices_component_type) {
+ sparse_indices_component_type = p_sparse_indices_component_type;
+}
+
+int GLTFAccessor::get_sparse_values_buffer_view() {
+ return sparse_values_buffer_view;
+}
+
+void GLTFAccessor::set_sparse_values_buffer_view(int p_sparse_values_buffer_view) {
+ sparse_values_buffer_view = p_sparse_values_buffer_view;
+}
+
+int GLTFAccessor::get_sparse_values_byte_offset() {
+ return sparse_values_byte_offset;
+}
+
+void GLTFAccessor::set_sparse_values_byte_offset(int p_sparse_values_byte_offset) {
+ sparse_values_byte_offset = p_sparse_values_byte_offset;
+}
diff --git a/modules/gltf/gltf_accessor.h b/modules/gltf/gltf_accessor.h
new file mode 100644
index 0000000000..949a601730
--- /dev/null
+++ b/modules/gltf/gltf_accessor.h
@@ -0,0 +1,104 @@
+/*************************************************************************/
+/* gltf_accessor.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GLTF_ACCESSOR_H
+#define GLTF_ACCESSOR_H
+
+#include "core/io/resource.h"
+#include "gltf_document.h"
+
+struct GLTFAccessor : public Resource {
+ GDCLASS(GLTFAccessor, Resource);
+ friend class GLTFDocument;
+
+private:
+ GLTFBufferViewIndex buffer_view = 0;
+ int byte_offset = 0;
+ int component_type = 0;
+ bool normalized = false;
+ int count = 0;
+ GLTFDocument::GLTFType
+ type = GLTFDocument::TYPE_SCALAR;
+ Vector<double> min;
+ Vector<double> max;
+ int sparse_count = 0;
+ int sparse_indices_buffer_view = 0;
+ int sparse_indices_byte_offset = 0;
+ int sparse_indices_component_type = 0;
+ int sparse_values_buffer_view = 0;
+ int sparse_values_byte_offset = 0;
+
+protected:
+ static void _bind_methods();
+
+public:
+ GLTFBufferViewIndex get_buffer_view();
+ void set_buffer_view(GLTFBufferViewIndex p_buffer_view);
+
+ int get_byte_offset();
+ void set_byte_offset(int p_byte_offset);
+
+ int get_component_type();
+ void set_component_type(int p_component_type);
+
+ bool get_normalized();
+ void set_normalized(bool p_normalized);
+
+ int get_count();
+ void set_count(int p_count);
+
+ int get_type();
+ void set_type(int p_type);
+
+ Vector<double> get_min();
+ void set_min(Vector<double> p_min);
+
+ Vector<double> get_max();
+ void set_max(Vector<double> p_max);
+
+ int get_sparse_count();
+ void set_sparse_count(int p_sparse_count);
+
+ int get_sparse_indices_buffer_view();
+ void set_sparse_indices_buffer_view(int p_sparse_indices_buffer_view);
+
+ int get_sparse_indices_byte_offset();
+ void set_sparse_indices_byte_offset(int p_sparse_indices_byte_offset);
+
+ int get_sparse_indices_component_type();
+ void set_sparse_indices_component_type(int p_sparse_indices_component_type);
+
+ int get_sparse_values_buffer_view();
+ void set_sparse_values_buffer_view(int p_sparse_values_buffer_view);
+
+ int get_sparse_values_byte_offset();
+ void set_sparse_values_byte_offset(int p_sparse_values_byte_offset);
+};
+#endif // GLTF_ACCESSOR_H
diff --git a/modules/gltf/gltf_animation.cpp b/modules/gltf/gltf_animation.cpp
new file mode 100644
index 0000000000..889a8e8870
--- /dev/null
+++ b/modules/gltf/gltf_animation.cpp
@@ -0,0 +1,53 @@
+/*************************************************************************/
+/* gltf_animation.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gltf_animation.h"
+
+void GLTFAnimation::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_loop"), &GLTFAnimation::get_loop);
+ ClassDB::bind_method(D_METHOD("set_loop", "loop"), &GLTFAnimation::set_loop);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "get_loop"); // bool
+}
+
+bool GLTFAnimation::get_loop() const {
+ return loop;
+}
+
+void GLTFAnimation::set_loop(bool p_val) {
+ loop = p_val;
+}
+
+Map<int, GLTFAnimation::Track> &GLTFAnimation::get_tracks() {
+ return tracks;
+}
+
+GLTFAnimation::GLTFAnimation() {
+}
diff --git a/modules/gltf/gltf_animation.h b/modules/gltf/gltf_animation.h
new file mode 100644
index 0000000000..a494e6bd67
--- /dev/null
+++ b/modules/gltf/gltf_animation.h
@@ -0,0 +1,74 @@
+/*************************************************************************/
+/* gltf_animation.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GLTF_ANIMATION_H
+#define GLTF_ANIMATION_H
+
+#include "core/io/resource.h"
+
+class GLTFAnimation : public Resource {
+ GDCLASS(GLTFAnimation, Resource);
+
+protected:
+ static void _bind_methods();
+
+public:
+ enum Interpolation {
+ INTERP_LINEAR,
+ INTERP_STEP,
+ INTERP_CATMULLROMSPLINE,
+ INTERP_CUBIC_SPLINE,
+ };
+
+ template <class T>
+ struct Channel {
+ Interpolation interpolation;
+ Vector<float> times;
+ Vector<T> values;
+ };
+
+ struct Track {
+ Channel<Vector3> translation_track;
+ Channel<Quat> rotation_track;
+ Channel<Vector3> scale_track;
+ Vector<Channel<float>> weight_tracks;
+ };
+
+public:
+ bool get_loop() const;
+ void set_loop(bool p_val);
+ Map<int, GLTFAnimation::Track> &get_tracks();
+ GLTFAnimation();
+
+private:
+ bool loop = false;
+ Map<int, Track> tracks;
+};
+#endif // GLTF_ANIMATION_H
diff --git a/modules/gltf/gltf_buffer_view.cpp b/modules/gltf/gltf_buffer_view.cpp
new file mode 100644
index 0000000000..ba38a11c4c
--- /dev/null
+++ b/modules/gltf/gltf_buffer_view.cpp
@@ -0,0 +1,90 @@
+/*************************************************************************/
+/* gltf_buffer_view.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gltf_buffer_view.h"
+
+void GLTFBufferView::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_buffer"), &GLTFBufferView::get_buffer);
+ ClassDB::bind_method(D_METHOD("set_buffer", "buffer"), &GLTFBufferView::set_buffer);
+ ClassDB::bind_method(D_METHOD("get_byte_offset"), &GLTFBufferView::get_byte_offset);
+ ClassDB::bind_method(D_METHOD("set_byte_offset", "byte_offset"), &GLTFBufferView::set_byte_offset);
+ ClassDB::bind_method(D_METHOD("get_byte_length"), &GLTFBufferView::get_byte_length);
+ ClassDB::bind_method(D_METHOD("set_byte_length", "byte_length"), &GLTFBufferView::set_byte_length);
+ ClassDB::bind_method(D_METHOD("get_byte_stride"), &GLTFBufferView::get_byte_stride);
+ ClassDB::bind_method(D_METHOD("set_byte_stride", "byte_stride"), &GLTFBufferView::set_byte_stride);
+ ClassDB::bind_method(D_METHOD("get_indices"), &GLTFBufferView::get_indices);
+ ClassDB::bind_method(D_METHOD("set_indices", "indices"), &GLTFBufferView::set_indices);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "buffer"), "set_buffer", "get_buffer"); // GLTFBufferIndex
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "byte_offset"), "set_byte_offset", "get_byte_offset"); // int
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "byte_length"), "set_byte_length", "get_byte_length"); // int
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "byte_stride"), "set_byte_stride", "get_byte_stride"); // int
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "indices"), "set_indices", "get_indices"); // bool
+}
+
+GLTFBufferIndex GLTFBufferView::get_buffer() {
+ return buffer;
+}
+
+void GLTFBufferView::set_buffer(GLTFBufferIndex p_buffer) {
+ buffer = p_buffer;
+}
+
+int GLTFBufferView::get_byte_offset() {
+ return byte_offset;
+}
+
+void GLTFBufferView::set_byte_offset(int p_byte_offset) {
+ byte_offset = p_byte_offset;
+}
+
+int GLTFBufferView::get_byte_length() {
+ return byte_length;
+}
+
+void GLTFBufferView::set_byte_length(int p_byte_length) {
+ byte_length = p_byte_length;
+}
+
+int GLTFBufferView::get_byte_stride() {
+ return byte_stride;
+}
+
+void GLTFBufferView::set_byte_stride(int p_byte_stride) {
+ byte_stride = p_byte_stride;
+}
+
+bool GLTFBufferView::get_indices() {
+ return indices;
+}
+
+void GLTFBufferView::set_indices(bool p_indices) {
+ indices = p_indices;
+}
diff --git a/modules/gltf/gltf_buffer_view.h b/modules/gltf/gltf_buffer_view.h
new file mode 100644
index 0000000000..63af5e7c0d
--- /dev/null
+++ b/modules/gltf/gltf_buffer_view.h
@@ -0,0 +1,68 @@
+/*************************************************************************/
+/* gltf_buffer_view.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GLTF_BUFFER_VIEW_H
+#define GLTF_BUFFER_VIEW_H
+
+#include "core/io/resource.h"
+#include "gltf_document.h"
+
+class GLTFBufferView : public Resource {
+ GDCLASS(GLTFBufferView, Resource);
+ friend class GLTFDocument;
+
+private:
+ GLTFBufferIndex buffer = -1;
+ int byte_offset = 0;
+ int byte_length = 0;
+ int byte_stride = -1;
+ bool indices = false;
+
+protected:
+ static void _bind_methods();
+
+public:
+ GLTFBufferIndex get_buffer();
+ void set_buffer(GLTFBufferIndex p_buffer);
+
+ int get_byte_offset();
+ void set_byte_offset(int p_byte_offset);
+
+ int get_byte_length();
+ void set_byte_length(int p_byte_length);
+
+ int get_byte_stride();
+ void set_byte_stride(int p_byte_stride);
+
+ bool get_indices();
+ void set_indices(bool p_indices);
+ // matrices need to be transformed to this
+};
+#endif // GLTF_BUFFER_VIEW_H
diff --git a/modules/gltf/gltf_camera.cpp b/modules/gltf/gltf_camera.cpp
new file mode 100644
index 0000000000..efa7c5d6d7
--- /dev/null
+++ b/modules/gltf/gltf_camera.cpp
@@ -0,0 +1,47 @@
+/*************************************************************************/
+/* gltf_camera.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gltf_camera.h"
+
+void GLTFCamera::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_perspective"), &GLTFCamera::get_perspective);
+ ClassDB::bind_method(D_METHOD("set_perspective", "perspective"), &GLTFCamera::set_perspective);
+ ClassDB::bind_method(D_METHOD("get_fov_size"), &GLTFCamera::get_fov_size);
+ ClassDB::bind_method(D_METHOD("set_fov_size", "fov_size"), &GLTFCamera::set_fov_size);
+ ClassDB::bind_method(D_METHOD("get_zfar"), &GLTFCamera::get_zfar);
+ ClassDB::bind_method(D_METHOD("set_zfar", "zfar"), &GLTFCamera::set_zfar);
+ ClassDB::bind_method(D_METHOD("get_znear"), &GLTFCamera::get_znear);
+ ClassDB::bind_method(D_METHOD("set_znear", "znear"), &GLTFCamera::set_znear);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "perspective"), "set_perspective", "get_perspective"); // bool
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fov_size"), "set_fov_size", "get_fov_size"); // float
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "zfar"), "set_zfar", "get_zfar"); // float
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "znear"), "set_znear", "get_znear"); // float
+}
diff --git a/modules/arkit/arkit_session_delegate.mm b/modules/gltf/gltf_camera.h
index f44f46b7b7..e5c2041793 100644
--- a/modules/arkit/arkit_session_delegate.mm
+++ b/modules/gltf/gltf_camera.h
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* arkit_session_delegate.mm */
+/* gltf_camera.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -28,29 +28,31 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "arkit_session_delegate.h"
-#include "arkit_interface.h"
+#ifndef GLTF_CAMERA_H
+#define GLTF_CAMERA_H
-@implementation ARKitSessionDelegate
+#include "core/io/resource.h"
-@synthesize arkit_interface;
+class GLTFCamera : public Resource {
+ GDCLASS(GLTFCamera, Resource);
-- (void)session:(ARSession *)session didAddAnchors:(NSArray<ARAnchor *> *)anchors {
- for (ARAnchor *anchor in anchors) {
- arkit_interface->_add_or_update_anchor(anchor);
- }
-}
+private:
+ bool perspective = true;
+ float fov_size = 75;
+ float zfar = 4000;
+ float znear = 0.05;
-- (void)session:(ARSession *)session didRemoveAnchors:(NSArray<ARAnchor *> *)anchors {
- for (ARAnchor *anchor in anchors) {
- arkit_interface->_remove_anchor(anchor);
- }
-}
+protected:
+ static void _bind_methods();
-- (void)session:(ARSession *)session didUpdateAnchors:(NSArray<ARAnchor *> *)anchors {
- for (ARAnchor *anchor in anchors) {
- arkit_interface->_add_or_update_anchor(anchor);
- }
-}
-
-@end
+public:
+ bool get_perspective() const { return perspective; }
+ void set_perspective(bool p_val) { perspective = p_val; }
+ float get_fov_size() const { return fov_size; }
+ void set_fov_size(float p_val) { fov_size = p_val; }
+ float get_zfar() const { return zfar; }
+ void set_zfar(float p_val) { zfar = p_val; }
+ float get_znear() const { return znear; }
+ void set_znear(float p_val) { znear = p_val; }
+};
+#endif // GLTF_CAMERA_H
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
new file mode 100644
index 0000000000..cce0740121
--- /dev/null
+++ b/modules/gltf/gltf_document.cpp
@@ -0,0 +1,6554 @@
+/*************************************************************************/
+/* gltf_document.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gltf_document.h"
+#include "core/error/error_list.h"
+#include "core/error/error_macros.h"
+#include "core/variant/variant.h"
+#include "gltf_accessor.h"
+#include "gltf_animation.h"
+#include "gltf_camera.h"
+#include "gltf_light.h"
+#include "gltf_mesh.h"
+#include "gltf_node.h"
+#include "gltf_skeleton.h"
+#include "gltf_skin.h"
+#include "gltf_spec_gloss.h"
+#include "gltf_state.h"
+#include "gltf_texture.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "core/core_bind.h"
+#include "core/crypto/crypto_core.h"
+#include "core/io/json.h"
+#include "core/math/disjoint_set.h"
+#include "core/os/file_access.h"
+#include "core/variant/typed_array.h"
+#include "core/version.h"
+#include "core/version_hash.gen.h"
+#include "drivers/png/png_driver_common.h"
+#include "editor/import/resource_importer_scene.h"
+#ifdef MODULE_CSG_ENABLED
+#include "modules/csg/csg_shape.h"
+#endif // MODULE_CSG_ENABLED
+#ifdef MODULE_GRIDMAP_ENABLED
+#include "modules/gridmap/grid_map.h"
+#endif // MODULE_GRIDMAP_ENABLED
+#include "modules/regex/regex.h"
+#include "scene/2d/node_2d.h"
+#include "scene/3d/bone_attachment_3d.h"
+#include "scene/3d/camera_3d.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/3d/multimesh_instance_3d.h"
+#include "scene/3d/node_3d.h"
+#include "scene/3d/skeleton_3d.h"
+#include "scene/animation/animation_player.h"
+#include "scene/resources/surface_tool.h"
+#include <limits>
+
+Error GLTFDocument::serialize(Ref<GLTFState> state, Node *p_root, const String &p_path) {
+ uint64_t begin_time = OS::get_singleton()->get_ticks_usec();
+
+ _convert_scene_node(state, p_root, p_root, -1, -1);
+ if (!state->buffers.size()) {
+ state->buffers.push_back(Vector<uint8_t>());
+ }
+
+ /* STEP 1 CONVERT MESH INSTANCES */
+ _convert_mesh_instances(state);
+
+ /* STEP 2 SERIALIZE CAMERAS */
+ Error err = _serialize_cameras(state);
+ if (err != OK) {
+ return Error::FAILED;
+ }
+
+ /* STEP 3 CREATE SKINS */
+ err = _serialize_skins(state);
+ if (err != OK) {
+ return Error::FAILED;
+ }
+ /* STEP 4 CREATE BONE ATTACHMENTS */
+ err = _serialize_bone_attachment(state);
+ if (err != OK) {
+ return Error::FAILED;
+ }
+ /* STEP 5 SERIALIZE MESHES (we have enough info now) */
+ err = _serialize_meshes(state);
+ if (err != OK) {
+ return Error::FAILED;
+ }
+
+ /* STEP 6 SERIALIZE TEXTURES */
+ err = _serialize_materials(state);
+ if (err != OK) {
+ return Error::FAILED;
+ }
+
+ /* STEP 7 SERIALIZE IMAGES */
+ err = _serialize_images(state, p_path);
+ if (err != OK) {
+ return Error::FAILED;
+ }
+
+ /* STEP 8 SERIALIZE TEXTURES */
+ err = _serialize_textures(state);
+ if (err != OK) {
+ return Error::FAILED;
+ }
+
+ // /* STEP 9 SERIALIZE ANIMATIONS */
+ err = _serialize_animations(state);
+ if (err != OK) {
+ return Error::FAILED;
+ }
+
+ /* STEP 10 SERIALIZE ACCESSORS */
+ err = _encode_accessors(state);
+ if (err != OK) {
+ return Error::FAILED;
+ }
+
+ for (GLTFBufferViewIndex i = 0; i < state->buffer_views.size(); i++) {
+ state->buffer_views.write[i]->buffer = 0;
+ }
+
+ /* STEP 11 SERIALIZE BUFFER VIEWS */
+ err = _encode_buffer_views(state);
+ if (err != OK) {
+ return Error::FAILED;
+ }
+
+ /* STEP 12 SERIALIZE NODES */
+ err = _serialize_nodes(state);
+ if (err != OK) {
+ return Error::FAILED;
+ }
+
+ /* STEP 13 SERIALIZE SCENE */
+ err = _serialize_scenes(state);
+ if (err != OK) {
+ return Error::FAILED;
+ }
+
+ /* STEP 14 SERIALIZE SCENE */
+ err = _serialize_lights(state);
+ if (err != OK) {
+ return Error::FAILED;
+ }
+
+ /* STEP 15 SERIALIZE EXTENSIONS */
+ err = _serialize_extensions(state);
+ if (err != OK) {
+ return Error::FAILED;
+ }
+
+ /* STEP 16 SERIALIZE VERSION */
+ err = _serialize_version(state);
+ if (err != OK) {
+ return Error::FAILED;
+ }
+
+ /* STEP 17 SERIALIZE FILE */
+ err = _serialize_file(state, p_path);
+ if (err != OK) {
+ return Error::FAILED;
+ }
+ uint64_t elapsed = OS::get_singleton()->get_ticks_usec() - begin_time;
+ float elapsed_sec = double(elapsed) / 1000000.0;
+ elapsed_sec = Math::snapped(elapsed_sec, 0.01f);
+ print_line("glTF: Export time elapsed seconds " + rtos(elapsed_sec).pad_decimals(2));
+
+ return OK;
+}
+
+Error GLTFDocument::_serialize_extensions(Ref<GLTFState> state) const {
+ const String texture_transform = "KHR_texture_transform";
+ const String punctual_lights = "KHR_lights_punctual";
+ Array extensions_used;
+ extensions_used.push_back(punctual_lights);
+ extensions_used.push_back(texture_transform);
+ state->json["extensionsUsed"] = extensions_used;
+ Array extensions_required;
+ extensions_required.push_back(texture_transform);
+ state->json["extensionsRequired"] = extensions_required;
+ return OK;
+}
+
+Error GLTFDocument::_serialize_scenes(Ref<GLTFState> state) {
+ Array scenes;
+ const int loaded_scene = 0;
+ state->json["scene"] = loaded_scene;
+
+ if (state->nodes.size()) {
+ Dictionary s;
+ if (!state->scene_name.is_empty()) {
+ s["name"] = state->scene_name;
+ }
+
+ Array nodes;
+ nodes.push_back(0);
+ s["nodes"] = nodes;
+ scenes.push_back(s);
+ }
+ state->json["scenes"] = scenes;
+
+ return OK;
+}
+
+Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> state) {
+ Error err;
+ FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err);
+ if (!f) {
+ return err;
+ }
+
+ Vector<uint8_t> array;
+ array.resize(f->get_len());
+ f->get_buffer(array.ptrw(), array.size());
+ String text;
+ text.parse_utf8((const char *)array.ptr(), array.size());
+
+ String err_txt;
+ int err_line;
+ Variant v;
+ err = JSON::parse(text, v, err_txt, err_line);
+ if (err != OK) {
+ _err_print_error("", p_path.utf8().get_data(), err_line, err_txt.utf8().get_data(), ERR_HANDLER_SCRIPT);
+ return err;
+ }
+ state->json = v;
+
+ return OK;
+}
+
+Error GLTFDocument::_serialize_bone_attachment(Ref<GLTFState> state) {
+ for (int skeleton_i = 0; skeleton_i < state->skeletons.size(); skeleton_i++) {
+ for (int attachment_i = 0; attachment_i < state->skeletons[skeleton_i]->bone_attachments.size(); attachment_i++) {
+ BoneAttachment3D *bone_attachment = state->skeletons[skeleton_i]->bone_attachments[attachment_i];
+ String bone_name = bone_attachment->get_bone_name();
+ bone_name = _sanitize_bone_name(bone_name);
+ int32_t bone = state->skeletons[skeleton_i]->godot_skeleton->find_bone(bone_name);
+ ERR_CONTINUE(bone == -1);
+ for (int skin_i = 0; skin_i < state->skins.size(); skin_i++) {
+ if (state->skins[skin_i]->skeleton != skeleton_i) {
+ continue;
+ }
+
+ for (int node_i = 0; node_i < bone_attachment->get_child_count(); node_i++) {
+ ERR_CONTINUE(bone >= state->skins[skin_i]->joints.size());
+ _convert_scene_node(state, bone_attachment->get_child(node_i), bone_attachment->get_owner(), state->skins[skin_i]->joints[bone], 0);
+ }
+ break;
+ }
+ }
+ }
+ return OK;
+}
+
+Error GLTFDocument::_parse_glb(const String &p_path, Ref<GLTFState> state) {
+ Error err;
+ FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err);
+ if (!f) {
+ return err;
+ }
+
+ uint32_t magic = f->get_32();
+ ERR_FAIL_COND_V(magic != 0x46546C67, ERR_FILE_UNRECOGNIZED); //glTF
+ f->get_32(); // version
+ f->get_32(); // length
+
+ uint32_t chunk_length = f->get_32();
+ uint32_t chunk_type = f->get_32();
+
+ ERR_FAIL_COND_V(chunk_type != 0x4E4F534A, ERR_PARSE_ERROR); //JSON
+ Vector<uint8_t> json_data;
+ json_data.resize(chunk_length);
+ uint32_t len = f->get_buffer(json_data.ptrw(), chunk_length);
+ ERR_FAIL_COND_V(len != chunk_length, ERR_FILE_CORRUPT);
+
+ String text;
+ text.parse_utf8((const char *)json_data.ptr(), json_data.size());
+
+ String err_txt;
+ int err_line;
+ Variant v;
+ err = JSON::parse(text, v, err_txt, err_line);
+ if (err != OK) {
+ _err_print_error("", p_path.utf8().get_data(), err_line, err_txt.utf8().get_data(), ERR_HANDLER_SCRIPT);
+ return err;
+ }
+
+ state->json = v;
+
+ //data?
+
+ chunk_length = f->get_32();
+ chunk_type = f->get_32();
+
+ if (f->eof_reached()) {
+ return OK; //all good
+ }
+
+ ERR_FAIL_COND_V(chunk_type != 0x004E4942, ERR_PARSE_ERROR); //BIN
+
+ state->glb_data.resize(chunk_length);
+ len = f->get_buffer(state->glb_data.ptrw(), chunk_length);
+ ERR_FAIL_COND_V(len != chunk_length, ERR_FILE_CORRUPT);
+
+ return OK;
+}
+
+static Array _vec3_to_arr(const Vector3 &p_vec3) {
+ Array array;
+ array.resize(3);
+ array[0] = p_vec3.x;
+ array[1] = p_vec3.y;
+ array[2] = p_vec3.z;
+ return array;
+}
+
+static Vector3 _arr_to_vec3(const Array &p_array) {
+ ERR_FAIL_COND_V(p_array.size() != 3, Vector3());
+ return Vector3(p_array[0], p_array[1], p_array[2]);
+}
+
+static Array _quat_to_array(const Quat &p_quat) {
+ Array array;
+ array.resize(4);
+ array[0] = p_quat.x;
+ array[1] = p_quat.y;
+ array[2] = p_quat.z;
+ array[3] = p_quat.w;
+ return array;
+}
+
+static Quat _arr_to_quat(const Array &p_array) {
+ ERR_FAIL_COND_V(p_array.size() != 4, Quat());
+ return Quat(p_array[0], p_array[1], p_array[2], p_array[3]);
+}
+
+static Transform _arr_to_xform(const Array &p_array) {
+ ERR_FAIL_COND_V(p_array.size() != 16, Transform());
+
+ Transform 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.set_origin(Vector3(p_array[12], p_array[13], p_array[14]));
+
+ return xform;
+}
+
+static Vector<real_t> _xform_to_array(const Transform p_transform) {
+ Vector<real_t> array;
+ array.resize(16);
+ Vector3 axis_x = p_transform.get_basis().get_axis(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);
+ 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);
+ array.write[8] = axis_z.x;
+ array.write[9] = axis_z.y;
+ array.write[10] = axis_z.z;
+ array.write[11] = 0.0f;
+ Vector3 origin = p_transform.get_origin();
+ array.write[12] = origin.x;
+ array.write[13] = origin.y;
+ array.write[14] = origin.z;
+ array.write[15] = 1.0f;
+ return array;
+}
+
+Error GLTFDocument::_serialize_nodes(Ref<GLTFState> state) {
+ Array nodes;
+ for (int i = 0; i < state->nodes.size(); i++) {
+ Dictionary node;
+ Ref<GLTFNode> n = state->nodes[i];
+ Dictionary extensions;
+ node["extensions"] = extensions;
+ if (!n->get_name().is_empty()) {
+ node["name"] = n->get_name();
+ }
+ if (n->camera != -1) {
+ node["camera"] = n->camera;
+ }
+ if (n->light != -1) {
+ Dictionary lights_punctual;
+ extensions["KHR_lights_punctual"] = lights_punctual;
+ lights_punctual["light"] = n->light;
+ }
+ if (n->mesh != -1) {
+ node["mesh"] = n->mesh;
+ }
+ if (n->skin != -1) {
+ node["skin"] = n->skin;
+ }
+ if (n->skeleton != -1 && n->skin < 0) {
+ }
+ if (n->xform != Transform()) {
+ node["matrix"] = _xform_to_array(n->xform);
+ }
+
+ if (!n->rotation.is_equal_approx(Quat())) {
+ node["rotation"] = _quat_to_array(n->rotation);
+ }
+
+ if (!n->scale.is_equal_approx(Vector3(1.0f, 1.0f, 1.0f))) {
+ node["scale"] = _vec3_to_arr(n->scale);
+ }
+
+ if (!n->translation.is_equal_approx(Vector3())) {
+ node["translation"] = _vec3_to_arr(n->translation);
+ }
+ if (n->children.size()) {
+ Array children;
+ for (int j = 0; j < n->children.size(); j++) {
+ children.push_back(n->children[j]);
+ }
+ node["children"] = children;
+ }
+ nodes.push_back(node);
+ }
+ state->json["nodes"] = nodes;
+ return OK;
+}
+
+String GLTFDocument::_sanitize_scene_name(const String &name) {
+ RegEx regex("([^a-zA-Z0-9_ -]+)");
+ String p_name = regex.sub(name, "", true);
+ return p_name;
+}
+
+String GLTFDocument::_gen_unique_name(Ref<GLTFState> state, const String &p_name) {
+ const String s_name = _sanitize_scene_name(p_name);
+
+ String name;
+ int index = 1;
+ while (true) {
+ name = s_name;
+
+ if (index > 1) {
+ name += " " + itos(index);
+ }
+ if (!state->unique_names.has(name)) {
+ break;
+ }
+ index++;
+ }
+
+ state->unique_names.insert(name);
+
+ return name;
+}
+
+String GLTFDocument::_sanitize_bone_name(const String &name) {
+ String p_name = name.camelcase_to_underscore(true);
+
+ RegEx pattern_nocolon(":");
+ p_name = pattern_nocolon.sub(p_name, "_", true);
+
+ RegEx pattern_noslash("/");
+ p_name = pattern_noslash.sub(p_name, "_", true);
+
+ RegEx pattern_nospace(" +");
+ p_name = pattern_nospace.sub(p_name, "_", true);
+
+ RegEx pattern_multiple("_+");
+ p_name = pattern_multiple.sub(p_name, "_", true);
+
+ RegEx pattern_padded("0+(\\d+)");
+ p_name = pattern_padded.sub(p_name, "$1", true);
+
+ return p_name;
+}
+
+String GLTFDocument::_gen_unique_bone_name(Ref<GLTFState> state, const GLTFSkeletonIndex skel_i, const String &p_name) {
+ String s_name = _sanitize_bone_name(p_name);
+ if (s_name.is_empty()) {
+ s_name = "bone";
+ }
+ String name;
+ int index = 1;
+ while (true) {
+ name = s_name;
+
+ if (index > 1) {
+ name += "_" + itos(index);
+ }
+ if (!state->skeletons[skel_i]->unique_names.has(name)) {
+ break;
+ }
+ index++;
+ }
+
+ state->skeletons.write[skel_i]->unique_names.insert(name);
+
+ return name;
+}
+
+Error GLTFDocument::_parse_scenes(Ref<GLTFState> state) {
+ ERR_FAIL_COND_V(!state->json.has("scenes"), ERR_FILE_CORRUPT);
+ const Array &scenes = state->json["scenes"];
+ int loaded_scene = 0;
+ if (state->json.has("scene")) {
+ loaded_scene = state->json["scene"];
+ } else {
+ WARN_PRINT("The load-time scene is not defined in the glTF2 file. Picking the first scene.");
+ }
+
+ if (scenes.size()) {
+ ERR_FAIL_COND_V(loaded_scene >= scenes.size(), ERR_FILE_CORRUPT);
+ const Dictionary &s = scenes[loaded_scene];
+ ERR_FAIL_COND_V(!s.has("nodes"), ERR_UNAVAILABLE);
+ const Array &nodes = s["nodes"];
+ for (int j = 0; j < nodes.size(); j++) {
+ state->root_nodes.push_back(nodes[j]);
+ }
+
+ if (s.has("name") && s["name"] != "") {
+ state->scene_name = _gen_unique_name(state, s["name"]);
+ } else {
+ state->scene_name = _gen_unique_name(state, "Scene");
+ }
+ }
+
+ return OK;
+}
+
+Error GLTFDocument::_parse_nodes(Ref<GLTFState> state) {
+ ERR_FAIL_COND_V(!state->json.has("nodes"), ERR_FILE_CORRUPT);
+ const Array &nodes = state->json["nodes"];
+ for (int i = 0; i < nodes.size(); i++) {
+ Ref<GLTFNode> node;
+ node.instance();
+ const Dictionary &n = nodes[i];
+
+ if (n.has("name")) {
+ node->set_name(n["name"]);
+ }
+ if (n.has("camera")) {
+ node->camera = n["camera"];
+ }
+ if (n.has("mesh")) {
+ node->mesh = n["mesh"];
+ }
+ if (n.has("skin")) {
+ node->skin = n["skin"];
+ }
+ if (n.has("matrix")) {
+ node->xform = _arr_to_xform(n["matrix"]);
+ } else {
+ if (n.has("translation")) {
+ node->translation = _arr_to_vec3(n["translation"]);
+ }
+ if (n.has("rotation")) {
+ node->rotation = _arr_to_quat(n["rotation"]);
+ }
+ if (n.has("scale")) {
+ node->scale = _arr_to_vec3(n["scale"]);
+ }
+
+ node->xform.basis.set_quat_scale(node->rotation, node->scale);
+ node->xform.origin = node->translation;
+ }
+
+ if (n.has("extensions")) {
+ Dictionary extensions = n["extensions"];
+ if (extensions.has("KHR_lights_punctual")) {
+ Dictionary lights_punctual = extensions["KHR_lights_punctual"];
+ if (lights_punctual.has("light")) {
+ GLTFLightIndex light = lights_punctual["light"];
+ node->light = light;
+ }
+ }
+ }
+
+ if (n.has("children")) {
+ const Array &children = n["children"];
+ for (int j = 0; j < children.size(); j++) {
+ node->children.push_back(children[j]);
+ }
+ }
+
+ state->nodes.push_back(node);
+ }
+
+ // build the hierarchy
+ for (GLTFNodeIndex node_i = 0; node_i < state->nodes.size(); node_i++) {
+ for (int j = 0; j < state->nodes[node_i]->children.size(); j++) {
+ GLTFNodeIndex child_i = state->nodes[node_i]->children[j];
+
+ ERR_FAIL_INDEX_V(child_i, state->nodes.size(), ERR_FILE_CORRUPT);
+ ERR_CONTINUE(state->nodes[child_i]->parent != -1); //node already has a parent, wtf.
+
+ state->nodes.write[child_i]->parent = node_i;
+ }
+ }
+
+ _compute_node_heights(state);
+
+ return OK;
+}
+
+void GLTFDocument::_compute_node_heights(Ref<GLTFState> state) {
+ state->root_nodes.clear();
+ for (GLTFNodeIndex node_i = 0; node_i < state->nodes.size(); ++node_i) {
+ Ref<GLTFNode> node = state->nodes[node_i];
+ node->height = 0;
+
+ GLTFNodeIndex current_i = node_i;
+ while (current_i >= 0) {
+ const GLTFNodeIndex parent_i = state->nodes[current_i]->parent;
+ if (parent_i >= 0) {
+ ++node->height;
+ }
+ current_i = parent_i;
+ }
+
+ if (node->height == 0) {
+ state->root_nodes.push_back(node_i);
+ }
+ }
+}
+
+static Vector<uint8_t> _parse_base64_uri(const String &uri) {
+ int start = uri.find(",");
+ ERR_FAIL_COND_V(start == -1, Vector<uint8_t>());
+
+ CharString substr = uri.right(start + 1).ascii();
+
+ int strlen = substr.length();
+
+ Vector<uint8_t> buf;
+ buf.resize(strlen / 4 * 3 + 1 + 1);
+
+ size_t len = 0;
+ ERR_FAIL_COND_V(CryptoCore::b64_decode(buf.ptrw(), buf.size(), &len, (unsigned char *)substr.get_data(), strlen) != OK, Vector<uint8_t>());
+
+ buf.resize(len);
+
+ return buf;
+}
+Error GLTFDocument::_encode_buffer_glb(Ref<GLTFState> state, const String &p_path) {
+ print_verbose("glTF: Total buffers: " + itos(state->buffers.size()));
+
+ if (!state->buffers.size()) {
+ return OK;
+ }
+ Array buffers;
+ if (state->buffers.size()) {
+ Vector<uint8_t> buffer_data = state->buffers[0];
+ Dictionary gltf_buffer;
+
+ gltf_buffer["byteLength"] = buffer_data.size();
+ buffers.push_back(gltf_buffer);
+ }
+
+ for (GLTFBufferIndex i = 1; i < state->buffers.size() - 1; i++) {
+ Vector<uint8_t> buffer_data = state->buffers[i];
+ Dictionary gltf_buffer;
+ 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) {
+ return err;
+ }
+ if (buffer_data.size() == 0) {
+ return OK;
+ }
+ 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);
+ }
+ state->json["buffers"] = buffers;
+
+ return OK;
+}
+
+Error GLTFDocument::_encode_buffer_bins(Ref<GLTFState> state, const String &p_path) {
+ print_verbose("glTF: Total buffers: " + itos(state->buffers.size()));
+
+ if (!state->buffers.size()) {
+ return OK;
+ }
+ Array buffers;
+
+ for (GLTFBufferIndex i = 0; i < state->buffers.size(); i++) {
+ Vector<uint8_t> buffer_data = state->buffers[i];
+ Dictionary gltf_buffer;
+ 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) {
+ return err;
+ }
+ if (buffer_data.size() == 0) {
+ return OK;
+ }
+ 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);
+ }
+ state->json["buffers"] = buffers;
+
+ return OK;
+}
+
+Error GLTFDocument::_parse_buffers(Ref<GLTFState> state, const String &p_base_path) {
+ if (!state->json.has("buffers")) {
+ return OK;
+ }
+
+ const Array &buffers = state->json["buffers"];
+ for (GLTFBufferIndex i = 0; i < buffers.size(); i++) {
+ if (i == 0 && state->glb_data.size()) {
+ state->buffers.push_back(state->glb_data);
+
+ } else {
+ const Dictionary &buffer = buffers[i];
+ if (buffer.has("uri")) {
+ Vector<uint8_t> buffer_data;
+ String uri = buffer["uri"];
+
+ if (uri.begins_with("data:")) { // Embedded data using base64.
+ // Validate data MIME types and throw an error if it's one we don't know/support.
+ if (!uri.begins_with("data:application/octet-stream;base64") &&
+ !uri.begins_with("data:application/gltf-buffer;base64")) {
+ ERR_PRINT("glTF: Got buffer with an unknown URI data type: " + uri);
+ }
+ buffer_data = _parse_base64_uri(uri);
+ } else { // Relative path to an external image file.
+ uri = p_base_path.plus_file(uri).replace("\\", "/"); // Fix for Windows.
+ buffer_data = FileAccess::get_file_as_array(uri);
+ ERR_FAIL_COND_V_MSG(buffer.size() == 0, ERR_PARSE_ERROR, "glTF: Couldn't load binary file as an array: " + uri);
+ }
+
+ ERR_FAIL_COND_V(!buffer.has("byteLength"), ERR_PARSE_ERROR);
+ int byteLength = buffer["byteLength"];
+ ERR_FAIL_COND_V(byteLength < buffer_data.size(), ERR_PARSE_ERROR);
+ state->buffers.push_back(buffer_data);
+ }
+ }
+ }
+
+ print_verbose("glTF: Total buffers: " + itos(state->buffers.size()));
+
+ return OK;
+}
+
+Error GLTFDocument::_encode_buffer_views(Ref<GLTFState> state) {
+ Array buffers;
+ for (GLTFBufferViewIndex i = 0; i < state->buffer_views.size(); i++) {
+ Dictionary d;
+
+ Ref<GLTFBufferView> buffer_view = state->buffer_views[i];
+
+ d["buffer"] = buffer_view->buffer;
+ d["byteLength"] = buffer_view->byte_length;
+
+ d["byteOffset"] = buffer_view->byte_offset;
+
+ if (buffer_view->byte_stride != -1) {
+ d["byteStride"] = buffer_view->byte_stride;
+ }
+
+ // TODO Sparse
+ // d["target"] = buffer_view->indices;
+
+ ERR_FAIL_COND_V(!d.has("buffer"), ERR_INVALID_DATA);
+ ERR_FAIL_COND_V(!d.has("byteLength"), ERR_INVALID_DATA);
+ buffers.push_back(d);
+ }
+ print_verbose("glTF: Total buffer views: " + itos(state->buffer_views.size()));
+ state->json["bufferViews"] = buffers;
+ return OK;
+}
+
+Error GLTFDocument::_parse_buffer_views(Ref<GLTFState> state) {
+ if (!state->json.has("bufferViews")) {
+ return OK;
+ }
+ const Array &buffers = state->json["bufferViews"];
+ for (GLTFBufferViewIndex i = 0; i < buffers.size(); i++) {
+ const Dictionary &d = buffers[i];
+
+ Ref<GLTFBufferView> buffer_view;
+ buffer_view.instance();
+
+ ERR_FAIL_COND_V(!d.has("buffer"), ERR_PARSE_ERROR);
+ buffer_view->buffer = d["buffer"];
+ ERR_FAIL_COND_V(!d.has("byteLength"), ERR_PARSE_ERROR);
+ buffer_view->byte_length = d["byteLength"];
+
+ if (d.has("byteOffset")) {
+ buffer_view->byte_offset = d["byteOffset"];
+ }
+
+ if (d.has("byteStride")) {
+ buffer_view->byte_stride = d["byteStride"];
+ }
+
+ if (d.has("target")) {
+ const int target = d["target"];
+ buffer_view->indices = target == GLTFDocument::ELEMENT_ARRAY_BUFFER;
+ }
+
+ state->buffer_views.push_back(buffer_view);
+ }
+
+ print_verbose("glTF: Total buffer views: " + itos(state->buffer_views.size()));
+
+ return OK;
+}
+
+Error GLTFDocument::_encode_accessors(Ref<GLTFState> state) {
+ Array accessors;
+ for (GLTFAccessorIndex i = 0; i < state->accessors.size(); i++) {
+ Dictionary d;
+
+ Ref<GLTFAccessor> accessor = state->accessors[i];
+ d["componentType"] = accessor->component_type;
+ d["count"] = accessor->count;
+ d["type"] = _get_accessor_type_name(accessor->type);
+ d["byteOffset"] = accessor->byte_offset;
+ d["normalized"] = accessor->normalized;
+ d["max"] = accessor->max;
+ d["min"] = accessor->min;
+ d["bufferView"] = accessor->buffer_view; //optional because it may be sparse...
+
+ // Dictionary s;
+ // s["count"] = accessor->sparse_count;
+ // ERR_FAIL_COND_V(!s.has("count"), ERR_PARSE_ERROR);
+
+ // s["indices"] = accessor->sparse_accessors;
+ // ERR_FAIL_COND_V(!s.has("indices"), ERR_PARSE_ERROR);
+
+ // Dictionary si;
+
+ // si["bufferView"] = accessor->sparse_indices_buffer_view;
+
+ // ERR_FAIL_COND_V(!si.has("bufferView"), ERR_PARSE_ERROR);
+ // si["componentType"] = accessor->sparse_indices_component_type;
+
+ // if (si.has("byteOffset")) {
+ // si["byteOffset"] = accessor->sparse_indices_byte_offset;
+ // }
+
+ // ERR_FAIL_COND_V(!si.has("componentType"), ERR_PARSE_ERROR);
+ // s["indices"] = si;
+ // Dictionary sv;
+
+ // sv["bufferView"] = accessor->sparse_values_buffer_view;
+ // if (sv.has("byteOffset")) {
+ // sv["byteOffset"] = accessor->sparse_values_byte_offset;
+ // }
+ // ERR_FAIL_COND_V(!sv.has("bufferView"), ERR_PARSE_ERROR);
+ // s["values"] = sv;
+ // ERR_FAIL_COND_V(!s.has("values"), ERR_PARSE_ERROR);
+ // d["sparse"] = s;
+ accessors.push_back(d);
+ }
+
+ state->json["accessors"] = accessors;
+ ERR_FAIL_COND_V(!state->json.has("accessors"), ERR_FILE_CORRUPT);
+ print_verbose("glTF: Total accessors: " + itos(state->accessors.size()));
+
+ return OK;
+}
+
+String GLTFDocument::_get_accessor_type_name(const GLTFDocument::GLTFType p_type) {
+ if (p_type == GLTFDocument::TYPE_SCALAR) {
+ return "SCALAR";
+ }
+ if (p_type == GLTFDocument::TYPE_VEC2) {
+ return "VEC2";
+ }
+ if (p_type == GLTFDocument::TYPE_VEC3) {
+ return "VEC3";
+ }
+ if (p_type == GLTFDocument::TYPE_VEC4) {
+ return "VEC4";
+ }
+
+ if (p_type == GLTFDocument::TYPE_MAT2) {
+ return "MAT2";
+ }
+ if (p_type == GLTFDocument::TYPE_MAT3) {
+ return "MAT3";
+ }
+ if (p_type == GLTFDocument::TYPE_MAT4) {
+ return "MAT4";
+ }
+ ERR_FAIL_V("SCALAR");
+}
+
+GLTFDocument::GLTFType GLTFDocument::_get_type_from_str(const String &p_string) {
+ if (p_string == "SCALAR")
+ return GLTFDocument::TYPE_SCALAR;
+
+ if (p_string == "VEC2")
+ return GLTFDocument::TYPE_VEC2;
+ if (p_string == "VEC3")
+ return GLTFDocument::TYPE_VEC3;
+ if (p_string == "VEC4")
+ return GLTFDocument::TYPE_VEC4;
+
+ if (p_string == "MAT2")
+ return GLTFDocument::TYPE_MAT2;
+ if (p_string == "MAT3")
+ return GLTFDocument::TYPE_MAT3;
+ if (p_string == "MAT4")
+ return GLTFDocument::TYPE_MAT4;
+
+ ERR_FAIL_V(GLTFDocument::TYPE_SCALAR);
+}
+
+Error GLTFDocument::_parse_accessors(Ref<GLTFState> state) {
+ if (!state->json.has("accessors")) {
+ return OK;
+ }
+ const Array &accessors = state->json["accessors"];
+ for (GLTFAccessorIndex i = 0; i < accessors.size(); i++) {
+ const Dictionary &d = accessors[i];
+
+ Ref<GLTFAccessor> accessor;
+ accessor.instance();
+
+ ERR_FAIL_COND_V(!d.has("componentType"), ERR_PARSE_ERROR);
+ accessor->component_type = d["componentType"];
+ ERR_FAIL_COND_V(!d.has("count"), ERR_PARSE_ERROR);
+ accessor->count = d["count"];
+ ERR_FAIL_COND_V(!d.has("type"), ERR_PARSE_ERROR);
+ accessor->type = _get_type_from_str(d["type"]);
+
+ if (d.has("bufferView")) {
+ accessor->buffer_view = d["bufferView"]; //optional because it may be sparse...
+ }
+
+ if (d.has("byteOffset")) {
+ accessor->byte_offset = d["byteOffset"];
+ }
+
+ if (d.has("normalized")) {
+ accessor->normalized = d["normalized"];
+ }
+
+ if (d.has("max")) {
+ accessor->max = d["max"];
+ }
+
+ if (d.has("min")) {
+ accessor->min = d["min"];
+ }
+
+ if (d.has("sparse")) {
+ //eeh..
+
+ const Dictionary &s = d["sparse"];
+
+ ERR_FAIL_COND_V(!s.has("count"), ERR_PARSE_ERROR);
+ accessor->sparse_count = s["count"];
+ ERR_FAIL_COND_V(!s.has("indices"), ERR_PARSE_ERROR);
+ const Dictionary &si = s["indices"];
+
+ ERR_FAIL_COND_V(!si.has("bufferView"), ERR_PARSE_ERROR);
+ accessor->sparse_indices_buffer_view = si["bufferView"];
+ ERR_FAIL_COND_V(!si.has("componentType"), ERR_PARSE_ERROR);
+ accessor->sparse_indices_component_type = si["componentType"];
+
+ if (si.has("byteOffset")) {
+ accessor->sparse_indices_byte_offset = si["byteOffset"];
+ }
+
+ ERR_FAIL_COND_V(!s.has("values"), ERR_PARSE_ERROR);
+ const Dictionary &sv = s["values"];
+
+ ERR_FAIL_COND_V(!sv.has("bufferView"), ERR_PARSE_ERROR);
+ accessor->sparse_values_buffer_view = sv["bufferView"];
+ if (sv.has("byteOffset")) {
+ accessor->sparse_values_byte_offset = sv["byteOffset"];
+ }
+ }
+
+ state->accessors.push_back(accessor);
+ }
+
+ print_verbose("glTF: Total accessors: " + itos(state->accessors.size()));
+
+ return OK;
+}
+
+double GLTFDocument::_filter_number(double p_float) {
+ if (Math::is_nan(p_float)) {
+ return 0.0f;
+ }
+ return p_float;
+}
+
+String GLTFDocument::_get_component_type_name(const uint32_t p_component) {
+ switch (p_component) {
+ case GLTFDocument::COMPONENT_TYPE_BYTE:
+ return "Byte";
+ case GLTFDocument::COMPONENT_TYPE_UNSIGNED_BYTE:
+ return "UByte";
+ case GLTFDocument::COMPONENT_TYPE_SHORT:
+ return "Short";
+ case GLTFDocument::COMPONENT_TYPE_UNSIGNED_SHORT:
+ return "UShort";
+ case GLTFDocument::COMPONENT_TYPE_INT:
+ return "Int";
+ case GLTFDocument::COMPONENT_TYPE_FLOAT:
+ return "Float";
+ }
+
+ return "<Error>";
+}
+
+String GLTFDocument::_get_type_name(const GLTFType p_component) {
+ static const char *names[] = {
+ "float",
+ "vec2",
+ "vec3",
+ "vec4",
+ "mat2",
+ "mat3",
+ "mat4"
+ };
+
+ return names[p_component];
+}
+
+Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src, const int count, const GLTFType type, const int component_type, const bool normalized, const int byte_offset, const bool for_vertex, GLTFBufferViewIndex &r_accessor) {
+ const int component_count_for_type[7] = {
+ 1, 2, 3, 4, 4, 9, 16
+ };
+
+ const int component_count = component_count_for_type[type];
+ const int component_size = _get_component_type_size(component_type);
+ ERR_FAIL_COND_V(component_size == 0, FAILED);
+
+ int skip_every = 0;
+ int skip_bytes = 0;
+ //special case of alignments, as described in spec
+ switch (component_type) {
+ case COMPONENT_TYPE_BYTE:
+ case COMPONENT_TYPE_UNSIGNED_BYTE: {
+ if (type == TYPE_MAT2) {
+ skip_every = 2;
+ skip_bytes = 2;
+ }
+ if (type == TYPE_MAT3) {
+ skip_every = 3;
+ skip_bytes = 1;
+ }
+ } break;
+ case COMPONENT_TYPE_SHORT:
+ case COMPONENT_TYPE_UNSIGNED_SHORT: {
+ if (type == TYPE_MAT3) {
+ skip_every = 6;
+ skip_bytes = 4;
+ }
+ } break;
+ default: {
+ }
+ }
+
+ Ref<GLTFBufferView> bv;
+ bv.instance();
+ const uint32_t offset = bv->byte_offset = byte_offset;
+ Vector<uint8_t> &gltf_buffer = state->buffers.write[0];
+
+ int stride = _get_component_type_size(component_type);
+ if (for_vertex && stride % 4) {
+ stride += 4 - (stride % 4); //according to spec must be multiple of 4
+ }
+ //use to debug
+ print_verbose("glTF: encoding type " + _get_type_name(type) + " component type: " + _get_component_type_name(component_type) + " stride: " + itos(stride) + " amount " + itos(count));
+
+ print_verbose("glTF: encoding accessor offset " + itos(byte_offset) + " view offset: " + itos(bv->byte_offset) + " total buffer len: " + itos(gltf_buffer.size()) + " view len " + itos(bv->byte_length));
+
+ const int buffer_end = (stride * (count - 1)) + _get_component_type_size(component_type);
+ // TODO define bv->byte_stride
+ bv->byte_offset = gltf_buffer.size();
+
+ switch (component_type) {
+ case COMPONENT_TYPE_BYTE: {
+ Vector<int8_t> buffer;
+ buffer.resize(count * component_count);
+ int32_t dst_i = 0;
+ for (int i = 0; i < count; i++) {
+ for (int j = 0; j < component_count; j++) {
+ if (skip_every && j > 0 && (j % skip_every) == 0) {
+ dst_i += skip_bytes;
+ }
+ double d = *src;
+ if (normalized) {
+ buffer.write[dst_i] = d * 128.0;
+ } else {
+ buffer.write[dst_i] = d;
+ }
+ src++;
+ dst_i++;
+ }
+ }
+ int64_t old_size = gltf_buffer.size();
+ gltf_buffer.resize(old_size + (buffer.size() * sizeof(int8_t)));
+ copymem(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int8_t));
+ bv->byte_length = buffer.size() * sizeof(int8_t);
+ } break;
+ case COMPONENT_TYPE_UNSIGNED_BYTE: {
+ Vector<uint8_t> buffer;
+ buffer.resize(count * component_count);
+ int32_t dst_i = 0;
+ for (int i = 0; i < count; i++) {
+ for (int j = 0; j < component_count; j++) {
+ if (skip_every && j > 0 && (j % skip_every) == 0) {
+ dst_i += skip_bytes;
+ }
+ double d = *src;
+ if (normalized) {
+ buffer.write[dst_i] = d * 255.0;
+ } else {
+ buffer.write[dst_i] = d;
+ }
+ src++;
+ dst_i++;
+ }
+ }
+ gltf_buffer.append_array(buffer);
+ bv->byte_length = buffer.size() * sizeof(uint8_t);
+ } break;
+ case COMPONENT_TYPE_SHORT: {
+ Vector<int16_t> buffer;
+ buffer.resize(count * component_count);
+ int32_t dst_i = 0;
+ for (int i = 0; i < count; i++) {
+ for (int j = 0; j < component_count; j++) {
+ if (skip_every && j > 0 && (j % skip_every) == 0) {
+ dst_i += skip_bytes;
+ }
+ double d = *src;
+ if (normalized) {
+ buffer.write[dst_i] = d * 32768.0;
+ } else {
+ buffer.write[dst_i] = d;
+ }
+ src++;
+ dst_i++;
+ }
+ }
+ int64_t old_size = gltf_buffer.size();
+ gltf_buffer.resize(old_size + (buffer.size() * sizeof(int16_t)));
+ copymem(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int16_t));
+ bv->byte_length = buffer.size() * sizeof(int16_t);
+ } break;
+ case COMPONENT_TYPE_UNSIGNED_SHORT: {
+ Vector<uint16_t> buffer;
+ buffer.resize(count * component_count);
+ int32_t dst_i = 0;
+ for (int i = 0; i < count; i++) {
+ for (int j = 0; j < component_count; j++) {
+ if (skip_every && j > 0 && (j % skip_every) == 0) {
+ dst_i += skip_bytes;
+ }
+ double d = *src;
+ if (normalized) {
+ buffer.write[dst_i] = d * 65535.0;
+ } else {
+ buffer.write[dst_i] = d;
+ }
+ src++;
+ dst_i++;
+ }
+ }
+ int64_t old_size = gltf_buffer.size();
+ gltf_buffer.resize(old_size + (buffer.size() * sizeof(uint16_t)));
+ copymem(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(uint16_t));
+ bv->byte_length = buffer.size() * sizeof(uint16_t);
+ } break;
+ case COMPONENT_TYPE_INT: {
+ Vector<int> buffer;
+ buffer.resize(count * component_count);
+ int32_t dst_i = 0;
+ for (int i = 0; i < count; i++) {
+ for (int j = 0; j < component_count; j++) {
+ if (skip_every && j > 0 && (j % skip_every) == 0) {
+ dst_i += skip_bytes;
+ }
+ double d = *src;
+ buffer.write[dst_i] = d;
+ src++;
+ dst_i++;
+ }
+ }
+ int64_t old_size = gltf_buffer.size();
+ gltf_buffer.resize(old_size + (buffer.size() * sizeof(int32_t)));
+ copymem(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int32_t));
+ bv->byte_length = buffer.size() * sizeof(int32_t);
+ } break;
+ case COMPONENT_TYPE_FLOAT: {
+ Vector<float> buffer;
+ buffer.resize(count * component_count);
+ int32_t dst_i = 0;
+ for (int i = 0; i < count; i++) {
+ for (int j = 0; j < component_count; j++) {
+ if (skip_every && j > 0 && (j % skip_every) == 0) {
+ dst_i += skip_bytes;
+ }
+ double d = *src;
+ buffer.write[dst_i] = d;
+ src++;
+ dst_i++;
+ }
+ }
+ int64_t old_size = gltf_buffer.size();
+ gltf_buffer.resize(old_size + (buffer.size() * sizeof(float)));
+ copymem(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(float));
+ bv->byte_length = buffer.size() * sizeof(float);
+ } break;
+ }
+ ERR_FAIL_COND_V(buffer_end > bv->byte_length, ERR_INVALID_DATA);
+
+ ERR_FAIL_COND_V((int)(offset + buffer_end) > gltf_buffer.size(), ERR_INVALID_DATA);
+ r_accessor = bv->buffer = state->buffer_views.size();
+ state->buffer_views.push_back(bv);
+ return OK;
+}
+
+Error GLTFDocument::_decode_buffer_view(Ref<GLTFState> state, double *dst, const GLTFBufferViewIndex p_buffer_view, const int skip_every, const int skip_bytes, const int element_size, const int count, const GLTFType type, const int component_count, const int component_type, const int component_size, const bool normalized, const int byte_offset, const bool for_vertex) {
+ const Ref<GLTFBufferView> bv = state->buffer_views[p_buffer_view];
+
+ int stride = element_size;
+ if (bv->byte_stride != -1) {
+ stride = bv->byte_stride;
+ }
+ if (for_vertex && stride % 4) {
+ stride += 4 - (stride % 4); //according to spec must be multiple of 4
+ }
+
+ ERR_FAIL_INDEX_V(bv->buffer, state->buffers.size(), ERR_PARSE_ERROR);
+
+ const uint32_t offset = bv->byte_offset + byte_offset;
+ Vector<uint8_t> buffer = state->buffers[bv->buffer]; //copy on write, so no performance hit
+ const uint8_t *bufptr = buffer.ptr();
+
+ //use to debug
+ print_verbose("glTF: type " + _get_type_name(type) + " component type: " + _get_component_type_name(component_type) + " stride: " + itos(stride) + " amount " + itos(count));
+ print_verbose("glTF: accessor offset " + itos(byte_offset) + " view offset: " + itos(bv->byte_offset) + " total buffer len: " + itos(buffer.size()) + " view len " + itos(bv->byte_length));
+
+ const int buffer_end = (stride * (count - 1)) + element_size;
+ ERR_FAIL_COND_V(buffer_end > bv->byte_length, ERR_PARSE_ERROR);
+
+ ERR_FAIL_COND_V((int)(offset + buffer_end) > buffer.size(), ERR_PARSE_ERROR);
+
+ //fill everything as doubles
+
+ for (int i = 0; i < count; i++) {
+ const uint8_t *src = &bufptr[offset + i * stride];
+
+ for (int j = 0; j < component_count; j++) {
+ if (skip_every && j > 0 && (j % skip_every) == 0) {
+ src += skip_bytes;
+ }
+
+ double d = 0;
+
+ switch (component_type) {
+ case COMPONENT_TYPE_BYTE: {
+ int8_t b = int8_t(*src);
+ if (normalized) {
+ d = (double(b) / 128.0);
+ } else {
+ d = double(b);
+ }
+ } break;
+ case COMPONENT_TYPE_UNSIGNED_BYTE: {
+ uint8_t b = *src;
+ if (normalized) {
+ d = (double(b) / 255.0);
+ } else {
+ d = double(b);
+ }
+ } break;
+ case COMPONENT_TYPE_SHORT: {
+ int16_t s = *(int16_t *)src;
+ if (normalized) {
+ d = (double(s) / 32768.0);
+ } else {
+ d = double(s);
+ }
+ } break;
+ case COMPONENT_TYPE_UNSIGNED_SHORT: {
+ uint16_t s = *(uint16_t *)src;
+ if (normalized) {
+ d = (double(s) / 65535.0);
+ } else {
+ d = double(s);
+ }
+ } break;
+ case COMPONENT_TYPE_INT: {
+ d = *(int *)src;
+ } break;
+ case COMPONENT_TYPE_FLOAT: {
+ d = *(float *)src;
+ } break;
+ }
+
+ *dst++ = d;
+ src += component_size;
+ }
+ }
+
+ return OK;
+}
+
+int GLTFDocument::_get_component_type_size(const int component_type) {
+ switch (component_type) {
+ case COMPONENT_TYPE_BYTE:
+ case COMPONENT_TYPE_UNSIGNED_BYTE:
+ return 1;
+ break;
+ case COMPONENT_TYPE_SHORT:
+ case COMPONENT_TYPE_UNSIGNED_SHORT:
+ return 2;
+ break;
+ case COMPONENT_TYPE_INT:
+ case COMPONENT_TYPE_FLOAT:
+ return 4;
+ break;
+ default: {
+ ERR_FAIL_V(0);
+ }
+ }
+ return 0;
+}
+
+Vector<double> GLTFDocument::_decode_accessor(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+ //spec, for reference:
+ //https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#data-alignment
+
+ ERR_FAIL_INDEX_V(p_accessor, state->accessors.size(), Vector<double>());
+
+ const Ref<GLTFAccessor> a = state->accessors[p_accessor];
+
+ const int component_count_for_type[7] = {
+ 1, 2, 3, 4, 4, 9, 16
+ };
+
+ const int component_count = component_count_for_type[a->type];
+ const int component_size = _get_component_type_size(a->component_type);
+ ERR_FAIL_COND_V(component_size == 0, Vector<double>());
+ int element_size = component_count * component_size;
+
+ int skip_every = 0;
+ int skip_bytes = 0;
+ //special case of alignments, as described in spec
+ switch (a->component_type) {
+ case COMPONENT_TYPE_BYTE:
+ case COMPONENT_TYPE_UNSIGNED_BYTE: {
+ if (a->type == TYPE_MAT2) {
+ skip_every = 2;
+ skip_bytes = 2;
+ element_size = 8; //override for this case
+ }
+ if (a->type == TYPE_MAT3) {
+ skip_every = 3;
+ skip_bytes = 1;
+ element_size = 12; //override for this case
+ }
+ } break;
+ case COMPONENT_TYPE_SHORT:
+ case COMPONENT_TYPE_UNSIGNED_SHORT: {
+ if (a->type == TYPE_MAT3) {
+ skip_every = 6;
+ skip_bytes = 4;
+ element_size = 16; //override for this case
+ }
+ } break;
+ default: {
+ }
+ }
+
+ Vector<double> dst_buffer;
+ dst_buffer.resize(component_count * a->count);
+ double *dst = dst_buffer.ptrw();
+
+ if (a->buffer_view >= 0) {
+ ERR_FAIL_INDEX_V(a->buffer_view, state->buffer_views.size(), Vector<double>());
+
+ const Error err = _decode_buffer_view(state, dst, a->buffer_view, skip_every, skip_bytes, element_size, a->count, a->type, component_count, a->component_type, component_size, a->normalized, a->byte_offset, p_for_vertex);
+ if (err != OK)
+ return Vector<double>();
+ } else {
+ //fill with zeros, as bufferview is not defined.
+ for (int i = 0; i < (a->count * component_count); i++) {
+ dst_buffer.write[i] = 0;
+ }
+ }
+
+ if (a->sparse_count > 0) {
+ // I could not find any file using this, so this code is so far untested
+ Vector<double> indices;
+ indices.resize(a->sparse_count);
+ const int indices_component_size = _get_component_type_size(a->sparse_indices_component_type);
+
+ Error err = _decode_buffer_view(state, indices.ptrw(), a->sparse_indices_buffer_view, 0, 0, indices_component_size, a->sparse_count, TYPE_SCALAR, 1, a->sparse_indices_component_type, indices_component_size, false, a->sparse_indices_byte_offset, false);
+ if (err != OK)
+ return Vector<double>();
+
+ Vector<double> data;
+ data.resize(component_count * a->sparse_count);
+ err = _decode_buffer_view(state, data.ptrw(), a->sparse_values_buffer_view, skip_every, skip_bytes, element_size, a->sparse_count, a->type, component_count, a->component_type, component_size, a->normalized, a->sparse_values_byte_offset, p_for_vertex);
+ if (err != OK)
+ return Vector<double>();
+
+ for (int i = 0; i < indices.size(); i++) {
+ const int write_offset = int(indices[i]) * component_count;
+
+ for (int j = 0; j < component_count; j++) {
+ dst[write_offset + j] = data[i * component_count + j];
+ }
+ }
+ }
+
+ return dst_buffer;
+}
+
+GLTFAccessorIndex GLTFDocument::_encode_accessor_as_ints(Ref<GLTFState> state, const Vector<int32_t> p_attribs, const bool p_for_vertex) {
+ if (p_attribs.size() == 0) {
+ return -1;
+ }
+ const int element_count = 1;
+ const int ret_size = p_attribs.size();
+ Vector<double> attribs;
+ attribs.resize(ret_size);
+ Vector<double> type_max;
+ type_max.resize(element_count);
+ Vector<double> type_min;
+ type_min.resize(element_count);
+ for (int i = 0; i < p_attribs.size(); i++) {
+ attribs.write[i] = Math::snapped(p_attribs[i], 1.0);
+ if (i == 0) {
+ for (int32_t type_i = 0; type_i < element_count; type_i++) {
+ type_max.write[type_i] = attribs[(i * element_count) + type_i];
+ type_min.write[type_i] = attribs[(i * element_count) + type_i];
+ }
+ }
+ for (int32_t type_i = 0; type_i < element_count; type_i++) {
+ type_max.write[type_i] = MAX(attribs[(i * element_count) + type_i], type_max[type_i]);
+ type_min.write[type_i] = MIN(attribs[(i * element_count) + type_i], type_min[type_i]);
+ type_max.write[type_i] = _filter_number(type_max.write[type_i]);
+ type_min.write[type_i] = _filter_number(type_min.write[type_i]);
+ }
+ }
+
+ ERR_FAIL_COND_V(attribs.size() == 0, -1);
+
+ Ref<GLTFAccessor> accessor;
+ accessor.instance();
+ GLTFBufferIndex buffer_view_i;
+ int64_t size = state->buffers[0].size();
+ const GLTFDocument::GLTFType type = GLTFDocument::TYPE_SCALAR;
+ const int component_type = GLTFDocument::COMPONENT_TYPE_INT;
+
+ accessor->max = type_max;
+ accessor->min = type_min;
+ accessor->normalized = false;
+ accessor->count = ret_size;
+ accessor->type = type;
+ accessor->component_type = component_type;
+ accessor->byte_offset = 0;
+ Error err = _encode_buffer_view(state, attribs.ptr(), attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
+ if (err != OK) {
+ return -1;
+ }
+ accessor->buffer_view = buffer_view_i;
+ state->accessors.push_back(accessor);
+ return state->accessors.size() - 1;
+}
+
+Vector<int> GLTFDocument::_decode_accessor_as_ints(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+ const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+ Vector<int> ret;
+
+ if (attribs.size() == 0)
+ return ret;
+
+ const double *attribs_ptr = attribs.ptr();
+ const int ret_size = attribs.size();
+ ret.resize(ret_size);
+ {
+ for (int i = 0; i < ret_size; i++) {
+ ret.write[i] = int(attribs_ptr[i]);
+ }
+ }
+ return ret;
+}
+
+Vector<float> GLTFDocument::_decode_accessor_as_floats(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+ const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+ Vector<float> ret;
+
+ if (attribs.size() == 0)
+ return ret;
+
+ const double *attribs_ptr = attribs.ptr();
+ const int ret_size = attribs.size();
+ ret.resize(ret_size);
+ {
+ for (int i = 0; i < ret_size; i++) {
+ ret.write[i] = float(attribs_ptr[i]);
+ }
+ }
+ return ret;
+}
+
+GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec2(Ref<GLTFState> state, const Vector<Vector2> p_attribs, const bool p_for_vertex) {
+ if (p_attribs.size() == 0) {
+ return -1;
+ }
+ const int element_count = 2;
+
+ const int ret_size = p_attribs.size() * element_count;
+ Vector<double> attribs;
+ attribs.resize(ret_size);
+ Vector<double> type_max;
+ type_max.resize(element_count);
+ Vector<double> type_min;
+ type_min.resize(element_count);
+
+ for (int i = 0; i < p_attribs.size(); i++) {
+ Vector2 attrib = p_attribs[i];
+ attribs.write[(i * element_count) + 0] = Math::snapped(attrib.x, CMP_NORMALIZE_TOLERANCE);
+ attribs.write[(i * element_count) + 1] = Math::snapped(attrib.y, CMP_NORMALIZE_TOLERANCE);
+ _calc_accessor_min_max(i, element_count, type_max, attribs, type_min);
+ }
+
+ ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1);
+
+ Ref<GLTFAccessor> accessor;
+ accessor.instance();
+ GLTFBufferIndex buffer_view_i;
+ int64_t size = state->buffers[0].size();
+ const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC2;
+ const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT;
+
+ accessor->max = type_max;
+ accessor->min = type_min;
+ accessor->normalized = false;
+ accessor->count = p_attribs.size();
+ accessor->type = type;
+ accessor->component_type = component_type;
+ accessor->byte_offset = 0;
+ Error err = _encode_buffer_view(state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
+ if (err != OK) {
+ return -1;
+ }
+ accessor->buffer_view = buffer_view_i;
+ state->accessors.push_back(accessor);
+ return state->accessors.size() - 1;
+}
+
+GLTFAccessorIndex GLTFDocument::_encode_accessor_as_color(Ref<GLTFState> state, const Vector<Color> p_attribs, const bool p_for_vertex) {
+ if (p_attribs.size() == 0) {
+ return -1;
+ }
+
+ const int ret_size = p_attribs.size() * 4;
+ Vector<double> attribs;
+ attribs.resize(ret_size);
+
+ const int element_count = 4;
+ Vector<double> type_max;
+ type_max.resize(element_count);
+ Vector<double> type_min;
+ type_min.resize(element_count);
+ for (int i = 0; i < p_attribs.size(); i++) {
+ Color attrib = p_attribs[i];
+ attribs.write[(i * element_count) + 0] = Math::snapped(attrib.r, CMP_NORMALIZE_TOLERANCE);
+ attribs.write[(i * element_count) + 1] = Math::snapped(attrib.g, CMP_NORMALIZE_TOLERANCE);
+ attribs.write[(i * element_count) + 2] = Math::snapped(attrib.b, CMP_NORMALIZE_TOLERANCE);
+ attribs.write[(i * element_count) + 3] = Math::snapped(attrib.a, CMP_NORMALIZE_TOLERANCE);
+
+ _calc_accessor_min_max(i, element_count, type_max, attribs, type_min);
+ }
+
+ ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1);
+
+ Ref<GLTFAccessor> accessor;
+ accessor.instance();
+ GLTFBufferIndex buffer_view_i;
+ int64_t size = state->buffers[0].size();
+ const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC4;
+ const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT;
+
+ accessor->max = type_max;
+ accessor->min = type_min;
+ accessor->normalized = false;
+ accessor->count = p_attribs.size();
+ accessor->type = type;
+ accessor->component_type = component_type;
+ accessor->byte_offset = 0;
+ Error err = _encode_buffer_view(state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
+ if (err != OK) {
+ return -1;
+ }
+ accessor->buffer_view = buffer_view_i;
+ state->accessors.push_back(accessor);
+ return state->accessors.size() - 1;
+}
+
+void GLTFDocument::_calc_accessor_min_max(int i, const int element_count, Vector<double> &type_max, Vector<double> attribs, Vector<double> &type_min) {
+ if (i == 0) {
+ for (int32_t type_i = 0; type_i < element_count; type_i++) {
+ type_max.write[type_i] = attribs[(i * element_count) + type_i];
+ type_min.write[type_i] = attribs[(i * element_count) + type_i];
+ }
+ }
+ for (int32_t type_i = 0; type_i < element_count; type_i++) {
+ type_max.write[type_i] = MAX(attribs[(i * element_count) + type_i], type_max[type_i]);
+ type_min.write[type_i] = MIN(attribs[(i * element_count) + type_i], type_min[type_i]);
+ type_max.write[type_i] = _filter_number(type_max.write[type_i]);
+ type_min.write[type_i] = _filter_number(type_min.write[type_i]);
+ }
+}
+
+GLTFAccessorIndex GLTFDocument::_encode_accessor_as_weights(Ref<GLTFState> state, const Vector<Color> p_attribs, const bool p_for_vertex) {
+ if (p_attribs.size() == 0) {
+ return -1;
+ }
+
+ const int ret_size = p_attribs.size() * 4;
+ Vector<double> attribs;
+ attribs.resize(ret_size);
+
+ const int element_count = 4;
+
+ Vector<double> type_max;
+ type_max.resize(element_count);
+ Vector<double> type_min;
+ type_min.resize(element_count);
+ for (int i = 0; i < p_attribs.size(); i++) {
+ Color attrib = p_attribs[i];
+ attribs.write[(i * element_count) + 0] = Math::snapped(attrib.r, CMP_NORMALIZE_TOLERANCE);
+ attribs.write[(i * element_count) + 1] = Math::snapped(attrib.g, CMP_NORMALIZE_TOLERANCE);
+ attribs.write[(i * element_count) + 2] = Math::snapped(attrib.b, CMP_NORMALIZE_TOLERANCE);
+ attribs.write[(i * element_count) + 3] = Math::snapped(attrib.a, CMP_NORMALIZE_TOLERANCE);
+
+ _calc_accessor_min_max(i, element_count, type_max, attribs, type_min);
+ }
+
+ ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1);
+
+ Ref<GLTFAccessor> accessor;
+ accessor.instance();
+ GLTFBufferIndex buffer_view_i;
+ int64_t size = state->buffers[0].size();
+ const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC4;
+ const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT;
+
+ accessor->max = type_max;
+ accessor->min = type_min;
+ accessor->normalized = false;
+ accessor->count = p_attribs.size();
+ accessor->type = type;
+ accessor->component_type = component_type;
+ accessor->byte_offset = 0;
+ Error err = _encode_buffer_view(state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
+ if (err != OK) {
+ return -1;
+ }
+ accessor->buffer_view = buffer_view_i;
+ state->accessors.push_back(accessor);
+ return state->accessors.size() - 1;
+}
+
+GLTFAccessorIndex GLTFDocument::_encode_accessor_as_joints(Ref<GLTFState> state, const Vector<Color> p_attribs, const bool p_for_vertex) {
+ if (p_attribs.size() == 0) {
+ return -1;
+ }
+
+ const int element_count = 4;
+ const int ret_size = p_attribs.size() * element_count;
+ Vector<double> attribs;
+ attribs.resize(ret_size);
+
+ Vector<double> type_max;
+ type_max.resize(element_count);
+ Vector<double> type_min;
+ type_min.resize(element_count);
+ for (int i = 0; i < p_attribs.size(); i++) {
+ Color attrib = p_attribs[i];
+ attribs.write[(i * element_count) + 0] = Math::snapped(attrib.r, CMP_NORMALIZE_TOLERANCE);
+ attribs.write[(i * element_count) + 1] = Math::snapped(attrib.g, CMP_NORMALIZE_TOLERANCE);
+ attribs.write[(i * element_count) + 2] = Math::snapped(attrib.b, CMP_NORMALIZE_TOLERANCE);
+ attribs.write[(i * element_count) + 3] = Math::snapped(attrib.a, CMP_NORMALIZE_TOLERANCE);
+ _calc_accessor_min_max(i, element_count, type_max, attribs, type_min);
+ }
+ ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1);
+
+ Ref<GLTFAccessor> accessor;
+ accessor.instance();
+ GLTFBufferIndex buffer_view_i;
+ int64_t size = state->buffers[0].size();
+ const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC4;
+ const int component_type = GLTFDocument::COMPONENT_TYPE_UNSIGNED_SHORT;
+
+ accessor->max = type_max;
+ accessor->min = type_min;
+ accessor->normalized = false;
+ accessor->count = p_attribs.size();
+ accessor->type = type;
+ accessor->component_type = component_type;
+ accessor->byte_offset = 0;
+ Error err = _encode_buffer_view(state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
+ if (err != OK) {
+ return -1;
+ }
+ accessor->buffer_view = buffer_view_i;
+ state->accessors.push_back(accessor);
+ return state->accessors.size() - 1;
+}
+
+GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quats(Ref<GLTFState> state, const Vector<Quat> p_attribs, const bool p_for_vertex) {
+ if (p_attribs.size() == 0) {
+ return -1;
+ }
+ const int element_count = 4;
+
+ const int ret_size = p_attribs.size() * element_count;
+ Vector<double> attribs;
+ attribs.resize(ret_size);
+
+ Vector<double> type_max;
+ type_max.resize(element_count);
+ Vector<double> type_min;
+ type_min.resize(element_count);
+ for (int i = 0; i < p_attribs.size(); i++) {
+ Quat quat = p_attribs[i];
+ attribs.write[(i * element_count) + 0] = Math::snapped(quat.x, CMP_NORMALIZE_TOLERANCE);
+ attribs.write[(i * element_count) + 1] = Math::snapped(quat.y, CMP_NORMALIZE_TOLERANCE);
+ attribs.write[(i * element_count) + 2] = Math::snapped(quat.z, CMP_NORMALIZE_TOLERANCE);
+ attribs.write[(i * element_count) + 3] = Math::snapped(quat.w, CMP_NORMALIZE_TOLERANCE);
+
+ _calc_accessor_min_max(i, element_count, type_max, attribs, type_min);
+ }
+
+ ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1);
+
+ Ref<GLTFAccessor> accessor;
+ accessor.instance();
+ GLTFBufferIndex buffer_view_i;
+ int64_t size = state->buffers[0].size();
+ const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC4;
+ const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT;
+
+ accessor->max = type_max;
+ accessor->min = type_min;
+ accessor->normalized = false;
+ accessor->count = p_attribs.size();
+ accessor->type = type;
+ accessor->component_type = component_type;
+ accessor->byte_offset = 0;
+ Error err = _encode_buffer_view(state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
+ if (err != OK) {
+ return -1;
+ }
+ accessor->buffer_view = buffer_view_i;
+ state->accessors.push_back(accessor);
+ return state->accessors.size() - 1;
+}
+
+Vector<Vector2> GLTFDocument::_decode_accessor_as_vec2(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+ const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+ Vector<Vector2> ret;
+
+ if (attribs.size() == 0)
+ return ret;
+
+ ERR_FAIL_COND_V(attribs.size() % 2 != 0, ret);
+ const double *attribs_ptr = attribs.ptr();
+ const int ret_size = attribs.size() / 2;
+ ret.resize(ret_size);
+ {
+ for (int i = 0; i < ret_size; i++) {
+ ret.write[i] = Vector2(attribs_ptr[i * 2 + 0], attribs_ptr[i * 2 + 1]);
+ }
+ }
+ return ret;
+}
+
+GLTFAccessorIndex GLTFDocument::_encode_accessor_as_floats(Ref<GLTFState> state, const Vector<real_t> p_attribs, const bool p_for_vertex) {
+ if (p_attribs.size() == 0) {
+ return -1;
+ }
+ const int element_count = 1;
+ const int ret_size = p_attribs.size();
+ Vector<double> attribs;
+ attribs.resize(ret_size);
+
+ Vector<double> type_max;
+ type_max.resize(element_count);
+ Vector<double> type_min;
+ type_min.resize(element_count);
+
+ for (int i = 0; i < p_attribs.size(); i++) {
+ attribs.write[i] = Math::snapped(p_attribs[i], CMP_NORMALIZE_TOLERANCE);
+
+ _calc_accessor_min_max(i, element_count, type_max, attribs, type_min);
+ }
+
+ ERR_FAIL_COND_V(!attribs.size(), -1);
+
+ Ref<GLTFAccessor> accessor;
+ accessor.instance();
+ GLTFBufferIndex buffer_view_i;
+ int64_t size = state->buffers[0].size();
+ const GLTFDocument::GLTFType type = GLTFDocument::TYPE_SCALAR;
+ const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT;
+
+ accessor->max = type_max;
+ accessor->min = type_min;
+ accessor->normalized = false;
+ accessor->count = ret_size;
+ accessor->type = type;
+ accessor->component_type = component_type;
+ accessor->byte_offset = 0;
+ Error err = _encode_buffer_view(state, attribs.ptr(), attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
+ if (err != OK) {
+ return -1;
+ }
+ accessor->buffer_view = buffer_view_i;
+ state->accessors.push_back(accessor);
+ return state->accessors.size() - 1;
+}
+
+GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec3(Ref<GLTFState> state, const Vector<Vector3> p_attribs, const bool p_for_vertex) {
+ if (p_attribs.size() == 0) {
+ return -1;
+ }
+ const int element_count = 3;
+ const int ret_size = p_attribs.size() * element_count;
+ Vector<double> attribs;
+ attribs.resize(ret_size);
+
+ Vector<double> type_max;
+ type_max.resize(element_count);
+ Vector<double> type_min;
+ type_min.resize(element_count);
+ for (int i = 0; i < p_attribs.size(); i++) {
+ Vector3 attrib = p_attribs[i];
+ attribs.write[(i * element_count) + 0] = Math::snapped(attrib.x, CMP_NORMALIZE_TOLERANCE);
+ attribs.write[(i * element_count) + 1] = Math::snapped(attrib.y, CMP_NORMALIZE_TOLERANCE);
+ attribs.write[(i * element_count) + 2] = Math::snapped(attrib.z, CMP_NORMALIZE_TOLERANCE);
+
+ _calc_accessor_min_max(i, element_count, type_max, attribs, type_min);
+ }
+ ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1);
+
+ Ref<GLTFAccessor> accessor;
+ accessor.instance();
+ GLTFBufferIndex buffer_view_i;
+ int64_t size = state->buffers[0].size();
+ const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC3;
+ const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT;
+
+ accessor->max = type_max;
+ accessor->min = type_min;
+ accessor->normalized = false;
+ accessor->count = p_attribs.size();
+ accessor->type = type;
+ accessor->component_type = component_type;
+ accessor->byte_offset = 0;
+ Error err = _encode_buffer_view(state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
+ if (err != OK) {
+ return -1;
+ }
+ accessor->buffer_view = buffer_view_i;
+ state->accessors.push_back(accessor);
+ return state->accessors.size() - 1;
+}
+
+GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> state, const Vector<Transform> p_attribs, const bool p_for_vertex) {
+ if (p_attribs.size() == 0) {
+ return -1;
+ }
+ const int element_count = 16;
+ const int ret_size = p_attribs.size() * element_count;
+ Vector<double> attribs;
+ attribs.resize(ret_size);
+
+ Vector<double> type_max;
+ type_max.resize(element_count);
+ Vector<double> type_min;
+ type_min.resize(element_count);
+ for (int i = 0; i < p_attribs.size(); i++) {
+ Transform attrib = p_attribs[i];
+ Basis basis = attrib.get_basis();
+ Vector3 axis_0 = basis.get_axis(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);
+ 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);
+ 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);
+ attribs.write[i * element_count + 11] = 0.0;
+
+ Vector3 origin = attrib.get_origin();
+ attribs.write[i * element_count + 12] = Math::snapped(origin.x, CMP_NORMALIZE_TOLERANCE);
+ attribs.write[i * element_count + 13] = Math::snapped(origin.y, CMP_NORMALIZE_TOLERANCE);
+ attribs.write[i * element_count + 14] = Math::snapped(origin.z, CMP_NORMALIZE_TOLERANCE);
+ attribs.write[i * element_count + 15] = 1.0;
+
+ _calc_accessor_min_max(i, element_count, type_max, attribs, type_min);
+ }
+ ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1);
+
+ Ref<GLTFAccessor> accessor;
+ accessor.instance();
+ GLTFBufferIndex buffer_view_i;
+ int64_t size = state->buffers[0].size();
+ const GLTFDocument::GLTFType type = GLTFDocument::TYPE_MAT4;
+ const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT;
+
+ accessor->max = type_max;
+ accessor->min = type_min;
+ accessor->normalized = false;
+ accessor->count = p_attribs.size();
+ accessor->type = type;
+ accessor->component_type = component_type;
+ accessor->byte_offset = 0;
+ Error err = _encode_buffer_view(state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
+ if (err != OK) {
+ return -1;
+ }
+ accessor->buffer_view = buffer_view_i;
+ state->accessors.push_back(accessor);
+ return state->accessors.size() - 1;
+}
+
+Vector<Vector3> GLTFDocument::_decode_accessor_as_vec3(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+ const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+ Vector<Vector3> ret;
+
+ if (attribs.size() == 0)
+ return ret;
+
+ ERR_FAIL_COND_V(attribs.size() % 3 != 0, ret);
+ const double *attribs_ptr = attribs.ptr();
+ const int ret_size = attribs.size() / 3;
+ ret.resize(ret_size);
+ {
+ for (int i = 0; i < ret_size; i++) {
+ ret.write[i] = Vector3(attribs_ptr[i * 3 + 0], attribs_ptr[i * 3 + 1], attribs_ptr[i * 3 + 2]);
+ }
+ }
+ return ret;
+}
+
+Vector<Color> GLTFDocument::_decode_accessor_as_color(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+ const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+ Vector<Color> ret;
+
+ if (attribs.size() == 0)
+ return ret;
+
+ const int type = state->accessors[p_accessor]->type;
+ ERR_FAIL_COND_V(!(type == TYPE_VEC3 || type == TYPE_VEC4), ret);
+ int vec_len = 3;
+ if (type == TYPE_VEC4) {
+ vec_len = 4;
+ }
+
+ ERR_FAIL_COND_V(attribs.size() % vec_len != 0, ret);
+ const double *attribs_ptr = attribs.ptr();
+ const int ret_size = attribs.size() / vec_len;
+ ret.resize(ret_size);
+ {
+ for (int i = 0; i < ret_size; i++) {
+ ret.write[i] = Color(attribs_ptr[i * vec_len + 0], attribs_ptr[i * vec_len + 1], attribs_ptr[i * vec_len + 2], vec_len == 4 ? attribs_ptr[i * 4 + 3] : 1.0);
+ }
+ }
+ return ret;
+}
+Vector<Quat> GLTFDocument::_decode_accessor_as_quat(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+ const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+ Vector<Quat> ret;
+
+ if (attribs.size() == 0)
+ return ret;
+
+ ERR_FAIL_COND_V(attribs.size() % 4 != 0, ret);
+ const double *attribs_ptr = attribs.ptr();
+ const int ret_size = attribs.size() / 4;
+ ret.resize(ret_size);
+ {
+ for (int i = 0; i < ret_size; i++) {
+ ret.write[i] = Quat(attribs_ptr[i * 4 + 0], attribs_ptr[i * 4 + 1], attribs_ptr[i * 4 + 2], attribs_ptr[i * 4 + 3]).normalized();
+ }
+ }
+ return ret;
+}
+Vector<Transform2D> GLTFDocument::_decode_accessor_as_xform2d(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+ const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+ Vector<Transform2D> ret;
+
+ if (attribs.size() == 0)
+ return ret;
+
+ ERR_FAIL_COND_V(attribs.size() % 4 != 0, ret);
+ ret.resize(attribs.size() / 4);
+ for (int i = 0; i < ret.size(); i++) {
+ ret.write[i][0] = Vector2(attribs[i * 4 + 0], attribs[i * 4 + 1]);
+ ret.write[i][1] = Vector2(attribs[i * 4 + 2], attribs[i * 4 + 3]);
+ }
+ return ret;
+}
+
+Vector<Basis> GLTFDocument::_decode_accessor_as_basis(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+ const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+ Vector<Basis> ret;
+
+ if (attribs.size() == 0)
+ return ret;
+
+ 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]));
+ }
+ return ret;
+}
+
+Vector<Transform> GLTFDocument::_decode_accessor_as_xform(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+ const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+ Vector<Transform> ret;
+
+ if (attribs.size() == 0)
+ return ret;
+
+ 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].set_origin(Vector3(attribs[i * 16 + 12], attribs[i * 16 + 13], attribs[i * 16 + 14]));
+ }
+ return ret;
+}
+
+Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
+ Array meshes;
+ for (GLTFMeshIndex gltf_mesh_i = 0; gltf_mesh_i < state->meshes.size(); gltf_mesh_i++) {
+ print_verbose("glTF: Serializing mesh: " + itos(gltf_mesh_i));
+ Ref<EditorSceneImporterMesh> import_mesh = state->meshes.write[gltf_mesh_i]->get_mesh();
+ if (import_mesh.is_null()) {
+ continue;
+ }
+ Array primitives;
+ Array targets;
+ Dictionary gltf_mesh;
+ Array target_names;
+ Array weights;
+ for (int surface_i = 0; surface_i < import_mesh->get_surface_count(); surface_i++) {
+ Dictionary primitive;
+ Mesh::PrimitiveType primitive_type = import_mesh->get_surface_primitive_type(surface_i);
+ switch (primitive_type) {
+ case Mesh::PRIMITIVE_POINTS: {
+ primitive["mode"] = 0;
+ break;
+ }
+ case Mesh::PRIMITIVE_LINES: {
+ primitive["mode"] = 1;
+ break;
+ }
+ // case Mesh::PRIMITIVE_LINE_LOOP: {
+ // primitive["mode"] = 2;
+ // break;
+ // }
+ case Mesh::PRIMITIVE_LINE_STRIP: {
+ primitive["mode"] = 3;
+ break;
+ }
+ case Mesh::PRIMITIVE_TRIANGLES: {
+ primitive["mode"] = 4;
+ break;
+ }
+ case Mesh::PRIMITIVE_TRIANGLE_STRIP: {
+ primitive["mode"] = 5;
+ break;
+ }
+ // case Mesh::PRIMITIVE_TRIANGLE_FAN: {
+ // primitive["mode"] = 6;
+ // break;
+ // }
+ default: {
+ ERR_FAIL_V(FAILED);
+ }
+ }
+
+ Array array = import_mesh->get_surface_arrays(surface_i);
+ Dictionary attributes;
+ {
+ Vector<Vector3> a = array[Mesh::ARRAY_VERTEX];
+ ERR_FAIL_COND_V(!a.size(), ERR_INVALID_DATA);
+ attributes["POSITION"] = _encode_accessor_as_vec3(state, a, true);
+ }
+ {
+ Vector<real_t> a = array[Mesh::ARRAY_TANGENT];
+ if (a.size()) {
+ const int ret_size = a.size() / 4;
+ Vector<Color> attribs;
+ attribs.resize(ret_size);
+ for (int i = 0; i < ret_size; i++) {
+ Color out;
+ out.r = a[(i * 4) + 0];
+ out.g = a[(i * 4) + 1];
+ out.b = a[(i * 4) + 2];
+ out.a = a[(i * 4) + 3];
+ attribs.write[i] = out;
+ }
+ attributes["TANGENT"] = _encode_accessor_as_color(state, attribs, true);
+ }
+ }
+ {
+ Vector<Vector3> a = array[Mesh::ARRAY_NORMAL];
+ if (a.size()) {
+ const int ret_size = a.size();
+ Vector<Vector3> attribs;
+ attribs.resize(ret_size);
+ for (int i = 0; i < ret_size; i++) {
+ attribs.write[i] = Vector3(a[i]).normalized();
+ }
+ attributes["NORMAL"] = _encode_accessor_as_vec3(state, attribs, true);
+ }
+ }
+ {
+ Vector<Vector2> a = array[Mesh::ARRAY_TEX_UV];
+ if (a.size()) {
+ attributes["TEXCOORD_0"] = _encode_accessor_as_vec2(state, a, true);
+ }
+ }
+ {
+ Vector<Vector2> a = array[Mesh::ARRAY_TEX_UV2];
+ if (a.size()) {
+ attributes["TEXCOORD_1"] = _encode_accessor_as_vec2(state, a, true);
+ }
+ }
+ {
+ Vector<Color> a = array[Mesh::ARRAY_COLOR];
+ if (a.size()) {
+ attributes["COLOR_0"] = _encode_accessor_as_color(state, a, true);
+ }
+ }
+ Map<int, int> joint_i_to_bone_i;
+ for (GLTFNodeIndex node_i = 0; node_i < state->nodes.size(); node_i++) {
+ GLTFSkinIndex skin_i = -1;
+ if (state->nodes[node_i]->mesh == gltf_mesh_i) {
+ skin_i = state->nodes[node_i]->skin;
+ }
+ if (skin_i != -1) {
+ joint_i_to_bone_i = state->skins[skin_i]->joint_i_to_bone_i;
+ break;
+ }
+ }
+ {
+ const Array &a = array[Mesh::ARRAY_BONES];
+ const Vector<Vector3> &vertex_array = array[Mesh::ARRAY_VERTEX];
+ if ((a.size() / JOINT_GROUP_SIZE) == vertex_array.size()) {
+ const int ret_size = a.size() / JOINT_GROUP_SIZE;
+ Vector<Color> attribs;
+ attribs.resize(ret_size);
+ {
+ for (int array_i = 0; array_i < attribs.size(); array_i++) {
+ int32_t joint_0 = a[(array_i * JOINT_GROUP_SIZE) + 0];
+ int32_t joint_1 = a[(array_i * JOINT_GROUP_SIZE) + 1];
+ int32_t joint_2 = a[(array_i * JOINT_GROUP_SIZE) + 2];
+ int32_t joint_3 = a[(array_i * JOINT_GROUP_SIZE) + 3];
+ attribs.write[array_i] = Color(joint_0, joint_1, joint_2, joint_3);
+ }
+ }
+ attributes["JOINTS_0"] = _encode_accessor_as_joints(state, attribs, true);
+ } else if ((a.size() / (JOINT_GROUP_SIZE * 2)) >= vertex_array.size()) {
+ int32_t vertex_count = vertex_array.size();
+ Vector<Color> joints_0;
+ joints_0.resize(vertex_count);
+ Vector<Color> joints_1;
+ joints_1.resize(vertex_count);
+ int32_t weights_8_count = JOINT_GROUP_SIZE * 2;
+ for (int32_t vertex_i = 0; vertex_i < vertex_count; vertex_i++) {
+ Color joint_0;
+ joint_0.r = a[vertex_i * weights_8_count + 0];
+ joint_0.g = a[vertex_i * weights_8_count + 1];
+ joint_0.b = a[vertex_i * weights_8_count + 2];
+ joint_0.a = a[vertex_i * weights_8_count + 3];
+ joints_0.write[vertex_i] = joint_0;
+ Color joint_1;
+ joint_1.r = a[vertex_i * weights_8_count + 4];
+ joint_1.g = a[vertex_i * weights_8_count + 5];
+ joint_1.b = a[vertex_i * weights_8_count + 6];
+ joint_1.a = a[vertex_i * weights_8_count + 7];
+ joints_1.write[vertex_i] = joint_1;
+ }
+ attributes["JOINTS_0"] = _encode_accessor_as_joints(state, joints_0, true);
+ attributes["JOINTS_1"] = _encode_accessor_as_joints(state, joints_1, true);
+ }
+ }
+ {
+ const Array &a = array[Mesh::ARRAY_WEIGHTS];
+ const Vector<Vector3> &vertex_array = array[Mesh::ARRAY_VERTEX];
+ if ((a.size() / JOINT_GROUP_SIZE) == vertex_array.size()) {
+ const int ret_size = a.size() / JOINT_GROUP_SIZE;
+ Vector<Color> attribs;
+ attribs.resize(ret_size);
+ for (int i = 0; i < ret_size; i++) {
+ attribs.write[i] = Color(a[(i * JOINT_GROUP_SIZE) + 0], a[(i * JOINT_GROUP_SIZE) + 1], a[(i * JOINT_GROUP_SIZE) + 2], a[(i * JOINT_GROUP_SIZE) + 3]);
+ }
+ attributes["WEIGHTS_0"] = _encode_accessor_as_weights(state, attribs, true);
+ } else if ((a.size() / (JOINT_GROUP_SIZE * 2)) >= vertex_array.size()) {
+ int32_t vertex_count = vertex_array.size();
+ Vector<Color> weights_0;
+ weights_0.resize(vertex_count);
+ Vector<Color> weights_1;
+ weights_1.resize(vertex_count);
+ int32_t weights_8_count = JOINT_GROUP_SIZE * 2;
+ for (int32_t vertex_i = 0; vertex_i < vertex_count; vertex_i++) {
+ Color weight_0;
+ weight_0.r = a[vertex_i * weights_8_count + 0];
+ weight_0.g = a[vertex_i * weights_8_count + 1];
+ weight_0.b = a[vertex_i * weights_8_count + 2];
+ weight_0.a = a[vertex_i * weights_8_count + 3];
+ weights_0.write[vertex_i] = weight_0;
+ Color weight_1;
+ weight_1.r = a[vertex_i * weights_8_count + 4];
+ weight_1.g = a[vertex_i * weights_8_count + 5];
+ weight_1.b = a[vertex_i * weights_8_count + 6];
+ weight_1.a = a[vertex_i * weights_8_count + 7];
+ weights_1.write[vertex_i] = weight_1;
+ }
+ attributes["WEIGHTS_0"] = _encode_accessor_as_weights(state, weights_0, true);
+ attributes["WEIGHTS_1"] = _encode_accessor_as_weights(state, weights_1, true);
+ }
+ }
+ {
+ Vector<int32_t> mesh_indices = array[Mesh::ARRAY_INDEX];
+ if (mesh_indices.size()) {
+ if (primitive_type == Mesh::PRIMITIVE_TRIANGLES) {
+ //swap around indices, convert ccw to cw for front face
+ const int is = mesh_indices.size();
+ for (int k = 0; k < is; k += 3) {
+ SWAP(mesh_indices.write[k + 0], mesh_indices.write[k + 2]);
+ }
+ }
+ primitive["indices"] = _encode_accessor_as_ints(state, mesh_indices, true);
+ } else {
+ if (primitive_type == Mesh::PRIMITIVE_TRIANGLES) {
+ //generate indices because they need to be swapped for CW/CCW
+ const Vector<Vector3> &vertices = array[Mesh::ARRAY_VERTEX];
+ Ref<SurfaceTool> st;
+ st.instance();
+ st->create_from_triangle_arrays(array);
+ st->index();
+ Vector<int32_t> generated_indices = st->commit_to_arrays()[Mesh::ARRAY_INDEX];
+ const int vs = vertices.size();
+ generated_indices.resize(vs);
+ {
+ for (int k = 0; k < vs; k += 3) {
+ generated_indices.write[k] = k;
+ generated_indices.write[k + 1] = k + 2;
+ generated_indices.write[k + 2] = k + 1;
+ }
+ }
+ primitive["indices"] = _encode_accessor_as_ints(state, generated_indices, true);
+ }
+ }
+ }
+
+ primitive["attributes"] = attributes;
+
+ //blend shapes
+ print_verbose("glTF: Mesh has targets");
+ if (import_mesh->get_blend_shape_count()) {
+ ArrayMesh::BlendShapeMode shape_mode = import_mesh->get_blend_shape_mode();
+ for (int morph_i = 0; morph_i < import_mesh->get_blend_shape_count(); morph_i++) {
+ Array array_morph = import_mesh->get_surface_blend_shape_arrays(surface_i, morph_i);
+ target_names.push_back(import_mesh->get_blend_shape_name(morph_i));
+ Dictionary t;
+ Vector<Vector3> varr = array_morph[Mesh::ARRAY_VERTEX];
+ Array mesh_arrays = import_mesh->get_surface_arrays(surface_i);
+ if (varr.size()) {
+ Vector<Vector3> src_varr = array[Mesh::ARRAY_VERTEX];
+ if (shape_mode == ArrayMesh::BlendShapeMode::BLEND_SHAPE_MODE_NORMALIZED) {
+ const int max_idx = src_varr.size();
+ for (int blend_i = 0; blend_i < max_idx; blend_i++) {
+ varr.write[blend_i] = Vector3(varr[blend_i]) - src_varr[blend_i];
+ }
+ }
+
+ t["POSITION"] = _encode_accessor_as_vec3(state, varr, true);
+ }
+
+ Vector<Vector3> narr = array_morph[Mesh::ARRAY_NORMAL];
+ if (varr.size()) {
+ t["NORMAL"] = _encode_accessor_as_vec3(state, narr, true);
+ }
+ Vector<real_t> tarr = array_morph[Mesh::ARRAY_TANGENT];
+ if (tarr.size()) {
+ const int ret_size = tarr.size() / 4;
+ Vector<Color> attribs;
+ attribs.resize(ret_size);
+ for (int i = 0; i < ret_size; i++) {
+ Color tangent;
+ tangent.r = tarr[(i * 4) + 0];
+ tangent.r = tarr[(i * 4) + 1];
+ tangent.r = tarr[(i * 4) + 2];
+ tangent.r = tarr[(i * 4) + 3];
+ }
+ t["TANGENT"] = _encode_accessor_as_color(state, attribs, true);
+ }
+ targets.push_back(t);
+ }
+ }
+
+ Ref<BaseMaterial3D> mat = import_mesh->get_surface_material(surface_i);
+ if (mat.is_valid()) {
+ Map<Ref<BaseMaterial3D>, GLTFMaterialIndex>::Element *material_cache_i = state->material_cache.find(mat);
+ if (material_cache_i && material_cache_i->get() != -1) {
+ primitive["material"] = material_cache_i->get();
+ } else {
+ GLTFMaterialIndex mat_i = state->materials.size();
+ state->materials.push_back(mat);
+ primitive["material"] = mat_i;
+ state->material_cache.insert(mat, mat_i);
+ }
+ }
+
+ if (targets.size()) {
+ primitive["targets"] = targets;
+ }
+
+ primitives.push_back(primitive);
+ }
+
+ Dictionary e;
+ e["targetNames"] = target_names;
+
+ for (int j = 0; j < target_names.size(); j++) {
+ real_t weight = 0;
+ if (j < state->meshes.write[gltf_mesh_i]->get_blend_weights().size()) {
+ weight = state->meshes.write[gltf_mesh_i]->get_blend_weights()[j];
+ }
+ weights.push_back(weight);
+ }
+ if (weights.size()) {
+ gltf_mesh["weights"] = weights;
+ }
+
+ ERR_FAIL_COND_V(target_names.size() != weights.size(), FAILED);
+
+ gltf_mesh["extras"] = e;
+
+ gltf_mesh["primitives"] = primitives;
+
+ meshes.push_back(gltf_mesh);
+ }
+
+ state->json["meshes"] = meshes;
+ print_verbose("glTF: Total meshes: " + itos(meshes.size()));
+
+ return OK;
+}
+
+Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
+ if (!state->json.has("meshes")) {
+ return OK;
+ }
+
+ Array meshes = state->json["meshes"];
+ for (GLTFMeshIndex i = 0; i < meshes.size(); i++) {
+ print_verbose("glTF: Parsing mesh: " + itos(i));
+ Dictionary d = meshes[i];
+
+ Ref<GLTFMesh> mesh;
+ mesh.instance();
+ bool has_vertex_color = false;
+
+ ERR_FAIL_COND_V(!d.has("primitives"), ERR_PARSE_ERROR);
+
+ Array primitives = d["primitives"];
+ const Dictionary &extras = d.has("extras") ? (Dictionary)d["extras"] : Dictionary();
+ Ref<EditorSceneImporterMesh> import_mesh;
+ import_mesh.instance();
+ for (int j = 0; j < primitives.size(); j++) {
+ Dictionary p = primitives[j];
+
+ Array array;
+ array.resize(Mesh::ARRAY_MAX);
+
+ ERR_FAIL_COND_V(!p.has("attributes"), ERR_PARSE_ERROR);
+
+ Dictionary a = p["attributes"];
+
+ Mesh::PrimitiveType primitive = Mesh::PRIMITIVE_TRIANGLES;
+ if (p.has("mode")) {
+ const int mode = p["mode"];
+ ERR_FAIL_INDEX_V(mode, 7, ERR_FILE_CORRUPT);
+ static const Mesh::PrimitiveType primitives2[7] = {
+ Mesh::PRIMITIVE_POINTS,
+ Mesh::PRIMITIVE_LINES,
+ Mesh::PRIMITIVE_LINES, //loop not supported, should ce converted
+ Mesh::PRIMITIVE_LINES,
+ Mesh::PRIMITIVE_TRIANGLES,
+ Mesh::PRIMITIVE_TRIANGLE_STRIP,
+ Mesh::PRIMITIVE_TRIANGLES, //fan not supported, should be converted
+#ifndef _MSC_VER
+#warning line loop and triangle fan are not supported and need to be converted to lines and triangles
+#endif
+
+ };
+
+ primitive = primitives2[mode];
+ }
+
+ ERR_FAIL_COND_V(!a.has("POSITION"), ERR_PARSE_ERROR);
+ if (a.has("POSITION")) {
+ array[Mesh::ARRAY_VERTEX] = _decode_accessor_as_vec3(state, a["POSITION"], true);
+ }
+ if (a.has("NORMAL")) {
+ array[Mesh::ARRAY_NORMAL] = _decode_accessor_as_vec3(state, a["NORMAL"], true);
+ }
+ if (a.has("TANGENT")) {
+ array[Mesh::ARRAY_TANGENT] = _decode_accessor_as_floats(state, a["TANGENT"], true);
+ }
+ if (a.has("TEXCOORD_0")) {
+ array[Mesh::ARRAY_TEX_UV] = _decode_accessor_as_vec2(state, a["TEXCOORD_0"], true);
+ }
+ if (a.has("TEXCOORD_1")) {
+ array[Mesh::ARRAY_TEX_UV2] = _decode_accessor_as_vec2(state, a["TEXCOORD_1"], true);
+ }
+ if (a.has("COLOR_0")) {
+ array[Mesh::ARRAY_COLOR] = _decode_accessor_as_color(state, a["COLOR_0"], true);
+ has_vertex_color = true;
+ }
+ if (a.has("JOINTS_0") && !a.has("JOINTS_1")) {
+ array[Mesh::ARRAY_BONES] = _decode_accessor_as_ints(state, a["JOINTS_0"], true);
+ } else if (a.has("JOINTS_0") && a.has("JOINTS_1")) {
+ PackedInt32Array joints_0 = _decode_accessor_as_ints(state, a["JOINTS_0"], true);
+ PackedInt32Array joints_1 = _decode_accessor_as_ints(state, a["JOINTS_1"], true);
+ ERR_FAIL_COND_V(joints_0.size() != joints_0.size(), ERR_INVALID_DATA);
+ int32_t weight_8_count = JOINT_GROUP_SIZE * 2;
+ int32_t vertex_count = joints_0.size() / JOINT_GROUP_SIZE;
+ Vector<int> joints;
+ joints.resize(vertex_count * weight_8_count);
+ for (int32_t vertex_i = 0; vertex_i < vertex_count; vertex_i++) {
+ joints.write[vertex_i * weight_8_count + 0] = joints_0[vertex_i * JOINT_GROUP_SIZE + 0];
+ joints.write[vertex_i * weight_8_count + 1] = joints_0[vertex_i * JOINT_GROUP_SIZE + 1];
+ joints.write[vertex_i * weight_8_count + 2] = joints_0[vertex_i * JOINT_GROUP_SIZE + 2];
+ joints.write[vertex_i * weight_8_count + 3] = joints_0[vertex_i * JOINT_GROUP_SIZE + 3];
+ joints.write[vertex_i * weight_8_count + 4] = joints_1[vertex_i * JOINT_GROUP_SIZE + 0];
+ joints.write[vertex_i * weight_8_count + 5] = joints_1[vertex_i * JOINT_GROUP_SIZE + 1];
+ joints.write[vertex_i * weight_8_count + 6] = joints_1[vertex_i * JOINT_GROUP_SIZE + 2];
+ joints.write[vertex_i * weight_8_count + 7] = joints_1[vertex_i * JOINT_GROUP_SIZE + 3];
+ }
+ array[Mesh::ARRAY_BONES] = joints;
+ }
+ if (a.has("WEIGHTS_0") && !a.has("WEIGHTS_1")) {
+ Vector<float> weights = _decode_accessor_as_floats(state, a["WEIGHTS_0"], true);
+ { //gltf does not seem to normalize the weights for some reason..
+ int wc = weights.size();
+ float *w = weights.ptrw();
+
+ for (int k = 0; k < wc; k += 4) {
+ float total = 0.0;
+ total += w[k + 0];
+ total += w[k + 1];
+ total += w[k + 2];
+ total += w[k + 3];
+ if (total > 0.0) {
+ w[k + 0] /= total;
+ w[k + 1] /= total;
+ w[k + 2] /= total;
+ w[k + 3] /= total;
+ }
+ }
+ }
+ array[Mesh::ARRAY_WEIGHTS] = weights;
+ } else if (a.has("WEIGHTS_0") && a.has("WEIGHTS_1")) {
+ Vector<float> weights_0 = _decode_accessor_as_floats(state, a["WEIGHTS_0"], true);
+ Vector<float> weights_1 = _decode_accessor_as_floats(state, a["WEIGHTS_1"], true);
+ Vector<float> weights;
+ ERR_FAIL_COND_V(weights_0.size() != weights_1.size(), ERR_INVALID_DATA);
+ int32_t weight_8_count = JOINT_GROUP_SIZE * 2;
+ int32_t vertex_count = weights_0.size() / JOINT_GROUP_SIZE;
+ weights.resize(vertex_count * weight_8_count);
+ for (int32_t vertex_i = 0; vertex_i < vertex_count; vertex_i++) {
+ weights.write[vertex_i * weight_8_count + 0] = weights_0[vertex_i * JOINT_GROUP_SIZE + 0];
+ weights.write[vertex_i * weight_8_count + 1] = weights_0[vertex_i * JOINT_GROUP_SIZE + 1];
+ weights.write[vertex_i * weight_8_count + 2] = weights_0[vertex_i * JOINT_GROUP_SIZE + 2];
+ weights.write[vertex_i * weight_8_count + 3] = weights_0[vertex_i * JOINT_GROUP_SIZE + 3];
+ weights.write[vertex_i * weight_8_count + 4] = weights_1[vertex_i * JOINT_GROUP_SIZE + 0];
+ weights.write[vertex_i * weight_8_count + 5] = weights_1[vertex_i * JOINT_GROUP_SIZE + 1];
+ weights.write[vertex_i * weight_8_count + 6] = weights_1[vertex_i * JOINT_GROUP_SIZE + 2];
+ weights.write[vertex_i * weight_8_count + 7] = weights_1[vertex_i * JOINT_GROUP_SIZE + 3];
+ }
+ { //gltf does not seem to normalize the weights for some reason..
+ int wc = weights.size();
+ float *w = weights.ptrw();
+
+ for (int k = 0; k < wc; k += weight_8_count) {
+ float total = 0.0;
+ total += w[k + 0];
+ total += w[k + 1];
+ total += w[k + 2];
+ total += w[k + 3];
+ total += w[k + 4];
+ total += w[k + 5];
+ total += w[k + 6];
+ total += w[k + 7];
+ if (total > 0.0) {
+ w[k + 0] /= total;
+ w[k + 1] /= total;
+ w[k + 2] /= total;
+ w[k + 3] /= total;
+ w[k + 4] /= total;
+ w[k + 5] /= total;
+ w[k + 6] /= total;
+ w[k + 7] /= total;
+ }
+ }
+ }
+ array[Mesh::ARRAY_WEIGHTS] = weights;
+ }
+
+ if (p.has("indices")) {
+ Vector<int> indices = _decode_accessor_as_ints(state, p["indices"], false);
+
+ if (primitive == Mesh::PRIMITIVE_TRIANGLES) {
+ //swap around indices, convert ccw to cw for front face
+
+ const int is = indices.size();
+ int *w = indices.ptrw();
+ for (int k = 0; k < is; k += 3) {
+ SWAP(w[k + 1], w[k + 2]);
+ }
+ }
+ array[Mesh::ARRAY_INDEX] = indices;
+
+ } else if (primitive == Mesh::PRIMITIVE_TRIANGLES) {
+ //generate indices because they need to be swapped for CW/CCW
+ const Vector<Vector3> &vertices = array[Mesh::ARRAY_VERTEX];
+ ERR_FAIL_COND_V(vertices.size() == 0, ERR_PARSE_ERROR);
+ Vector<int> indices;
+ const int vs = vertices.size();
+ indices.resize(vs);
+ {
+ int *w = indices.ptrw();
+ for (int k = 0; k < vs; k += 3) {
+ w[k] = k;
+ w[k + 1] = k + 2;
+ w[k + 2] = k + 1;
+ }
+ }
+ array[Mesh::ARRAY_INDEX] = indices;
+ }
+
+ bool generate_tangents = (primitive == Mesh::PRIMITIVE_TRIANGLES && !a.has("TANGENT") && a.has("TEXCOORD_0") && a.has("NORMAL"));
+
+ if (generate_tangents) {
+ //must generate mikktspace tangents.. ergh..
+ Ref<SurfaceTool> st;
+ st.instance();
+ if (a.has("JOINTS_0") && a.has("JOINTS_1")) {
+ st->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS);
+ }
+ st->create_from_triangle_arrays(array);
+ st->generate_tangents();
+ array = st->commit_to_arrays();
+ }
+
+ Array morphs;
+ //blend shapes
+ if (p.has("targets")) {
+ print_verbose("glTF: Mesh has targets");
+ const Array &targets = p["targets"];
+
+ //ideally BLEND_SHAPE_MODE_RELATIVE since gltf2 stores in displacement
+ //but it could require a larger refactor?
+ import_mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED);
+
+ if (j == 0) {
+ const Array &target_names = extras.has("targetNames") ? (Array)extras["targetNames"] : Array();
+ for (int k = 0; k < targets.size(); k++) {
+ const String name = k < target_names.size() ? (String)target_names[k] : String("morph_") + itos(k);
+ import_mesh->add_blend_shape(name);
+ }
+ }
+
+ for (int k = 0; k < targets.size(); k++) {
+ const Dictionary &t = targets[k];
+
+ Array array_copy;
+ array_copy.resize(Mesh::ARRAY_MAX);
+
+ for (int l = 0; l < Mesh::ARRAY_MAX; l++) {
+ array_copy[l] = array[l];
+ }
+
+ array_copy[Mesh::ARRAY_INDEX] = Variant();
+
+ if (t.has("POSITION")) {
+ Vector<Vector3> varr = _decode_accessor_as_vec3(state, t["POSITION"], true);
+ const Vector<Vector3> src_varr = array[Mesh::ARRAY_VERTEX];
+ const int size = src_varr.size();
+ ERR_FAIL_COND_V(size == 0, ERR_PARSE_ERROR);
+ {
+ const int max_idx = varr.size();
+ varr.resize(size);
+
+ Vector3 *w_varr = varr.ptrw();
+ const Vector3 *r_varr = varr.ptr();
+ const Vector3 *r_src_varr = src_varr.ptr();
+ for (int l = 0; l < size; l++) {
+ if (l < max_idx) {
+ w_varr[l] = r_varr[l] + r_src_varr[l];
+ } else {
+ w_varr[l] = r_src_varr[l];
+ }
+ }
+ }
+ array_copy[Mesh::ARRAY_VERTEX] = varr;
+ }
+ if (t.has("NORMAL")) {
+ Vector<Vector3> narr = _decode_accessor_as_vec3(state, t["NORMAL"], true);
+ const Vector<Vector3> src_narr = array[Mesh::ARRAY_NORMAL];
+ int size = src_narr.size();
+ ERR_FAIL_COND_V(size == 0, ERR_PARSE_ERROR);
+ {
+ int max_idx = narr.size();
+ narr.resize(size);
+
+ Vector3 *w_narr = narr.ptrw();
+ const Vector3 *r_narr = narr.ptr();
+ const Vector3 *r_src_narr = src_narr.ptr();
+ for (int l = 0; l < size; l++) {
+ if (l < max_idx) {
+ w_narr[l] = r_narr[l] + r_src_narr[l];
+ } else {
+ w_narr[l] = r_src_narr[l];
+ }
+ }
+ }
+ array_copy[Mesh::ARRAY_NORMAL] = narr;
+ }
+ if (t.has("TANGENT")) {
+ const Vector<Vector3> tangents_v3 = _decode_accessor_as_vec3(state, t["TANGENT"], true);
+ const Vector<float> src_tangents = array[Mesh::ARRAY_TANGENT];
+ ERR_FAIL_COND_V(src_tangents.size() == 0, ERR_PARSE_ERROR);
+
+ Vector<float> tangents_v4;
+
+ {
+ int max_idx = tangents_v3.size();
+
+ int size4 = src_tangents.size();
+ tangents_v4.resize(size4);
+ float *w4 = tangents_v4.ptrw();
+
+ const Vector3 *r3 = tangents_v3.ptr();
+ const float *r4 = src_tangents.ptr();
+
+ for (int l = 0; l < size4 / 4; l++) {
+ if (l < max_idx) {
+ w4[l * 4 + 0] = r3[l].x + r4[l * 4 + 0];
+ w4[l * 4 + 1] = r3[l].y + r4[l * 4 + 1];
+ w4[l * 4 + 2] = r3[l].z + r4[l * 4 + 2];
+ } else {
+ w4[l * 4 + 0] = r4[l * 4 + 0];
+ w4[l * 4 + 1] = r4[l * 4 + 1];
+ w4[l * 4 + 2] = r4[l * 4 + 2];
+ }
+ w4[l * 4 + 3] = r4[l * 4 + 3]; //copy flip value
+ }
+ }
+
+ array_copy[Mesh::ARRAY_TANGENT] = tangents_v4;
+ }
+
+ if (generate_tangents) {
+ Ref<SurfaceTool> st;
+ st.instance();
+ if (a.has("JOINTS_0") && a.has("JOINTS_1")) {
+ st->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS);
+ }
+ st->create_from_triangle_arrays(array_copy);
+ st->deindex();
+ st->generate_tangents();
+ array_copy = st->commit_to_arrays();
+ }
+
+ 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];
+ if (has_vertex_color) {
+ mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ }
+ mat = mat3d;
+
+ } else if (has_vertex_color) {
+ Ref<StandardMaterial3D> mat3d;
+ mat3d.instance();
+ mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ mat = mat3d;
+ }
+
+ import_mesh->add_surface(primitive, array, morphs, Dictionary(), mat);
+ }
+
+ Vector<float> blend_weights;
+ blend_weights.resize(import_mesh->get_blend_shape_count());
+ for (int32_t weight_i = 0; weight_i < blend_weights.size(); weight_i++) {
+ blend_weights.write[weight_i] = 0.0f;
+ }
+
+ if (d.has("weights")) {
+ const Array &weights = d["weights"];
+ for (int j = 0; j < weights.size(); j++) {
+ if (j >= blend_weights.size()) {
+ break;
+ }
+ blend_weights.write[j] = weights[j];
+ }
+ mesh->set_blend_weights(blend_weights);
+ }
+ mesh->set_mesh(import_mesh);
+
+ state->meshes.push_back(mesh);
+ }
+
+ print_verbose("glTF: Total meshes: " + itos(state->meshes.size()));
+
+ return OK;
+}
+
+Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path) {
+ Array images;
+ for (int i = 0; i < state->images.size(); i++) {
+ Dictionary d;
+
+ ERR_CONTINUE(state->images[i].is_null());
+
+ Ref<Image> image = state->images[i]->get_data();
+ ERR_CONTINUE(image.is_null());
+
+ if (p_path.to_lower().ends_with("glb")) {
+ GLTFBufferViewIndex bvi;
+
+ Ref<GLTFBufferView> bv;
+ bv.instance();
+
+ const GLTFBufferIndex bi = 0;
+ bv->buffer = bi;
+ bv->byte_offset = state->buffers[bi].size();
+ ERR_FAIL_INDEX_V(bi, state->buffers.size(), ERR_PARAMETER_RANGE_ERROR);
+
+ Vector<uint8_t> buffer;
+ Ref<ImageTexture> img_tex = image;
+ if (img_tex.is_valid()) {
+ image = img_tex->get_data();
+ }
+ Error err = PNGDriverCommon::image_to_png(image, buffer);
+ ERR_FAIL_COND_V_MSG(err, err, "Can't convert image to PNG.");
+
+ bv->byte_length = buffer.size();
+ state->buffers.write[bi].resize(state->buffers[bi].size() + bv->byte_length);
+ copymem(&state->buffers.write[bi].write[bv->byte_offset], buffer.ptr(), buffer.size());
+ ERR_FAIL_COND_V(bv->byte_offset + bv->byte_length > state->buffers[bi].size(), ERR_FILE_CORRUPT);
+
+ state->buffer_views.push_back(bv);
+ bvi = state->buffer_views.size() - 1;
+ d["bufferView"] = bvi;
+ d["mimeType"] = "image/png";
+ } else {
+ String name = state->images[i]->get_name();
+ if (name.is_empty()) {
+ name = itos(i);
+ }
+ name = _gen_unique_name(state, name);
+ name = name.pad_zeros(3);
+ Ref<_Directory> dir;
+ dir.instance();
+ String texture_dir = "textures";
+ String new_texture_dir = p_path.get_base_dir() + "/" + texture_dir;
+ dir->open(p_path.get_base_dir());
+ if (!dir->dir_exists(new_texture_dir)) {
+ dir->make_dir(new_texture_dir);
+ }
+ name = name + ".png";
+ image->save_png(new_texture_dir.plus_file(name));
+ d["uri"] = texture_dir.plus_file(name);
+ }
+ images.push_back(d);
+ }
+
+ print_verbose("Total images: " + itos(state->images.size()));
+
+ if (!images.size()) {
+ return OK;
+ }
+ state->json["images"] = images;
+
+ return OK;
+}
+
+Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_path) {
+ if (!state->json.has("images")) {
+ return OK;
+ }
+
+ // Ref: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#images
+
+ const Array &images = state->json["images"];
+ for (int i = 0; i < images.size(); i++) {
+ const Dictionary &d = images[i];
+
+ // glTF 2.0 supports PNG and JPEG types, which can be specified as (from spec):
+ // "- a URI to an external file in one of the supported images formats, or
+ // - a URI with embedded base64-encoded data, or
+ // - a reference to a bufferView; in that case mimeType must be defined."
+ // Since mimeType is optional for external files and base64 data, we'll have to
+ // fall back on letting Godot parse the data to figure out if it's PNG or JPEG.
+
+ // We'll assume that we use either URI or bufferView, so let's warn the user
+ // if their image somehow uses both. And fail if it has neither.
+ ERR_CONTINUE_MSG(!d.has("uri") && !d.has("bufferView"), "Invalid image definition in glTF file, it should specific an 'uri' or 'bufferView'.");
+ if (d.has("uri") && d.has("bufferView")) {
+ WARN_PRINT("Invalid image definition in glTF file using both 'uri' and 'bufferView'. 'bufferView' will take precedence.");
+ }
+
+ String mimetype;
+ if (d.has("mimeType")) { // Should be "image/png" or "image/jpeg".
+ mimetype = d["mimeType"];
+ }
+
+ Vector<uint8_t> data;
+ const uint8_t *data_ptr = nullptr;
+ int data_size = 0;
+
+ if (d.has("uri")) {
+ // Handles the first two bullet points from the spec (embedded data, or external file).
+ String uri = d["uri"];
+
+ if (uri.begins_with("data:")) { // Embedded data using base64.
+ // Validate data MIME types and throw a warning if it's one we don't know/support.
+ if (!uri.begins_with("data:application/octet-stream;base64") &&
+ !uri.begins_with("data:application/gltf-buffer;base64") &&
+ !uri.begins_with("data:image/png;base64") &&
+ !uri.begins_with("data:image/jpeg;base64")) {
+ WARN_PRINT(vformat("glTF: Image index '%d' uses an unsupported URI data type: %s. Skipping it.", i, uri));
+ state->images.push_back(Ref<Texture2D>()); // Placeholder to keep count.
+ continue;
+ }
+ data = _parse_base64_uri(uri);
+ data_ptr = data.ptr();
+ data_size = data.size();
+ // mimeType is optional, but if we have it defined in the URI, let's use it.
+ if (mimetype.is_empty()) {
+ if (uri.begins_with("data:image/png;base64")) {
+ mimetype = "image/png";
+ } else if (uri.begins_with("data:image/jpeg;base64")) {
+ mimetype = "image/jpeg";
+ }
+ }
+ } else { // Relative path to an external image file.
+ uri = p_base_path.plus_file(uri).replace("\\", "/"); // Fix for Windows.
+ // ResourceLoader will rely on the file extension to use the relevant loader.
+ // The spec says that if mimeType is defined, it should take precedence (e.g.
+ // there could be a `.png` image which is actually JPEG), but there's no easy
+ // API for that in Godot, so we'd have to load as a buffer (i.e. embedded in
+ // the material), so we do this only as fallback.
+ Ref<Texture2D> texture = ResourceLoader::load(uri);
+ if (texture.is_valid()) {
+ state->images.push_back(texture);
+ continue;
+ } else if (mimetype == "image/png" || mimetype == "image/jpeg") {
+ // Fallback to loading as byte array.
+ // This enables us to support the spec's requirement that we honor mimetype
+ // regardless of file URI.
+ data = FileAccess::get_file_as_array(uri);
+ if (data.size() == 0) {
+ WARN_PRINT(vformat("glTF: Image index '%d' couldn't be loaded as a buffer of MIME type '%s' from URI: %s. Skipping it.", i, mimetype, uri));
+ state->images.push_back(Ref<Texture2D>()); // Placeholder to keep count.
+ continue;
+ }
+ data_ptr = data.ptr();
+ data_size = data.size();
+ } else {
+ WARN_PRINT(vformat("glTF: Image index '%d' couldn't be loaded from URI: %s. Skipping it.", i, uri));
+ state->images.push_back(Ref<Texture2D>()); // Placeholder to keep count.
+ continue;
+ }
+ }
+ } else if (d.has("bufferView")) {
+ // Handles the third bullet point from the spec (bufferView).
+ ERR_FAIL_COND_V_MSG(mimetype.is_empty(), ERR_FILE_CORRUPT,
+ vformat("glTF: Image index '%d' specifies 'bufferView' but no 'mimeType', which is invalid.", i));
+
+ const GLTFBufferViewIndex bvi = d["bufferView"];
+
+ ERR_FAIL_INDEX_V(bvi, state->buffer_views.size(), ERR_PARAMETER_RANGE_ERROR);
+
+ Ref<GLTFBufferView> bv = state->buffer_views[bvi];
+
+ const GLTFBufferIndex bi = bv->buffer;
+ ERR_FAIL_INDEX_V(bi, state->buffers.size(), ERR_PARAMETER_RANGE_ERROR);
+
+ ERR_FAIL_COND_V(bv->byte_offset + bv->byte_length > state->buffers[bi].size(), ERR_FILE_CORRUPT);
+
+ data_ptr = &state->buffers[bi][bv->byte_offset];
+ data_size = bv->byte_length;
+ }
+
+ Ref<Image> img;
+
+ if (mimetype == "image/png") { // Load buffer as PNG.
+ ERR_FAIL_COND_V(Image::_png_mem_loader_func == nullptr, ERR_UNAVAILABLE);
+ img = Image::_png_mem_loader_func(data_ptr, data_size);
+ } else if (mimetype == "image/jpeg") { // Loader buffer as JPEG.
+ ERR_FAIL_COND_V(Image::_jpg_mem_loader_func == nullptr, ERR_UNAVAILABLE);
+ img = Image::_jpg_mem_loader_func(data_ptr, data_size);
+ } else {
+ // We can land here if we got an URI with base64-encoded data with application/* MIME type,
+ // and the optional mimeType property was not defined to tell us how to handle this data (or was invalid).
+ // So let's try PNG first, then JPEG.
+ ERR_FAIL_COND_V(Image::_png_mem_loader_func == nullptr, ERR_UNAVAILABLE);
+ img = Image::_png_mem_loader_func(data_ptr, data_size);
+ if (img.is_null()) {
+ ERR_FAIL_COND_V(Image::_jpg_mem_loader_func == nullptr, ERR_UNAVAILABLE);
+ img = Image::_jpg_mem_loader_func(data_ptr, data_size);
+ }
+ }
+
+ ERR_FAIL_COND_V_MSG(img.is_null(), ERR_FILE_CORRUPT,
+ vformat("glTF: Couldn't load image index '%d' with its given mimetype: %s.", i, mimetype));
+
+ Ref<ImageTexture> t;
+ t.instance();
+ t->create_from_image(img);
+
+ state->images.push_back(t);
+ }
+
+ print_verbose("glTF: Total images: " + itos(state->images.size()));
+
+ return OK;
+}
+
+Error GLTFDocument::_serialize_textures(Ref<GLTFState> state) {
+ if (!state->textures.size()) {
+ return OK;
+ }
+
+ Array textures;
+ for (int32_t i = 0; i < state->textures.size(); i++) {
+ Dictionary d;
+ Ref<GLTFTexture> t = state->textures[i];
+ ERR_CONTINUE(t->get_src_image() == -1);
+ d["source"] = t->get_src_image();
+ textures.push_back(d);
+ }
+ state->json["textures"] = textures;
+
+ return OK;
+}
+
+Error GLTFDocument::_parse_textures(Ref<GLTFState> state) {
+ if (!state->json.has("textures"))
+ return OK;
+
+ const Array &textures = state->json["textures"];
+ for (GLTFTextureIndex i = 0; i < textures.size(); i++) {
+ const Dictionary &d = textures[i];
+
+ ERR_FAIL_COND_V(!d.has("source"), ERR_PARSE_ERROR);
+
+ Ref<GLTFTexture> t;
+ t.instance();
+ t->set_src_image(d["source"]);
+ state->textures.push_back(t);
+ }
+
+ return OK;
+}
+
+GLTFTextureIndex GLTFDocument::_set_texture(Ref<GLTFState> state, Ref<Texture2D> p_texture) {
+ ERR_FAIL_COND_V(p_texture.is_null(), -1);
+ Ref<GLTFTexture> gltf_texture;
+ gltf_texture.instance();
+ ERR_FAIL_COND_V(p_texture->get_data().is_null(), -1);
+ GLTFImageIndex gltf_src_image_i = state->images.size();
+ state->images.push_back(p_texture);
+ gltf_texture->set_src_image(gltf_src_image_i);
+ GLTFTextureIndex gltf_texture_i = state->textures.size();
+ state->textures.push_back(gltf_texture);
+ return gltf_texture_i;
+}
+
+Ref<Texture2D> GLTFDocument::_get_texture(Ref<GLTFState> state, const GLTFTextureIndex p_texture) {
+ ERR_FAIL_INDEX_V(p_texture, state->textures.size(), Ref<Texture2D>());
+ const GLTFImageIndex image = state->textures[p_texture]->get_src_image();
+
+ ERR_FAIL_INDEX_V(image, state->images.size(), Ref<Texture2D>());
+
+ return state->images[image];
+}
+
+Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
+ Array materials;
+ for (int32_t i = 0; i < state->materials.size(); i++) {
+ Dictionary d;
+
+ Ref<BaseMaterial3D> material = state->materials[i];
+ if (material.is_null()) {
+ materials.push_back(d);
+ continue;
+ }
+ if (!material->get_name().is_empty()) {
+ d["name"] = _gen_unique_name(state, material->get_name());
+ }
+ {
+ Dictionary mr;
+ {
+ Array arr;
+ const Color c = material->get_albedo().to_linear();
+ arr.push_back(c.r);
+ arr.push_back(c.g);
+ arr.push_back(c.b);
+ arr.push_back(c.a);
+ mr["baseColorFactor"] = arr;
+ }
+ {
+ Dictionary bct;
+ Ref<Texture2D> albedo_texture = material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO);
+ GLTFTextureIndex gltf_texture_index = -1;
+
+ if (albedo_texture.is_valid() && albedo_texture->get_data().is_valid()) {
+ albedo_texture->set_name(material->get_name() + "_albedo");
+ gltf_texture_index = _set_texture(state, albedo_texture);
+ }
+ if (gltf_texture_index != -1) {
+ bct["index"] = gltf_texture_index;
+ bct["extensions"] = _serialize_texture_transform_uv1(material);
+ mr["baseColorTexture"] = bct;
+ }
+ }
+
+ mr["metallicFactor"] = material->get_metallic();
+ mr["roughnessFactor"] = material->get_roughness();
+ bool has_roughness = material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_data().is_valid();
+ bool has_ao = material->get_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION) && material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION).is_valid();
+ bool has_metalness = material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_data().is_valid();
+ if (has_ao || has_roughness || has_metalness) {
+ Dictionary mrt;
+ Ref<Texture2D> roughness_texture = material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS);
+ BaseMaterial3D::TextureChannel roughness_channel = material->get_roughness_texture_channel();
+ Ref<Texture2D> metallic_texture = material->get_texture(BaseMaterial3D::TEXTURE_METALLIC);
+ BaseMaterial3D::TextureChannel metalness_channel = material->get_metallic_texture_channel();
+ Ref<Texture2D> ao_texture = material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION);
+ BaseMaterial3D::TextureChannel ao_channel = material->get_ao_texture_channel();
+ Ref<ImageTexture> orm_texture;
+ orm_texture.instance();
+ Ref<Image> orm_image;
+ orm_image.instance();
+ int32_t height = 0;
+ int32_t width = 0;
+ Ref<Image> ao_image;
+ if (has_ao) {
+ height = ao_texture->get_height();
+ width = ao_texture->get_width();
+ ao_image = ao_texture->get_data();
+ Ref<ImageTexture> img_tex = ao_image;
+ if (img_tex.is_valid()) {
+ ao_image = img_tex->get_data();
+ }
+ if (ao_image->is_compressed()) {
+ ao_image->decompress();
+ }
+ }
+ Ref<Image> roughness_image;
+ if (has_roughness) {
+ height = roughness_texture->get_height();
+ width = roughness_texture->get_width();
+ roughness_image = roughness_texture->get_data();
+ Ref<ImageTexture> img_tex = roughness_image;
+ if (img_tex.is_valid()) {
+ roughness_image = img_tex->get_data();
+ }
+ if (roughness_image->is_compressed()) {
+ roughness_image->decompress();
+ }
+ }
+ Ref<Image> metallness_image;
+ if (has_metalness) {
+ height = metallic_texture->get_height();
+ width = metallic_texture->get_width();
+ metallness_image = metallic_texture->get_data();
+ Ref<ImageTexture> img_tex = metallness_image;
+ if (img_tex.is_valid()) {
+ metallness_image = img_tex->get_data();
+ }
+ if (metallness_image->is_compressed()) {
+ metallness_image->decompress();
+ }
+ }
+ Ref<Texture2D> albedo_texture = material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO);
+ if (albedo_texture.is_valid() && albedo_texture->get_data().is_valid()) {
+ height = albedo_texture->get_height();
+ width = albedo_texture->get_width();
+ }
+ orm_image->create(width, height, false, Image::FORMAT_RGBA8);
+ if (ao_image.is_valid() && ao_image->get_size() != Vector2(width, height)) {
+ ao_image->resize(width, height, Image::INTERPOLATE_LANCZOS);
+ }
+ if (roughness_image.is_valid() && roughness_image->get_size() != Vector2(width, height)) {
+ roughness_image->resize(width, height, Image::INTERPOLATE_LANCZOS);
+ }
+ if (metallness_image.is_valid() && metallness_image->get_size() != Vector2(width, height)) {
+ metallness_image->resize(width, height, Image::INTERPOLATE_LANCZOS);
+ }
+ for (int32_t h = 0; h < height; h++) {
+ for (int32_t w = 0; w < width; w++) {
+ Color c = Color(1.0f, 1.0f, 1.0f);
+ if (has_ao) {
+ if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == ao_channel) {
+ c.r = ao_image->get_pixel(w, h).r;
+ } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == ao_channel) {
+ c.r = ao_image->get_pixel(w, h).g;
+ } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == ao_channel) {
+ c.r = ao_image->get_pixel(w, h).b;
+ } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == ao_channel) {
+ c.r = ao_image->get_pixel(w, h).a;
+ }
+ }
+ if (has_roughness) {
+ if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == roughness_channel) {
+ c.g = roughness_image->get_pixel(w, h).r;
+ } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == roughness_channel) {
+ c.g = roughness_image->get_pixel(w, h).g;
+ } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == roughness_channel) {
+ c.g = roughness_image->get_pixel(w, h).b;
+ } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == roughness_channel) {
+ c.g = roughness_image->get_pixel(w, h).a;
+ }
+ }
+ if (has_metalness) {
+ if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == metalness_channel) {
+ c.b = metallness_image->get_pixel(w, h).r;
+ } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == metalness_channel) {
+ c.b = metallness_image->get_pixel(w, h).g;
+ } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == metalness_channel) {
+ c.b = metallness_image->get_pixel(w, h).b;
+ } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == metalness_channel) {
+ c.b = metallness_image->get_pixel(w, h).a;
+ }
+ }
+ orm_image->set_pixel(w, h, c);
+ }
+ }
+ orm_image->generate_mipmaps();
+ orm_texture->create_from_image(orm_image);
+ GLTFTextureIndex orm_texture_index = -1;
+ if (has_ao || has_roughness || has_metalness) {
+ orm_texture->set_name(material->get_name() + "_orm");
+ orm_texture_index = _set_texture(state, orm_texture);
+ }
+ if (has_ao) {
+ Dictionary ot;
+ ot["index"] = orm_texture_index;
+ d["occlusionTexture"] = ot;
+ }
+ if (has_roughness || has_metalness) {
+ mrt["index"] = orm_texture_index;
+ mrt["extensions"] = _serialize_texture_transform_uv1(material);
+ mr["metallicRoughnessTexture"] = mrt;
+ }
+ }
+ d["pbrMetallicRoughness"] = mr;
+ }
+
+ if (material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING)) {
+ Dictionary nt;
+ Ref<ImageTexture> tex;
+ tex.instance();
+ {
+ Ref<Texture2D> normal_texture = material->get_texture(BaseMaterial3D::TEXTURE_NORMAL);
+ // Code for uncompressing RG normal maps
+ Ref<Image> img = normal_texture->get_data();
+ Ref<ImageTexture> img_tex = img;
+ if (img_tex.is_valid()) {
+ img = img_tex->get_data();
+ }
+ img->decompress();
+ img->convert(Image::FORMAT_RGBA8);
+ for (int32_t y = 0; y < img->get_height(); y++) {
+ for (int32_t x = 0; x < img->get_width(); x++) {
+ Color c = img->get_pixel(x, y);
+ Vector2 red_green = Vector2(c.r, c.g);
+ red_green = red_green * Vector2(2.0f, 2.0f) - Vector2(1.0f, 1.0f);
+ float blue = 1.0f - red_green.dot(red_green);
+ blue = MAX(0.0f, blue);
+ c.b = Math::sqrt(blue);
+ img->set_pixel(x, y, c);
+ }
+ }
+ tex->create_from_image(img);
+ }
+ Ref<Texture2D> normal_texture = material->get_texture(BaseMaterial3D::TEXTURE_NORMAL);
+ GLTFTextureIndex gltf_texture_index = -1;
+ if (tex.is_valid() && tex->get_data().is_valid()) {
+ tex->set_name(material->get_name() + "_normal");
+ gltf_texture_index = _set_texture(state, tex);
+ }
+ nt["scale"] = material->get_normal_scale();
+ if (gltf_texture_index != -1) {
+ nt["index"] = gltf_texture_index;
+ d["normalTexture"] = nt;
+ }
+ }
+
+ if (material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) {
+ const Color c = material->get_emission().to_srgb();
+ Array arr;
+ arr.push_back(c.r);
+ arr.push_back(c.g);
+ arr.push_back(c.b);
+ d["emissiveFactor"] = arr;
+ }
+ if (material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) {
+ Dictionary et;
+ Ref<Texture2D> emission_texture = material->get_texture(BaseMaterial3D::TEXTURE_EMISSION);
+ GLTFTextureIndex gltf_texture_index = -1;
+ if (emission_texture.is_valid() && emission_texture->get_data().is_valid()) {
+ emission_texture->set_name(material->get_name() + "_emission");
+ gltf_texture_index = _set_texture(state, emission_texture);
+ }
+
+ if (gltf_texture_index != -1) {
+ et["index"] = gltf_texture_index;
+ d["emissiveTexture"] = et;
+ }
+ }
+ const bool ds = material->get_cull_mode() == BaseMaterial3D::CULL_DISABLED;
+ if (ds) {
+ d["doubleSided"] = ds;
+ }
+ if (material->get_transparency() == BaseMaterial3D::TRANSPARENCY_ALPHA_SCISSOR) {
+ d["alphaMode"] = "MASK";
+ d["alphaCutoff"] = material->get_alpha_scissor_threshold();
+ } else if (material->get_transparency() != BaseMaterial3D::TRANSPARENCY_DISABLED) {
+ d["alphaMode"] = "BLEND";
+ }
+ materials.push_back(d);
+ }
+ state->json["materials"] = materials;
+ print_verbose("Total materials: " + itos(state->materials.size()));
+
+ return OK;
+}
+
+Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
+ if (!state->json.has("materials"))
+ return OK;
+
+ const Array &materials = state->json["materials"];
+ for (GLTFMaterialIndex i = 0; i < materials.size(); i++) {
+ const Dictionary &d = materials[i];
+
+ Ref<StandardMaterial3D> material;
+ material.instance();
+ if (d.has("name")) {
+ material->set_name(d["name"]);
+ }
+ material->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ Dictionary pbr_spec_gloss_extensions;
+ if (d.has("extensions")) {
+ pbr_spec_gloss_extensions = d["extensions"];
+ }
+ if (pbr_spec_gloss_extensions.has("KHR_materials_pbrSpecularGlossiness")) {
+ WARN_PRINT("Material uses a specular and glossiness workflow. Textures will be converted to roughness and metallic workflow, which may not be 100% accurate.");
+ Dictionary sgm = pbr_spec_gloss_extensions["KHR_materials_pbrSpecularGlossiness"];
+
+ Ref<GLTFSpecGloss> spec_gloss;
+ spec_gloss.instance();
+ if (sgm.has("diffuseTexture")) {
+ const Dictionary &diffuse_texture_dict = sgm["diffuseTexture"];
+ if (diffuse_texture_dict.has("index")) {
+ Ref<Texture2D> diffuse_texture = _get_texture(state, diffuse_texture_dict["index"]);
+ if (diffuse_texture.is_valid()) {
+ spec_gloss->diffuse_img = diffuse_texture->get_data();
+ material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, diffuse_texture);
+ }
+ }
+ }
+ 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();
+ spec_gloss->diffuse_factor = c;
+ material->set_albedo(spec_gloss->diffuse_factor);
+ }
+
+ if (sgm.has("specularFactor")) {
+ const Array &arr = sgm["specularFactor"];
+ ERR_FAIL_COND_V(arr.size() != 3, ERR_PARSE_ERROR);
+ spec_gloss->specular_factor = Color(arr[0], arr[1], arr[2]);
+ }
+
+ if (sgm.has("glossinessFactor")) {
+ spec_gloss->gloss_factor = sgm["glossinessFactor"];
+ material->set_roughness(1.0f - CLAMP(spec_gloss->gloss_factor, 0.0f, 1.0f));
+ }
+ if (sgm.has("specularGlossinessTexture")) {
+ const Dictionary &spec_gloss_texture = sgm["specularGlossinessTexture"];
+ if (spec_gloss_texture.has("index")) {
+ const Ref<Texture2D> orig_texture = _get_texture(state, spec_gloss_texture["index"]);
+ if (orig_texture.is_valid()) {
+ spec_gloss->spec_gloss_img = orig_texture->get_data();
+ }
+ }
+ }
+ spec_gloss_to_rough_metal(spec_gloss, material);
+
+ } else if (d.has("pbrMetallicRoughness")) {
+ const Dictionary &mr = d["pbrMetallicRoughness"];
+ 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();
+ material->set_albedo(c);
+ }
+
+ if (mr.has("baseColorTexture")) {
+ const Dictionary &bct = mr["baseColorTexture"];
+ if (bct.has("index")) {
+ material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, _get_texture(state, bct["index"]));
+ }
+ if (!mr.has("baseColorFactor")) {
+ material->set_albedo(Color(1, 1, 1));
+ }
+ _set_texture_transform_uv1(bct, material);
+ }
+
+ if (mr.has("metallicFactor")) {
+ material->set_metallic(mr["metallicFactor"]);
+ } else {
+ material->set_metallic(1.0);
+ }
+
+ if (mr.has("roughnessFactor")) {
+ material->set_roughness(mr["roughnessFactor"]);
+ } else {
+ material->set_roughness(1.0);
+ }
+
+ if (mr.has("metallicRoughnessTexture")) {
+ const Dictionary &bct = mr["metallicRoughnessTexture"];
+ if (bct.has("index")) {
+ const Ref<Texture2D> t = _get_texture(state, bct["index"]);
+ material->set_texture(BaseMaterial3D::TEXTURE_METALLIC, t);
+ material->set_metallic_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_BLUE);
+ material->set_texture(BaseMaterial3D::TEXTURE_ROUGHNESS, t);
+ material->set_roughness_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_GREEN);
+ if (!mr.has("metallicFactor")) {
+ material->set_metallic(1);
+ }
+ if (!mr.has("roughnessFactor")) {
+ material->set_roughness(1);
+ }
+ }
+ }
+ }
+
+ if (d.has("normalTexture")) {
+ const Dictionary &bct = d["normalTexture"];
+ if (bct.has("index")) {
+ material->set_texture(BaseMaterial3D::TEXTURE_NORMAL, _get_texture(state, bct["index"]));
+ material->set_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING, true);
+ }
+ if (bct.has("scale")) {
+ material->set_normal_scale(bct["scale"]);
+ }
+ }
+ if (d.has("occlusionTexture")) {
+ const Dictionary &bct = d["occlusionTexture"];
+ if (bct.has("index")) {
+ material->set_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION, _get_texture(state, bct["index"]));
+ material->set_ao_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_RED);
+ material->set_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION, true);
+ }
+ }
+
+ 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();
+ material->set_feature(BaseMaterial3D::FEATURE_EMISSION, true);
+
+ material->set_emission(c);
+ }
+
+ if (d.has("emissiveTexture")) {
+ const Dictionary &bct = d["emissiveTexture"];
+ if (bct.has("index")) {
+ material->set_texture(BaseMaterial3D::TEXTURE_EMISSION, _get_texture(state, bct["index"]));
+ material->set_feature(BaseMaterial3D::FEATURE_EMISSION, true);
+ material->set_emission(Color(0, 0, 0));
+ }
+ }
+
+ if (d.has("doubleSided")) {
+ const bool ds = d["doubleSided"];
+ if (ds) {
+ material->set_cull_mode(BaseMaterial3D::CULL_DISABLED);
+ }
+ }
+
+ if (d.has("alphaMode")) {
+ const String &am = d["alphaMode"];
+ if (am == "BLEND") {
+ material->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA_DEPTH_PRE_PASS);
+ } else if (am == "MASK") {
+ material->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA_SCISSOR);
+ if (d.has("alphaCutoff")) {
+ material->set_alpha_scissor_threshold(d["alphaCutoff"]);
+ } else {
+ material->set_alpha_scissor_threshold(0.5f);
+ }
+ }
+ }
+ state->materials.push_back(material);
+ }
+
+ print_verbose("Total materials: " + itos(state->materials.size()));
+
+ return OK;
+}
+
+void GLTFDocument::_set_texture_transform_uv1(const Dictionary &d, Ref<BaseMaterial3D> material) {
+ if (d.has("extensions")) {
+ const Dictionary &extensions = d["extensions"];
+ if (extensions.has("KHR_texture_transform")) {
+ const Dictionary &texture_transform = extensions["KHR_texture_transform"];
+ const Array &offset_arr = texture_transform["offset"];
+ if (offset_arr.size() == 2) {
+ const Vector3 offset_vector3 = Vector3(offset_arr[0], offset_arr[1], 0.0f);
+ material->set_uv1_offset(offset_vector3);
+ }
+
+ const Array &scale_arr = texture_transform["scale"];
+ if (scale_arr.size() == 2) {
+ const Vector3 scale_vector3 = Vector3(scale_arr[0], scale_arr[1], 1.0f);
+ material->set_uv1_scale(scale_vector3);
+ }
+ }
+ }
+}
+
+void GLTFDocument::spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, Ref<BaseMaterial3D> p_material) {
+ if (r_spec_gloss->spec_gloss_img.is_null()) {
+ return;
+ }
+ if (r_spec_gloss->diffuse_img.is_null()) {
+ return;
+ }
+ Ref<Image> rm_img;
+ rm_img.instance();
+ bool has_roughness = false;
+ bool has_metal = false;
+ p_material->set_roughness(1.0f);
+ p_material->set_metallic(1.0f);
+ rm_img->create(r_spec_gloss->spec_gloss_img->get_width(), r_spec_gloss->spec_gloss_img->get_height(), false, Image::FORMAT_RGBA8);
+ r_spec_gloss->spec_gloss_img->decompress();
+ if (r_spec_gloss->diffuse_img.is_valid()) {
+ r_spec_gloss->diffuse_img->decompress();
+ r_spec_gloss->diffuse_img->resize(r_spec_gloss->spec_gloss_img->get_width(), r_spec_gloss->spec_gloss_img->get_height(), Image::INTERPOLATE_LANCZOS);
+ r_spec_gloss->spec_gloss_img->resize(r_spec_gloss->diffuse_img->get_width(), r_spec_gloss->diffuse_img->get_height(), Image::INTERPOLATE_LANCZOS);
+ }
+ 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();
+ 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();
+ float metallic = 0.0f;
+ Color base_color;
+ spec_gloss_to_metal_base_color(specular, diffuse, base_color, metallic);
+ Color mr = Color(1.0f, 1.0f, 1.0f);
+ mr.g = specular_pixel.a;
+ mr.b = metallic;
+ if (!Math::is_equal_approx(mr.g, 1.0f)) {
+ has_roughness = true;
+ }
+ if (!Math::is_equal_approx(mr.b, 0.0f)) {
+ has_metal = true;
+ }
+ mr.g *= r_spec_gloss->gloss_factor;
+ 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());
+ }
+ }
+ }
+ rm_img->generate_mipmaps();
+ r_spec_gloss->diffuse_img->generate_mipmaps();
+ Ref<ImageTexture> diffuse_image_texture;
+ diffuse_image_texture.instance();
+ diffuse_image_texture->create_from_image(r_spec_gloss->diffuse_img);
+ p_material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, diffuse_image_texture);
+ Ref<ImageTexture> rm_image_texture;
+ rm_image_texture.instance();
+ rm_image_texture->create_from_image(rm_img);
+ if (has_roughness) {
+ p_material->set_texture(BaseMaterial3D::TEXTURE_ROUGHNESS, rm_image_texture);
+ p_material->set_roughness_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_GREEN);
+ }
+
+ if (has_metal) {
+ p_material->set_texture(BaseMaterial3D::TEXTURE_METALLIC, rm_image_texture);
+ p_material->set_metallic_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_BLUE);
+ }
+}
+
+void GLTFDocument::spec_gloss_to_metal_base_color(const Color &p_specular_factor, const Color &p_diffuse, Color &r_base_color, float &r_metallic) {
+ const Color DIELECTRIC_SPECULAR = Color(0.04f, 0.04f, 0.04f);
+ Color specular = Color(p_specular_factor.r, p_specular_factor.g, p_specular_factor.b);
+ const float one_minus_specular_strength = 1.0f - get_max_component(specular);
+ const float dielectric_specular_red = DIELECTRIC_SPECULAR.r;
+ float brightness_diffuse = get_perceived_brightness(p_diffuse);
+ const float brightness_specular = get_perceived_brightness(specular);
+ r_metallic = solve_metallic(dielectric_specular_red, brightness_diffuse, brightness_specular, one_minus_specular_strength);
+ const float one_minus_metallic = 1.0f - r_metallic;
+ const Color base_color_from_diffuse = p_diffuse * (one_minus_specular_strength / (1.0f - dielectric_specular_red) / MAX(one_minus_metallic, CMP_EPSILON));
+ const Color base_color_from_specular = (specular - (DIELECTRIC_SPECULAR * (one_minus_metallic))) * (1.0f / MAX(r_metallic, CMP_EPSILON));
+ r_base_color.r = Math::lerp(base_color_from_diffuse.r, base_color_from_specular.r, r_metallic * r_metallic);
+ r_base_color.g = Math::lerp(base_color_from_diffuse.g, base_color_from_specular.g, r_metallic * r_metallic);
+ r_base_color.b = Math::lerp(base_color_from_diffuse.b, base_color_from_specular.b, r_metallic * r_metallic);
+ r_base_color.a = p_diffuse.a;
+ r_base_color.r = CLAMP(r_base_color.r, 0.0f, 1.0f);
+ r_base_color.g = CLAMP(r_base_color.g, 0.0f, 1.0f);
+ r_base_color.b = CLAMP(r_base_color.b, 0.0f, 1.0f);
+ r_base_color.a = CLAMP(r_base_color.a, 0.0f, 1.0f);
+}
+
+GLTFNodeIndex GLTFDocument::_find_highest_node(Ref<GLTFState> state, const Vector<GLTFNodeIndex> &subset) {
+ int highest = -1;
+ GLTFNodeIndex best_node = -1;
+
+ for (int i = 0; i < subset.size(); ++i) {
+ const GLTFNodeIndex node_i = subset[i];
+ const Ref<GLTFNode> node = state->nodes[node_i];
+
+ if (highest == -1 || node->height < highest) {
+ highest = node->height;
+ best_node = node_i;
+ }
+ }
+
+ return best_node;
+}
+
+bool GLTFDocument::_capture_nodes_in_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin, const GLTFNodeIndex node_index) {
+ bool found_joint = false;
+
+ for (int i = 0; i < state->nodes[node_index]->children.size(); ++i) {
+ found_joint |= _capture_nodes_in_skin(state, skin, state->nodes[node_index]->children[i]);
+ }
+
+ if (found_joint) {
+ // Mark it if we happen to find another skins joint...
+ if (state->nodes[node_index]->joint && skin->joints.find(node_index) < 0) {
+ skin->joints.push_back(node_index);
+ } else if (skin->non_joints.find(node_index) < 0) {
+ skin->non_joints.push_back(node_index);
+ }
+ }
+
+ if (skin->joints.find(node_index) > 0) {
+ return true;
+ }
+
+ return false;
+}
+
+void GLTFDocument::_capture_nodes_for_multirooted_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) {
+ DisjointSet<GLTFNodeIndex> disjoint_set;
+
+ for (int i = 0; i < skin->joints.size(); ++i) {
+ const GLTFNodeIndex node_index = skin->joints[i];
+ const GLTFNodeIndex parent = state->nodes[node_index]->parent;
+ disjoint_set.insert(node_index);
+
+ if (skin->joints.find(parent) >= 0) {
+ disjoint_set.create_union(parent, node_index);
+ }
+ }
+
+ Vector<GLTFNodeIndex> roots;
+ disjoint_set.get_representatives(roots);
+
+ if (roots.size() <= 1) {
+ return;
+ }
+
+ int maxHeight = -1;
+
+ // Determine the max height rooted tree
+ for (int i = 0; i < roots.size(); ++i) {
+ const GLTFNodeIndex root = roots[i];
+
+ if (maxHeight == -1 || state->nodes[root]->height < maxHeight) {
+ maxHeight = state->nodes[root]->height;
+ }
+ }
+
+ // Go up the tree till all of the multiple roots of the skin are at the same hierarchy level.
+ // This sucks, but 99% of all game engines (not just Godot) would have this same issue.
+ for (int i = 0; i < roots.size(); ++i) {
+ GLTFNodeIndex current_node = roots[i];
+ while (state->nodes[current_node]->height > maxHeight) {
+ GLTFNodeIndex parent = state->nodes[current_node]->parent;
+
+ if (state->nodes[parent]->joint && skin->joints.find(parent) < 0) {
+ skin->joints.push_back(parent);
+ } else if (skin->non_joints.find(parent) < 0) {
+ skin->non_joints.push_back(parent);
+ }
+
+ current_node = parent;
+ }
+
+ // replace the roots
+ roots.write[i] = current_node;
+ }
+
+ // Climb up the tree until they all have the same parent
+ bool all_same;
+
+ do {
+ all_same = true;
+ const GLTFNodeIndex first_parent = state->nodes[roots[0]]->parent;
+
+ for (int i = 1; i < roots.size(); ++i) {
+ all_same &= (first_parent == state->nodes[roots[i]]->parent);
+ }
+
+ if (!all_same) {
+ for (int i = 0; i < roots.size(); ++i) {
+ const GLTFNodeIndex current_node = roots[i];
+ const GLTFNodeIndex parent = state->nodes[current_node]->parent;
+
+ if (state->nodes[parent]->joint && skin->joints.find(parent) < 0) {
+ skin->joints.push_back(parent);
+ } else if (skin->non_joints.find(parent) < 0) {
+ skin->non_joints.push_back(parent);
+ }
+
+ roots.write[i] = parent;
+ }
+ }
+
+ } while (!all_same);
+}
+
+Error GLTFDocument::_expand_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) {
+ _capture_nodes_for_multirooted_skin(state, skin);
+
+ // Grab all nodes that lay in between skin joints/nodes
+ DisjointSet<GLTFNodeIndex> disjoint_set;
+
+ Vector<GLTFNodeIndex> all_skin_nodes;
+ all_skin_nodes.append_array(skin->joints);
+ all_skin_nodes.append_array(skin->non_joints);
+
+ for (int i = 0; i < all_skin_nodes.size(); ++i) {
+ const GLTFNodeIndex node_index = all_skin_nodes[i];
+ const GLTFNodeIndex parent = state->nodes[node_index]->parent;
+ disjoint_set.insert(node_index);
+
+ if (all_skin_nodes.find(parent) >= 0) {
+ disjoint_set.create_union(parent, node_index);
+ }
+ }
+
+ Vector<GLTFNodeIndex> out_owners;
+ disjoint_set.get_representatives(out_owners);
+
+ Vector<GLTFNodeIndex> out_roots;
+
+ for (int i = 0; i < out_owners.size(); ++i) {
+ Vector<GLTFNodeIndex> set;
+ disjoint_set.get_members(set, out_owners[i]);
+
+ const GLTFNodeIndex root = _find_highest_node(state, set);
+ ERR_FAIL_COND_V(root < 0, FAILED);
+ out_roots.push_back(root);
+ }
+
+ out_roots.sort();
+
+ for (int i = 0; i < out_roots.size(); ++i) {
+ _capture_nodes_in_skin(state, skin, out_roots[i]);
+ }
+
+ skin->roots = out_roots;
+
+ return OK;
+}
+
+Error GLTFDocument::_verify_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) {
+ // This may seem duplicated from expand_skins, but this is really a sanity check! (so it kinda is)
+ // In case additional interpolating logic is added to the skins, this will help ensure that you
+ // do not cause it to self implode into a fiery blaze
+
+ // We are going to re-calculate the root nodes and compare them to the ones saved in the skin,
+ // then ensure the multiple trees (if they exist) are on the same sublevel
+
+ // Grab all nodes that lay in between skin joints/nodes
+ DisjointSet<GLTFNodeIndex> disjoint_set;
+
+ Vector<GLTFNodeIndex> all_skin_nodes;
+ all_skin_nodes.append_array(skin->joints);
+ all_skin_nodes.append_array(skin->non_joints);
+
+ for (int i = 0; i < all_skin_nodes.size(); ++i) {
+ const GLTFNodeIndex node_index = all_skin_nodes[i];
+ const GLTFNodeIndex parent = state->nodes[node_index]->parent;
+ disjoint_set.insert(node_index);
+
+ if (all_skin_nodes.find(parent) >= 0) {
+ disjoint_set.create_union(parent, node_index);
+ }
+ }
+
+ Vector<GLTFNodeIndex> out_owners;
+ disjoint_set.get_representatives(out_owners);
+
+ Vector<GLTFNodeIndex> out_roots;
+
+ for (int i = 0; i < out_owners.size(); ++i) {
+ Vector<GLTFNodeIndex> set;
+ disjoint_set.get_members(set, out_owners[i]);
+
+ const GLTFNodeIndex root = _find_highest_node(state, set);
+ ERR_FAIL_COND_V(root < 0, FAILED);
+ out_roots.push_back(root);
+ }
+
+ out_roots.sort();
+
+ ERR_FAIL_COND_V(out_roots.size() == 0, FAILED);
+
+ // Make sure the roots are the exact same (they better be)
+ ERR_FAIL_COND_V(out_roots.size() != skin->roots.size(), FAILED);
+ for (int i = 0; i < out_roots.size(); ++i) {
+ ERR_FAIL_COND_V(out_roots[i] != skin->roots[i], FAILED);
+ }
+
+ // Single rooted skin? Perfectly ok!
+ if (out_roots.size() == 1) {
+ return OK;
+ }
+
+ // Make sure all parents of a multi-rooted skin are the SAME
+ const GLTFNodeIndex parent = state->nodes[out_roots[0]]->parent;
+ for (int i = 1; i < out_roots.size(); ++i) {
+ if (state->nodes[out_roots[i]]->parent != parent) {
+ return FAILED;
+ }
+ }
+
+ return OK;
+}
+
+Error GLTFDocument::_parse_skins(Ref<GLTFState> state) {
+ if (!state->json.has("skins"))
+ return OK;
+
+ const Array &skins = state->json["skins"];
+
+ // Create the base skins, and mark nodes that are joints
+ for (int i = 0; i < skins.size(); i++) {
+ const Dictionary &d = skins[i];
+
+ Ref<GLTFSkin> skin;
+ skin.instance();
+
+ ERR_FAIL_COND_V(!d.has("joints"), ERR_PARSE_ERROR);
+
+ const Array &joints = d["joints"];
+
+ if (d.has("inverseBindMatrices")) {
+ skin->inverse_binds = _decode_accessor_as_xform(state, d["inverseBindMatrices"], false);
+ ERR_FAIL_COND_V(skin->inverse_binds.size() != joints.size(), ERR_PARSE_ERROR);
+ }
+
+ for (int j = 0; j < joints.size(); j++) {
+ const GLTFNodeIndex node = joints[j];
+ ERR_FAIL_INDEX_V(node, state->nodes.size(), ERR_PARSE_ERROR);
+
+ skin->joints.push_back(node);
+ skin->joints_original.push_back(node);
+
+ state->nodes.write[node]->joint = true;
+ }
+
+ if (d.has("name")) {
+ skin->set_name(d["name"]);
+ }
+
+ if (d.has("skeleton")) {
+ skin->skin_root = d["skeleton"];
+ }
+
+ state->skins.push_back(skin);
+ }
+
+ for (GLTFSkinIndex i = 0; i < state->skins.size(); ++i) {
+ Ref<GLTFSkin> skin = state->skins.write[i];
+
+ // Expand the skin to capture all the extra non-joints that lie in between the actual joints,
+ // and expand the hierarchy to ensure multi-rooted trees lie on the same height level
+ ERR_FAIL_COND_V(_expand_skin(state, skin), ERR_PARSE_ERROR);
+ ERR_FAIL_COND_V(_verify_skin(state, skin), ERR_PARSE_ERROR);
+ }
+
+ print_verbose("glTF: Total skins: " + itos(state->skins.size()));
+
+ return OK;
+}
+
+Error GLTFDocument::_determine_skeletons(Ref<GLTFState> state) {
+ // Using a disjoint set, we are going to potentially combine all skins that are actually branches
+ // of a main skeleton, or treat skins defining the same set of nodes as ONE skeleton.
+ // This is another unclear issue caused by the current glTF specification.
+
+ DisjointSet<GLTFNodeIndex> skeleton_sets;
+
+ for (GLTFSkinIndex skin_i = 0; skin_i < state->skins.size(); ++skin_i) {
+ const Ref<GLTFSkin> skin = state->skins[skin_i];
+
+ Vector<GLTFNodeIndex> all_skin_nodes;
+ all_skin_nodes.append_array(skin->joints);
+ all_skin_nodes.append_array(skin->non_joints);
+
+ for (int i = 0; i < all_skin_nodes.size(); ++i) {
+ const GLTFNodeIndex node_index = all_skin_nodes[i];
+ const GLTFNodeIndex parent = state->nodes[node_index]->parent;
+ skeleton_sets.insert(node_index);
+
+ if (all_skin_nodes.find(parent) >= 0) {
+ skeleton_sets.create_union(parent, node_index);
+ }
+ }
+
+ // We are going to connect the separate skin subtrees in each skin together
+ // so that the final roots are entire sets of valid skin trees
+ for (int i = 1; i < skin->roots.size(); ++i) {
+ skeleton_sets.create_union(skin->roots[0], skin->roots[i]);
+ }
+ }
+
+ { // attempt to joint all touching subsets (siblings/parent are part of another skin)
+ Vector<GLTFNodeIndex> groups_representatives;
+ skeleton_sets.get_representatives(groups_representatives);
+
+ Vector<GLTFNodeIndex> highest_group_members;
+ Vector<Vector<GLTFNodeIndex>> groups;
+ for (int i = 0; i < groups_representatives.size(); ++i) {
+ Vector<GLTFNodeIndex> group;
+ skeleton_sets.get_members(group, groups_representatives[i]);
+ highest_group_members.push_back(_find_highest_node(state, group));
+ groups.push_back(group);
+ }
+
+ for (int i = 0; i < highest_group_members.size(); ++i) {
+ const GLTFNodeIndex node_i = highest_group_members[i];
+
+ // Attach any siblings together (this needs to be done n^2/2 times)
+ for (int j = i + 1; j < highest_group_members.size(); ++j) {
+ const GLTFNodeIndex node_j = highest_group_members[j];
+
+ // Even if they are siblings under the root! :)
+ if (state->nodes[node_i]->parent == state->nodes[node_j]->parent) {
+ skeleton_sets.create_union(node_i, node_j);
+ }
+ }
+
+ // Attach any parenting going on together (we need to do this n^2 times)
+ const GLTFNodeIndex node_i_parent = state->nodes[node_i]->parent;
+ if (node_i_parent >= 0) {
+ for (int j = 0; j < groups.size() && i != j; ++j) {
+ const Vector<GLTFNodeIndex> &group = groups[j];
+
+ if (group.find(node_i_parent) >= 0) {
+ const GLTFNodeIndex node_j = highest_group_members[j];
+ skeleton_sets.create_union(node_i, node_j);
+ }
+ }
+ }
+ }
+ }
+
+ // At this point, the skeleton groups should be finalized
+ Vector<GLTFNodeIndex> skeleton_owners;
+ skeleton_sets.get_representatives(skeleton_owners);
+
+ // Mark all the skins actual skeletons, after we have merged them
+ for (GLTFSkeletonIndex skel_i = 0; skel_i < skeleton_owners.size(); ++skel_i) {
+ const GLTFNodeIndex skeleton_owner = skeleton_owners[skel_i];
+ Ref<GLTFSkeleton> skeleton;
+ skeleton.instance();
+
+ Vector<GLTFNodeIndex> skeleton_nodes;
+ skeleton_sets.get_members(skeleton_nodes, skeleton_owner);
+
+ for (GLTFSkinIndex skin_i = 0; skin_i < state->skins.size(); ++skin_i) {
+ Ref<GLTFSkin> skin = state->skins.write[skin_i];
+
+ // If any of the the skeletons nodes exist in a skin, that skin now maps to the skeleton
+ for (int i = 0; i < skeleton_nodes.size(); ++i) {
+ GLTFNodeIndex skel_node_i = skeleton_nodes[i];
+ if (skin->joints.find(skel_node_i) >= 0 || skin->non_joints.find(skel_node_i) >= 0) {
+ skin->skeleton = skel_i;
+ continue;
+ }
+ }
+ }
+
+ Vector<GLTFNodeIndex> non_joints;
+ for (int i = 0; i < skeleton_nodes.size(); ++i) {
+ const GLTFNodeIndex node_i = skeleton_nodes[i];
+
+ if (state->nodes[node_i]->joint) {
+ skeleton->joints.push_back(node_i);
+ } else {
+ non_joints.push_back(node_i);
+ }
+ }
+
+ state->skeletons.push_back(skeleton);
+
+ _reparent_non_joint_skeleton_subtrees(state, state->skeletons.write[skel_i], non_joints);
+ }
+
+ for (GLTFSkeletonIndex skel_i = 0; skel_i < state->skeletons.size(); ++skel_i) {
+ Ref<GLTFSkeleton> skeleton = state->skeletons.write[skel_i];
+
+ for (int i = 0; i < skeleton->joints.size(); ++i) {
+ const GLTFNodeIndex node_i = skeleton->joints[i];
+ Ref<GLTFNode> node = state->nodes[node_i];
+
+ ERR_FAIL_COND_V(!node->joint, ERR_PARSE_ERROR);
+ ERR_FAIL_COND_V(node->skeleton >= 0, ERR_PARSE_ERROR);
+ node->skeleton = skel_i;
+ }
+
+ ERR_FAIL_COND_V(_determine_skeleton_roots(state, skel_i), ERR_PARSE_ERROR);
+ }
+
+ return OK;
+}
+
+Error GLTFDocument::_reparent_non_joint_skeleton_subtrees(Ref<GLTFState> state, Ref<GLTFSkeleton> skeleton, const Vector<GLTFNodeIndex> &non_joints) {
+ DisjointSet<GLTFNodeIndex> subtree_set;
+
+ // Populate the disjoint set with ONLY non joints that are in the skeleton hierarchy (non_joints vector)
+ // This way we can find any joints that lie in between joints, as the current glTF specification
+ // mentions nothing about non-joints being in between joints of the same skin. Hopefully one day we
+ // can remove this code.
+
+ // skinD depicted here explains this issue:
+ // https://github.com/KhronosGroup/glTF-Asset-Generator/blob/master/Output/Positive/Animation_Skin
+
+ for (int i = 0; i < non_joints.size(); ++i) {
+ const GLTFNodeIndex node_i = non_joints[i];
+
+ subtree_set.insert(node_i);
+
+ const GLTFNodeIndex parent_i = state->nodes[node_i]->parent;
+ if (parent_i >= 0 && non_joints.find(parent_i) >= 0 && !state->nodes[parent_i]->joint) {
+ subtree_set.create_union(parent_i, node_i);
+ }
+ }
+
+ // Find all the non joint subtrees and re-parent them to a new "fake" joint
+
+ Vector<GLTFNodeIndex> non_joint_subtree_roots;
+ subtree_set.get_representatives(non_joint_subtree_roots);
+
+ for (int root_i = 0; root_i < non_joint_subtree_roots.size(); ++root_i) {
+ const GLTFNodeIndex subtree_root = non_joint_subtree_roots[root_i];
+
+ Vector<GLTFNodeIndex> subtree_nodes;
+ subtree_set.get_members(subtree_nodes, subtree_root);
+
+ for (int subtree_i = 0; subtree_i < subtree_nodes.size(); ++subtree_i) {
+ ERR_FAIL_COND_V(_reparent_to_fake_joint(state, skeleton, subtree_nodes[subtree_i]), FAILED);
+
+ // We modified the tree, recompute all the heights
+ _compute_node_heights(state);
+ }
+ }
+
+ return OK;
+}
+
+Error GLTFDocument::_reparent_to_fake_joint(Ref<GLTFState> state, Ref<GLTFSkeleton> skeleton, const GLTFNodeIndex node_index) {
+ Ref<GLTFNode> node = state->nodes[node_index];
+
+ // Can we just "steal" this joint if it is just a spatial node?
+ if (node->skin < 0 && node->mesh < 0 && node->camera < 0) {
+ node->joint = true;
+ // Add the joint to the skeletons joints
+ skeleton->joints.push_back(node_index);
+ return OK;
+ }
+
+ GLTFNode *fake_joint = memnew(GLTFNode);
+ const GLTFNodeIndex fake_joint_index = state->nodes.size();
+ state->nodes.push_back(fake_joint);
+
+ // We better not be a joint, or we messed up in our logic
+ if (node->joint)
+ return FAILED;
+
+ fake_joint->translation = node->translation;
+ fake_joint->rotation = node->rotation;
+ fake_joint->scale = node->scale;
+ fake_joint->xform = node->xform;
+ fake_joint->joint = true;
+
+ // We can use the exact same name here, because the joint will be inside a skeleton and not the scene
+ fake_joint->set_name(node->get_name());
+
+ // Clear the nodes transforms, since it will be parented to the fake joint
+ node->translation = Vector3(0, 0, 0);
+ node->rotation = Quat();
+ node->scale = Vector3(1, 1, 1);
+ node->xform = Transform();
+
+ // Transfer the node children to the fake joint
+ for (int child_i = 0; child_i < node->children.size(); ++child_i) {
+ Ref<GLTFNode> child = state->nodes[node->children[child_i]];
+ child->parent = fake_joint_index;
+ }
+
+ fake_joint->children = node->children;
+ node->children.clear();
+
+ // add the fake joint to the parent and remove the original joint
+ if (node->parent >= 0) {
+ Ref<GLTFNode> parent = state->nodes[node->parent];
+ parent->children.erase(node_index);
+ parent->children.push_back(fake_joint_index);
+ fake_joint->parent = node->parent;
+ }
+
+ // Add the node to the fake joint
+ fake_joint->children.push_back(node_index);
+ node->parent = fake_joint_index;
+ node->fake_joint_parent = fake_joint_index;
+
+ // Add the fake joint to the skeletons joints
+ skeleton->joints.push_back(fake_joint_index);
+
+ // Replace skin_skeletons with fake joints if we must.
+ for (GLTFSkinIndex skin_i = 0; skin_i < state->skins.size(); ++skin_i) {
+ Ref<GLTFSkin> skin = state->skins.write[skin_i];
+ if (skin->skin_root == node_index) {
+ skin->skin_root = fake_joint_index;
+ }
+ }
+
+ return OK;
+}
+
+Error GLTFDocument::_determine_skeleton_roots(Ref<GLTFState> state, const GLTFSkeletonIndex skel_i) {
+ DisjointSet<GLTFNodeIndex> disjoint_set;
+
+ for (GLTFNodeIndex i = 0; i < state->nodes.size(); ++i) {
+ const Ref<GLTFNode> node = state->nodes[i];
+
+ if (node->skeleton != skel_i) {
+ continue;
+ }
+
+ disjoint_set.insert(i);
+
+ if (node->parent >= 0 && state->nodes[node->parent]->skeleton == skel_i) {
+ disjoint_set.create_union(node->parent, i);
+ }
+ }
+
+ Ref<GLTFSkeleton> skeleton = state->skeletons.write[skel_i];
+
+ Vector<GLTFNodeIndex> owners;
+ disjoint_set.get_representatives(owners);
+
+ Vector<GLTFNodeIndex> roots;
+
+ for (int i = 0; i < owners.size(); ++i) {
+ Vector<GLTFNodeIndex> set;
+ disjoint_set.get_members(set, owners[i]);
+ const GLTFNodeIndex root = _find_highest_node(state, set);
+ ERR_FAIL_COND_V(root < 0, FAILED);
+ roots.push_back(root);
+ }
+
+ roots.sort();
+
+ skeleton->roots = roots;
+
+ if (roots.size() == 0) {
+ return FAILED;
+ } else if (roots.size() == 1) {
+ return OK;
+ }
+
+ // Check that the subtrees have the same parent root
+ const GLTFNodeIndex parent = state->nodes[roots[0]]->parent;
+ for (int i = 1; i < roots.size(); ++i) {
+ if (state->nodes[roots[i]]->parent != parent) {
+ return FAILED;
+ }
+ }
+
+ return OK;
+}
+
+Error GLTFDocument::_create_skeletons(Ref<GLTFState> state) {
+ for (GLTFSkeletonIndex skel_i = 0; skel_i < state->skeletons.size(); ++skel_i) {
+ Ref<GLTFSkeleton> gltf_skeleton = state->skeletons.write[skel_i];
+
+ Skeleton3D *skeleton = memnew(Skeleton3D);
+ gltf_skeleton->godot_skeleton = skeleton;
+
+ // Make a unique name, no gltf node represents this skeleton
+ skeleton->set_name(_gen_unique_name(state, "Skeleton3D"));
+
+ List<GLTFNodeIndex> bones;
+
+ for (int i = 0; i < gltf_skeleton->roots.size(); ++i) {
+ bones.push_back(gltf_skeleton->roots[i]);
+ }
+
+ // Make the skeleton creation deterministic by going through the roots in
+ // a sorted order, and DEPTH FIRST
+ bones.sort();
+
+ while (!bones.is_empty()) {
+ const GLTFNodeIndex node_i = bones.front()->get();
+ bones.pop_front();
+
+ Ref<GLTFNode> node = state->nodes[node_i];
+ ERR_FAIL_COND_V(node->skeleton != skel_i, FAILED);
+
+ { // Add all child nodes to the stack (deterministically)
+ Vector<GLTFNodeIndex> child_nodes;
+ for (int i = 0; i < node->children.size(); ++i) {
+ const GLTFNodeIndex child_i = node->children[i];
+ if (state->nodes[child_i]->skeleton == skel_i) {
+ child_nodes.push_back(child_i);
+ }
+ }
+
+ // Depth first insertion
+ child_nodes.sort();
+ for (int i = child_nodes.size() - 1; i >= 0; --i) {
+ bones.push_front(child_nodes[i]);
+ }
+ }
+
+ const int bone_index = skeleton->get_bone_count();
+
+ if (node->get_name().is_empty()) {
+ node->set_name("bone");
+ }
+
+ node->set_name(_gen_unique_bone_name(state, skel_i, node->get_name()));
+
+ skeleton->add_bone(node->get_name());
+ skeleton->set_bone_rest(bone_index, node->xform);
+
+ if (node->parent >= 0 && state->nodes[node->parent]->skeleton == skel_i) {
+ const int bone_parent = skeleton->find_bone(state->nodes[node->parent]->get_name());
+ ERR_FAIL_COND_V(bone_parent < 0, FAILED);
+ skeleton->set_bone_parent(bone_index, skeleton->find_bone(state->nodes[node->parent]->get_name()));
+ }
+
+ state->scene_nodes.insert(node_i, skeleton);
+ }
+ }
+
+ ERR_FAIL_COND_V(_map_skin_joints_indices_to_skeleton_bone_indices(state), ERR_PARSE_ERROR);
+
+ return OK;
+}
+
+Error GLTFDocument::_map_skin_joints_indices_to_skeleton_bone_indices(Ref<GLTFState> state) {
+ for (GLTFSkinIndex skin_i = 0; skin_i < state->skins.size(); ++skin_i) {
+ Ref<GLTFSkin> skin = state->skins.write[skin_i];
+
+ Ref<GLTFSkeleton> skeleton = state->skeletons[skin->skeleton];
+
+ for (int joint_index = 0; joint_index < skin->joints_original.size(); ++joint_index) {
+ const GLTFNodeIndex node_i = skin->joints_original[joint_index];
+ const Ref<GLTFNode> node = state->nodes[node_i];
+
+ const int bone_index = skeleton->godot_skeleton->find_bone(node->get_name());
+ ERR_FAIL_COND_V(bone_index < 0, FAILED);
+
+ skin->joint_i_to_bone_i.insert(joint_index, bone_index);
+ }
+ }
+
+ return OK;
+}
+
+Error GLTFDocument::_serialize_skins(Ref<GLTFState> state) {
+ _remove_duplicate_skins(state);
+ return OK;
+}
+
+Error GLTFDocument::_create_skins(Ref<GLTFState> state) {
+ for (GLTFSkinIndex skin_i = 0; skin_i < state->skins.size(); ++skin_i) {
+ Ref<GLTFSkin> gltf_skin = state->skins.write[skin_i];
+
+ Ref<Skin> skin;
+ skin.instance();
+
+ // Some skins don't have IBM's! What absolute monsters!
+ const bool has_ibms = !gltf_skin->inverse_binds.is_empty();
+
+ for (int joint_i = 0; joint_i < gltf_skin->joints_original.size(); ++joint_i) {
+ GLTFNodeIndex node = gltf_skin->joints_original[joint_i];
+ String bone_name = state->nodes[node]->get_name();
+
+ Transform xform;
+ if (has_ibms) {
+ xform = gltf_skin->inverse_binds[joint_i];
+ }
+
+ if (state->use_named_skin_binds) {
+ skin->add_named_bind(bone_name, xform);
+ } else {
+ int32_t bone_i = gltf_skin->joint_i_to_bone_i[joint_i];
+ skin->add_bind(bone_i, xform);
+ }
+ }
+
+ gltf_skin->godot_skin = skin;
+ }
+
+ // Purge the duplicates!
+ _remove_duplicate_skins(state);
+
+ // Create unique names now, after removing duplicates
+ for (GLTFSkinIndex skin_i = 0; skin_i < state->skins.size(); ++skin_i) {
+ Ref<Skin> skin = state->skins.write[skin_i]->godot_skin;
+ if (skin->get_name().is_empty()) {
+ // Make a unique name, no gltf node represents this skin
+ skin->set_name(_gen_unique_name(state, "Skin"));
+ }
+ }
+
+ return OK;
+}
+
+bool GLTFDocument::_skins_are_same(const Ref<Skin> skin_a, const Ref<Skin> skin_b) {
+ if (skin_a->get_bind_count() != skin_b->get_bind_count()) {
+ return false;
+ }
+
+ for (int i = 0; i < skin_a->get_bind_count(); ++i) {
+ if (skin_a->get_bind_bone(i) != skin_b->get_bind_bone(i)) {
+ return false;
+ }
+
+ Transform a_xform = skin_a->get_bind_pose(i);
+ Transform b_xform = skin_b->get_bind_pose(i);
+
+ if (a_xform != b_xform) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void GLTFDocument::_remove_duplicate_skins(Ref<GLTFState> state) {
+ for (int i = 0; i < state->skins.size(); ++i) {
+ for (int j = i + 1; j < state->skins.size(); ++j) {
+ const Ref<Skin> skin_i = state->skins[i]->godot_skin;
+ const Ref<Skin> skin_j = state->skins[j]->godot_skin;
+
+ if (_skins_are_same(skin_i, skin_j)) {
+ // replace it and delete the old
+ state->skins.write[j]->godot_skin = skin_i;
+ }
+ }
+ }
+}
+
+Error GLTFDocument::_serialize_lights(Ref<GLTFState> state) {
+ Array lights;
+ for (GLTFLightIndex i = 0; i < state->lights.size(); i++) {
+ Dictionary d;
+ Ref<GLTFLight> light = state->lights[i];
+ Array color;
+ color.resize(3);
+ color[0] = light->color.r;
+ color[1] = light->color.g;
+ color[2] = light->color.b;
+ d["color"] = color;
+ d["type"] = light->type;
+ if (light->type == "spot") {
+ Dictionary s;
+ float inner_cone_angle = light->inner_cone_angle;
+ s["innerConeAngle"] = inner_cone_angle;
+ float outer_cone_angle = light->outer_cone_angle;
+ s["outerConeAngle"] = outer_cone_angle;
+ d["spot"] = s;
+ }
+ float intensity = light->intensity;
+ d["intensity"] = intensity;
+ float range = light->range;
+ d["range"] = range;
+ lights.push_back(d);
+ }
+
+ if (!state->lights.size()) {
+ return OK;
+ }
+
+ Dictionary extensions;
+ if (state->json.has("extensions")) {
+ extensions = state->json["extensions"];
+ } else {
+ state->json["extensions"] = extensions;
+ }
+ Dictionary lights_punctual;
+ extensions["KHR_lights_punctual"] = lights_punctual;
+ lights_punctual["lights"] = lights;
+
+ print_verbose("glTF: Total lights: " + itos(state->lights.size()));
+
+ return OK;
+}
+
+Error GLTFDocument::_serialize_cameras(Ref<GLTFState> state) {
+ Array cameras;
+ cameras.resize(state->cameras.size());
+ for (GLTFCameraIndex i = 0; i < state->cameras.size(); i++) {
+ Dictionary d;
+
+ Ref<GLTFCamera> camera = state->cameras[i];
+
+ if (camera->get_perspective() == false) {
+ Dictionary og;
+ og["ymag"] = Math::deg2rad(camera->get_fov_size());
+ og["xmag"] = Math::deg2rad(camera->get_fov_size());
+ og["zfar"] = camera->get_zfar();
+ og["znear"] = camera->get_znear();
+ d["orthographic"] = og;
+ d["type"] = "orthographic";
+ } else if (camera->get_perspective()) {
+ Dictionary ppt;
+ // GLTF spec is in radians, Godot's camera is in degrees.
+ ppt["yfov"] = Math::deg2rad(camera->get_fov_size());
+ ppt["zfar"] = camera->get_zfar();
+ ppt["znear"] = camera->get_znear();
+ d["perspective"] = ppt;
+ d["type"] = "perspective";
+ }
+ cameras[i] = d;
+ }
+
+ if (!state->cameras.size()) {
+ return OK;
+ }
+
+ state->json["cameras"] = cameras;
+
+ print_verbose("glTF: Total cameras: " + itos(state->cameras.size()));
+
+ return OK;
+}
+
+Error GLTFDocument::_parse_lights(Ref<GLTFState> state) {
+ if (!state->json.has("extensions")) {
+ return OK;
+ }
+ Dictionary extensions = state->json["extensions"];
+ if (!extensions.has("KHR_lights_punctual")) {
+ return OK;
+ }
+ Dictionary lights_punctual = extensions["KHR_lights_punctual"];
+ if (!lights_punctual.has("lights")) {
+ return OK;
+ }
+
+ const Array &lights = lights_punctual["lights"];
+
+ for (GLTFLightIndex light_i = 0; light_i < lights.size(); light_i++) {
+ const Dictionary &d = lights[light_i];
+
+ Ref<GLTFLight> light;
+ light.instance();
+ ERR_FAIL_COND_V(!d.has("type"), ERR_PARSE_ERROR);
+ const String &type = d["type"];
+ light->type = type;
+
+ 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();
+ light->color = c;
+ }
+ if (d.has("intensity")) {
+ light->intensity = d["intensity"];
+ }
+ if (d.has("range")) {
+ light->range = d["range"];
+ }
+ if (type == "spot") {
+ const Dictionary &spot = d["spot"];
+ light->inner_cone_angle = spot["innerConeAngle"];
+ light->outer_cone_angle = spot["outerConeAngle"];
+ ERR_FAIL_COND_V_MSG(light->inner_cone_angle >= light->outer_cone_angle, ERR_PARSE_ERROR, "The inner angle must be smaller than the outer angle.");
+ } else if (type != "point" && type != "directional") {
+ ERR_FAIL_V_MSG(ERR_PARSE_ERROR, "Light type is unknown.");
+ }
+
+ state->lights.push_back(light);
+ }
+
+ print_verbose("glTF: Total lights: " + itos(state->lights.size()));
+
+ return OK;
+}
+
+Error GLTFDocument::_parse_cameras(Ref<GLTFState> state) {
+ if (!state->json.has("cameras"))
+ return OK;
+
+ const Array cameras = state->json["cameras"];
+
+ for (GLTFCameraIndex i = 0; i < cameras.size(); i++) {
+ const Dictionary &d = cameras[i];
+
+ Ref<GLTFCamera> camera;
+ camera.instance();
+ ERR_FAIL_COND_V(!d.has("type"), ERR_PARSE_ERROR);
+ const String &type = d["type"];
+ if (type == "orthographic") {
+ camera->set_perspective(false);
+ if (d.has("orthographic")) {
+ const Dictionary &og = d["orthographic"];
+ // GLTF spec is in radians, Godot's camera is in degrees.
+ camera->set_fov_size(Math::rad2deg(real_t(og["ymag"])));
+ camera->set_zfar(og["zfar"]);
+ camera->set_znear(og["znear"]);
+ } else {
+ camera->set_fov_size(10);
+ }
+ } else if (type == "perspective") {
+ camera->set_perspective(true);
+ if (d.has("perspective")) {
+ const Dictionary &ppt = d["perspective"];
+ // GLTF spec is in radians, Godot's camera is in degrees.
+ camera->set_fov_size(Math::rad2deg(real_t(ppt["yfov"])));
+ camera->set_zfar(ppt["zfar"]);
+ camera->set_znear(ppt["znear"]);
+ } else {
+ camera->set_fov_size(10);
+ }
+ } else {
+ ERR_FAIL_V_MSG(ERR_PARSE_ERROR, "Camera3D should be in 'orthographic' or 'perspective'");
+ }
+
+ state->cameras.push_back(camera);
+ }
+
+ print_verbose("glTF: Total cameras: " + itos(state->cameras.size()));
+
+ return OK;
+}
+
+String GLTFDocument::interpolation_to_string(const GLTFAnimation::Interpolation p_interp) {
+ String interp = "LINEAR";
+ if (p_interp == GLTFAnimation::INTERP_STEP) {
+ interp = "STEP";
+ } else if (p_interp == GLTFAnimation::INTERP_LINEAR) {
+ interp = "LINEAR";
+ } else if (p_interp == GLTFAnimation::INTERP_CATMULLROMSPLINE) {
+ interp = "CATMULLROMSPLINE";
+ } else if (p_interp == GLTFAnimation::INTERP_CUBIC_SPLINE) {
+ interp = "CUBICSPLINE";
+ }
+
+ return interp;
+}
+
+Error GLTFDocument::_serialize_animations(Ref<GLTFState> state) {
+ if (!state->animation_players.size()) {
+ return OK;
+ }
+ for (int32_t player_i = 0; player_i < state->animation_players.size(); player_i++) {
+ List<StringName> animation_names;
+ AnimationPlayer *animation_player = state->animation_players[player_i];
+ animation_player->get_animation_list(&animation_names);
+ if (animation_names.size()) {
+ for (int animation_name_i = 0; animation_name_i < animation_names.size(); animation_name_i++) {
+ _convert_animation(state, animation_player, animation_names[animation_name_i]);
+ }
+ }
+ }
+ Array animations;
+ for (GLTFAnimationIndex animation_i = 0; animation_i < state->animations.size(); animation_i++) {
+ Dictionary d;
+ Ref<GLTFAnimation> gltf_animation = state->animations[animation_i];
+ if (!gltf_animation->get_tracks().size()) {
+ continue;
+ }
+
+ if (!gltf_animation->get_name().is_empty()) {
+ d["name"] = gltf_animation->get_name();
+ }
+ Array channels;
+ Array samplers;
+
+ for (Map<int, GLTFAnimation::Track>::Element *track_i = gltf_animation->get_tracks().front(); track_i; track_i = track_i->next()) {
+ GLTFAnimation::Track track = track_i->get();
+ if (track.translation_track.times.size()) {
+ Dictionary t;
+ t["sampler"] = samplers.size();
+ Dictionary s;
+
+ s["interpolation"] = interpolation_to_string(track.translation_track.interpolation);
+ Vector<real_t> times = Variant(track.translation_track.times);
+ s["input"] = _encode_accessor_as_floats(state, times, false);
+ Vector<Vector3> values = Variant(track.translation_track.values);
+ s["output"] = _encode_accessor_as_vec3(state, values, false);
+
+ samplers.push_back(s);
+
+ Dictionary target;
+ target["path"] = "translation";
+ target["node"] = track_i->key();
+
+ t["target"] = target;
+ channels.push_back(t);
+ }
+ if (track.rotation_track.times.size()) {
+ Dictionary t;
+ t["sampler"] = samplers.size();
+ Dictionary s;
+
+ s["interpolation"] = interpolation_to_string(track.rotation_track.interpolation);
+ Vector<real_t> times = Variant(track.rotation_track.times);
+ s["input"] = _encode_accessor_as_floats(state, times, false);
+ Vector<Quat> values = track.rotation_track.values;
+ s["output"] = _encode_accessor_as_quats(state, values, false);
+
+ samplers.push_back(s);
+
+ Dictionary target;
+ target["path"] = "rotation";
+ target["node"] = track_i->key();
+
+ t["target"] = target;
+ channels.push_back(t);
+ }
+ if (track.scale_track.times.size()) {
+ Dictionary t;
+ t["sampler"] = samplers.size();
+ Dictionary s;
+
+ s["interpolation"] = interpolation_to_string(track.scale_track.interpolation);
+ Vector<real_t> times = Variant(track.scale_track.times);
+ s["input"] = _encode_accessor_as_floats(state, times, false);
+ Vector<Vector3> values = Variant(track.scale_track.values);
+ s["output"] = _encode_accessor_as_vec3(state, values, false);
+
+ samplers.push_back(s);
+
+ Dictionary target;
+ target["path"] = "scale";
+ target["node"] = track_i->key();
+
+ t["target"] = target;
+ channels.push_back(t);
+ }
+ if (track.weight_tracks.size()) {
+ Dictionary t;
+ t["sampler"] = samplers.size();
+ Dictionary s;
+
+ Vector<real_t> times;
+ Vector<real_t> values;
+
+ for (int32_t times_i = 0; times_i < track.weight_tracks[0].times.size(); times_i++) {
+ real_t time = track.weight_tracks[0].times[times_i];
+ times.push_back(time);
+ }
+
+ values.resize(times.size() * track.weight_tracks.size());
+ // TODO Sort by order in blend shapes
+ for (int k = 0; k < track.weight_tracks.size(); k++) {
+ Vector<float> wdata = track.weight_tracks[k].values;
+ for (int l = 0; l < wdata.size(); l++) {
+ values.write[l * track.weight_tracks.size() + k] = wdata.write[l];
+ }
+ }
+
+ s["interpolation"] = interpolation_to_string(track.weight_tracks[track.weight_tracks.size() - 1].interpolation);
+ s["input"] = _encode_accessor_as_floats(state, times, false);
+ s["output"] = _encode_accessor_as_floats(state, values, false);
+
+ samplers.push_back(s);
+
+ Dictionary target;
+ target["path"] = "weights";
+ target["node"] = track_i->key();
+
+ t["target"] = target;
+ channels.push_back(t);
+ }
+ }
+ if (channels.size() && samplers.size()) {
+ d["channels"] = channels;
+ d["samplers"] = samplers;
+ animations.push_back(d);
+ }
+ }
+
+ state->json["animations"] = animations;
+
+ print_verbose("glTF: Total animations '" + itos(state->animations.size()) + "'.");
+
+ return OK;
+}
+
+Error GLTFDocument::_parse_animations(Ref<GLTFState> state) {
+ if (!state->json.has("animations"))
+ return OK;
+
+ const Array &animations = state->json["animations"];
+
+ for (GLTFAnimationIndex i = 0; i < animations.size(); i++) {
+ const Dictionary &d = animations[i];
+
+ Ref<GLTFAnimation> animation;
+ animation.instance();
+
+ if (!d.has("channels") || !d.has("samplers"))
+ continue;
+
+ Array channels = d["channels"];
+ Array samplers = d["samplers"];
+
+ if (d.has("name")) {
+ const String name = d["name"];
+ if (name.begins_with("loop") || name.ends_with("loop") || name.begins_with("cycle") || name.ends_with("cycle")) {
+ animation->set_loop(true);
+ }
+ animation->set_name(_sanitize_scene_name(name));
+ }
+
+ for (int j = 0; j < channels.size(); j++) {
+ const Dictionary &c = channels[j];
+ if (!c.has("target"))
+ continue;
+
+ const Dictionary &t = c["target"];
+ if (!t.has("node") || !t.has("path")) {
+ continue;
+ }
+
+ ERR_FAIL_COND_V(!c.has("sampler"), ERR_PARSE_ERROR);
+ const int sampler = c["sampler"];
+ ERR_FAIL_INDEX_V(sampler, samplers.size(), ERR_PARSE_ERROR);
+
+ GLTFNodeIndex node = t["node"];
+ String path = t["path"];
+
+ ERR_FAIL_INDEX_V(node, state->nodes.size(), ERR_PARSE_ERROR);
+
+ GLTFAnimation::Track *track = nullptr;
+
+ if (!animation->get_tracks().has(node)) {
+ animation->get_tracks()[node] = GLTFAnimation::Track();
+ }
+
+ track = &animation->get_tracks()[node];
+
+ const Dictionary &s = samplers[sampler];
+
+ ERR_FAIL_COND_V(!s.has("input"), ERR_PARSE_ERROR);
+ ERR_FAIL_COND_V(!s.has("output"), ERR_PARSE_ERROR);
+
+ const int input = s["input"];
+ const int output = s["output"];
+
+ GLTFAnimation::Interpolation interp = GLTFAnimation::INTERP_LINEAR;
+ int output_count = 1;
+ if (s.has("interpolation")) {
+ const String &in = s["interpolation"];
+ if (in == "STEP") {
+ interp = GLTFAnimation::INTERP_STEP;
+ } else if (in == "LINEAR") {
+ interp = GLTFAnimation::INTERP_LINEAR;
+ } else if (in == "CATMULLROMSPLINE") {
+ interp = GLTFAnimation::INTERP_CATMULLROMSPLINE;
+ output_count = 3;
+ } else if (in == "CUBICSPLINE") {
+ interp = GLTFAnimation::INTERP_CUBIC_SPLINE;
+ output_count = 3;
+ }
+ }
+
+ const Vector<float> times = _decode_accessor_as_floats(state, input, false);
+ if (path == "translation") {
+ const Vector<Vector3> translations = _decode_accessor_as_vec3(state, output, false);
+ track->translation_track.interpolation = interp;
+ track->translation_track.times = Variant(times); //convert via variant
+ track->translation_track.values = Variant(translations); //convert via variant
+ } else if (path == "rotation") {
+ const Vector<Quat> rotations = _decode_accessor_as_quat(state, output, false);
+ track->rotation_track.interpolation = interp;
+ track->rotation_track.times = Variant(times); //convert via variant
+ track->rotation_track.values = rotations;
+ } else if (path == "scale") {
+ const Vector<Vector3> scales = _decode_accessor_as_vec3(state, output, false);
+ track->scale_track.interpolation = interp;
+ track->scale_track.times = Variant(times); //convert via variant
+ track->scale_track.values = Variant(scales); //convert via variant
+ } else if (path == "weights") {
+ const Vector<float> weights = _decode_accessor_as_floats(state, output, false);
+
+ ERR_FAIL_INDEX_V(state->nodes[node]->mesh, state->meshes.size(), ERR_PARSE_ERROR);
+ Ref<GLTFMesh> mesh = state->meshes[state->nodes[node]->mesh];
+ ERR_CONTINUE(!mesh->get_blend_weights().size());
+ const int wc = mesh->get_blend_weights().size();
+
+ track->weight_tracks.resize(wc);
+
+ const int expected_value_count = times.size() * output_count * wc;
+ ERR_FAIL_COND_V_MSG(weights.size() != expected_value_count, ERR_PARSE_ERROR, "Invalid weight data, expected " + itos(expected_value_count) + " weight values, got " + itos(weights.size()) + " instead.");
+
+ const int wlen = weights.size() / wc;
+ for (int k = 0; k < wc; k++) { //separate tracks, having them together is not such a good idea
+ GLTFAnimation::Channel<float> cf;
+ cf.interpolation = interp;
+ cf.times = Variant(times);
+ Vector<float> wdata;
+ wdata.resize(wlen);
+ for (int l = 0; l < wlen; l++) {
+ wdata.write[l] = weights[l * wc + k];
+ }
+
+ cf.values = wdata;
+ track->weight_tracks.write[k] = cf;
+ }
+ } else {
+ WARN_PRINT("Invalid path '" + path + "'.");
+ }
+ }
+
+ state->animations.push_back(animation);
+ }
+
+ print_verbose("glTF: Total animations '" + itos(state->animations.size()) + "'.");
+
+ return OK;
+}
+
+void GLTFDocument::_assign_scene_names(Ref<GLTFState> state) {
+ for (int i = 0; i < state->nodes.size(); i++) {
+ Ref<GLTFNode> n = state->nodes[i];
+
+ // Any joints get unique names generated when the skeleton is made, unique to the skeleton
+ if (n->skeleton >= 0)
+ continue;
+
+ if (n->get_name().is_empty()) {
+ if (n->mesh >= 0) {
+ n->set_name(_gen_unique_name(state, "Mesh"));
+ } else if (n->camera >= 0) {
+ n->set_name(_gen_unique_name(state, "Camera3D"));
+ } else {
+ n->set_name(_gen_unique_name(state, "Node"));
+ }
+ }
+
+ n->set_name(_gen_unique_name(state, n->get_name()));
+ }
+}
+
+BoneAttachment3D *GLTFDocument::_generate_bone_attachment(Ref<GLTFState> state, Skeleton3D *skeleton, const GLTFNodeIndex node_index) {
+ Ref<GLTFNode> gltf_node = state->nodes[node_index];
+ Ref<GLTFNode> bone_node = state->nodes[gltf_node->parent];
+
+ BoneAttachment3D *bone_attachment = memnew(BoneAttachment3D);
+ print_verbose("glTF: Creating bone attachment for: " + gltf_node->get_name());
+
+ ERR_FAIL_COND_V(!bone_node->joint, nullptr);
+
+ bone_attachment->set_bone_name(bone_node->get_name());
+
+ return bone_attachment;
+}
+
+GLTFMeshIndex GLTFDocument::_convert_mesh_instance(Ref<GLTFState> state, MeshInstance3D *p_mesh_instance) {
+ ERR_FAIL_NULL_V(p_mesh_instance, -1);
+ if (p_mesh_instance->get_mesh().is_null()) {
+ return -1;
+ }
+ Ref<EditorSceneImporterMesh> import_mesh;
+ import_mesh.instance();
+ Ref<Mesh> godot_mesh = p_mesh_instance->get_mesh();
+ if (godot_mesh.is_null()) {
+ return -1;
+ }
+ Vector<float> blend_weights;
+ Vector<String> blend_names;
+ int32_t blend_count = godot_mesh->get_blend_shape_count();
+ blend_names.resize(blend_count);
+ blend_weights.resize(blend_count);
+ for (int32_t blend_i = 0; blend_i < godot_mesh->get_blend_shape_count(); blend_i++) {
+ String blend_name = godot_mesh->get_blend_shape_name(blend_i);
+ blend_names.write[blend_i] = blend_name;
+ import_mesh->add_blend_shape(blend_name);
+ }
+ for (int32_t surface_i = 0; surface_i < godot_mesh->get_surface_count(); surface_i++) {
+ Mesh::PrimitiveType primitive_type = godot_mesh->surface_get_primitive_type(surface_i);
+ Array arrays = godot_mesh->surface_get_arrays(surface_i);
+ Array blend_shape_arrays = godot_mesh->surface_get_blend_shape_arrays(surface_i);
+ Ref<Material> mat = godot_mesh->surface_get_material(surface_i);
+ Ref<ArrayMesh> godot_array_mesh = godot_mesh;
+ String surface_name;
+ if (godot_array_mesh.is_valid()) {
+ surface_name = godot_array_mesh->surface_get_name(surface_i);
+ }
+ if (p_mesh_instance->get_surface_material(surface_i).is_valid()) {
+ mat = p_mesh_instance->get_surface_material(surface_i);
+ }
+ if (p_mesh_instance->get_material_override().is_valid()) {
+ mat = p_mesh_instance->get_material_override();
+ }
+ import_mesh->add_surface(primitive_type, arrays, blend_shape_arrays, Dictionary(), mat, surface_name);
+ }
+ for (int32_t blend_i = 0; blend_i < blend_count; blend_i++) {
+ blend_weights.write[blend_i] = 0.0f;
+ }
+ Ref<GLTFMesh> gltf_mesh;
+ gltf_mesh.instance();
+ gltf_mesh->set_mesh(import_mesh);
+ gltf_mesh->set_blend_weights(blend_weights);
+ GLTFMeshIndex mesh_i = state->meshes.size();
+ state->meshes.push_back(gltf_mesh);
+ return mesh_i;
+}
+
+EditorSceneImporterMeshNode3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index) {
+ Ref<GLTFNode> gltf_node = state->nodes[node_index];
+
+ ERR_FAIL_INDEX_V(gltf_node->mesh, state->meshes.size(), nullptr);
+
+ EditorSceneImporterMeshNode3D *mi = memnew(EditorSceneImporterMeshNode3D);
+ print_verbose("glTF: Creating mesh for: " + gltf_node->get_name());
+
+ Ref<GLTFMesh> mesh = state->meshes.write[gltf_node->mesh];
+ if (mesh.is_null()) {
+ return mi;
+ }
+ Ref<EditorSceneImporterMesh> import_mesh = mesh->get_mesh();
+ if (import_mesh.is_null()) {
+ return mi;
+ }
+ mi->set_mesh(import_mesh);
+ for (int i = 0; i < mesh->get_blend_weights().size(); i++) {
+ mi->set("blend_shapes/" + mesh->get_mesh()->get_blend_shape_name(i), mesh->get_blend_weights()[i]);
+ }
+ return mi;
+}
+
+Light3D *GLTFDocument::_generate_light(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index) {
+ Ref<GLTFNode> gltf_node = state->nodes[node_index];
+
+ ERR_FAIL_INDEX_V(gltf_node->light, state->lights.size(), nullptr);
+
+ print_verbose("glTF: Creating light for: " + gltf_node->get_name());
+
+ Ref<GLTFLight> l = state->lights[gltf_node->light];
+
+ float intensity = l->intensity;
+ if (intensity > 10) {
+ // GLTF spec has the default around 1, but Blender defaults lights to 100.
+ // The only sane way to handle this is to check where it came from and
+ // handle it accordingly. If it's over 10, it probably came from Blender.
+ intensity /= 100;
+ }
+
+ if (l->type == "directional") {
+ DirectionalLight3D *light = memnew(DirectionalLight3D);
+ light->set_param(Light3D::PARAM_ENERGY, intensity);
+ light->set_color(l->color);
+ return light;
+ }
+
+ const float range = CLAMP(l->range, 0, 4096);
+ // Doubling the range will double the effective brightness, so we need double attenuation (half brightness).
+ // We want to have double intensity give double brightness, so we need half the attenuation.
+ const float attenuation = range / intensity;
+ if (l->type == "point") {
+ OmniLight3D *light = memnew(OmniLight3D);
+ light->set_param(OmniLight3D::PARAM_ATTENUATION, attenuation);
+ light->set_param(OmniLight3D::PARAM_RANGE, range);
+ light->set_color(l->color);
+ return light;
+ }
+ if (l->type == "spot") {
+ SpotLight3D *light = memnew(SpotLight3D);
+ light->set_param(SpotLight3D::PARAM_ATTENUATION, attenuation);
+ light->set_param(SpotLight3D::PARAM_RANGE, range);
+ light->set_param(SpotLight3D::PARAM_SPOT_ANGLE, Math::rad2deg(l->outer_cone_angle));
+ light->set_color(l->color);
+
+ // Line of best fit derived from guessing, see https://www.desmos.com/calculator/biiflubp8b
+ // The points in desmos are not exact, except for (1, infinity).
+ float angle_ratio = l->inner_cone_angle / l->outer_cone_angle;
+ float angle_attenuation = 0.2 / (1 - angle_ratio) - 0.1;
+ light->set_param(SpotLight3D::PARAM_SPOT_ATTENUATION, angle_attenuation);
+ return light;
+ }
+ return nullptr;
+}
+
+Camera3D *GLTFDocument::_generate_camera(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index) {
+ Ref<GLTFNode> gltf_node = state->nodes[node_index];
+
+ ERR_FAIL_INDEX_V(gltf_node->camera, state->cameras.size(), nullptr);
+
+ Camera3D *camera = memnew(Camera3D);
+ print_verbose("glTF: Creating camera for: " + gltf_node->get_name());
+
+ Ref<GLTFCamera> c = state->cameras[gltf_node->camera];
+ if (c->get_perspective()) {
+ camera->set_perspective(c->get_fov_size(), c->get_znear(), c->get_zfar());
+ } else {
+ camera->set_orthogonal(c->get_fov_size(), c->get_znear(), c->get_zfar());
+ }
+
+ return camera;
+}
+
+GLTFCameraIndex GLTFDocument::_convert_camera(Ref<GLTFState> state, Camera3D *p_camera) {
+ print_verbose("glTF: Converting camera: " + p_camera->get_name());
+
+ Ref<GLTFCamera> c;
+ c.instance();
+
+ if (p_camera->get_projection() == Camera3D::Projection::PROJECTION_PERSPECTIVE) {
+ c->set_perspective(true);
+ c->set_fov_size(p_camera->get_fov());
+ c->set_zfar(p_camera->get_far());
+ c->set_znear(p_camera->get_near());
+ } else {
+ c->set_fov_size(p_camera->get_fov());
+ c->set_zfar(p_camera->get_far());
+ c->set_znear(p_camera->get_near());
+ }
+ GLTFCameraIndex camera_index = state->cameras.size();
+ state->cameras.push_back(c);
+ return camera_index;
+}
+
+GLTFLightIndex GLTFDocument::_convert_light(Ref<GLTFState> state, Light3D *p_light) {
+ print_verbose("glTF: Converting light: " + p_light->get_name());
+
+ Ref<GLTFLight> l;
+ l.instance();
+ l->color = p_light->get_color();
+ if (cast_to<DirectionalLight3D>(p_light)) {
+ l->type = "directional";
+ DirectionalLight3D *light = cast_to<DirectionalLight3D>(p_light);
+ l->intensity = light->get_param(DirectionalLight3D::PARAM_ENERGY);
+ l->range = FLT_MAX; // Range for directional lights is infinite in Godot.
+ } else if (cast_to<OmniLight3D>(p_light)) {
+ l->type = "point";
+ OmniLight3D *light = cast_to<OmniLight3D>(p_light);
+ l->range = light->get_param(OmniLight3D::PARAM_RANGE);
+ float attenuation = p_light->get_param(OmniLight3D::PARAM_ATTENUATION);
+ l->intensity = l->range / attenuation;
+ } else if (cast_to<SpotLight3D>(p_light)) {
+ l->type = "spot";
+ SpotLight3D *light = cast_to<SpotLight3D>(p_light);
+ l->range = light->get_param(SpotLight3D::PARAM_RANGE);
+ float attenuation = light->get_param(SpotLight3D::PARAM_ATTENUATION);
+ l->intensity = l->range / attenuation;
+ l->outer_cone_angle = Math::deg2rad(light->get_param(SpotLight3D::PARAM_SPOT_ANGLE));
+
+ // This equation is the inverse of the import equation (which has a desmos link).
+ float angle_ratio = 1 - (0.2 / (0.1 + light->get_param(SpotLight3D::PARAM_SPOT_ATTENUATION)));
+ angle_ratio = MAX(0, angle_ratio);
+ l->inner_cone_angle = l->outer_cone_angle * angle_ratio;
+ }
+
+ GLTFLightIndex light_index = state->lights.size();
+ state->lights.push_back(l);
+ return light_index;
+}
+
+GLTFSkeletonIndex GLTFDocument::_convert_skeleton(Ref<GLTFState> state, Skeleton3D *p_skeleton) {
+ print_verbose("glTF: Converting skeleton: " + p_skeleton->get_name());
+ Ref<GLTFSkeleton> gltf_skeleton;
+ gltf_skeleton.instance();
+ gltf_skeleton->set_name(_gen_unique_name(state, p_skeleton->get_name()));
+ gltf_skeleton->godot_skeleton = p_skeleton;
+ GLTFSkeletonIndex skeleton_i = state->skeletons.size();
+ state->skeletons.push_back(gltf_skeleton);
+ return skeleton_i;
+}
+
+void GLTFDocument::_convert_spatial(Ref<GLTFState> state, Node3D *p_spatial, Ref<GLTFNode> p_node) {
+ Transform xform = p_spatial->get_transform();
+ p_node->scale = xform.basis.get_scale();
+ p_node->rotation = xform.basis.get_rotation_quat();
+ p_node->translation = xform.origin;
+}
+
+Node3D *GLTFDocument::_generate_spatial(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index) {
+ Ref<GLTFNode> gltf_node = state->nodes[node_index];
+
+ Node3D *spatial = memnew(Node3D);
+ print_verbose("glTF: Converting spatial: " + gltf_node->get_name());
+
+ return spatial;
+}
+void GLTFDocument::_convert_scene_node(Ref<GLTFState> state, Node *p_current, Node *p_root, const GLTFNodeIndex p_gltf_parent, const GLTFNodeIndex p_gltf_root) {
+ bool retflag = true;
+ _check_visibility(p_current, retflag);
+ if (retflag) {
+ return;
+ }
+ Ref<GLTFNode> gltf_node;
+ gltf_node.instance();
+ gltf_node->set_name(_gen_unique_name(state, p_current->get_name()));
+ if (cast_to<Node3D>(p_current)) {
+ Node3D *spatial = cast_to<Node3D>(p_current);
+ _convert_spatial(state, spatial, gltf_node);
+ }
+ if (cast_to<MeshInstance3D>(p_current)) {
+ Node3D *spatial = cast_to<Node3D>(p_current);
+ _convert_mesh_to_gltf(p_current, state, spatial, gltf_node);
+ } else if (cast_to<BoneAttachment3D>(p_current)) {
+ _convert_bone_attachment_to_gltf(p_current, state, gltf_node, retflag);
+ // TODO 2020-12-21 iFire Handle the case of objects under the bone attachment.
+ return;
+ } else if (cast_to<Skeleton3D>(p_current)) {
+ _convert_skeleton_to_gltf(p_current, state, p_gltf_parent, p_gltf_root, gltf_node, p_root);
+ // We ignore the Godot Engine node that is the skeleton.
+ return;
+ } else if (cast_to<MultiMeshInstance3D>(p_current)) {
+ _convert_mult_mesh_instance_to_gltf(p_current, p_gltf_parent, p_gltf_root, gltf_node, state, p_root);
+#ifdef MODULE_CSG_ENABLED
+ } else if (cast_to<CSGShape3D>(p_current)) {
+ if (p_current->get_parent() && cast_to<CSGShape3D>(p_current)->is_root_shape()) {
+ _convert_csg_shape_to_gltf(p_current, p_gltf_parent, gltf_node, state);
+ }
+#endif // MODULE_CSG_ENABLED
+#ifdef MODULE_GRIDMAP_ENABLED
+ } else if (cast_to<GridMap>(p_current)) {
+ _convert_grid_map_to_gltf(p_current, p_gltf_parent, p_gltf_root, gltf_node, state, p_root);
+#endif // MODULE_GRIDMAP_ENABLED
+ } else if (cast_to<Camera3D>(p_current)) {
+ Camera3D *camera = Object::cast_to<Camera3D>(p_current);
+ _convert_camera_to_gltf(camera, state, camera, gltf_node);
+ } else if (cast_to<Light3D>(p_current)) {
+ Light3D *light = Object::cast_to<Light3D>(p_current);
+ _convert_light_to_gltf(light, state, light, gltf_node);
+ } else if (cast_to<AnimationPlayer>(p_current)) {
+ AnimationPlayer *animation_player = Object::cast_to<AnimationPlayer>(p_current);
+ _convert_animation_player_to_gltf(animation_player, state, p_gltf_parent, p_gltf_root, gltf_node, p_current, p_root);
+ }
+ GLTFNodeIndex current_node_i = state->nodes.size();
+ GLTFNodeIndex gltf_root = p_gltf_root;
+ if (gltf_root == -1) {
+ gltf_root = current_node_i;
+ Array scenes;
+ scenes.push_back(gltf_root);
+ state->json["scene"] = scenes;
+ }
+ _create_gltf_node(state, p_current, current_node_i, p_gltf_parent, gltf_root, gltf_node);
+ for (int node_i = 0; node_i < p_current->get_child_count(); node_i++) {
+ _convert_scene_node(state, p_current->get_child(node_i), p_root, current_node_i, gltf_root);
+ }
+}
+
+#ifdef MODULE_CSG_ENABLED
+void GLTFDocument::_convert_csg_shape_to_gltf(Node *p_current, GLTFNodeIndex p_gltf_parent, Ref<GLTFNode> gltf_node, Ref<GLTFState> state) {
+ CSGShape3D *csg = Object::cast_to<CSGShape3D>(p_current);
+ csg->call("_update_shape");
+ Array meshes = csg->get_meshes();
+ if (meshes.size() != 2) {
+ return;
+ }
+ Ref<Material> mat;
+ if (csg->get_material_override().is_valid()) {
+ mat = csg->get_material_override();
+ }
+ Ref<GLTFMesh> gltf_mesh;
+ gltf_mesh.instance();
+ Ref<EditorSceneImporterMesh> import_mesh;
+ import_mesh.instance();
+ Ref<ArrayMesh> array_mesh = csg->get_meshes()[1];
+ for (int32_t surface_i = 0; surface_i < array_mesh->get_surface_count(); surface_i++) {
+ import_mesh->add_surface(Mesh::PrimitiveType::PRIMITIVE_TRIANGLES, array_mesh->surface_get_arrays(surface_i), Array(), Dictionary(), mat, array_mesh->surface_get_name(surface_i));
+ }
+ gltf_mesh->set_mesh(import_mesh);
+ GLTFMeshIndex mesh_i = state->meshes.size();
+ state->meshes.push_back(gltf_mesh);
+ gltf_node->mesh = mesh_i;
+ gltf_node->xform = csg->get_meshes()[0];
+ gltf_node->set_name(_gen_unique_name(state, csg->get_name()));
+}
+#endif // MODULE_CSG_ENABLED
+
+void GLTFDocument::_create_gltf_node(Ref<GLTFState> state, Node *p_scene_parent, GLTFNodeIndex current_node_i,
+ GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_gltf_node, Ref<GLTFNode> gltf_node) {
+ state->scene_nodes.insert(current_node_i, p_scene_parent);
+ state->nodes.push_back(gltf_node);
+ if (current_node_i == p_parent_node_index) {
+ return;
+ }
+ if (p_parent_node_index == -1) {
+ return;
+ }
+ state->nodes.write[p_parent_node_index]->children.push_back(current_node_i);
+}
+
+void GLTFDocument::_convert_animation_player_to_gltf(AnimationPlayer *animation_player, Ref<GLTFState> state, const GLTFNodeIndex &p_gltf_current, const GLTFNodeIndex &p_gltf_root_index, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent, Node *p_root) {
+ ERR_FAIL_COND(!animation_player);
+ state->animation_players.push_back(animation_player);
+ print_verbose(String("glTF: Converting animation player: ") + animation_player->get_name());
+}
+
+void GLTFDocument::_check_visibility(Node *p_node, bool &retflag) {
+ retflag = true;
+ Node3D *spatial = Object::cast_to<Node3D>(p_node);
+ Node2D *node_2d = Object::cast_to<Node2D>(p_node);
+ if (node_2d && !node_2d->is_visible()) {
+ return;
+ }
+ if (spatial && !spatial->is_visible()) {
+ return;
+ }
+ retflag = false;
+}
+
+void GLTFDocument::_convert_camera_to_gltf(Camera3D *camera, Ref<GLTFState> state, Node3D *spatial, Ref<GLTFNode> gltf_node) {
+ ERR_FAIL_COND(!camera);
+ GLTFCameraIndex camera_index = _convert_camera(state, camera);
+ if (camera_index != -1) {
+ gltf_node->camera = camera_index;
+ }
+}
+
+void GLTFDocument::_convert_light_to_gltf(Light3D *light, Ref<GLTFState> state, Node3D *spatial, Ref<GLTFNode> gltf_node) {
+ ERR_FAIL_COND(!light);
+ GLTFLightIndex light_index = _convert_light(state, light);
+ if (light_index != -1) {
+ gltf_node->light = light_index;
+ }
+}
+
+#ifdef MODULE_GRIDMAP_ENABLED
+void GLTFDocument::_convert_grid_map_to_gltf(Node *p_scene_parent, const GLTFNodeIndex &p_parent_node_index, const GLTFNodeIndex &p_root_node_index, Ref<GLTFNode> gltf_node, Ref<GLTFState> state, Node *p_root_node) {
+ GridMap *grid_map = Object::cast_to<GridMap>(p_scene_parent);
+ ERR_FAIL_COND(!grid_map);
+ Array cells = grid_map->get_used_cells();
+ for (int32_t k = 0; k < cells.size(); k++) {
+ GLTFNode *new_gltf_node = memnew(GLTFNode);
+ gltf_node->children.push_back(state->nodes.size());
+ state->nodes.push_back(new_gltf_node);
+ Vector3 cell_location = cells[k];
+ int32_t cell = grid_map->get_cell_item(
+ Vector3(cell_location.x, cell_location.y, cell_location.z));
+ EditorSceneImporterMeshNode3D *import_mesh_node = memnew(EditorSceneImporterMeshNode3D);
+ import_mesh_node->set_mesh(grid_map->get_mesh_library()->get_item_mesh(cell));
+ Transform cell_xform;
+ cell_xform.basis.set_orthogonal_index(
+ grid_map->get_cell_item_orientation(
+ Vector3(cell_location.x, cell_location.y, cell_location.z)));
+ cell_xform.basis.scale(Vector3(grid_map->get_cell_scale(),
+ grid_map->get_cell_scale(),
+ grid_map->get_cell_scale()));
+ cell_xform.set_origin(grid_map->map_to_world(
+ Vector3(cell_location.x, cell_location.y, cell_location.z)));
+ Ref<GLTFMesh> gltf_mesh;
+ gltf_mesh.instance();
+ gltf_mesh = import_mesh_node;
+ new_gltf_node->mesh = state->meshes.size();
+ state->meshes.push_back(gltf_mesh);
+ new_gltf_node->xform = cell_xform * grid_map->get_transform();
+ new_gltf_node->set_name(_gen_unique_name(state, grid_map->get_mesh_library()->get_item_name(cell)));
+ }
+}
+#endif // MODULE_GRIDMAP_ENABLED
+
+void GLTFDocument::_convert_mult_mesh_instance_to_gltf(Node *p_scene_parent, const GLTFNodeIndex &p_parent_node_index, const GLTFNodeIndex &p_root_node_index, Ref<GLTFNode> gltf_node, Ref<GLTFState> state, Node *p_root_node) {
+ MultiMeshInstance3D *multi_mesh_instance = Object::cast_to<MultiMeshInstance3D>(p_scene_parent);
+ ERR_FAIL_COND(!multi_mesh_instance);
+ Ref<MultiMesh> multi_mesh = multi_mesh_instance->get_multimesh();
+ if (multi_mesh.is_valid()) {
+ for (int32_t instance_i = 0; instance_i < multi_mesh->get_instance_count();
+ instance_i++) {
+ GLTFNode *new_gltf_node = memnew(GLTFNode);
+ Transform transform;
+ if (multi_mesh->get_transform_format() == MultiMesh::TRANSFORM_2D) {
+ Transform2D xform_2d = multi_mesh->get_instance_transform_2d(instance_i);
+ transform.origin =
+ Vector3(xform_2d.get_origin().x, 0, xform_2d.get_origin().y);
+ real_t rotation = xform_2d.get_rotation();
+ Quat quat(Vector3(0, 1, 0), rotation);
+ Size2 scale = xform_2d.get_scale();
+ transform.basis.set_quat_scale(quat,
+ Vector3(scale.x, 0, scale.y));
+ transform =
+ multi_mesh_instance->get_transform() * transform;
+ } else if (multi_mesh->get_transform_format() == MultiMesh::TRANSFORM_3D) {
+ transform = multi_mesh_instance->get_transform() *
+ multi_mesh->get_instance_transform(instance_i);
+ }
+ Ref<ArrayMesh> mm = multi_mesh->get_mesh();
+ if (mm.is_valid()) {
+ Ref<EditorSceneImporterMesh> mesh;
+ mesh.instance();
+ for (int32_t surface_i = 0; surface_i < mm->get_surface_count(); surface_i++) {
+ Array surface = mm->surface_get_arrays(surface_i);
+ mesh->add_surface(mm->surface_get_primitive_type(surface_i), surface, Array(), Dictionary(),
+ mm->surface_get_material(surface_i), mm->get_name());
+ }
+ Ref<GLTFMesh> gltf_mesh;
+ gltf_mesh.instance();
+ gltf_mesh->set_name(multi_mesh->get_name());
+ gltf_mesh->set_mesh(mesh);
+ new_gltf_node->mesh = state->meshes.size();
+ state->meshes.push_back(gltf_mesh);
+ }
+ new_gltf_node->xform = transform;
+ new_gltf_node->set_name(_gen_unique_name(state, multi_mesh_instance->get_name()));
+ gltf_node->children.push_back(state->nodes.size());
+ state->nodes.push_back(new_gltf_node);
+ }
+ }
+}
+
+void GLTFDocument::_convert_skeleton_to_gltf(Node *p_scene_parent, Ref<GLTFState> state, const GLTFNodeIndex &p_parent_node_index, const GLTFNodeIndex &p_root_node_index, Ref<GLTFNode> gltf_node, Node *p_root_node) {
+ Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_scene_parent);
+ if (skeleton) {
+ // Remove placeholder skeleton3d node by not creating the gltf node
+ // Skins are per mesh
+ for (int node_i = 0; node_i < skeleton->get_child_count(); node_i++) {
+ _convert_scene_node(state, skeleton->get_child(node_i), p_root_node, p_parent_node_index, p_root_node_index);
+ }
+ }
+}
+
+void GLTFDocument::_convert_bone_attachment_to_gltf(Node *p_scene_parent, Ref<GLTFState> state, Ref<GLTFNode> gltf_node, bool &retflag) {
+ retflag = true;
+ BoneAttachment3D *bone_attachment = Object::cast_to<BoneAttachment3D>(p_scene_parent);
+ if (bone_attachment) {
+ Node *node = bone_attachment->get_parent();
+ while (node) {
+ Skeleton3D *bone_attachment_skeleton = Object::cast_to<Skeleton3D>(node);
+ if (bone_attachment_skeleton) {
+ for (GLTFSkeletonIndex skeleton_i = 0; skeleton_i < state->skeletons.size(); skeleton_i++) {
+ if (state->skeletons[skeleton_i]->godot_skeleton != bone_attachment_skeleton) {
+ continue;
+ }
+ state->skeletons.write[skeleton_i]->bone_attachments.push_back(bone_attachment);
+ break;
+ }
+ break;
+ }
+ node = node->get_parent();
+ }
+ gltf_node.unref();
+ return;
+ }
+ retflag = false;
+}
+
+void GLTFDocument::_convert_mesh_to_gltf(Node *p_scene_parent, Ref<GLTFState> state, Node3D *spatial, Ref<GLTFNode> gltf_node) {
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_scene_parent);
+ if (mi) {
+ GLTFMeshIndex gltf_mesh_index = _convert_mesh_instance(state, mi);
+ if (gltf_mesh_index != -1) {
+ gltf_node->mesh = gltf_mesh_index;
+ }
+ }
+}
+
+void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index) {
+ Ref<GLTFNode> gltf_node = state->nodes[node_index];
+
+ Node3D *current_node = nullptr;
+
+ // Is our parent a skeleton
+ Skeleton3D *active_skeleton = Object::cast_to<Skeleton3D>(scene_parent);
+
+ if (gltf_node->skeleton >= 0) {
+ Skeleton3D *skeleton = state->skeletons[gltf_node->skeleton]->godot_skeleton;
+
+ if (active_skeleton != skeleton) {
+ ERR_FAIL_COND_MSG(active_skeleton != nullptr, "glTF: Generating scene detected direct parented Skeletons");
+
+ // Add it to the scene if it has not already been added
+ if (skeleton->get_parent() == nullptr) {
+ scene_parent->add_child(skeleton);
+ skeleton->set_owner(scene_root);
+ }
+ }
+
+ active_skeleton = skeleton;
+ current_node = skeleton;
+ }
+
+ // If we have an active skeleton, and the node is node skinned, we need to create a bone attachment
+ if (current_node == nullptr && active_skeleton != nullptr && gltf_node->skin < 0) {
+ BoneAttachment3D *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index);
+
+ scene_parent->add_child(bone_attachment);
+ bone_attachment->set_owner(scene_root);
+
+ // There is no gltf_node that represent this, so just directly create a unique name
+ bone_attachment->set_name(_gen_unique_name(state, "BoneAttachment3D"));
+
+ // We change the scene_parent to our bone attachment now. We do not set current_node because we want to make the node
+ // and attach it to the bone_attachment
+ scene_parent = bone_attachment;
+ }
+
+ // We still have not managed to make a node
+ if (current_node == nullptr) {
+ if (gltf_node->mesh >= 0) {
+ current_node = _generate_mesh_instance(state, scene_parent, node_index);
+ } else if (gltf_node->camera >= 0) {
+ current_node = _generate_camera(state, scene_parent, node_index);
+ } else if (gltf_node->light >= 0) {
+ current_node = _generate_light(state, scene_parent, node_index);
+ }
+
+ if (!current_node) {
+ current_node = _generate_spatial(state, scene_parent, node_index);
+ }
+
+ scene_parent->add_child(current_node);
+ if (current_node != scene_root) {
+ current_node->set_owner(scene_root);
+ }
+ current_node->set_transform(gltf_node->xform);
+ current_node->set_name(gltf_node->get_name());
+ }
+
+ state->scene_nodes.insert(node_index, current_node);
+
+ for (int i = 0; i < gltf_node->children.size(); ++i) {
+ _generate_scene_node(state, current_node, scene_root, gltf_node->children[i]);
+ }
+}
+
+template <class T>
+struct EditorSceneImporterGLTFInterpolate {
+ 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 EditorSceneImporterGLTFInterpolate<Quat> {
+ Quat lerp(const Quat &a, const Quat &b, const float c) const {
+ ERR_FAIL_COND_V_MSG(!a.is_normalized(), Quat(), "The quaternion \"a\" must be normalized.");
+ ERR_FAIL_COND_V_MSG(!b.is_normalized(), Quat(), "The quaternion \"b\" must be normalized.");
+
+ return a.slerp(b, c).normalized();
+ }
+
+ Quat catmull_rom(const Quat &p0, const Quat &p1, const Quat &p2, const Quat &p3, const float c) {
+ ERR_FAIL_COND_V_MSG(!p1.is_normalized(), Quat(), "The quaternion \"p1\" must be normalized.");
+ ERR_FAIL_COND_V_MSG(!p2.is_normalized(), Quat(), "The quaternion \"p2\" must be normalized.");
+
+ return p1.slerp(p2, c).normalized();
+ }
+
+ Quat bezier(const Quat start, const Quat control_1, const Quat control_2, const Quat end, const float t) {
+ ERR_FAIL_COND_V_MSG(!start.is_normalized(), Quat(), "The start quaternion must be normalized.");
+ ERR_FAIL_COND_V_MSG(!end.is_normalized(), Quat(), "The end quaternion must be normalized.");
+
+ return start.slerp(end, t).normalized();
+ }
+};
+
+template <class T>
+T GLTFDocument::_interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, const float p_time, const GLTFAnimation::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++;
+ }
+
+ EditorSceneImporterGLTFInterpolate<T> interp;
+
+ switch (p_interp) {
+ case GLTFAnimation::INTERP_LINEAR: {
+ if (idx == -1) {
+ return p_values[0];
+ } else if (idx >= p_times.size() - 1) {
+ return p_values[p_times.size() - 1];
+ }
+
+ const 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 GLTFAnimation::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 GLTFAnimation::INTERP_CATMULLROMSPLINE: {
+ if (idx == -1) {
+ return p_values[1];
+ } else if (idx >= p_times.size() - 1) {
+ return p_values[1 + p_times.size() - 1];
+ }
+
+ const 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 GLTFAnimation::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];
+ }
+
+ const float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]);
+
+ const T from = p_values[idx * 3 + 1];
+ const T c1 = from + p_values[idx * 3 + 2];
+ const T to = p_values[idx * 3 + 4];
+ const T c2 = to + p_values[idx * 3 + 3];
+
+ return interp.bezier(from, c1, c2, to, c);
+ } break;
+ }
+
+ ERR_FAIL_V(p_values[0]);
+}
+
+void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, const GLTFAnimationIndex index, const int bake_fps) {
+ Ref<GLTFAnimation> anim = state->animations[index];
+
+ String name = anim->get_name();
+ if (name.is_empty()) {
+ // No node represent these, and they are not in the hierarchy, so just make a unique name
+ name = _gen_unique_name(state, "Animation");
+ }
+
+ Ref<Animation> animation;
+ animation.instance();
+ animation->set_name(name);
+
+ if (anim->get_loop()) {
+ animation->set_loop(true);
+ }
+
+ float length = 0;
+
+ for (Map<int, GLTFAnimation::Track>::Element *track_i = anim->get_tracks().front(); track_i; track_i = track_i->next()) {
+ const GLTFAnimation::Track &track = track_i->get();
+ //need to find the path
+ NodePath node_path;
+
+ GLTFNodeIndex node_index = track_i->key();
+ if (state->nodes[node_index]->fake_joint_parent >= 0) {
+ // Should be same as parent
+ node_index = state->nodes[node_index]->fake_joint_parent;
+ }
+
+ const Ref<GLTFNode> gltf_node = state->nodes[track_i->key()];
+
+ if (gltf_node->skeleton >= 0) {
+ const Skeleton3D *sk = Object::cast_to<Skeleton3D>(state->scene_nodes.find(node_index)->get());
+ ERR_FAIL_COND(sk == nullptr);
+
+ const String path = ap->get_parent()->get_path_to(sk);
+ const String bone = gltf_node->get_name();
+ node_path = path + ":" + bone;
+ } else {
+ Node *root = ap->get_parent();
+ Node *godot_node = state->scene_nodes.find(node_index)->get();
+ node_path = root->get_path_to(godot_node);
+ }
+
+ for (int i = 0; i < track.rotation_track.times.size(); i++) {
+ length = MAX(length, track.rotation_track.times[i]);
+ }
+ for (int i = 0; i < track.translation_track.times.size(); i++) {
+ length = MAX(length, track.translation_track.times[i]);
+ }
+ for (int i = 0; i < track.scale_track.times.size(); i++) {
+ length = MAX(length, track.scale_track.times[i]);
+ }
+
+ for (int i = 0; i < track.weight_tracks.size(); i++) {
+ for (int j = 0; j < track.weight_tracks[i].times.size(); j++) {
+ length = MAX(length, track.weight_tracks[i].times[j]);
+ }
+ }
+
+ if (track.rotation_track.values.size() || track.translation_track.values.size() || track.scale_track.values.size()) {
+ //make transform track
+ int track_idx = animation->get_track_count();
+ animation->add_track(Animation::TYPE_TRANSFORM);
+ animation->track_set_path(track_idx, node_path);
+ //first determine animation length
+
+ const float increment = 1.0 / float(bake_fps);
+ float time = 0.0;
+
+ Vector3 base_pos;
+ Quat base_rot;
+ Vector3 base_scale = Vector3(1, 1, 1);
+
+ if (!track.rotation_track.values.size()) {
+ base_rot = state->nodes[track_i->key()]->rotation.normalized();
+ }
+
+ if (!track.translation_track.values.size()) {
+ base_pos = state->nodes[track_i->key()]->translation;
+ }
+
+ if (!track.scale_track.values.size()) {
+ base_scale = state->nodes[track_i->key()]->scale;
+ }
+
+ bool last = false;
+ while (true) {
+ Vector3 pos = base_pos;
+ Quat rot = base_rot;
+ Vector3 scale = base_scale;
+
+ if (track.translation_track.times.size()) {
+ pos = _interpolate_track<Vector3>(track.translation_track.times, track.translation_track.values, time, track.translation_track.interpolation);
+ }
+
+ if (track.rotation_track.times.size()) {
+ rot = _interpolate_track<Quat>(track.rotation_track.times, track.rotation_track.values, time, track.rotation_track.interpolation);
+ }
+
+ if (track.scale_track.times.size()) {
+ scale = _interpolate_track<Vector3>(track.scale_track.times, track.scale_track.values, time, track.scale_track.interpolation);
+ }
+
+ if (gltf_node->skeleton >= 0) {
+ Transform xform;
+ xform.basis.set_quat_scale(rot, scale);
+ xform.origin = pos;
+
+ const Skeleton3D *skeleton = state->skeletons[gltf_node->skeleton]->godot_skeleton;
+ const int bone_idx = skeleton->find_bone(gltf_node->get_name());
+ xform = skeleton->get_bone_rest(bone_idx).affine_inverse() * xform;
+
+ rot = xform.basis.get_rotation_quat();
+ rot.normalize();
+ scale = xform.basis.get_scale();
+ pos = xform.origin;
+ }
+
+ animation->transform_track_insert_key(track_idx, time, pos, rot, scale);
+
+ if (last) {
+ break;
+ }
+ time += increment;
+ if (time >= length) {
+ last = true;
+ time = length;
+ }
+ }
+ }
+
+ for (int i = 0; i < track.weight_tracks.size(); i++) {
+ ERR_CONTINUE(gltf_node->mesh < 0 || gltf_node->mesh >= state->meshes.size());
+ Ref<GLTFMesh> mesh = state->meshes[gltf_node->mesh];
+ ERR_CONTINUE(mesh.is_null());
+ ERR_CONTINUE(mesh->get_mesh().is_null());
+ ERR_CONTINUE(mesh->get_mesh()->get_mesh().is_null());
+ const String prop = "blend_shapes/" + mesh->get_mesh()->get_blend_shape_name(i);
+
+ const String blend_path = String(node_path) + ":" + prop;
+
+ const int track_idx = animation->get_track_count();
+ animation->add_track(Animation::TYPE_VALUE);
+ animation->track_set_path(track_idx, blend_path);
+
+ // Only LINEAR and STEP (NEAREST) can be supported out of the box by Godot's Animation,
+ // the other modes have to be baked.
+ GLTFAnimation::Interpolation gltf_interp = track.weight_tracks[i].interpolation;
+ if (gltf_interp == GLTFAnimation::INTERP_LINEAR || gltf_interp == GLTFAnimation::INTERP_STEP) {
+ animation->track_set_interpolation_type(track_idx, gltf_interp == GLTFAnimation::INTERP_STEP ? Animation::INTERPOLATION_NEAREST : Animation::INTERPOLATION_LINEAR);
+ for (int j = 0; j < track.weight_tracks[i].times.size(); j++) {
+ const float t = track.weight_tracks[i].times[j];
+ const float attribs = track.weight_tracks[i].values[j];
+ animation->track_insert_key(track_idx, t, attribs);
+ }
+ } else {
+ // CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies.
+ const float increment = 1.0 / float(bake_fps);
+ float time = 0.0;
+ bool last = false;
+ while (true) {
+ _interpolate_track<float>(track.weight_tracks[i].times, track.weight_tracks[i].values, time, gltf_interp);
+ if (last) {
+ break;
+ }
+ time += increment;
+ if (time >= length) {
+ last = true;
+ time = length;
+ }
+ }
+ }
+ }
+ }
+
+ animation->set_length(length);
+
+ ap->add_animation(name, animation);
+}
+
+void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) {
+ for (GLTFNodeIndex mi_node_i = 0; mi_node_i < state->nodes.size(); ++mi_node_i) {
+ Ref<GLTFNode> node = state->nodes[mi_node_i];
+
+ if (node->mesh < 0) {
+ continue;
+ }
+ Array json_skins;
+ if (state->json.has("skins")) {
+ json_skins = state->json["skins"];
+ }
+ Map<GLTFNodeIndex, Node *>::Element *mi_element = state->scene_nodes.find(mi_node_i);
+ if (!mi_element) {
+ continue;
+ }
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(mi_element->get());
+ ERR_CONTINUE(!mi);
+ Transform mi_xform = mi->get_transform();
+ node->scale = mi_xform.basis.get_scale();
+ node->rotation = mi_xform.basis.get_rotation_quat();
+ node->translation = mi_xform.origin;
+
+ Dictionary json_skin;
+ Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(mi->get_node(mi->get_skeleton_path()));
+ if (!skeleton) {
+ continue;
+ }
+ if (!skeleton->get_bone_count()) {
+ continue;
+ }
+ Ref<Skin> skin = mi->get_skin();
+ if (skin.is_null()) {
+ skin = skeleton->register_skin(nullptr)->get_skin();
+ }
+ Ref<GLTFSkin> gltf_skin;
+ gltf_skin.instance();
+ Array json_joints;
+ GLTFSkeletonIndex skeleton_gltf_i = -1;
+
+ NodePath skeleton_path = mi->get_skeleton_path();
+ bool is_unique = true;
+ for (int32_t skin_i = 0; skin_i < state->skins.size(); skin_i++) {
+ Ref<GLTFSkin> prev_gltf_skin = state->skins.write[skin_i];
+ if (gltf_skin.is_null()) {
+ continue;
+ }
+ GLTFSkeletonIndex prev_skeleton = prev_gltf_skin->get_skeleton();
+ if (prev_skeleton == -1 || prev_skeleton >= state->skeletons.size()) {
+ continue;
+ }
+ if (prev_gltf_skin->get_godot_skin() == skin && state->skeletons[prev_skeleton]->godot_skeleton == skeleton) {
+ node->skin = skin_i;
+ node->skeleton = prev_skeleton;
+ is_unique = false;
+ break;
+ }
+ }
+ if (!is_unique) {
+ continue;
+ }
+ GLTFSkeletonIndex skeleton_i = _convert_skeleton(state, skeleton);
+ skeleton_gltf_i = skeleton_i;
+ ERR_CONTINUE(skeleton_gltf_i == -1);
+ gltf_skin->skeleton = skeleton_gltf_i;
+ Ref<GLTFSkeleton> gltf_skeleton = state->skeletons.write[skeleton_gltf_i];
+ for (int32_t bind_i = 0; bind_i < skin->get_bind_count(); bind_i++) {
+ String godot_bone_name = skin->get_bind_name(bind_i);
+ if (godot_bone_name.is_empty()) {
+ int32_t bone = skin->get_bind_bone(bind_i);
+ godot_bone_name = skeleton->get_bone_name(bone);
+ }
+ if (skeleton->find_bone(godot_bone_name) == -1) {
+ godot_bone_name = skeleton->get_bone_name(0);
+ }
+ BoneId bone_index = skeleton->find_bone(godot_bone_name);
+ ERR_CONTINUE(bone_index == -1);
+ Ref<GLTFNode> joint_node;
+ joint_node.instance();
+ String gltf_bone_name = _gen_unique_bone_name(state, skeleton_gltf_i, godot_bone_name);
+ joint_node->set_name(gltf_bone_name);
+
+ Transform bone_rest_xform = skeleton->get_bone_rest(bone_index);
+ joint_node->scale = bone_rest_xform.basis.get_scale();
+ joint_node->rotation = bone_rest_xform.basis.get_rotation_quat();
+ joint_node->translation = bone_rest_xform.origin;
+ joint_node->joint = true;
+
+ int32_t joint_node_i = state->nodes.size();
+ state->nodes.push_back(joint_node);
+ gltf_skeleton->godot_bone_node.insert(bone_index, joint_node_i);
+ int32_t joint_index = gltf_skin->joints.size();
+ gltf_skin->joint_i_to_bone_i.insert(joint_index, bone_index);
+ gltf_skin->joints.push_back(joint_node_i);
+ gltf_skin->joints_original.push_back(joint_node_i);
+ gltf_skin->inverse_binds.push_back(skin->get_bind_pose(bind_i));
+ json_joints.push_back(joint_node_i);
+ for (Map<GLTFNodeIndex, Node *>::Element *skin_scene_node_i = state->scene_nodes.front(); skin_scene_node_i; skin_scene_node_i = skin_scene_node_i->next()) {
+ if (skin_scene_node_i->get() == skeleton) {
+ gltf_skin->skin_root = skin_scene_node_i->key();
+ json_skin["skeleton"] = skin_scene_node_i->key();
+ }
+ }
+ gltf_skin->godot_skin = skin;
+ gltf_skin->set_name(_gen_unique_name(state, skin->get_name()));
+ }
+ for (int32_t bind_i = 0; bind_i < skin->get_bind_count(); bind_i++) {
+ String bone_name = skeleton->get_bone_name(bind_i);
+ String godot_bone_name = skin->get_bind_name(bind_i);
+ int32_t bone = -1;
+ if (skin->get_bind_bone(bind_i) != -1) {
+ bone = skin->get_bind_bone(bind_i);
+ godot_bone_name = skeleton->get_bone_name(bone);
+ }
+ bone = skeleton->find_bone(godot_bone_name);
+ if (bone == -1) {
+ continue;
+ }
+ BoneId bone_parent = skeleton->get_bone_parent(bone);
+ GLTFNodeIndex joint_node_i = gltf_skeleton->godot_bone_node[bone];
+ ERR_CONTINUE(joint_node_i >= state->nodes.size());
+ if (bone_parent != -1) {
+ GLTFNodeIndex parent_joint_gltf_node = gltf_skin->joints[bone_parent];
+ Ref<GLTFNode> parent_joint_node = state->nodes.write[parent_joint_gltf_node];
+ parent_joint_node->children.push_back(joint_node_i);
+ } else {
+ Node *node_parent = skeleton->get_parent();
+ ERR_CONTINUE(!node_parent);
+ for (Map<GLTFNodeIndex, Node *>::Element *E = state->scene_nodes.front(); E; E = E->next()) {
+ if (E->get() == node_parent) {
+ GLTFNodeIndex gltf_node_i = E->key();
+ Ref<GLTFNode> gltf_node = state->nodes.write[gltf_node_i];
+ gltf_node->children.push_back(joint_node_i);
+ break;
+ }
+ }
+ }
+ }
+ _expand_skin(state, gltf_skin);
+ node->skin = state->skins.size();
+ state->skins.push_back(gltf_skin);
+
+ json_skin["inverseBindMatrices"] = _encode_accessor_as_xform(state, gltf_skin->inverse_binds, false);
+ json_skin["joints"] = json_joints;
+ json_skin["name"] = gltf_skin->get_name();
+ json_skins.push_back(json_skin);
+ state->json["skins"] = json_skins;
+ }
+}
+
+float GLTFDocument::solve_metallic(float p_dielectric_specular, float diffuse, float specular, float p_one_minus_specular_strength) {
+ if (specular <= p_dielectric_specular) {
+ return 0.0f;
+ }
+
+ const float a = p_dielectric_specular;
+ const float b = diffuse * p_one_minus_specular_strength / (1.0f - p_dielectric_specular) + specular - 2.0f * p_dielectric_specular;
+ const float c = p_dielectric_specular - specular;
+ const float D = b * b - 4.0f * a * c;
+ return CLAMP((-b + Math::sqrt(D)) / (2.0f * a), 0.0f, 1.0f);
+}
+
+float GLTFDocument::get_perceived_brightness(const Color p_color) {
+ const Color coeff = Color(R_BRIGHTNESS_COEFF, G_BRIGHTNESS_COEFF, B_BRIGHTNESS_COEFF);
+ const Color value = coeff * (p_color * p_color);
+
+ const float r = value.r;
+ const float g = value.g;
+ const float b = value.b;
+
+ return Math::sqrt(r + g + b);
+}
+
+float GLTFDocument::get_max_component(const Color &p_color) {
+ const float r = p_color.r;
+ const float g = p_color.g;
+ const float b = p_color.b;
+
+ return MAX(MAX(r, g), b);
+}
+
+void GLTFDocument::_process_mesh_instances(Ref<GLTFState> state, Node *scene_root) {
+ for (GLTFNodeIndex node_i = 0; node_i < state->nodes.size(); ++node_i) {
+ Ref<GLTFNode> node = state->nodes[node_i];
+
+ if (node->skin >= 0 && node->mesh >= 0) {
+ const GLTFSkinIndex skin_i = node->skin;
+
+ Map<GLTFNodeIndex, Node *>::Element *mi_element = state->scene_nodes.find(node_i);
+ EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(mi_element->get());
+ ERR_FAIL_COND(mi == nullptr);
+
+ const GLTFSkeletonIndex skel_i = state->skins.write[node->skin]->skeleton;
+ Ref<GLTFSkeleton> gltf_skeleton = state->skeletons.write[skel_i];
+ Skeleton3D *skeleton = gltf_skeleton->godot_skeleton;
+ ERR_FAIL_COND(skeleton == nullptr);
+
+ mi->get_parent()->remove_child(mi);
+ skeleton->add_child(mi);
+ mi->set_owner(skeleton->get_owner());
+
+ mi->set_skin(state->skins.write[skin_i]->godot_skin);
+ mi->set_skeleton_path(mi->get_path_to(skeleton));
+ mi->set_transform(Transform());
+ }
+ }
+}
+
+GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state, GLTFAnimation::Track p_track, Ref<Animation> p_animation, Transform p_bone_rest, int32_t p_track_i, GLTFNodeIndex p_node_i) {
+ Animation::InterpolationType interpolation = p_animation->track_get_interpolation_type(p_track_i);
+
+ GLTFAnimation::Interpolation gltf_interpolation = GLTFAnimation::INTERP_LINEAR;
+ if (interpolation == Animation::InterpolationType::INTERPOLATION_LINEAR) {
+ gltf_interpolation = GLTFAnimation::INTERP_LINEAR;
+ } else if (interpolation == Animation::InterpolationType::INTERPOLATION_NEAREST) {
+ gltf_interpolation = GLTFAnimation::INTERP_STEP;
+ } else if (interpolation == Animation::InterpolationType::INTERPOLATION_CUBIC) {
+ gltf_interpolation = GLTFAnimation::INTERP_CUBIC_SPLINE;
+ }
+ Animation::TrackType track_type = p_animation->track_get_type(p_track_i);
+ int32_t key_count = p_animation->track_get_key_count(p_track_i);
+ Vector<float> times;
+ times.resize(key_count);
+ String path = p_animation->track_get_path(p_track_i);
+ for (int32_t key_i = 0; key_i < key_count; key_i++) {
+ times.write[key_i] = p_animation->track_get_key_time(p_track_i, key_i);
+ }
+ const float BAKE_FPS = 30.0f;
+ if (track_type == Animation::TYPE_TRANSFORM) {
+ p_track.translation_track.times = times;
+ p_track.translation_track.interpolation = gltf_interpolation;
+ p_track.rotation_track.times = times;
+ p_track.rotation_track.interpolation = gltf_interpolation;
+ p_track.scale_track.times = times;
+ p_track.scale_track.interpolation = gltf_interpolation;
+
+ p_track.scale_track.values.resize(key_count);
+ p_track.scale_track.interpolation = gltf_interpolation;
+ p_track.translation_track.values.resize(key_count);
+ p_track.translation_track.interpolation = gltf_interpolation;
+ p_track.rotation_track.values.resize(key_count);
+ p_track.rotation_track.interpolation = gltf_interpolation;
+ for (int32_t key_i = 0; key_i < key_count; key_i++) {
+ Vector3 translation;
+ Quat rotation;
+ Vector3 scale;
+ Error err = p_animation->transform_track_get_key(p_track_i, key_i, &translation, &rotation, &scale);
+ ERR_CONTINUE(err != OK);
+ Transform xform;
+ xform.basis.set_quat_scale(rotation, scale);
+ xform.origin = translation;
+ xform = p_bone_rest * xform;
+ p_track.translation_track.values.write[key_i] = xform.get_origin();
+ p_track.rotation_track.values.write[key_i] = xform.basis.get_rotation_quat();
+ p_track.scale_track.values.write[key_i] = xform.basis.get_scale();
+ }
+ } else if (path.find(":transform") != -1) {
+ p_track.translation_track.times = times;
+ p_track.translation_track.interpolation = gltf_interpolation;
+ p_track.rotation_track.times = times;
+ p_track.rotation_track.interpolation = gltf_interpolation;
+ p_track.scale_track.times = times;
+ p_track.scale_track.interpolation = gltf_interpolation;
+
+ p_track.scale_track.values.resize(key_count);
+ p_track.scale_track.interpolation = gltf_interpolation;
+ p_track.translation_track.values.resize(key_count);
+ p_track.translation_track.interpolation = gltf_interpolation;
+ p_track.rotation_track.values.resize(key_count);
+ p_track.rotation_track.interpolation = gltf_interpolation;
+ for (int32_t key_i = 0; key_i < key_count; key_i++) {
+ Transform xform = p_animation->track_get_key_value(p_track_i, key_i);
+ p_track.translation_track.values.write[key_i] = xform.get_origin();
+ p_track.rotation_track.values.write[key_i] = xform.basis.get_rotation_quat();
+ p_track.scale_track.values.write[key_i] = xform.basis.get_scale();
+ }
+ } else if (track_type == Animation::TYPE_VALUE) {
+ if (path.find("/rotation_quat") != -1) {
+ p_track.rotation_track.times = times;
+ p_track.rotation_track.interpolation = gltf_interpolation;
+
+ p_track.rotation_track.values.resize(key_count);
+ p_track.rotation_track.interpolation = gltf_interpolation;
+
+ for (int32_t key_i = 0; key_i < key_count; key_i++) {
+ Quat rotation_track = p_animation->track_get_key_value(p_track_i, key_i);
+ p_track.rotation_track.values.write[key_i] = rotation_track;
+ }
+ } else if (path.find(":translation") != -1) {
+ p_track.translation_track.times = times;
+ p_track.translation_track.interpolation = gltf_interpolation;
+
+ p_track.translation_track.values.resize(key_count);
+ p_track.translation_track.interpolation = gltf_interpolation;
+
+ for (int32_t key_i = 0; key_i < key_count; key_i++) {
+ Vector3 translation = p_animation->track_get_key_value(p_track_i, key_i);
+ p_track.translation_track.values.write[key_i] = translation;
+ }
+ } else if (path.find(":rotation_degrees") != -1) {
+ p_track.rotation_track.times = times;
+ p_track.rotation_track.interpolation = gltf_interpolation;
+
+ p_track.rotation_track.values.resize(key_count);
+ p_track.rotation_track.interpolation = gltf_interpolation;
+
+ for (int32_t key_i = 0; key_i < key_count; key_i++) {
+ Vector3 rotation_degrees = p_animation->track_get_key_value(p_track_i, key_i);
+ Vector3 rotation_radian;
+ rotation_radian.x = Math::deg2rad(rotation_degrees.x);
+ rotation_radian.y = Math::deg2rad(rotation_degrees.y);
+ rotation_radian.z = Math::deg2rad(rotation_degrees.z);
+ p_track.rotation_track.values.write[key_i] = Quat(rotation_radian);
+ }
+ } else if (path.find(":scale") != -1) {
+ p_track.scale_track.times = times;
+ p_track.scale_track.interpolation = gltf_interpolation;
+
+ p_track.scale_track.values.resize(key_count);
+ p_track.scale_track.interpolation = gltf_interpolation;
+
+ for (int32_t key_i = 0; key_i < key_count; key_i++) {
+ Vector3 scale_track = p_animation->track_get_key_value(p_track_i, key_i);
+ p_track.scale_track.values.write[key_i] = scale_track;
+ }
+ }
+ } else if (track_type == Animation::TYPE_BEZIER) {
+ if (path.find("/scale") != -1) {
+ const int32_t keys = p_animation->track_get_key_time(p_track_i, key_count - 1) * BAKE_FPS;
+ if (!p_track.scale_track.times.size()) {
+ Vector<float> new_times;
+ new_times.resize(keys);
+ for (int32_t key_i = 0; key_i < keys; key_i++) {
+ new_times.write[key_i] = key_i / BAKE_FPS;
+ }
+ p_track.scale_track.times = new_times;
+ p_track.scale_track.interpolation = gltf_interpolation;
+
+ p_track.scale_track.values.resize(keys);
+
+ for (int32_t key_i = 0; key_i < keys; key_i++) {
+ p_track.scale_track.values.write[key_i] = Vector3(1.0f, 1.0f, 1.0f);
+ }
+ p_track.scale_track.interpolation = gltf_interpolation;
+ }
+
+ for (int32_t key_i = 0; key_i < keys; key_i++) {
+ Vector3 bezier_track = p_track.scale_track.values[key_i];
+ if (path.find("/scale:x") != -1) {
+ bezier_track.x = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
+ bezier_track.x = p_bone_rest.affine_inverse().basis.get_scale().x * bezier_track.x;
+ } else if (path.find("/scale:y") != -1) {
+ bezier_track.y = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
+ bezier_track.y = p_bone_rest.affine_inverse().basis.get_scale().y * bezier_track.y;
+ } else if (path.find("/scale:z") != -1) {
+ bezier_track.z = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
+ bezier_track.z = p_bone_rest.affine_inverse().basis.get_scale().z * bezier_track.z;
+ }
+ p_track.scale_track.values.write[key_i] = bezier_track;
+ }
+ } else if (path.find("/translation") != -1) {
+ const int32_t keys = p_animation->track_get_key_time(p_track_i, key_count - 1) * BAKE_FPS;
+ if (!p_track.translation_track.times.size()) {
+ Vector<float> new_times;
+ new_times.resize(keys);
+ for (int32_t key_i = 0; key_i < keys; key_i++) {
+ new_times.write[key_i] = key_i / BAKE_FPS;
+ }
+ p_track.translation_track.times = new_times;
+ p_track.translation_track.interpolation = gltf_interpolation;
+
+ p_track.translation_track.values.resize(keys);
+ p_track.translation_track.interpolation = gltf_interpolation;
+ }
+
+ for (int32_t key_i = 0; key_i < keys; key_i++) {
+ Vector3 bezier_track = p_track.translation_track.values[key_i];
+ if (path.find("/translation:x") != -1) {
+ bezier_track.x = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
+ bezier_track.x = p_bone_rest.affine_inverse().origin.x * bezier_track.x;
+ } else if (path.find("/translation:y") != -1) {
+ bezier_track.y = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
+ bezier_track.y = p_bone_rest.affine_inverse().origin.y * bezier_track.y;
+ } else if (path.find("/translation:z") != -1) {
+ bezier_track.z = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
+ bezier_track.z = p_bone_rest.affine_inverse().origin.z * bezier_track.z;
+ }
+ p_track.translation_track.values.write[key_i] = bezier_track;
+ }
+ }
+ }
+
+ return p_track;
+}
+
+void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, String p_animation_track_name) {
+ Ref<Animation> animation = ap->get_animation(p_animation_track_name);
+ Ref<GLTFAnimation> gltf_animation;
+ gltf_animation.instance();
+ gltf_animation->set_name(_gen_unique_name(state, p_animation_track_name));
+
+ for (int32_t track_i = 0; track_i < animation->get_track_count(); track_i++) {
+ if (!animation->track_is_enabled(track_i)) {
+ continue;
+ }
+ String orig_track_path = animation->track_get_path(track_i);
+ if (String(orig_track_path).find(":translation") != -1) {
+ const Vector<String> node_suffix = String(orig_track_path).split(":translation");
+ const NodePath path = node_suffix[0];
+ const Node *node = ap->get_parent()->get_node_or_null(path);
+ for (Map<GLTFNodeIndex, Node *>::Element *translation_scene_node_i = state->scene_nodes.front(); translation_scene_node_i; translation_scene_node_i = translation_scene_node_i->next()) {
+ if (translation_scene_node_i->get() == node) {
+ GLTFNodeIndex node_index = translation_scene_node_i->key();
+ Map<int, GLTFAnimation::Track>::Element *translation_track_i = gltf_animation->get_tracks().find(node_index);
+ GLTFAnimation::Track track;
+ if (translation_track_i) {
+ track = translation_track_i->get();
+ }
+ track = _convert_animation_track(state, track, animation, Transform(), track_i, node_index);
+ gltf_animation->get_tracks().insert(node_index, track);
+ }
+ }
+ } else if (String(orig_track_path).find(":rotation_degrees") != -1) {
+ const Vector<String> node_suffix = String(orig_track_path).split(":rotation_degrees");
+ const NodePath path = node_suffix[0];
+ const Node *node = ap->get_parent()->get_node_or_null(path);
+ for (Map<GLTFNodeIndex, Node *>::Element *rotation_degree_scene_node_i = state->scene_nodes.front(); rotation_degree_scene_node_i; rotation_degree_scene_node_i = rotation_degree_scene_node_i->next()) {
+ if (rotation_degree_scene_node_i->get() == node) {
+ GLTFNodeIndex node_index = rotation_degree_scene_node_i->key();
+ Map<int, GLTFAnimation::Track>::Element *rotation_degree_track_i = gltf_animation->get_tracks().find(node_index);
+ GLTFAnimation::Track track;
+ if (rotation_degree_track_i) {
+ track = rotation_degree_track_i->get();
+ }
+ track = _convert_animation_track(state, track, animation, Transform(), track_i, node_index);
+ gltf_animation->get_tracks().insert(node_index, track);
+ }
+ }
+ } else if (String(orig_track_path).find(":scale") != -1) {
+ const Vector<String> node_suffix = String(orig_track_path).split(":scale");
+ const NodePath path = node_suffix[0];
+ const Node *node = ap->get_parent()->get_node_or_null(path);
+ for (Map<GLTFNodeIndex, Node *>::Element *scale_scene_node_i = state->scene_nodes.front(); scale_scene_node_i; scale_scene_node_i = scale_scene_node_i->next()) {
+ if (scale_scene_node_i->get() == node) {
+ GLTFNodeIndex node_index = scale_scene_node_i->key();
+ Map<int, GLTFAnimation::Track>::Element *scale_track_i = gltf_animation->get_tracks().find(node_index);
+ GLTFAnimation::Track track;
+ if (scale_track_i) {
+ track = scale_track_i->get();
+ }
+ track = _convert_animation_track(state, track, animation, Transform(), track_i, node_index);
+ gltf_animation->get_tracks().insert(node_index, track);
+ }
+ }
+ } else if (String(orig_track_path).find(":transform") != -1) {
+ const Vector<String> node_suffix = String(orig_track_path).split(":transform");
+ const NodePath path = node_suffix[0];
+ const Node *node = ap->get_parent()->get_node_or_null(path);
+ for (Map<GLTFNodeIndex, Node *>::Element *transform_track_i = state->scene_nodes.front(); transform_track_i; transform_track_i = transform_track_i->next()) {
+ if (transform_track_i->get() == node) {
+ GLTFAnimation::Track track;
+ track = _convert_animation_track(state, track, animation, Transform(), track_i, transform_track_i->key());
+ gltf_animation->get_tracks().insert(transform_track_i->key(), track);
+ }
+ }
+ } else if (String(orig_track_path).find(":blend_shapes/") != -1) {
+ const Vector<String> node_suffix = String(orig_track_path).split(":blend_shapes/");
+ const NodePath path = node_suffix[0];
+ const String suffix = node_suffix[1];
+ const Node *node = ap->get_parent()->get_node_or_null(path);
+ for (Map<GLTFNodeIndex, Node *>::Element *transform_track_i = state->scene_nodes.front(); transform_track_i; transform_track_i = transform_track_i->next()) {
+ if (transform_track_i->get() == node) {
+ const MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(node);
+ if (!mi) {
+ continue;
+ }
+ Ref<ArrayMesh> array_mesh = mi->get_mesh();
+ if (array_mesh.is_null()) {
+ continue;
+ }
+ if (node_suffix.size() != 2) {
+ continue;
+ }
+ GLTFNodeIndex mesh_index = -1;
+ for (GLTFNodeIndex node_i = 0; node_i < state->scene_nodes.size(); node_i++) {
+ if (state->scene_nodes[node_i] == node) {
+ mesh_index = node_i;
+ break;
+ }
+ }
+ ERR_CONTINUE(mesh_index == -1);
+ Ref<Mesh> mesh = mi->get_mesh();
+ ERR_CONTINUE(mesh.is_null());
+ for (int32_t shape_i = 0; shape_i < mesh->get_blend_shape_count(); shape_i++) {
+ if (mesh->get_blend_shape_name(shape_i) != suffix) {
+ continue;
+ }
+ GLTFAnimation::Track track;
+ Map<int, GLTFAnimation::Track>::Element *blend_shape_track_i = gltf_animation->get_tracks().find(mesh_index);
+ if (blend_shape_track_i) {
+ track = blend_shape_track_i->get();
+ }
+ Animation::InterpolationType interpolation = animation->track_get_interpolation_type(track_i);
+
+ GLTFAnimation::Interpolation gltf_interpolation = GLTFAnimation::INTERP_LINEAR;
+ if (interpolation == Animation::InterpolationType::INTERPOLATION_LINEAR) {
+ gltf_interpolation = GLTFAnimation::INTERP_LINEAR;
+ } else if (interpolation == Animation::InterpolationType::INTERPOLATION_NEAREST) {
+ gltf_interpolation = GLTFAnimation::INTERP_STEP;
+ } else if (interpolation == Animation::InterpolationType::INTERPOLATION_CUBIC) {
+ gltf_interpolation = GLTFAnimation::INTERP_CUBIC_SPLINE;
+ }
+ Animation::TrackType track_type = animation->track_get_type(track_i);
+ if (track_type == Animation::TYPE_VALUE) {
+ int32_t key_count = animation->track_get_key_count(track_i);
+ GLTFAnimation::Channel<float> weight;
+ weight.interpolation = gltf_interpolation;
+ weight.times.resize(key_count);
+ for (int32_t time_i = 0; time_i < key_count; time_i++) {
+ weight.times.write[time_i] = animation->track_get_key_time(track_i, time_i);
+ }
+ weight.values.resize(key_count);
+ for (int32_t value_i = 0; value_i < key_count; value_i++) {
+ weight.values.write[value_i] = animation->track_get_key_value(track_i, value_i);
+ }
+ track.weight_tracks.push_back(weight);
+ }
+ gltf_animation->get_tracks()[mesh_index] = track;
+ }
+ }
+ }
+
+ } else if (String(orig_track_path).find(":") != -1) {
+ //Process skeleton
+ const Vector<String> node_suffix = String(orig_track_path).split(":");
+ const String node = node_suffix[0];
+ const NodePath node_path = node;
+ const String suffix = node_suffix[1];
+ Node *godot_node = ap->get_parent()->get_node_or_null(node_path);
+ Skeleton3D *skeleton = nullptr;
+ GLTFSkeletonIndex skeleton_gltf_i = -1;
+ for (GLTFSkeletonIndex skeleton_i = 0; skeleton_i < state->skeletons.size(); skeleton_i++) {
+ if (state->skeletons[skeleton_i]->godot_skeleton == cast_to<Skeleton3D>(godot_node)) {
+ skeleton = state->skeletons[skeleton_i]->godot_skeleton;
+ skeleton_gltf_i = skeleton_i;
+ ERR_CONTINUE(!skeleton);
+ Ref<GLTFSkeleton> skeleton_gltf = state->skeletons[skeleton_gltf_i];
+ int32_t bone = skeleton->find_bone(suffix);
+ ERR_CONTINUE(bone == -1);
+ Transform xform = skeleton->get_bone_rest(bone);
+ if (!skeleton_gltf->godot_bone_node.has(bone)) {
+ continue;
+ }
+ GLTFNodeIndex node_i = skeleton_gltf->godot_bone_node[bone];
+ Map<int, GLTFAnimation::Track>::Element *property_track_i = gltf_animation->get_tracks().find(node_i);
+ GLTFAnimation::Track track;
+ if (property_track_i) {
+ track = property_track_i->get();
+ }
+ track = _convert_animation_track(state, track, animation, xform, track_i, node_i);
+ gltf_animation->get_tracks()[node_i] = track;
+ }
+ }
+ } else if (String(orig_track_path).find(":") == -1) {
+ ERR_CONTINUE(!ap->get_parent());
+ for (int32_t node_i = 0; node_i < ap->get_parent()->get_child_count(); node_i++) {
+ const Node *child = ap->get_parent()->get_child(node_i);
+ const Node *node = child->get_node_or_null(orig_track_path);
+ for (Map<GLTFNodeIndex, Node *>::Element *scene_node_i = state->scene_nodes.front(); scene_node_i; scene_node_i = scene_node_i->next()) {
+ if (scene_node_i->get() == node) {
+ GLTFNodeIndex node_index = scene_node_i->key();
+ Map<int, GLTFAnimation::Track>::Element *node_track_i = gltf_animation->get_tracks().find(node_index);
+ GLTFAnimation::Track track;
+ if (node_track_i) {
+ track = node_track_i->get();
+ }
+ track = _convert_animation_track(state, track, animation, Transform(), track_i, node_index);
+ gltf_animation->get_tracks().insert(node_index, track);
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (gltf_animation->get_tracks().size()) {
+ state->animations.push_back(gltf_animation);
+ }
+}
+
+Error GLTFDocument::parse(Ref<GLTFState> state, String p_path, bool p_read_binary) {
+ Error err;
+ FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err);
+ if (!f) {
+ return err;
+ }
+ uint32_t magic = f->get_32();
+ if (magic == 0x46546C67) {
+ //binary file
+ //text file
+ err = _parse_glb(p_path, state);
+ if (err)
+ return FAILED;
+ } else {
+ //text file
+ err = _parse_json(p_path, state);
+ if (err)
+ return FAILED;
+ }
+ f->close();
+
+ ERR_FAIL_COND_V(!state->json.has("asset"), Error::FAILED);
+
+ Dictionary asset = state->json["asset"];
+
+ ERR_FAIL_COND_V(!asset.has("version"), Error::FAILED);
+
+ String version = asset["version"];
+
+ state->major_version = version.get_slice(".", 0).to_int();
+ state->minor_version = version.get_slice(".", 1).to_int();
+
+ /* STEP 0 PARSE SCENE */
+ err = _parse_scenes(state);
+ if (err != OK)
+ return Error::FAILED;
+
+ /* STEP 1 PARSE NODES */
+ err = _parse_nodes(state);
+ if (err != OK)
+ return Error::FAILED;
+
+ /* STEP 2 PARSE BUFFERS */
+ err = _parse_buffers(state, p_path.get_base_dir());
+ if (err != OK)
+ return Error::FAILED;
+
+ /* STEP 3 PARSE BUFFER VIEWS */
+ err = _parse_buffer_views(state);
+ if (err != OK)
+ return Error::FAILED;
+
+ /* STEP 4 PARSE ACCESSORS */
+ err = _parse_accessors(state);
+ if (err != OK)
+ return Error::FAILED;
+
+ /* STEP 5 PARSE IMAGES */
+ err = _parse_images(state, p_path.get_base_dir());
+ if (err != OK)
+ return Error::FAILED;
+
+ /* STEP 6 PARSE TEXTURES */
+ err = _parse_textures(state);
+ if (err != OK)
+ return Error::FAILED;
+
+ /* STEP 7 PARSE TEXTURES */
+ err = _parse_materials(state);
+ if (err != OK)
+ return Error::FAILED;
+
+ /* STEP 9 PARSE SKINS */
+ err = _parse_skins(state);
+ if (err != OK)
+ return Error::FAILED;
+
+ /* STEP 10 DETERMINE SKELETONS */
+ err = _determine_skeletons(state);
+ if (err != OK)
+ return Error::FAILED;
+
+ /* STEP 11 CREATE SKELETONS */
+ err = _create_skeletons(state);
+ if (err != OK)
+ return Error::FAILED;
+
+ /* STEP 12 CREATE SKINS */
+ err = _create_skins(state);
+ if (err != OK)
+ return Error::FAILED;
+
+ /* STEP 13 PARSE MESHES (we have enough info now) */
+ err = _parse_meshes(state);
+ if (err != OK)
+ return Error::FAILED;
+
+ /* STEP 14 PARSE LIGHTS */
+ err = _parse_lights(state);
+ if (err != OK) {
+ return Error::FAILED;
+ }
+
+ /* STEP 15 PARSE CAMERAS */
+ err = _parse_cameras(state);
+ if (err != OK)
+ return Error::FAILED;
+
+ /* STEP 16 PARSE ANIMATIONS */
+ err = _parse_animations(state);
+ if (err != OK)
+ return Error::FAILED;
+
+ /* STEP 17 ASSIGN SCENE NAMES */
+ _assign_scene_names(state);
+
+ return OK;
+}
+
+Dictionary GLTFDocument::_serialize_texture_transform_uv2(Ref<BaseMaterial3D> p_material) {
+ Dictionary extension;
+ Ref<BaseMaterial3D> mat = p_material;
+ if (mat.is_valid()) {
+ Dictionary texture_transform;
+ Array offset;
+ offset.resize(2);
+ offset[0] = mat->get_uv2_offset().x;
+ offset[1] = mat->get_uv2_offset().y;
+ texture_transform["offset"] = offset;
+ Array scale;
+ scale.resize(2);
+ scale[0] = mat->get_uv2_scale().x;
+ scale[1] = mat->get_uv2_scale().y;
+ texture_transform["scale"] = scale;
+ // Godot doesn't support texture rotation
+ extension["KHR_texture_transform"] = texture_transform;
+ }
+ return extension;
+}
+
+Dictionary GLTFDocument::_serialize_texture_transform_uv1(Ref<BaseMaterial3D> p_material) {
+ Dictionary extension;
+ if (p_material.is_valid()) {
+ Dictionary texture_transform;
+ Array offset;
+ offset.resize(2);
+ offset[0] = p_material->get_uv1_offset().x;
+ offset[1] = p_material->get_uv1_offset().y;
+ texture_transform["offset"] = offset;
+ Array scale;
+ scale.resize(2);
+ scale[0] = p_material->get_uv1_scale().x;
+ scale[1] = p_material->get_uv1_scale().y;
+ texture_transform["scale"] = scale;
+ // Godot doesn't support texture rotation
+ extension["KHR_texture_transform"] = texture_transform;
+ }
+ return extension;
+}
+
+Error GLTFDocument::_serialize_version(Ref<GLTFState> state) {
+ const String version = "2.0";
+ state->major_version = version.get_slice(".", 0).to_int();
+ state->minor_version = version.get_slice(".", 1).to_int();
+ Dictionary asset;
+ asset["version"] = version;
+
+ String hash = VERSION_HASH;
+ asset["generator"] = String(VERSION_FULL_NAME) + String("@") + (hash.length() == 0 ? String("unknown") : hash);
+ state->json["asset"] = asset;
+ ERR_FAIL_COND_V(!asset.has("version"), Error::FAILED);
+ ERR_FAIL_COND_V(!state->json.has("asset"), Error::FAILED);
+ return OK;
+}
+
+Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) {
+ Error err = FAILED;
+ 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);
+
+ String json = JSON::print(state->json);
+
+ const uint32_t magic = 0x46546C67; // GLTF
+ const int32_t header_size = 12;
+ const int32_t chunk_header_size = 8;
+
+ for (int32_t pad_i = 0; pad_i < (chunk_header_size + json.utf8().length()) % 4; pad_i++) {
+ json += " ";
+ }
+ CharString cs = json.utf8();
+ const uint32_t text_chunk_length = cs.length();
+
+ const uint32_t text_chunk_type = 0x4E4F534A; //JSON
+ int32_t binary_data_length = 0;
+ if (state->buffers.size()) {
+ binary_data_length = state->buffers[0].size();
+ }
+ const int32_t binary_chunk_length = binary_data_length;
+ const int32_t binary_chunk_type = 0x004E4942; //BIN
+
+ f->create(FileAccess::ACCESS_RESOURCES);
+ f->store_32(magic);
+ f->store_32(state->major_version); // version
+ f->store_32(header_size + chunk_header_size + text_chunk_length + chunk_header_size + binary_data_length); // length
+ f->store_32(text_chunk_length);
+ f->store_32(text_chunk_type);
+ f->store_buffer((uint8_t *)&cs[0], cs.length());
+ if (binary_chunk_length) {
+ f->store_32(binary_chunk_length);
+ f->store_32(binary_chunk_type);
+ f->store_buffer(state->buffers[0].ptr(), binary_data_length);
+ }
+
+ 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);
+
+ f->create(FileAccess::ACCESS_RESOURCES);
+ String json = JSON::print(state->json);
+ f->store_string(json);
+ f->close();
+ }
+ return err;
+}
diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h
new file mode 100644
index 0000000000..ddf307e6a7
--- /dev/null
+++ b/modules/gltf/gltf_document.h
@@ -0,0 +1,433 @@
+/*************************************************************************/
+/* gltf_document.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GLTF_DOCUMENT_H
+#define GLTF_DOCUMENT_H
+
+#include "editor/import/resource_importer_scene.h"
+#include "editor/import/scene_importer_mesh_node_3d.h"
+#include "gltf_animation.h"
+#include "modules/modules_enabled.gen.h"
+#include "scene/2d/node_2d.h"
+#include "scene/3d/bone_attachment_3d.h"
+#include "scene/3d/light_3d.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/material.h"
+#include "scene/resources/texture.h"
+
+class GLTFState;
+class GLTFSkin;
+class GLTFNode;
+class GLTFSpecGloss;
+class GLTFSkeleton;
+
+using GLTFAccessorIndex = int;
+using GLTFAnimationIndex = int;
+using GLTFBufferIndex = int;
+using GLTFBufferViewIndex = int;
+using GLTFCameraIndex = int;
+using GLTFImageIndex = int;
+using GLTFMaterialIndex = int;
+using GLTFMeshIndex = int;
+using GLTFLightIndex = int;
+using GLTFNodeIndex = int;
+using GLTFSkeletonIndex = int;
+using GLTFSkinIndex = int;
+using GLTFTextureIndex = int;
+
+class GLTFDocument : public Resource {
+ GDCLASS(GLTFDocument, Resource);
+ friend class GLTFState;
+ friend class GLTFSkin;
+ friend class GLTFSkeleton;
+
+public:
+ const int32_t JOINT_GROUP_SIZE = 4;
+ enum GLTFType {
+ TYPE_SCALAR,
+ TYPE_VEC2,
+ TYPE_VEC3,
+ TYPE_VEC4,
+ TYPE_MAT2,
+ TYPE_MAT3,
+ TYPE_MAT4,
+ };
+
+ enum {
+ ARRAY_BUFFER = 34962,
+ ELEMENT_ARRAY_BUFFER = 34963,
+
+ TYPE_BYTE = 5120,
+ TYPE_UNSIGNED_BYTE = 5121,
+ TYPE_SHORT = 5122,
+ TYPE_UNSIGNED_SHORT = 5123,
+ TYPE_UNSIGNED_INT = 5125,
+ TYPE_FLOAT = 5126,
+
+ COMPONENT_TYPE_BYTE = 5120,
+ COMPONENT_TYPE_UNSIGNED_BYTE = 5121,
+ COMPONENT_TYPE_SHORT = 5122,
+ COMPONENT_TYPE_UNSIGNED_SHORT = 5123,
+ COMPONENT_TYPE_INT = 5125,
+ COMPONENT_TYPE_FLOAT = 5126,
+ };
+
+private:
+ template <class T>
+ static Array to_array(const Vector<T> &p_inp) {
+ Array ret;
+ for (int i = 0; i < p_inp.size(); i++) {
+ ret.push_back(p_inp[i]);
+ }
+ return ret;
+ }
+
+ template <class T>
+ static Array to_array(const Set<T> &p_inp) {
+ Array ret;
+ typename Set<T>::Element *elem = p_inp.front();
+ while (elem) {
+ ret.push_back(elem->get());
+ elem = elem->next();
+ }
+ return ret;
+ }
+
+ template <class T>
+ static void set_from_array(Vector<T> &r_out, const Array &p_inp) {
+ r_out.clear();
+ for (int i = 0; i < p_inp.size(); i++) {
+ r_out.push_back(p_inp[i]);
+ }
+ }
+
+ template <class T>
+ static void set_from_array(Set<T> &r_out, const Array &p_inp) {
+ r_out.clear();
+ for (int i = 0; i < p_inp.size(); i++) {
+ r_out.insert(p_inp[i]);
+ }
+ }
+ template <class K, class V>
+ static Dictionary to_dict(const Map<K, V> &p_inp) {
+ Dictionary ret;
+ for (typename Map<K, V>::Element *E = p_inp.front(); E; E = E->next()) {
+ ret[E->key()] = E->value();
+ }
+ return ret;
+ }
+
+ template <class K, class V>
+ static void set_from_dict(Map<K, V> &r_out, const Dictionary &p_inp) {
+ r_out.clear();
+ Array keys = p_inp.keys();
+ for (int i = 0; i < keys.size(); i++) {
+ r_out[keys[i]] = p_inp[keys[i]];
+ }
+ }
+ double _filter_number(double p_float);
+ String _get_component_type_name(const uint32_t p_component);
+ int _get_component_type_size(const int component_type);
+ Error _parse_scenes(Ref<GLTFState> state);
+ Error _parse_nodes(Ref<GLTFState> state);
+ String _get_type_name(const GLTFType p_component);
+ String _get_accessor_type_name(const GLTFDocument::GLTFType p_type);
+ String _sanitize_scene_name(const String &name);
+ String _gen_unique_name(Ref<GLTFState> state, const String &p_name);
+ String _sanitize_bone_name(const String &name);
+ String _gen_unique_bone_name(Ref<GLTFState> state,
+ const GLTFSkeletonIndex skel_i,
+ const String &p_name);
+ GLTFTextureIndex _set_texture(Ref<GLTFState> state, Ref<Texture2D> p_texture);
+ Ref<Texture2D> _get_texture(Ref<GLTFState> state,
+ const GLTFTextureIndex p_texture);
+ Error _parse_json(const String &p_path, Ref<GLTFState> state);
+ Error _parse_glb(const String &p_path, 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);
+ GLTFType _get_type_from_str(const String &p_string);
+ Error _parse_accessors(Ref<GLTFState> state);
+ Error _decode_buffer_view(Ref<GLTFState> state, double *dst,
+ const GLTFBufferViewIndex p_buffer_view,
+ const int skip_every, const int skip_bytes,
+ const int element_size, const int count,
+ const GLTFType type, const int component_count,
+ const int component_type, const int component_size,
+ const bool normalized, const int byte_offset,
+ const bool for_vertex);
+ Vector<double> _decode_accessor(Ref<GLTFState> state,
+ const GLTFAccessorIndex p_accessor,
+ const bool p_for_vertex);
+ Vector<float> _decode_accessor_as_floats(Ref<GLTFState> state,
+ const GLTFAccessorIndex p_accessor,
+ const bool p_for_vertex);
+ Vector<int> _decode_accessor_as_ints(Ref<GLTFState> state,
+ const GLTFAccessorIndex p_accessor,
+ const bool p_for_vertex);
+ Vector<Vector2> _decode_accessor_as_vec2(Ref<GLTFState> state,
+ const GLTFAccessorIndex p_accessor,
+ const bool p_for_vertex);
+ Vector<Vector3> _decode_accessor_as_vec3(Ref<GLTFState> state,
+ const GLTFAccessorIndex p_accessor,
+ const bool p_for_vertex);
+ Vector<Color> _decode_accessor_as_color(Ref<GLTFState> state,
+ const GLTFAccessorIndex p_accessor,
+ const bool p_for_vertex);
+ Vector<Quat> _decode_accessor_as_quat(Ref<GLTFState> state,
+ const GLTFAccessorIndex p_accessor,
+ const bool p_for_vertex);
+ Vector<Transform2D> _decode_accessor_as_xform2d(Ref<GLTFState> state,
+ const GLTFAccessorIndex p_accessor,
+ const bool p_for_vertex);
+ Vector<Basis> _decode_accessor_as_basis(Ref<GLTFState> state,
+ const GLTFAccessorIndex p_accessor,
+ const bool p_for_vertex);
+ Vector<Transform> _decode_accessor_as_xform(Ref<GLTFState> state,
+ const GLTFAccessorIndex p_accessor,
+ const bool p_for_vertex);
+ Error _parse_meshes(Ref<GLTFState> state);
+ Error _serialize_textures(Ref<GLTFState> state);
+ Error _serialize_images(Ref<GLTFState> state, const String &p_path);
+ Error _serialize_lights(Ref<GLTFState> state);
+ Error _parse_images(Ref<GLTFState> state, const String &p_base_path);
+ Error _parse_textures(Ref<GLTFState> state);
+ Error _parse_materials(Ref<GLTFState> state);
+ void _set_texture_transform_uv1(const Dictionary &d, Ref<BaseMaterial3D> material);
+ void spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss,
+ Ref<BaseMaterial3D> p_material);
+ static void spec_gloss_to_metal_base_color(const Color &p_specular_factor,
+ const Color &p_diffuse,
+ Color &r_base_color,
+ float &r_metallic);
+ GLTFNodeIndex _find_highest_node(Ref<GLTFState> state,
+ const Vector<GLTFNodeIndex> &subset);
+ bool _capture_nodes_in_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin,
+ const GLTFNodeIndex node_index);
+ void _capture_nodes_for_multirooted_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin);
+ Error _expand_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin);
+ Error _verify_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin);
+ Error _parse_skins(Ref<GLTFState> state);
+ Error _determine_skeletons(Ref<GLTFState> state);
+ Error _reparent_non_joint_skeleton_subtrees(
+ Ref<GLTFState> state, Ref<GLTFSkeleton> skeleton,
+ const Vector<GLTFNodeIndex> &non_joints);
+ Error _reparent_to_fake_joint(Ref<GLTFState> state, Ref<GLTFSkeleton> skeleton,
+ const GLTFNodeIndex node_index);
+ Error _determine_skeleton_roots(Ref<GLTFState> state,
+ const GLTFSkeletonIndex skel_i);
+ Error _create_skeletons(Ref<GLTFState> state);
+ Error _map_skin_joints_indices_to_skeleton_bone_indices(Ref<GLTFState> state);
+ Error _serialize_skins(Ref<GLTFState> state);
+ Error _create_skins(Ref<GLTFState> state);
+ bool _skins_are_same(const Ref<Skin> skin_a, const Ref<Skin> skin_b);
+ void _remove_duplicate_skins(Ref<GLTFState> state);
+ Error _serialize_cameras(Ref<GLTFState> state);
+ Error _parse_cameras(Ref<GLTFState> state);
+ Error _parse_lights(Ref<GLTFState> state);
+ Error _parse_animations(Ref<GLTFState> state);
+ Error _serialize_animations(Ref<GLTFState> state);
+ BoneAttachment3D *_generate_bone_attachment(Ref<GLTFState> state,
+ Skeleton3D *skeleton,
+ const GLTFNodeIndex node_index);
+ EditorSceneImporterMeshNode3D *_generate_mesh_instance(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index);
+ Camera3D *_generate_camera(Ref<GLTFState> state, Node *scene_parent,
+ const GLTFNodeIndex node_index);
+ Light3D *_generate_light(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index);
+ Node3D *_generate_spatial(Ref<GLTFState> state, Node *scene_parent,
+ const GLTFNodeIndex node_index);
+ void _assign_scene_names(Ref<GLTFState> state);
+ template <class T>
+ T _interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values,
+ const float p_time,
+ const GLTFAnimation::Interpolation p_interp);
+ GLTFAccessorIndex _encode_accessor_as_quats(Ref<GLTFState> state,
+ const Vector<Quat> p_attribs,
+ const bool p_for_vertex);
+ GLTFAccessorIndex _encode_accessor_as_weights(Ref<GLTFState> state,
+ const Vector<Color> p_attribs,
+ const bool p_for_vertex);
+ GLTFAccessorIndex _encode_accessor_as_joints(Ref<GLTFState> state,
+ const Vector<Color> p_attribs,
+ const bool p_for_vertex);
+ GLTFAccessorIndex _encode_accessor_as_floats(Ref<GLTFState> state,
+ const Vector<real_t> p_attribs,
+ const bool p_for_vertex);
+ GLTFAccessorIndex _encode_accessor_as_vec2(Ref<GLTFState> state,
+ const Vector<Vector2> p_attribs,
+ const bool p_for_vertex);
+
+ void _calc_accessor_vec2_min_max(int i, const int element_count, Vector<double> &type_max, Vector2 attribs, Vector<double> &type_min) {
+ if (i == 0) {
+ for (int32_t type_i = 0; type_i < element_count; type_i++) {
+ type_max.write[type_i] = attribs[(i * element_count) + type_i];
+ type_min.write[type_i] = attribs[(i * element_count) + type_i];
+ }
+ }
+ for (int32_t type_i = 0; type_i < element_count; type_i++) {
+ type_max.write[type_i] = MAX(attribs[(i * element_count) + type_i], type_max[type_i]);
+ type_min.write[type_i] = MIN(attribs[(i * element_count) + type_i], type_min[type_i]);
+ type_max.write[type_i] = _filter_number(type_max.write[type_i]);
+ type_min.write[type_i] = _filter_number(type_min.write[type_i]);
+ }
+ }
+
+ GLTFAccessorIndex _encode_accessor_as_vec3(Ref<GLTFState> state,
+ const Vector<Vector3> p_attribs,
+ const bool p_for_vertex);
+ GLTFAccessorIndex _encode_accessor_as_color(Ref<GLTFState> state,
+ const Vector<Color> p_attribs,
+ const bool p_for_vertex);
+
+ void _calc_accessor_min_max(int p_i, const int p_element_count, Vector<double> &p_type_max, Vector<double> p_attribs, Vector<double> &p_type_min);
+
+ GLTFAccessorIndex _encode_accessor_as_ints(Ref<GLTFState> state,
+ const Vector<int32_t> p_attribs,
+ const bool p_for_vertex);
+ GLTFAccessorIndex _encode_accessor_as_xform(Ref<GLTFState> state,
+ const Vector<Transform> p_attribs,
+ const bool p_for_vertex);
+ Error _encode_buffer_view(Ref<GLTFState> state, const double *src,
+ const int count, const GLTFType type,
+ const int component_type, const bool normalized,
+ const int byte_offset, const bool for_vertex,
+ GLTFBufferViewIndex &r_accessor);
+ Error _encode_accessors(Ref<GLTFState> state);
+ Error _encode_buffer_views(Ref<GLTFState> state);
+ Error _serialize_materials(Ref<GLTFState> state);
+ Error _serialize_meshes(Ref<GLTFState> state);
+ Error _serialize_nodes(Ref<GLTFState> state);
+ Error _serialize_scenes(Ref<GLTFState> state);
+ String interpolation_to_string(const GLTFAnimation::Interpolation p_interp);
+ GLTFAnimation::Track _convert_animation_track(Ref<GLTFState> state,
+ GLTFAnimation::Track p_track,
+ Ref<Animation> p_animation, Transform p_bone_rest,
+ int32_t p_track_i,
+ GLTFNodeIndex p_node_i);
+ Error _encode_buffer_bins(Ref<GLTFState> state, const String &p_path);
+ Error _encode_buffer_glb(Ref<GLTFState> state, const String &p_path);
+ Error _serialize_bone_attachment(Ref<GLTFState> state);
+ Dictionary _serialize_texture_transform_uv1(Ref<BaseMaterial3D> p_material);
+ Dictionary _serialize_texture_transform_uv2(Ref<BaseMaterial3D> p_material);
+ Error _serialize_version(Ref<GLTFState> state);
+ Error _serialize_file(Ref<GLTFState> state, const String p_path);
+ Error _serialize_extensions(Ref<GLTFState> state) const;
+
+public:
+ // http://www.itu.int/rec/R-REC-BT.601
+ // http://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.601-7-201103-I!!PDF-E.pdf
+ static constexpr float R_BRIGHTNESS_COEFF = 0.299f;
+ static constexpr float G_BRIGHTNESS_COEFF = 0.587f;
+ static constexpr float B_BRIGHTNESS_COEFF = 0.114f;
+
+private:
+ // https://github.com/microsoft/glTF-SDK/blob/master/GLTFSDK/Source/PBRUtils.cpp#L9
+ // https://bghgary.github.io/glTF/convert-between-workflows-bjs/js/babylon.pbrUtilities.js
+ static float solve_metallic(float p_dielectric_specular, float diffuse,
+ float specular,
+ float p_one_minus_specular_strength);
+ static float get_perceived_brightness(const Color p_color);
+ static float get_max_component(const Color &p_color);
+
+public:
+ void _process_mesh_instances(Ref<GLTFState> state, Node *scene_root);
+ void _generate_scene_node(Ref<GLTFState> state, Node *scene_parent,
+ Node3D *scene_root,
+ const GLTFNodeIndex node_index);
+ void _import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
+ const GLTFAnimationIndex index, const int bake_fps);
+ GLTFMeshIndex _convert_mesh_instance(Ref<GLTFState> state,
+ MeshInstance3D *p_mesh_instance);
+ void _convert_mesh_instances(Ref<GLTFState> state);
+ GLTFCameraIndex _convert_camera(Ref<GLTFState> state, Camera3D *p_camera);
+ void _convert_light_to_gltf(Light3D *light, Ref<GLTFState> state, Node3D *spatial, Ref<GLTFNode> gltf_node);
+ GLTFLightIndex _convert_light(Ref<GLTFState> state, Light3D *p_light);
+ GLTFSkeletonIndex _convert_skeleton(Ref<GLTFState> state, Skeleton3D *p_skeleton);
+ void _convert_spatial(Ref<GLTFState> state, Node3D *p_spatial, Ref<GLTFNode> p_node);
+ void _convert_scene_node(Ref<GLTFState> state, Node *p_current, Node *p_root,
+ const GLTFNodeIndex p_gltf_current,
+ const GLTFNodeIndex p_gltf_root);
+
+#ifdef MODULE_CSG_ENABLED
+ void _convert_csg_shape_to_gltf(Node *p_current, GLTFNodeIndex p_gltf_parent, Ref<GLTFNode> gltf_node, Ref<GLTFState> state);
+#endif // MODULE_CSG_ENABLED
+
+ void _create_gltf_node(Ref<GLTFState> state,
+ Node *p_scene_parent,
+ GLTFNodeIndex current_node_i,
+ GLTFNodeIndex p_parent_node_index,
+ GLTFNodeIndex p_root_gltf_node,
+ Ref<GLTFNode> gltf_node);
+ void _convert_animation_player_to_gltf(
+ AnimationPlayer *animation_player, Ref<GLTFState> state,
+ const GLTFNodeIndex &p_gltf_current,
+ const GLTFNodeIndex &p_gltf_root_index,
+ Ref<GLTFNode> p_gltf_node, Node *p_scene_parent,
+ Node *p_root);
+ void _check_visibility(Node *p_node, bool &retflag);
+ void _convert_camera_to_gltf(Camera3D *camera, Ref<GLTFState> state,
+ Node3D *spatial,
+ Ref<GLTFNode> gltf_node);
+#ifdef MODULE_GRIDMAP_ENABLED
+ void _convert_grid_map_to_gltf(
+ Node *p_scene_parent,
+ const GLTFNodeIndex &p_parent_node_index,
+ const GLTFNodeIndex &p_root_node_index,
+ Ref<GLTFNode> gltf_node, Ref<GLTFState> state,
+ Node *p_root_node);
+#endif // MODULE_GRIDMAP_ENABLED
+ void _convert_mult_mesh_instance_to_gltf(
+ Node *p_scene_parent,
+ const GLTFNodeIndex &p_parent_node_index,
+ const GLTFNodeIndex &p_root_node_index,
+ Ref<GLTFNode> gltf_node, Ref<GLTFState> state,
+ Node *p_root_node);
+ void _convert_skeleton_to_gltf(
+ Node *p_scene_parent, Ref<GLTFState> state,
+ const GLTFNodeIndex &p_parent_node_index,
+ const GLTFNodeIndex &p_root_node_index,
+ Ref<GLTFNode> gltf_node, Node *p_root_node);
+ void _convert_bone_attachment_to_gltf(Node *p_scene_parent,
+ Ref<GLTFState> state,
+ Ref<GLTFNode> gltf_node,
+ bool &retflag);
+ void _convert_mesh_to_gltf(Node *p_scene_parent,
+ Ref<GLTFState> state, Node3D *spatial,
+ Ref<GLTFNode> gltf_node);
+ void _convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
+ String p_animation_track_name);
+ Error serialize(Ref<GLTFState> state, Node *p_root, const String &p_path);
+ Error parse(Ref<GLTFState> state, String p_paths, bool p_read_binary = false);
+};
+
+#endif // GLTF_DOCUMENT_H
diff --git a/modules/gltf/gltf_light.cpp b/modules/gltf/gltf_light.cpp
new file mode 100644
index 0000000000..95cca9cf71
--- /dev/null
+++ b/modules/gltf/gltf_light.cpp
@@ -0,0 +1,101 @@
+/*************************************************************************/
+/* gltf_light.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gltf_light.h"
+
+void GLTFLight::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_color"), &GLTFLight::get_color);
+ ClassDB::bind_method(D_METHOD("set_color", "color"), &GLTFLight::set_color);
+ ClassDB::bind_method(D_METHOD("get_intensity"), &GLTFLight::get_intensity);
+ ClassDB::bind_method(D_METHOD("set_intensity", "intensity"), &GLTFLight::set_intensity);
+ ClassDB::bind_method(D_METHOD("get_type"), &GLTFLight::get_type);
+ ClassDB::bind_method(D_METHOD("set_type", "type"), &GLTFLight::set_type);
+ ClassDB::bind_method(D_METHOD("get_range"), &GLTFLight::get_range);
+ ClassDB::bind_method(D_METHOD("set_range", "range"), &GLTFLight::set_range);
+ ClassDB::bind_method(D_METHOD("get_inner_cone_angle"), &GLTFLight::get_inner_cone_angle);
+ ClassDB::bind_method(D_METHOD("set_inner_cone_angle", "inner_cone_angle"), &GLTFLight::set_inner_cone_angle);
+ ClassDB::bind_method(D_METHOD("get_outer_cone_angle"), &GLTFLight::get_outer_cone_angle);
+ ClassDB::bind_method(D_METHOD("set_outer_cone_angle", "outer_cone_angle"), &GLTFLight::set_outer_cone_angle);
+
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); // Color
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "intensity"), "set_intensity", "get_intensity"); // float
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "type"), "set_type", "get_type"); // String
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "range"), "set_range", "get_range"); // float
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inner_cone_angle"), "set_inner_cone_angle", "get_inner_cone_angle"); // float
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "outer_cone_angle"), "set_outer_cone_angle", "get_outer_cone_angle"); // float
+}
+
+Color GLTFLight::get_color() {
+ return color;
+}
+
+void GLTFLight::set_color(Color p_color) {
+ color = p_color;
+}
+
+float GLTFLight::get_intensity() {
+ return intensity;
+}
+
+void GLTFLight::set_intensity(float p_intensity) {
+ intensity = p_intensity;
+}
+
+String GLTFLight::get_type() {
+ return type;
+}
+
+void GLTFLight::set_type(String p_type) {
+ type = p_type;
+}
+
+float GLTFLight::get_range() {
+ return range;
+}
+
+void GLTFLight::set_range(float p_range) {
+ range = p_range;
+}
+
+float GLTFLight::get_inner_cone_angle() {
+ return inner_cone_angle;
+}
+
+void GLTFLight::set_inner_cone_angle(float p_inner_cone_angle) {
+ inner_cone_angle = p_inner_cone_angle;
+}
+
+float GLTFLight::get_outer_cone_angle() {
+ return outer_cone_angle;
+}
+
+void GLTFLight::set_outer_cone_angle(float p_outer_cone_angle) {
+ outer_cone_angle = p_outer_cone_angle;
+}
diff --git a/modules/gltf/gltf_light.h b/modules/gltf/gltf_light.h
new file mode 100644
index 0000000000..a859ca1833
--- /dev/null
+++ b/modules/gltf/gltf_light.h
@@ -0,0 +1,72 @@
+/*************************************************************************/
+/* gltf_light.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GLTF_LIGHT_H
+#define GLTF_LIGHT_H
+
+#include "core/config/engine.h"
+#include "core/io/resource.h"
+
+class GLTFLight : public Resource {
+ GDCLASS(GLTFLight, Resource)
+ friend class GLTFDocument;
+
+protected:
+ static void _bind_methods();
+
+private:
+ Color color;
+ float intensity = 0.0f;
+ String type;
+ float range = 0.0f;
+ float inner_cone_angle = 0.0f;
+ float outer_cone_angle = 0.0f;
+
+public:
+ Color get_color();
+ void set_color(Color p_color);
+
+ float get_intensity();
+ void set_intensity(float p_intensity);
+
+ String get_type();
+ void set_type(String p_type);
+
+ float get_range();
+ void set_range(float p_range);
+
+ float get_inner_cone_angle();
+ void set_inner_cone_angle(float p_inner_cone_angle);
+
+ float get_outer_cone_angle();
+ void set_outer_cone_angle(float p_outer_cone_angle);
+};
+
+#endif // GLTF_LIGHT_H
diff --git a/modules/gltf/gltf_mesh.cpp b/modules/gltf/gltf_mesh.cpp
new file mode 100644
index 0000000000..8c10e42c89
--- /dev/null
+++ b/modules/gltf/gltf_mesh.cpp
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* gltf_mesh.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gltf_mesh.h"
+#include "editor/import/scene_importer_mesh.h"
+
+void GLTFMesh::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_mesh"), &GLTFMesh::get_mesh);
+ ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &GLTFMesh::set_mesh);
+ ClassDB::bind_method(D_METHOD("get_blend_weights"), &GLTFMesh::get_blend_weights);
+ ClassDB::bind_method(D_METHOD("set_blend_weights", "blend_weights"), &GLTFMesh::set_blend_weights);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh"), "set_mesh", "get_mesh");
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT32_ARRAY, "blend_weights"), "set_blend_weights", "get_blend_weights"); // Vector<float>
+}
+
+Ref<EditorSceneImporterMesh> GLTFMesh::get_mesh() {
+ return mesh;
+}
+
+void GLTFMesh::set_mesh(Ref<EditorSceneImporterMesh> p_mesh) {
+ mesh = p_mesh;
+}
+
+Vector<float> GLTFMesh::get_blend_weights() {
+ return blend_weights;
+}
+
+void GLTFMesh::set_blend_weights(Vector<float> p_blend_weights) {
+ blend_weights = p_blend_weights;
+}
diff --git a/modules/gltf/gltf_mesh.h b/modules/gltf/gltf_mesh.h
new file mode 100644
index 0000000000..0fc750fc9f
--- /dev/null
+++ b/modules/gltf/gltf_mesh.h
@@ -0,0 +1,55 @@
+/*************************************************************************/
+/* gltf_mesh.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GLTF_MESH_H
+#define GLTF_MESH_H
+
+#include "core/io/resource.h"
+#include "editor/import/resource_importer_scene.h"
+#include "editor/import/scene_importer_mesh.h"
+#include "scene/resources/mesh.h"
+
+class GLTFMesh : public Resource {
+ GDCLASS(GLTFMesh, Resource);
+
+private:
+ Ref<EditorSceneImporterMesh> mesh;
+ Vector<float> blend_weights;
+
+protected:
+ static void _bind_methods();
+
+public:
+ Ref<EditorSceneImporterMesh> get_mesh();
+ void set_mesh(Ref<EditorSceneImporterMesh> p_mesh);
+ Vector<float> get_blend_weights();
+ void set_blend_weights(Vector<float> p_blend_weights);
+};
+#endif // GLTF_MESH_H
diff --git a/modules/gltf/gltf_node.cpp b/modules/gltf/gltf_node.cpp
new file mode 100644
index 0000000000..777c6fbd9a
--- /dev/null
+++ b/modules/gltf/gltf_node.cpp
@@ -0,0 +1,189 @@
+/*************************************************************************/
+/* gltf_node.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gltf_node.h"
+
+void GLTFNode::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_parent"), &GLTFNode::get_parent);
+ ClassDB::bind_method(D_METHOD("set_parent", "parent"), &GLTFNode::set_parent);
+ ClassDB::bind_method(D_METHOD("get_height"), &GLTFNode::get_height);
+ ClassDB::bind_method(D_METHOD("set_height", "height"), &GLTFNode::set_height);
+ ClassDB::bind_method(D_METHOD("get_xform"), &GLTFNode::get_xform);
+ ClassDB::bind_method(D_METHOD("set_xform", "xform"), &GLTFNode::set_xform);
+ ClassDB::bind_method(D_METHOD("get_mesh"), &GLTFNode::get_mesh);
+ ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &GLTFNode::set_mesh);
+ ClassDB::bind_method(D_METHOD("get_camera"), &GLTFNode::get_camera);
+ ClassDB::bind_method(D_METHOD("set_camera", "camera"), &GLTFNode::set_camera);
+ ClassDB::bind_method(D_METHOD("get_skin"), &GLTFNode::get_skin);
+ ClassDB::bind_method(D_METHOD("set_skin", "skin"), &GLTFNode::set_skin);
+ ClassDB::bind_method(D_METHOD("get_skeleton"), &GLTFNode::get_skeleton);
+ ClassDB::bind_method(D_METHOD("set_skeleton", "skeleton"), &GLTFNode::set_skeleton);
+ ClassDB::bind_method(D_METHOD("get_joint"), &GLTFNode::get_joint);
+ ClassDB::bind_method(D_METHOD("set_joint", "joint"), &GLTFNode::set_joint);
+ ClassDB::bind_method(D_METHOD("get_translation"), &GLTFNode::get_translation);
+ ClassDB::bind_method(D_METHOD("set_translation", "translation"), &GLTFNode::set_translation);
+ ClassDB::bind_method(D_METHOD("get_rotation"), &GLTFNode::get_rotation);
+ ClassDB::bind_method(D_METHOD("set_rotation", "rotation"), &GLTFNode::set_rotation);
+ ClassDB::bind_method(D_METHOD("get_scale"), &GLTFNode::get_scale);
+ ClassDB::bind_method(D_METHOD("set_scale", "scale"), &GLTFNode::set_scale);
+ ClassDB::bind_method(D_METHOD("get_children"), &GLTFNode::get_children);
+ ClassDB::bind_method(D_METHOD("set_children", "children"), &GLTFNode::set_children);
+ ClassDB::bind_method(D_METHOD("get_fake_joint_parent"), &GLTFNode::get_fake_joint_parent);
+ ClassDB::bind_method(D_METHOD("set_fake_joint_parent", "fake_joint_parent"), &GLTFNode::set_fake_joint_parent);
+ ClassDB::bind_method(D_METHOD("get_light"), &GLTFNode::get_light);
+ ClassDB::bind_method(D_METHOD("set_light", "light"), &GLTFNode::set_light);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "parent"), "set_parent", "get_parent"); // GLTFNodeIndex
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "height"), "set_height", "get_height"); // int
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "xform"), "set_xform", "get_xform"); // Transform
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "mesh"), "set_mesh", "get_mesh"); // GLTFMeshIndex
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "camera"), "set_camera", "get_camera"); // GLTFCameraIndex
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "skin"), "set_skin", "get_skin"); // GLTFSkinIndex
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "skeleton"), "set_skeleton", "get_skeleton"); // GLTFSkeletonIndex
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "joint"), "set_joint", "get_joint"); // bool
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "translation"), "set_translation", "get_translation"); // Vector3
+ ADD_PROPERTY(PropertyInfo(Variant::QUAT, "rotation"), "set_rotation", "get_rotation"); // Quat
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale"), "set_scale", "get_scale"); // Vector3
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "children"), "set_children", "get_children"); // Vector<int>
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "fake_joint_parent"), "set_fake_joint_parent", "get_fake_joint_parent"); // GLTFNodeIndex
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "light"), "set_light", "get_light"); // GLTFLightIndex
+}
+
+GLTFNodeIndex GLTFNode::get_parent() {
+ return parent;
+}
+
+void GLTFNode::set_parent(GLTFNodeIndex p_parent) {
+ parent = p_parent;
+}
+
+int GLTFNode::get_height() {
+ return height;
+}
+
+void GLTFNode::set_height(int p_height) {
+ height = p_height;
+}
+
+Transform GLTFNode::get_xform() {
+ return xform;
+}
+
+void GLTFNode::set_xform(Transform p_xform) {
+ xform = p_xform;
+}
+
+GLTFMeshIndex GLTFNode::get_mesh() {
+ return mesh;
+}
+
+void GLTFNode::set_mesh(GLTFMeshIndex p_mesh) {
+ mesh = p_mesh;
+}
+
+GLTFCameraIndex GLTFNode::get_camera() {
+ return camera;
+}
+
+void GLTFNode::set_camera(GLTFCameraIndex p_camera) {
+ camera = p_camera;
+}
+
+GLTFSkinIndex GLTFNode::get_skin() {
+ return skin;
+}
+
+void GLTFNode::set_skin(GLTFSkinIndex p_skin) {
+ skin = p_skin;
+}
+
+GLTFSkeletonIndex GLTFNode::get_skeleton() {
+ return skeleton;
+}
+
+void GLTFNode::set_skeleton(GLTFSkeletonIndex p_skeleton) {
+ skeleton = p_skeleton;
+}
+
+bool GLTFNode::get_joint() {
+ return joint;
+}
+
+void GLTFNode::set_joint(bool p_joint) {
+ joint = p_joint;
+}
+
+Vector3 GLTFNode::get_translation() {
+ return translation;
+}
+
+void GLTFNode::set_translation(Vector3 p_translation) {
+ translation = p_translation;
+}
+
+Quat GLTFNode::get_rotation() {
+ return rotation;
+}
+
+void GLTFNode::set_rotation(Quat p_rotation) {
+ rotation = p_rotation;
+}
+
+Vector3 GLTFNode::get_scale() {
+ return scale;
+}
+
+void GLTFNode::set_scale(Vector3 p_scale) {
+ scale = p_scale;
+}
+
+Vector<int> GLTFNode::get_children() {
+ return children;
+}
+
+void GLTFNode::set_children(Vector<int> p_children) {
+ children = p_children;
+}
+
+GLTFNodeIndex GLTFNode::get_fake_joint_parent() {
+ return fake_joint_parent;
+}
+
+void GLTFNode::set_fake_joint_parent(GLTFNodeIndex p_fake_joint_parent) {
+ fake_joint_parent = p_fake_joint_parent;
+}
+
+GLTFLightIndex GLTFNode::get_light() {
+ return light;
+}
+
+void GLTFNode::set_light(GLTFLightIndex p_light) {
+ light = p_light;
+}
diff --git a/modules/gltf/gltf_node.h b/modules/gltf/gltf_node.h
new file mode 100644
index 0000000000..ce8aff8944
--- /dev/null
+++ b/modules/gltf/gltf_node.h
@@ -0,0 +1,105 @@
+/*************************************************************************/
+/* gltf_node.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GLTF_NODE_H
+#define GLTF_NODE_H
+
+#include "core/io/resource.h"
+#include "gltf_document.h"
+
+class GLTFNode : public Resource {
+ GDCLASS(GLTFNode, Resource);
+ friend class GLTFDocument;
+ friend class PackedSceneGLTF;
+
+private:
+ // matrices need to be transformed to this
+ GLTFNodeIndex parent = -1;
+ int height = -1;
+ Transform xform;
+ GLTFMeshIndex mesh = -1;
+ GLTFCameraIndex camera = -1;
+ GLTFSkinIndex skin = -1;
+ GLTFSkeletonIndex skeleton = -1;
+ bool joint = false;
+ Vector3 translation;
+ Quat rotation;
+ Vector3 scale = Vector3(1, 1, 1);
+ Vector<int> children;
+ GLTFNodeIndex fake_joint_parent = -1;
+ GLTFLightIndex light = -1;
+
+protected:
+ static void _bind_methods();
+
+public:
+ GLTFNodeIndex get_parent();
+ void set_parent(GLTFNodeIndex p_parent);
+
+ int get_height();
+ void set_height(int p_height);
+
+ Transform get_xform();
+ void set_xform(Transform p_xform);
+
+ GLTFMeshIndex get_mesh();
+ void set_mesh(GLTFMeshIndex p_mesh);
+
+ GLTFCameraIndex get_camera();
+ void set_camera(GLTFCameraIndex p_camera);
+
+ GLTFSkinIndex get_skin();
+ void set_skin(GLTFSkinIndex p_skin);
+
+ GLTFSkeletonIndex get_skeleton();
+ void set_skeleton(GLTFSkeletonIndex p_skeleton);
+
+ bool get_joint();
+ void set_joint(bool p_joint);
+
+ Vector3 get_translation();
+ void set_translation(Vector3 p_translation);
+
+ Quat get_rotation();
+ void set_rotation(Quat p_rotation);
+
+ Vector3 get_scale();
+ void set_scale(Vector3 p_scale);
+
+ Vector<int> get_children();
+ void set_children(Vector<int> p_children);
+
+ GLTFNodeIndex get_fake_joint_parent();
+ void set_fake_joint_parent(GLTFNodeIndex p_fake_joint_parent);
+
+ GLTFLightIndex get_light();
+ void set_light(GLTFLightIndex p_light);
+};
+#endif // GLTF_NODE_H
diff --git a/modules/gltf/gltf_skeleton.cpp b/modules/gltf/gltf_skeleton.cpp
new file mode 100644
index 0000000000..739779d3bd
--- /dev/null
+++ b/modules/gltf/gltf_skeleton.cpp
@@ -0,0 +1,95 @@
+/*************************************************************************/
+/* gltf_skeleton.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gltf_skeleton.h"
+
+void GLTFSkeleton::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_joints"), &GLTFSkeleton::get_joints);
+ ClassDB::bind_method(D_METHOD("set_joints", "joints"), &GLTFSkeleton::set_joints);
+ ClassDB::bind_method(D_METHOD("get_roots"), &GLTFSkeleton::get_roots);
+ ClassDB::bind_method(D_METHOD("set_roots", "roots"), &GLTFSkeleton::set_roots);
+ ClassDB::bind_method(D_METHOD("get_godot_skeleton"), &GLTFSkeleton::get_godot_skeleton);
+ ClassDB::bind_method(D_METHOD("get_unique_names"), &GLTFSkeleton::get_unique_names);
+ ClassDB::bind_method(D_METHOD("set_unique_names", "unique_names"), &GLTFSkeleton::set_unique_names);
+ ClassDB::bind_method(D_METHOD("get_godot_bone_node"), &GLTFSkeleton::get_godot_bone_node);
+ ClassDB::bind_method(D_METHOD("set_godot_bone_node", "godot_bone_node"), &GLTFSkeleton::set_godot_bone_node);
+ ClassDB::bind_method(D_METHOD("get_bone_attachment_count"), &GLTFSkeleton::get_bone_attachment_count);
+ ClassDB::bind_method(D_METHOD("get_bone_attachment"), &GLTFSkeleton::get_bone_attachment);
+
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "joints"), "set_joints", "get_joints"); // Vector<GLTFNodeIndex>
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "roots"), "set_roots", "get_roots"); // Vector<GLTFNodeIndex>
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "unique_names", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_unique_names", "get_unique_names"); // Set<String>
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "godot_bone_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_godot_bone_node", "get_godot_bone_node"); // Map<int32_t,
+}
+
+Vector<GLTFNodeIndex> GLTFSkeleton::get_joints() {
+ return joints;
+}
+
+void GLTFSkeleton::set_joints(Vector<GLTFNodeIndex> p_joints) {
+ joints = p_joints;
+}
+
+Vector<GLTFNodeIndex> GLTFSkeleton::get_roots() {
+ return roots;
+}
+
+void GLTFSkeleton::set_roots(Vector<GLTFNodeIndex> p_roots) {
+ roots = p_roots;
+}
+
+Skeleton3D *GLTFSkeleton::get_godot_skeleton() {
+ return godot_skeleton;
+}
+
+Array GLTFSkeleton::get_unique_names() {
+ return GLTFDocument::to_array(unique_names);
+}
+
+void GLTFSkeleton::set_unique_names(Array p_unique_names) {
+ GLTFDocument::set_from_array(unique_names, p_unique_names);
+}
+
+Dictionary GLTFSkeleton::get_godot_bone_node() {
+ return GLTFDocument::to_dict(godot_bone_node);
+}
+
+void GLTFSkeleton::set_godot_bone_node(Dictionary p_indict) {
+ GLTFDocument::set_from_dict(godot_bone_node, p_indict);
+}
+
+BoneAttachment3D *GLTFSkeleton::get_bone_attachment(int idx) {
+ ERR_FAIL_INDEX_V(idx, bone_attachments.size(), nullptr);
+ return bone_attachments[idx];
+}
+
+int32_t GLTFSkeleton::get_bone_attachment_count() {
+ return bone_attachments.size();
+}
diff --git a/modules/gltf/gltf_skeleton.h b/modules/gltf/gltf_skeleton.h
new file mode 100644
index 0000000000..d6986eb35a
--- /dev/null
+++ b/modules/gltf/gltf_skeleton.h
@@ -0,0 +1,101 @@
+/*************************************************************************/
+/* gltf_skeleton.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GLTF_SKELETON_H
+#define GLTF_SKELETON_H
+
+#include "core/io/resource.h"
+#include "gltf_document.h"
+
+class GLTFSkeleton : public Resource {
+ GDCLASS(GLTFSkeleton, Resource);
+ friend class GLTFDocument;
+
+private:
+ // The *synthesized* skeletons joints
+ Vector<GLTFNodeIndex> joints;
+
+ // The roots of the skeleton. If there are multiple, each root must have the
+ // same parent (ie roots are siblings)
+ Vector<GLTFNodeIndex> roots;
+
+ // The created Skeleton3D for the scene
+ Skeleton3D *godot_skeleton = nullptr;
+
+ // Set of unique bone names for the skeleton
+ Set<String> unique_names;
+
+ Map<int32_t, GLTFNodeIndex> godot_bone_node;
+
+ Vector<BoneAttachment3D *> bone_attachments;
+
+protected:
+ static void _bind_methods();
+
+public:
+ Vector<GLTFNodeIndex> get_joints();
+ void set_joints(Vector<GLTFNodeIndex> p_joints);
+
+ Vector<GLTFNodeIndex> get_roots();
+ void set_roots(Vector<GLTFNodeIndex> p_roots);
+
+ Skeleton3D *get_godot_skeleton();
+
+ // Skeleton *get_godot_skeleton() {
+ // return this->godot_skeleton;
+ // }
+ // void set_godot_skeleton(Skeleton p_*godot_skeleton) {
+ // this->godot_skeleton = p_godot_skeleton;
+ // }
+
+ Array get_unique_names();
+ void set_unique_names(Array p_unique_names);
+
+ //Map<int32_t, GLTFNodeIndex> get_godot_bone_node() {
+ // return this->godot_bone_node;
+ //}
+ //void set_godot_bone_node(Map<int32_t, GLTFNodeIndex> p_godot_bone_node) {
+ // this->godot_bone_node = p_godot_bone_node;
+ //}
+ Dictionary get_godot_bone_node();
+ void set_godot_bone_node(Dictionary p_indict);
+
+ //Dictionary get_godot_bone_node() {
+ // return VariantConversion::to_dict(this->godot_bone_node);
+ //}
+ //void set_godot_bone_node(Dictionary p_indict) {
+ // VariantConversion::set_from_dict(this->godot_bone_node, p_indict);
+ //}
+
+ BoneAttachment3D *get_bone_attachment(int idx);
+
+ int32_t get_bone_attachment_count();
+};
+#endif // GLTF_SKELETON_H
diff --git a/modules/gltf/gltf_skin.cpp b/modules/gltf/gltf_skin.cpp
new file mode 100644
index 0000000000..fd39e4f45a
--- /dev/null
+++ b/modules/gltf/gltf_skin.cpp
@@ -0,0 +1,155 @@
+/*************************************************************************/
+/* gltf_skin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gltf_skin.h"
+
+void GLTFSkin::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_skin_root"), &GLTFSkin::get_skin_root);
+ ClassDB::bind_method(D_METHOD("set_skin_root", "skin_root"), &GLTFSkin::set_skin_root);
+ ClassDB::bind_method(D_METHOD("get_joints_original"), &GLTFSkin::get_joints_original);
+ ClassDB::bind_method(D_METHOD("set_joints_original", "joints_original"), &GLTFSkin::set_joints_original);
+ ClassDB::bind_method(D_METHOD("get_inverse_binds"), &GLTFSkin::get_inverse_binds);
+ ClassDB::bind_method(D_METHOD("set_inverse_binds", "inverse_binds"), &GLTFSkin::set_inverse_binds);
+ ClassDB::bind_method(D_METHOD("get_joints"), &GLTFSkin::get_joints);
+ ClassDB::bind_method(D_METHOD("set_joints", "joints"), &GLTFSkin::set_joints);
+ ClassDB::bind_method(D_METHOD("get_non_joints"), &GLTFSkin::get_non_joints);
+ ClassDB::bind_method(D_METHOD("set_non_joints", "non_joints"), &GLTFSkin::set_non_joints);
+ ClassDB::bind_method(D_METHOD("get_roots"), &GLTFSkin::get_roots);
+ ClassDB::bind_method(D_METHOD("set_roots", "roots"), &GLTFSkin::set_roots);
+ ClassDB::bind_method(D_METHOD("get_skeleton"), &GLTFSkin::get_skeleton);
+ ClassDB::bind_method(D_METHOD("set_skeleton", "skeleton"), &GLTFSkin::set_skeleton);
+ ClassDB::bind_method(D_METHOD("get_joint_i_to_bone_i"), &GLTFSkin::get_joint_i_to_bone_i);
+ ClassDB::bind_method(D_METHOD("set_joint_i_to_bone_i", "joint_i_to_bone_i"), &GLTFSkin::set_joint_i_to_bone_i);
+ ClassDB::bind_method(D_METHOD("get_joint_i_to_name"), &GLTFSkin::get_joint_i_to_name);
+ ClassDB::bind_method(D_METHOD("set_joint_i_to_name", "joint_i_to_name"), &GLTFSkin::set_joint_i_to_name);
+ ClassDB::bind_method(D_METHOD("get_godot_skin"), &GLTFSkin::get_godot_skin);
+ ClassDB::bind_method(D_METHOD("set_godot_skin", "godot_skin"), &GLTFSkin::set_godot_skin);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "skin_root"), "set_skin_root", "get_skin_root"); // GLTFNodeIndex
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "joints_original"), "set_joints_original", "get_joints_original"); // Vector<GLTFNodeIndex>
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "inverse_binds", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL), "set_inverse_binds", "get_inverse_binds"); // Vector<Transform>
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "joints"), "set_joints", "get_joints"); // Vector<GLTFNodeIndex>
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "non_joints"), "set_non_joints", "get_non_joints"); // Vector<GLTFNodeIndex>
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "roots"), "set_roots", "get_roots"); // Vector<GLTFNodeIndex>
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "skeleton"), "set_skeleton", "get_skeleton"); // int
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "joint_i_to_bone_i", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL), "set_joint_i_to_bone_i", "get_joint_i_to_bone_i"); // Map<int,
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "joint_i_to_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL), "set_joint_i_to_name", "get_joint_i_to_name"); // Map<int,
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "godot_skin"), "set_godot_skin", "get_godot_skin"); // Ref<Skin>
+}
+
+GLTFNodeIndex GLTFSkin::get_skin_root() {
+ return skin_root;
+}
+
+void GLTFSkin::set_skin_root(GLTFNodeIndex p_skin_root) {
+ skin_root = p_skin_root;
+}
+
+Vector<GLTFNodeIndex> GLTFSkin::get_joints_original() {
+ return joints_original;
+}
+
+void GLTFSkin::set_joints_original(Vector<GLTFNodeIndex> p_joints_original) {
+ joints_original = p_joints_original;
+}
+
+Array GLTFSkin::get_inverse_binds() {
+ return GLTFDocument::to_array(inverse_binds);
+}
+
+void GLTFSkin::set_inverse_binds(Array p_inverse_binds) {
+ GLTFDocument::set_from_array(inverse_binds, p_inverse_binds);
+}
+
+Vector<GLTFNodeIndex> GLTFSkin::get_joints() {
+ return joints;
+}
+
+void GLTFSkin::set_joints(Vector<GLTFNodeIndex> p_joints) {
+ joints = p_joints;
+}
+
+Vector<GLTFNodeIndex> GLTFSkin::get_non_joints() {
+ return non_joints;
+}
+
+void GLTFSkin::set_non_joints(Vector<GLTFNodeIndex> p_non_joints) {
+ non_joints = p_non_joints;
+}
+
+Vector<GLTFNodeIndex> GLTFSkin::get_roots() {
+ return roots;
+}
+
+void GLTFSkin::set_roots(Vector<GLTFNodeIndex> p_roots) {
+ roots = p_roots;
+}
+
+int GLTFSkin::get_skeleton() {
+ return skeleton;
+}
+
+void GLTFSkin::set_skeleton(int p_skeleton) {
+ skeleton = p_skeleton;
+}
+
+Dictionary GLTFSkin::get_joint_i_to_bone_i() {
+ return GLTFDocument::to_dict(joint_i_to_bone_i);
+}
+
+void GLTFSkin::set_joint_i_to_bone_i(Dictionary p_joint_i_to_bone_i) {
+ GLTFDocument::set_from_dict(joint_i_to_bone_i, p_joint_i_to_bone_i);
+}
+
+Dictionary GLTFSkin::get_joint_i_to_name() {
+ Dictionary ret;
+ Map<int, StringName>::Element *elem = joint_i_to_name.front();
+ while (elem) {
+ ret[elem->key()] = String(elem->value());
+ elem = elem->next();
+ }
+ return ret;
+}
+
+void GLTFSkin::set_joint_i_to_name(Dictionary p_joint_i_to_name) {
+ joint_i_to_name = Map<int, StringName>();
+ Array keys = p_joint_i_to_name.keys();
+ for (int i = 0; i < keys.size(); i++) {
+ joint_i_to_name[keys[i]] = joint_i_to_name[keys[i]];
+ }
+}
+
+Ref<Skin> GLTFSkin::get_godot_skin() {
+ return godot_skin;
+}
+
+void GLTFSkin::set_godot_skin(Ref<Skin> p_godot_skin) {
+ godot_skin = p_godot_skin;
+}
diff --git a/modules/gltf/gltf_skin.h b/modules/gltf/gltf_skin.h
new file mode 100644
index 0000000000..7cc09d85bc
--- /dev/null
+++ b/modules/gltf/gltf_skin.h
@@ -0,0 +1,109 @@
+/*************************************************************************/
+/* gltf_skin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GLTF_SKIN_H
+#define GLTF_SKIN_H
+
+#include "core/io/resource.h"
+#include "gltf_document.h"
+
+class GLTFSkin : public Resource {
+ GDCLASS(GLTFSkin, Resource);
+ friend class GLTFDocument;
+
+private:
+ // The "skeleton" property defined in the gltf spec. -1 = Scene Root
+ GLTFNodeIndex skin_root = -1;
+
+ Vector<GLTFNodeIndex> joints_original;
+ Vector<Transform> inverse_binds;
+
+ // Note: joints + non_joints should form a complete subtree, or subtrees
+ // with a common parent
+
+ // All nodes that are skins that are caught in-between the original joints
+ // (inclusive of joints_original)
+ Vector<GLTFNodeIndex> joints;
+
+ // All Nodes that are caught in-between skin joint nodes, and are not
+ // defined as joints by any skin
+ Vector<GLTFNodeIndex> non_joints;
+
+ // The roots of the skin. In the case of multiple roots, their parent *must*
+ // be the same (the roots must be siblings)
+ Vector<GLTFNodeIndex> roots;
+
+ // The GLTF Skeleton this Skin points to (after we determine skeletons)
+ GLTFSkeletonIndex skeleton = -1;
+
+ // A mapping from the joint indices (in the order of joints_original) to the
+ // Godot Skeleton's bone_indices
+ Map<int, int> joint_i_to_bone_i;
+ Map<int, StringName> joint_i_to_name;
+
+ // The Actual Skin that will be created as a mapping between the IBM's of
+ // this skin to the generated skeleton for the mesh instances.
+ Ref<Skin> godot_skin;
+
+protected:
+ static void _bind_methods();
+
+public:
+ GLTFNodeIndex get_skin_root();
+ void set_skin_root(GLTFNodeIndex p_skin_root);
+
+ Vector<GLTFNodeIndex> get_joints_original();
+ void set_joints_original(Vector<GLTFNodeIndex> p_joints_original);
+
+ Array get_inverse_binds();
+ void set_inverse_binds(Array p_inverse_binds);
+
+ Vector<GLTFNodeIndex> get_joints();
+ void set_joints(Vector<GLTFNodeIndex> p_joints);
+
+ Vector<GLTFNodeIndex> get_non_joints();
+ void set_non_joints(Vector<GLTFNodeIndex> p_non_joints);
+
+ Vector<GLTFNodeIndex> get_roots();
+ void set_roots(Vector<GLTFNodeIndex> p_roots);
+
+ int get_skeleton();
+ void set_skeleton(int p_skeleton);
+
+ Dictionary get_joint_i_to_bone_i();
+ void set_joint_i_to_bone_i(Dictionary p_joint_i_to_bone_i);
+
+ Dictionary get_joint_i_to_name();
+ void set_joint_i_to_name(Dictionary p_joint_i_to_name);
+
+ Ref<Skin> get_godot_skin();
+ void set_godot_skin(Ref<Skin> p_godot_skin);
+};
+#endif // GLTF_SKIN_H
diff --git a/modules/gltf/gltf_spec_gloss.cpp b/modules/gltf/gltf_spec_gloss.cpp
new file mode 100644
index 0000000000..70b182da52
--- /dev/null
+++ b/modules/gltf/gltf_spec_gloss.cpp
@@ -0,0 +1,90 @@
+/*************************************************************************/
+/* gltf_spec_gloss.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gltf_spec_gloss.h"
+
+void GLTFSpecGloss::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_diffuse_img"), &GLTFSpecGloss::get_diffuse_img);
+ ClassDB::bind_method(D_METHOD("set_diffuse_img", "diffuse_img"), &GLTFSpecGloss::set_diffuse_img);
+ ClassDB::bind_method(D_METHOD("get_diffuse_factor"), &GLTFSpecGloss::get_diffuse_factor);
+ ClassDB::bind_method(D_METHOD("set_diffuse_factor", "diffuse_factor"), &GLTFSpecGloss::set_diffuse_factor);
+ ClassDB::bind_method(D_METHOD("get_gloss_factor"), &GLTFSpecGloss::get_gloss_factor);
+ ClassDB::bind_method(D_METHOD("set_gloss_factor", "gloss_factor"), &GLTFSpecGloss::set_gloss_factor);
+ ClassDB::bind_method(D_METHOD("get_specular_factor"), &GLTFSpecGloss::get_specular_factor);
+ ClassDB::bind_method(D_METHOD("set_specular_factor", "specular_factor"), &GLTFSpecGloss::set_specular_factor);
+ ClassDB::bind_method(D_METHOD("get_spec_gloss_img"), &GLTFSpecGloss::get_spec_gloss_img);
+ ClassDB::bind_method(D_METHOD("set_spec_gloss_img", "spec_gloss_img"), &GLTFSpecGloss::set_spec_gloss_img);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "diffuse_img"), "set_diffuse_img", "get_diffuse_img"); // Ref<Image>
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "diffuse_factor"), "set_diffuse_factor", "get_diffuse_factor"); // Color
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gloss_factor"), "set_gloss_factor", "get_gloss_factor"); // float
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "specular_factor"), "set_specular_factor", "get_specular_factor"); // Color
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "spec_gloss_img"), "set_spec_gloss_img", "get_spec_gloss_img"); // Ref<Image>
+}
+
+Ref<Image> GLTFSpecGloss::get_diffuse_img() {
+ return diffuse_img;
+}
+
+void GLTFSpecGloss::set_diffuse_img(Ref<Image> p_diffuse_img) {
+ diffuse_img = p_diffuse_img;
+}
+
+Color GLTFSpecGloss::get_diffuse_factor() {
+ return diffuse_factor;
+}
+
+void GLTFSpecGloss::set_diffuse_factor(Color p_diffuse_factor) {
+ diffuse_factor = p_diffuse_factor;
+}
+
+float GLTFSpecGloss::get_gloss_factor() {
+ return gloss_factor;
+}
+
+void GLTFSpecGloss::set_gloss_factor(float p_gloss_factor) {
+ gloss_factor = p_gloss_factor;
+}
+
+Color GLTFSpecGloss::get_specular_factor() {
+ return specular_factor;
+}
+
+void GLTFSpecGloss::set_specular_factor(Color p_specular_factor) {
+ specular_factor = p_specular_factor;
+}
+
+Ref<Image> GLTFSpecGloss::get_spec_gloss_img() {
+ return spec_gloss_img;
+}
+
+void GLTFSpecGloss::set_spec_gloss_img(Ref<Image> p_spec_gloss_img) {
+ spec_gloss_img = p_spec_gloss_img;
+}
diff --git a/modules/gltf/gltf_spec_gloss.h b/modules/gltf/gltf_spec_gloss.h
new file mode 100644
index 0000000000..3cc6fb09ed
--- /dev/null
+++ b/modules/gltf/gltf_spec_gloss.h
@@ -0,0 +1,67 @@
+/*************************************************************************/
+/* gltf_spec_gloss.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GLTF_SPEC_GLOSS_H
+#define GLTF_SPEC_GLOSS_H
+
+#include "core/io/image.h"
+#include "core/io/resource.h"
+
+class GLTFSpecGloss : public Resource {
+ GDCLASS(GLTFSpecGloss, Resource);
+ friend class GLTFDocument;
+
+private:
+ Ref<Image> diffuse_img = nullptr;
+ Color diffuse_factor = Color(1.0f, 1.0f, 1.0f);
+ float gloss_factor = 1.0f;
+ Color specular_factor = Color(1.0f, 1.0f, 1.0f);
+ Ref<Image> spec_gloss_img = nullptr;
+
+protected:
+ static void _bind_methods();
+
+public:
+ Ref<Image> get_diffuse_img();
+ void set_diffuse_img(Ref<Image> p_diffuse_img);
+
+ Color get_diffuse_factor();
+ void set_diffuse_factor(Color p_diffuse_factor);
+
+ float get_gloss_factor();
+ void set_gloss_factor(float p_gloss_factor);
+
+ Color get_specular_factor();
+ void set_specular_factor(Color p_specular_factor);
+
+ Ref<Image> get_spec_gloss_img();
+ void set_spec_gloss_img(Ref<Image> p_spec_gloss_img);
+};
+#endif // GLTF_SPEC_GLOSS_H
diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp
new file mode 100644
index 0000000000..eedc743330
--- /dev/null
+++ b/modules/gltf/gltf_state.cpp
@@ -0,0 +1,296 @@
+/*************************************************************************/
+/* gltf_state.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gltf_state.h"
+
+void GLTFState::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_json"), &GLTFState::get_json);
+ ClassDB::bind_method(D_METHOD("set_json", "json"), &GLTFState::set_json);
+ ClassDB::bind_method(D_METHOD("get_major_version"), &GLTFState::get_major_version);
+ ClassDB::bind_method(D_METHOD("set_major_version", "major_version"), &GLTFState::set_major_version);
+ ClassDB::bind_method(D_METHOD("get_minor_version"), &GLTFState::get_minor_version);
+ ClassDB::bind_method(D_METHOD("set_minor_version", "minor_version"), &GLTFState::set_minor_version);
+ ClassDB::bind_method(D_METHOD("get_glb_data"), &GLTFState::get_glb_data);
+ ClassDB::bind_method(D_METHOD("set_glb_data", "glb_data"), &GLTFState::set_glb_data);
+ ClassDB::bind_method(D_METHOD("get_use_named_skin_binds"), &GLTFState::get_use_named_skin_binds);
+ ClassDB::bind_method(D_METHOD("set_use_named_skin_binds", "use_named_skin_binds"), &GLTFState::set_use_named_skin_binds);
+ ClassDB::bind_method(D_METHOD("get_nodes"), &GLTFState::get_nodes);
+ ClassDB::bind_method(D_METHOD("set_nodes", "nodes"), &GLTFState::set_nodes);
+ ClassDB::bind_method(D_METHOD("get_buffers"), &GLTFState::get_buffers);
+ ClassDB::bind_method(D_METHOD("set_buffers", "buffers"), &GLTFState::set_buffers);
+ ClassDB::bind_method(D_METHOD("get_buffer_views"), &GLTFState::get_buffer_views);
+ ClassDB::bind_method(D_METHOD("set_buffer_views", "buffer_views"), &GLTFState::set_buffer_views);
+ ClassDB::bind_method(D_METHOD("get_accessors"), &GLTFState::get_accessors);
+ ClassDB::bind_method(D_METHOD("set_accessors", "accessors"), &GLTFState::set_accessors);
+ ClassDB::bind_method(D_METHOD("get_meshes"), &GLTFState::get_meshes);
+ ClassDB::bind_method(D_METHOD("set_meshes", "meshes"), &GLTFState::set_meshes);
+ ClassDB::bind_method(D_METHOD("get_animation_players_count"), &GLTFState::get_animation_players_count);
+ ClassDB::bind_method(D_METHOD("get_animation_player"), &GLTFState::get_animation_player);
+ ClassDB::bind_method(D_METHOD("get_materials"), &GLTFState::get_materials);
+ ClassDB::bind_method(D_METHOD("set_materials", "materials"), &GLTFState::set_materials);
+ ClassDB::bind_method(D_METHOD("get_scene_name"), &GLTFState::get_scene_name);
+ ClassDB::bind_method(D_METHOD("set_scene_name", "scene_name"), &GLTFState::set_scene_name);
+ ClassDB::bind_method(D_METHOD("get_root_nodes"), &GLTFState::get_root_nodes);
+ ClassDB::bind_method(D_METHOD("set_root_nodes", "root_nodes"), &GLTFState::set_root_nodes);
+ ClassDB::bind_method(D_METHOD("get_textures"), &GLTFState::get_textures);
+ ClassDB::bind_method(D_METHOD("set_textures", "textures"), &GLTFState::set_textures);
+ ClassDB::bind_method(D_METHOD("get_images"), &GLTFState::get_images);
+ ClassDB::bind_method(D_METHOD("set_images", "images"), &GLTFState::set_images);
+ ClassDB::bind_method(D_METHOD("get_skins"), &GLTFState::get_skins);
+ ClassDB::bind_method(D_METHOD("set_skins", "skins"), &GLTFState::set_skins);
+ ClassDB::bind_method(D_METHOD("get_cameras"), &GLTFState::get_cameras);
+ ClassDB::bind_method(D_METHOD("set_cameras", "cameras"), &GLTFState::set_cameras);
+ ClassDB::bind_method(D_METHOD("get_lights"), &GLTFState::get_lights);
+ ClassDB::bind_method(D_METHOD("set_lights", "lights"), &GLTFState::set_lights);
+ ClassDB::bind_method(D_METHOD("get_unique_names"), &GLTFState::get_unique_names);
+ ClassDB::bind_method(D_METHOD("set_unique_names", "unique_names"), &GLTFState::set_unique_names);
+ ClassDB::bind_method(D_METHOD("get_skeletons"), &GLTFState::get_skeletons);
+ ClassDB::bind_method(D_METHOD("set_skeletons", "skeletons"), &GLTFState::set_skeletons);
+ ClassDB::bind_method(D_METHOD("get_skeleton_to_node"), &GLTFState::get_skeleton_to_node);
+ ClassDB::bind_method(D_METHOD("set_skeleton_to_node", "skeleton_to_node"), &GLTFState::set_skeleton_to_node);
+ ClassDB::bind_method(D_METHOD("get_animations"), &GLTFState::get_animations);
+ ClassDB::bind_method(D_METHOD("set_animations", "animations"), &GLTFState::set_animations);
+ ClassDB::bind_method(D_METHOD("get_scene_node"), &GLTFState::get_scene_node);
+
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "json"), "set_json", "get_json"); // Dictionary
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "major_version"), "set_major_version", "get_major_version"); // int
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "minor_version"), "set_minor_version", "get_minor_version"); // int
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "glb_data"), "set_glb_data", "get_glb_data"); // Vector<uint8_t>
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_named_skin_binds"), "set_use_named_skin_binds", "get_use_named_skin_binds"); // bool
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "nodes", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_nodes", "get_nodes"); // Vector<Ref<GLTFNode>>
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "buffers"), "set_buffers", "get_buffers"); // Vector<Vector<uint8_t>
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "buffer_views", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_buffer_views", "get_buffer_views"); // Vector<Ref<GLTFBufferView>>
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "accessors", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_accessors", "get_accessors"); // Vector<Ref<GLTFAccessor>>
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "meshes", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_meshes", "get_meshes"); // Vector<Ref<GLTFMesh>>
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "materials", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_materials", "get_materials"); // Vector<Ref<Material>
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "scene_name"), "set_scene_name", "get_scene_name"); // String
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "root_nodes"), "set_root_nodes", "get_root_nodes"); // Vector<int>
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "textures", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_textures", "get_textures"); // Vector<Ref<GLTFTexture>>
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "images", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_images", "get_images"); // Vector<Ref<Texture>
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "skins", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_skins", "get_skins"); // Vector<Ref<GLTFSkin>>
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "cameras", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_cameras", "get_cameras"); // Vector<Ref<GLTFCamera>>
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "lights", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_lights", "get_lights"); // Vector<Ref<GLTFLight>>
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "unique_names", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_unique_names", "get_unique_names"); // Set<String>
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "skeletons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_skeletons", "get_skeletons"); // Vector<Ref<GLTFSkeleton>>
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "skeleton_to_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_skeleton_to_node", "get_skeleton_to_node"); // Map<GLTFSkeletonIndex,
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_animations", "get_animations"); // Vector<Ref<GLTFAnimation>>
+}
+
+Dictionary GLTFState::get_json() {
+ return json;
+}
+
+void GLTFState::set_json(Dictionary p_json) {
+ json = p_json;
+}
+
+int GLTFState::get_major_version() {
+ return major_version;
+}
+
+void GLTFState::set_major_version(int p_major_version) {
+ major_version = p_major_version;
+}
+
+int GLTFState::get_minor_version() {
+ return minor_version;
+}
+
+void GLTFState::set_minor_version(int p_minor_version) {
+ minor_version = p_minor_version;
+}
+
+Vector<uint8_t> GLTFState::get_glb_data() {
+ return glb_data;
+}
+
+void GLTFState::set_glb_data(Vector<uint8_t> p_glb_data) {
+ glb_data = p_glb_data;
+}
+
+bool GLTFState::get_use_named_skin_binds() {
+ return use_named_skin_binds;
+}
+
+void GLTFState::set_use_named_skin_binds(bool p_use_named_skin_binds) {
+ use_named_skin_binds = p_use_named_skin_binds;
+}
+
+Array GLTFState::get_nodes() {
+ return GLTFDocument::to_array(nodes);
+}
+
+void GLTFState::set_nodes(Array p_nodes) {
+ GLTFDocument::set_from_array(nodes, p_nodes);
+}
+
+Array GLTFState::get_buffers() {
+ return GLTFDocument::to_array(buffers);
+}
+
+void GLTFState::set_buffers(Array p_buffers) {
+ GLTFDocument::set_from_array(buffers, p_buffers);
+}
+
+Array GLTFState::get_buffer_views() {
+ return GLTFDocument::to_array(buffer_views);
+}
+
+void GLTFState::set_buffer_views(Array p_buffer_views) {
+ GLTFDocument::set_from_array(buffer_views, p_buffer_views);
+}
+
+Array GLTFState::get_accessors() {
+ return GLTFDocument::to_array(accessors);
+}
+
+void GLTFState::set_accessors(Array p_accessors) {
+ GLTFDocument::set_from_array(accessors, p_accessors);
+}
+
+Array GLTFState::get_meshes() {
+ return GLTFDocument::to_array(meshes);
+}
+
+void GLTFState::set_meshes(Array p_meshes) {
+ GLTFDocument::set_from_array(meshes, p_meshes);
+}
+
+Array GLTFState::get_materials() {
+ return GLTFDocument::to_array(materials);
+}
+
+void GLTFState::set_materials(Array p_materials) {
+ GLTFDocument::set_from_array(materials, p_materials);
+}
+
+String GLTFState::get_scene_name() {
+ return scene_name;
+}
+
+void GLTFState::set_scene_name(String p_scene_name) {
+ scene_name = p_scene_name;
+}
+
+Array GLTFState::get_root_nodes() {
+ return GLTFDocument::to_array(root_nodes);
+}
+
+void GLTFState::set_root_nodes(Array p_root_nodes) {
+ GLTFDocument::set_from_array(root_nodes, p_root_nodes);
+}
+
+Array GLTFState::get_textures() {
+ return GLTFDocument::to_array(textures);
+}
+
+void GLTFState::set_textures(Array p_textures) {
+ GLTFDocument::set_from_array(textures, p_textures);
+}
+
+Array GLTFState::get_images() {
+ return GLTFDocument::to_array(images);
+}
+
+void GLTFState::set_images(Array p_images) {
+ GLTFDocument::set_from_array(images, p_images);
+}
+
+Array GLTFState::get_skins() {
+ return GLTFDocument::to_array(skins);
+}
+
+void GLTFState::set_skins(Array p_skins) {
+ GLTFDocument::set_from_array(skins, p_skins);
+}
+
+Array GLTFState::get_cameras() {
+ return GLTFDocument::to_array(cameras);
+}
+
+void GLTFState::set_cameras(Array p_cameras) {
+ GLTFDocument::set_from_array(cameras, p_cameras);
+}
+
+Array GLTFState::get_lights() {
+ return GLTFDocument::to_array(lights);
+}
+
+void GLTFState::set_lights(Array p_lights) {
+ GLTFDocument::set_from_array(lights, p_lights);
+}
+
+Array GLTFState::get_unique_names() {
+ return GLTFDocument::to_array(unique_names);
+}
+
+void GLTFState::set_unique_names(Array p_unique_names) {
+ GLTFDocument::set_from_array(unique_names, p_unique_names);
+}
+
+Array GLTFState::get_skeletons() {
+ return GLTFDocument::to_array(skeletons);
+}
+
+void GLTFState::set_skeletons(Array p_skeletons) {
+ GLTFDocument::set_from_array(skeletons, p_skeletons);
+}
+
+Dictionary GLTFState::get_skeleton_to_node() {
+ return GLTFDocument::to_dict(skeleton_to_node);
+}
+
+void GLTFState::set_skeleton_to_node(Dictionary p_skeleton_to_node) {
+ GLTFDocument::set_from_dict(skeleton_to_node, p_skeleton_to_node);
+}
+
+Array GLTFState::get_animations() {
+ return GLTFDocument::to_array(animations);
+}
+
+void GLTFState::set_animations(Array p_animations) {
+ GLTFDocument::set_from_array(animations, p_animations);
+}
+
+Node *GLTFState::get_scene_node(GLTFNodeIndex idx) {
+ if (!scene_nodes.has(idx)) {
+ return nullptr;
+ }
+ return scene_nodes[idx];
+}
+
+int GLTFState::get_animation_players_count(int idx) {
+ return animation_players.size();
+}
+
+AnimationPlayer *GLTFState::get_animation_player(int idx) {
+ ERR_FAIL_INDEX_V(idx, animation_players.size(), nullptr);
+ return animation_players[idx];
+}
diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h
new file mode 100644
index 0000000000..4ce5aa9491
--- /dev/null
+++ b/modules/gltf/gltf_state.h
@@ -0,0 +1,180 @@
+/*************************************************************************/
+/* gltf_state.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GLTF_STATE_H
+#define GLTF_STATE_H
+
+#include "core/io/resource.h"
+#include "core/templates/vector.h"
+#include "editor_scene_importer_gltf.h"
+#include "gltf_accessor.h"
+#include "gltf_animation.h"
+#include "gltf_buffer_view.h"
+#include "gltf_camera.h"
+#include "gltf_document.h"
+#include "gltf_light.h"
+#include "gltf_mesh.h"
+#include "gltf_node.h"
+#include "gltf_skeleton.h"
+#include "gltf_skin.h"
+#include "gltf_texture.h"
+#include "scene/animation/animation_player.h"
+#include "scene/resources/texture.h"
+
+class GLTFState : public Resource {
+ GDCLASS(GLTFState, Resource);
+ friend class GLTFDocument;
+ friend class PackedSceneGLTF;
+
+ Dictionary json;
+ int major_version = 0;
+ int minor_version = 0;
+ Vector<uint8_t> glb_data;
+
+ bool use_named_skin_binds = false;
+
+ Vector<Ref<GLTFNode>> nodes;
+ Vector<Vector<uint8_t>> buffers;
+ Vector<Ref<GLTFBufferView>> buffer_views;
+ Vector<Ref<GLTFAccessor>> accessors;
+
+ Vector<Ref<GLTFMesh>> meshes; // meshes are loaded directly, no reason not to.
+
+ Vector<AnimationPlayer *> animation_players;
+ Map<Ref<BaseMaterial3D>, GLTFMaterialIndex> material_cache;
+ Vector<Ref<BaseMaterial3D>> materials;
+
+ String scene_name;
+ Vector<int> root_nodes;
+ Vector<Ref<GLTFTexture>> textures;
+ Vector<Ref<Texture2D>> images;
+
+ Vector<Ref<GLTFSkin>> skins;
+ Vector<Ref<GLTFCamera>> cameras;
+ Vector<Ref<GLTFLight>> lights;
+ Set<String> unique_names;
+
+ Vector<Ref<GLTFSkeleton>> skeletons;
+ Map<GLTFSkeletonIndex, GLTFNodeIndex> skeleton_to_node;
+ Vector<Ref<GLTFAnimation>> animations;
+ Map<GLTFNodeIndex, Node *> scene_nodes;
+
+protected:
+ static void _bind_methods();
+
+public:
+ Dictionary get_json();
+ void set_json(Dictionary p_json);
+
+ int get_major_version();
+ void set_major_version(int p_major_version);
+
+ int get_minor_version();
+ void set_minor_version(int p_minor_version);
+
+ Vector<uint8_t> get_glb_data();
+ void set_glb_data(Vector<uint8_t> p_glb_data);
+
+ bool get_use_named_skin_binds();
+ void set_use_named_skin_binds(bool p_use_named_skin_binds);
+
+ Array get_nodes();
+ void set_nodes(Array p_nodes);
+
+ Array get_buffers();
+ void set_buffers(Array p_buffers);
+
+ Array get_buffer_views();
+ void set_buffer_views(Array p_buffer_views);
+
+ Array get_accessors();
+ void set_accessors(Array p_accessors);
+
+ Array get_meshes();
+ void set_meshes(Array p_meshes);
+
+ Array get_materials();
+ void set_materials(Array p_materials);
+
+ String get_scene_name();
+ void set_scene_name(String p_scene_name);
+
+ Array get_root_nodes();
+ void set_root_nodes(Array p_root_nodes);
+
+ Array get_textures();
+ void set_textures(Array p_textures);
+
+ Array get_images();
+ void set_images(Array p_images);
+
+ Array get_skins();
+ void set_skins(Array p_skins);
+
+ Array get_cameras();
+ void set_cameras(Array p_cameras);
+
+ Array get_lights();
+ void set_lights(Array p_lights);
+
+ Array get_unique_names();
+ void set_unique_names(Array p_unique_names);
+
+ Array get_skeletons();
+ void set_skeletons(Array p_skeletons);
+
+ Dictionary get_skeleton_to_node();
+ void set_skeleton_to_node(Dictionary p_skeleton_to_node);
+
+ Array get_animations();
+ void set_animations(Array p_animations);
+
+ Node *get_scene_node(GLTFNodeIndex idx);
+
+ int get_animation_players_count(int idx);
+
+ AnimationPlayer *get_animation_player(int idx);
+
+ //void set_scene_nodes(Map<GLTFNodeIndex, Node *> p_scene_nodes) {
+ // this->scene_nodes = p_scene_nodes;
+ //}
+
+ //void set_animation_players(Vector<AnimationPlayer *> p_animation_players) {
+ // this->animation_players = p_animation_players;
+ //}
+
+ //Map<Ref<Material>, GLTFMaterialIndex> get_material_cache() {
+ // return this->material_cache;
+ //}
+ //void set_material_cache(Map<Ref<Material>, GLTFMaterialIndex> p_material_cache) {
+ // this->material_cache = p_material_cache;
+ //}
+};
+#endif // GLTF_STATE_H
diff --git a/modules/gltf/gltf_texture.cpp b/modules/gltf/gltf_texture.cpp
new file mode 100644
index 0000000000..0482c1064e
--- /dev/null
+++ b/modules/gltf/gltf_texture.cpp
@@ -0,0 +1,46 @@
+/*************************************************************************/
+/* gltf_texture.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gltf_texture.h"
+
+void GLTFTexture::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_src_image"), &GLTFTexture::get_src_image);
+ ClassDB::bind_method(D_METHOD("set_src_image", "src_image"), &GLTFTexture::set_src_image);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "src_image"), "set_src_image", "get_src_image"); // int
+}
+
+GLTFImageIndex GLTFTexture::get_src_image() const {
+ return src_image;
+}
+
+void GLTFTexture::set_src_image(GLTFImageIndex val) {
+ src_image = val;
+}
diff --git a/modules/gltf/gltf_texture.h b/modules/gltf/gltf_texture.h
new file mode 100644
index 0000000000..e1d0407fb4
--- /dev/null
+++ b/modules/gltf/gltf_texture.h
@@ -0,0 +1,51 @@
+/*************************************************************************/
+/* gltf_texture.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GLTF_TEXTURE_H
+#define GLTF_TEXTURE_H
+
+#include "core/io/resource.h"
+#include "gltf_document.h"
+
+class GLTFTexture : public Resource {
+ GDCLASS(GLTFTexture, Resource);
+
+private:
+ GLTFImageIndex src_image;
+
+protected:
+ static void _bind_methods();
+
+public:
+ GLTFImageIndex get_src_image() const;
+ void set_src_image(GLTFImageIndex val);
+};
+
+#endif // GLTF_TEXTURE_H
diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp
new file mode 100644
index 0000000000..dc995c9249
--- /dev/null
+++ b/modules/gltf/register_types.cpp
@@ -0,0 +1,88 @@
+/*************************************************************************/
+/* register_types.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "register_types.h"
+
+#include "editor/editor_node.h"
+#include "editor_scene_exporter_gltf_plugin.h"
+#include "editor_scene_importer_gltf.h"
+#include "gltf_accessor.h"
+#include "gltf_animation.h"
+#include "gltf_buffer_view.h"
+#include "gltf_camera.h"
+#include "gltf_document.h"
+#include "gltf_light.h"
+#include "gltf_mesh.h"
+#include "gltf_node.h"
+#include "gltf_skeleton.h"
+#include "gltf_skin.h"
+#include "gltf_spec_gloss.h"
+#include "gltf_state.h"
+#include "gltf_texture.h"
+
+#ifndef _3D_DISABLED
+#ifdef TOOLS_ENABLED
+static void _editor_init() {
+ Ref<EditorSceneImporterGLTF> import_gltf;
+ import_gltf.instance();
+ ResourceImporterScene::get_singleton()->add_importer(import_gltf);
+}
+#endif
+#endif
+
+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);
+ ClassDB::register_class<EditorSceneImporterGLTF>();
+ ClassDB::register_class<GLTFMesh>();
+ EditorPlugins::add_by_type<SceneExporterGLTFPlugin>();
+ ClassDB::set_current_api(prev_api);
+ EditorNode::add_init_callback(_editor_init);
+#endif
+ ClassDB::register_class<GLTFSpecGloss>();
+ ClassDB::register_class<GLTFNode>();
+ ClassDB::register_class<GLTFAnimation>();
+ ClassDB::register_class<GLTFBufferView>();
+ ClassDB::register_class<GLTFAccessor>();
+ ClassDB::register_class<GLTFTexture>();
+ ClassDB::register_class<GLTFSkeleton>();
+ ClassDB::register_class<GLTFSkin>();
+ ClassDB::register_class<GLTFCamera>();
+ ClassDB::register_class<GLTFLight>();
+ ClassDB::register_class<GLTFState>();
+ ClassDB::register_class<GLTFDocument>();
+ ClassDB::register_class<PackedSceneGLTF>();
+#endif
+}
+
+void unregister_gltf_types() {
+}
diff --git a/modules/gltf/register_types.h b/modules/gltf/register_types.h
new file mode 100644
index 0000000000..fefacb1106
--- /dev/null
+++ b/modules/gltf/register_types.h
@@ -0,0 +1,32 @@
+/*************************************************************************/
+/* register_types.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+void register_gltf_types();
+void unregister_gltf_types();
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index ccf1e49693..5a17541075 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,7 +31,7 @@
#include "grid_map.h"
#include "core/io/marshalls.h"
-#include "core/message_queue.h"
+#include "core/object/message_queue.h"
#include "scene/3d/light_3d.h"
#include "scene/resources/mesh_library.h"
#include "scene/resources/surface_tool.h"
@@ -706,7 +706,7 @@ void GridMap::_update_visibility() {
Octant *octant = e->value();
for (int i = 0; i < octant->multimesh_instances.size(); i++) {
const Octant::MultimeshInstance &mi = octant->multimesh_instances[i];
- RS::get_singleton()->instance_set_visible(mi.instance, is_visible());
+ RS::get_singleton()->instance_set_visible(mi.instance, is_visible_in_tree());
}
}
}
diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h
index ca7429ea26..48ad95f9ff 100644
--- a/modules/gridmap/grid_map.h
+++ b/modules/gridmap/grid_map.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp
index 0e6ec7f520..4732a3f62d 100644
--- a/modules/gridmap/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/grid_map_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -724,7 +724,7 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
return true;
} else {
selected_palette = -1;
- mesh_library_palette->unselect_all();
+ mesh_library_palette->deselect_all();
update_palette();
_update_cursor_instance();
return true;
@@ -1030,11 +1030,15 @@ void GridMapEditor::_notification(int p_what) {
for (int i = 0; i < 3; i++) {
grid[i] = RS::get_singleton()->mesh_create();
grid_instance[i] = RS::get_singleton()->instance_create2(grid[i], get_tree()->get_root()->get_world_3d()->get_scenario());
+ RenderingServer::get_singleton()->instance_set_layer_mask(grid_instance[i], 1 << Node3DEditorViewport::MISC_TOOL_LAYER);
selection_level_instance[i] = RenderingServer::get_singleton()->instance_create2(selection_level_mesh[i], get_tree()->get_root()->get_world_3d()->get_scenario());
+ RenderingServer::get_singleton()->instance_set_layer_mask(selection_level_instance[i], 1 << Node3DEditorViewport::MISC_TOOL_LAYER);
}
selection_instance = RenderingServer::get_singleton()->instance_create2(selection_mesh, get_tree()->get_root()->get_world_3d()->get_scenario());
+ RenderingServer::get_singleton()->instance_set_layer_mask(selection_instance, 1 << Node3DEditorViewport::MISC_TOOL_LAYER);
paste_instance = RenderingServer::get_singleton()->instance_create2(paste_mesh, get_tree()->get_root()->get_world_3d()->get_scenario());
+ RenderingServer::get_singleton()->instance_set_layer_mask(paste_instance, 1 << Node3DEditorViewport::MISC_TOOL_LAYER);
_update_selection_transform();
_update_paste_indicator();
@@ -1284,7 +1288,7 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
info_message->set_align(Label::ALIGN_CENTER);
info_message->set_autowrap(true);
info_message->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
- info_message->set_anchors_and_margins_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE);
+ info_message->set_anchors_and_offsets_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE);
mesh_library_palette->add_child(info_message);
edit_axis = Vector3::AXIS_Y;
diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/grid_map_editor_plugin.h
index 7e136ff9bb..0c0ec64680 100644
--- a/modules/gridmap/grid_map_editor_plugin.h
+++ b/modules/gridmap/grid_map_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -41,12 +41,10 @@ class GridMapEditor : public VBoxContainer {
GDCLASS(GridMapEditor, VBoxContainer);
enum {
-
GRID_CURSOR_SIZE = 50
};
enum InputAction {
-
INPUT_NONE,
INPUT_PAINT,
INPUT_ERASE,
@@ -56,7 +54,6 @@ class GridMapEditor : public VBoxContainer {
};
enum ClipMode {
-
CLIP_DISABLED,
CLIP_ABOVE,
CLIP_BELOW
@@ -93,7 +90,7 @@ class GridMapEditor : public VBoxContainer {
List<SetItem> set_items;
- GridMap *node;
+ GridMap *node = nullptr;
MeshLibrary *last_mesh_library;
ClipMode clip_mode;
@@ -158,7 +155,6 @@ class GridMapEditor : public VBoxContainer {
int cursor_rot;
enum Menu {
-
MENU_OPTION_NEXT_LEVEL,
MENU_OPTION_PREV_LEVEL,
MENU_OPTION_LOCK_VIEW,
diff --git a/modules/gridmap/icons/GridMap.svg b/modules/gridmap/icons/GridMap.svg
index eafe1211f2..7a36fd888c 100644
--- a/modules/gridmap/icons/GridMap.svg
+++ b/modules/gridmap/icons/GridMap.svg
@@ -1,5 +1 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1036.4)">
-<path transform="translate(0 1036.4)" d="m8 1-6 3v8l6 3 6-3v-2l-2-1-4 2-2-1v-4l2-1v-2l2-1zm4 2-2 1v2l2 1 2-1v-2z" fill="#fc9c9c" fill-opacity=".99608"/>
-</g>
-</svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1-6 3v8l6 3 6-3v-2l-2-1-4 2-2-1v-4l2-1v-2l2-1zm4 2-2 1v2l2 1 2-1v-2z" fill="#fc9c9c" fill-opacity=".99608"/></svg>
diff --git a/modules/gridmap/register_types.cpp b/modules/gridmap/register_types.cpp
index 906e506b62..5680664213 100644
--- a/modules/gridmap/register_types.cpp
+++ b/modules/gridmap/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,7 +30,7 @@
#include "register_types.h"
#ifndef _3D_DISABLED
-#include "core/class_db.h"
+#include "core/object/class_db.h"
#include "grid_map.h"
#include "grid_map_editor_plugin.h"
#endif
diff --git a/modules/gridmap/register_types.h b/modules/gridmap/register_types.h
index c0e3c39ca8..b977f4c5da 100644
--- a/modules/gridmap/register_types.h
+++ b/modules/gridmap/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/hdr/image_loader_hdr.cpp b/modules/hdr/image_loader_hdr.cpp
index 333b1cf377..9d6a399eff 100644
--- a/modules/hdr/image_loader_hdr.cpp
+++ b/modules/hdr/image_loader_hdr.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,7 +31,7 @@
#include "image_loader_hdr.h"
#include "core/os/os.h"
-#include "core/print_string.h"
+#include "core/string/print_string.h"
Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) {
String header = f->get_token();
diff --git a/modules/hdr/image_loader_hdr.h b/modules/hdr/image_loader_hdr.h
index ef8e116616..33fcdd1245 100644
--- a/modules/hdr/image_loader_hdr.h
+++ b/modules/hdr/image_loader_hdr.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/hdr/register_types.cpp b/modules/hdr/register_types.cpp
index e749928f60..5a4a1993e0 100644
--- a/modules/hdr/register_types.cpp
+++ b/modules/hdr/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/hdr/register_types.h b/modules/hdr/register_types.h
index 02441516ec..c85bc84dce 100644
--- a/modules/hdr/register_types.h
+++ b/modules/hdr/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/jpg/SCsub b/modules/jpg/SCsub
index 8ee8e6dd6e..7c6ceeea29 100644
--- a/modules/jpg/SCsub
+++ b/modules/jpg/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_jpg = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
# Not unbundled for now as they are not commonly available as shared library
thirdparty_dir = "#thirdparty/jpeg-compressor/"
thirdparty_sources = [
@@ -17,7 +20,15 @@ env_jpg.Prepend(CPPPATH=[thirdparty_dir])
env_thirdparty = env_jpg.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_jpg.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-# Godot's own source files
-env_jpg.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/jpg/image_loader_jpegd.cpp b/modules/jpg/image_loader_jpegd.cpp
index 9c7ace5cf2..7daf6a3a57 100644
--- a/modules/jpg/image_loader_jpegd.cpp
+++ b/modules/jpg/image_loader_jpegd.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,7 +31,7 @@
#include "image_loader_jpegd.h"
#include "core/os/os.h"
-#include "core/print_string.h"
+#include "core/string/print_string.h"
#include <jpgd.h>
#include <string.h>
diff --git a/modules/jpg/image_loader_jpegd.h b/modules/jpg/image_loader_jpegd.h
index 9aebaad9e3..be265b280c 100644
--- a/modules/jpg/image_loader_jpegd.h
+++ b/modules/jpg/image_loader_jpegd.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/jpg/register_types.cpp b/modules/jpg/register_types.cpp
index b31746f769..a6ae96635f 100644
--- a/modules/jpg/register_types.cpp
+++ b/modules/jpg/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/jpg/register_types.h b/modules/jpg/register_types.h
index 52cd378b3a..577e9b06f7 100644
--- a/modules/jpg/register_types.h
+++ b/modules/jpg/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/jsonrpc/jsonrpc.cpp b/modules/jsonrpc/jsonrpc.cpp
index 320da182f8..306c0ff087 100644
--- a/modules/jsonrpc/jsonrpc.cpp
+++ b/modules/jsonrpc/jsonrpc.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -151,7 +151,7 @@ Variant JSONRPC::process_action(const Variant &p_action, bool p_process_arr_elem
}
String JSONRPC::process_string(const String &p_input) {
- if (p_input.empty()) {
+ if (p_input.is_empty()) {
return String();
}
diff --git a/modules/jsonrpc/jsonrpc.h b/modules/jsonrpc/jsonrpc.h
index e2b7ab0975..9fd016602d 100644
--- a/modules/jsonrpc/jsonrpc.h
+++ b/modules/jsonrpc/jsonrpc.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,8 +31,8 @@
#ifndef GODOT_JSON_RPC_H
#define GODOT_JSON_RPC_H
-#include "core/object.h"
-#include "core/variant.h"
+#include "core/object/class_db.h"
+#include "core/variant/variant.h"
class JSONRPC : public Object {
GDCLASS(JSONRPC, Object)
diff --git a/modules/jsonrpc/register_types.cpp b/modules/jsonrpc/register_types.cpp
index 0d3e446e3e..d6b565ba84 100644
--- a/modules/jsonrpc/register_types.cpp
+++ b/modules/jsonrpc/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,7 +29,7 @@
/*************************************************************************/
#include "register_types.h"
-#include "core/class_db.h"
+#include "core/object/class_db.h"
#include "jsonrpc.h"
void register_jsonrpc_types() {
diff --git a/modules/jsonrpc/register_types.h b/modules/jsonrpc/register_types.h
index 854d73a21f..6a21a12444 100644
--- a/modules/jsonrpc/register_types.h
+++ b/modules/jsonrpc/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp
index 4de523baa0..f31eb3f066 100644
--- a/modules/lightmapper_rd/lightmapper_rd.cpp
+++ b/modules/lightmapper_rd/lightmapper_rd.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,8 +29,8 @@
/*************************************************************************/
#include "lightmapper_rd.h"
+#include "core/config/project_settings.h"
#include "core/math/geometry_2d.h"
-#include "core/project_settings.h"
#include "lm_blendseams.glsl.gen.h"
#include "lm_compute.glsl.gen.h"
#include "lm_raster.glsl.gen.h"
@@ -40,8 +40,8 @@
//#define DEBUG_TEXTURES
void LightmapperRD::add_mesh(const MeshData &p_mesh) {
- ERR_FAIL_COND(p_mesh.albedo_on_uv2.is_null() || p_mesh.albedo_on_uv2->empty());
- ERR_FAIL_COND(p_mesh.emission_on_uv2.is_null() || p_mesh.emission_on_uv2->empty());
+ ERR_FAIL_COND(p_mesh.albedo_on_uv2.is_null() || p_mesh.albedo_on_uv2->is_empty());
+ ERR_FAIL_COND(p_mesh.emission_on_uv2.is_null() || p_mesh.emission_on_uv2->is_empty());
ERR_FAIL_COND(p_mesh.albedo_on_uv2->get_width() != p_mesh.emission_on_uv2->get_width());
ERR_FAIL_COND(p_mesh.albedo_on_uv2->get_height() != p_mesh.emission_on_uv2->get_height());
ERR_FAIL_COND(p_mesh.points.size() == 0);
@@ -447,7 +447,6 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i
if (cell != last_cell) {
//cell changed, update pointer to indices
giw[cell * 2 + 1] = i;
- last_cell = cell;
solidw[cell] = true;
}
tiw[i] = triangle_sort[i].triangle_index;
@@ -543,7 +542,7 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i
tf.width = grid_size;
tf.height = grid_size;
tf.depth = grid_size;
- tf.type = RD::TEXTURE_TYPE_3D;
+ tf.texture_type = RD::TEXTURE_TYPE_3D;
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
Vector<Vector<uint8_t>> texdata;
@@ -695,7 +694,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
tf.width = atlas_size.width;
tf.height = atlas_size.height;
tf.array_layers = atlas_slices;
- tf.type = RD::TEXTURE_TYPE_2D_ARRAY;
+ tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
@@ -826,84 +825,84 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
{
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 1;
u.ids.push_back(vertex_buffer);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 2;
u.ids.push_back(triangle_buffer);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 3;
u.ids.push_back(box_buffer);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 4;
u.ids.push_back(triangle_cell_indices_buffer);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 5;
u.ids.push_back(lights_buffer);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 6;
u.ids.push_back(seams_buffer);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 7;
u.ids.push_back(probe_positions_buffer);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 8;
u.ids.push_back(grid_texture);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 9;
u.ids.push_back(grid_texture_sdf);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 10;
u.ids.push_back(albedo_array_tex);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 11;
u.ids.push_back(emission_array_tex);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_SAMPLER;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
u.binding = 12;
u.ids.push_back(sampler);
base_uniforms.push_back(u);
@@ -917,7 +916,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
tf.width = atlas_size.width;
tf.height = atlas_size.height;
tf.depth = 1;
- tf.type = RD::TEXTURE_TYPE_2D;
+ tf.texture_type = RD::TEXTURE_TYPE_2D;
tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
tf.format = RD::DATA_FORMAT_D32_SFLOAT;
@@ -1049,14 +1048,14 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
{
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 0;
u.ids.push_back(position_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 1;
u.ids.push_back(unocclude_tex); //will be unused
uniforms.push_back(u);
@@ -1089,42 +1088,42 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
{
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 0;
u.ids.push_back(light_source_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 1;
u.ids.push_back(light_dest_tex); //will be unused
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 2;
u.ids.push_back(position_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 3;
u.ids.push_back(normal_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 4;
u.ids.push_back(light_accum_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 5;
u.ids.push_back(light_primary_dynamic_tex);
uniforms.push_back(u);
@@ -1169,49 +1168,49 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
{
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 0;
u.ids.push_back(light_dest_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 1;
u.ids.push_back(light_source_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 2;
u.ids.push_back(position_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 3;
u.ids.push_back(normal_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 4;
u.ids.push_back(light_accum_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 5;
u.ids.push_back(unocclude_tex); //reuse unocclude tex
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 6;
u.ids.push_back(light_environment_tex); //reuse unocclude tex
uniforms.push_back(u);
@@ -1317,28 +1316,28 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
{
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 0;
u.ids.push_back(light_probe_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 1;
u.ids.push_back(light_dest_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 2;
u.ids.push_back(light_primary_dynamic_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 3;
u.ids.push_back(light_environment_tex);
uniforms.push_back(u);
@@ -1437,7 +1436,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
dst[j + 3] = src[j + 3];
}
}
- rd->texture_update(light_accum_tex, i, ds, true);
+ rd->texture_update(light_accum_tex, i, ds);
}
}
}
@@ -1463,14 +1462,14 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
{
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 0;
u.ids.push_back(light_accum_tex);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 1;
u.ids.push_back(light_accum_tex2);
uniforms.push_back(u);
@@ -1538,7 +1537,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
{
//pre copy
for (int i = 0; i < atlas_slices * (p_bake_sh ? 4 : 1); i++) {
- rd->texture_copy(light_accum_tex, light_accum_tex2, Vector3(), Vector3(), Vector3(atlas_size.width, atlas_size.height, 1), 0, 0, i, i, true);
+ rd->texture_copy(light_accum_tex, light_accum_tex2, Vector3(), Vector3(), Vector3(atlas_size.width, atlas_size.height, 1), 0, 0, i, i);
}
Vector<RID> framebuffers;
@@ -1554,7 +1553,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
{
{
RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 0;
u.ids.push_back(light_accum_tex2);
uniforms.push_back(u);
diff --git a/modules/lightmapper_rd/lightmapper_rd.h b/modules/lightmapper_rd/lightmapper_rd.h
index cd000414cf..bb735baf6c 100644
--- a/modules/lightmapper_rd/lightmapper_rd.h
+++ b/modules/lightmapper_rd/lightmapper_rd.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,7 +31,7 @@
#ifndef LIGHTMAPPER_RD_H
#define LIGHTMAPPER_RD_H
-#include "core/local_vector.h"
+#include "core/templates/local_vector.h"
#include "scene/3d/lightmapper.h"
#include "scene/resources/mesh.h"
#include "servers/rendering/rendering_device.h"
diff --git a/modules/lightmapper_rd/lm_compute.glsl b/modules/lightmapper_rd/lm_compute.glsl
index 56976bd623..8a9adbc5cc 100644
--- a/modules/lightmapper_rd/lm_compute.glsl
+++ b/modules/lightmapper_rd/lm_compute.glsl
@@ -249,6 +249,15 @@ float quick_hash(vec2 pos) {
return fract(sin(dot(pos * 19.19, vec2(49.5791, 97.413))) * 49831.189237);
}
+float get_omni_attenuation(float distance, float inv_range, float decay) {
+ float nd = distance * inv_range;
+ nd *= nd;
+ nd *= nd; // nd^4
+ nd = max(1.0 - nd, 0.0);
+ nd *= nd; // nd^2
+ return nd * pow(max(distance, 0.0001), -decay);
+}
+
void main() {
#ifdef MODE_LIGHT_PROBES
int probe_index = int(gl_GlobalInvocationID.x);
@@ -300,7 +309,7 @@ void main() {
d /= lights.data[i].range;
- attenuation = pow(max(1.0 - d, 0.0), lights.data[i].attenuation);
+ attenuation = get_omni_attenuation(d, 1.0 / lights.data[i].range, lights.data[i].attenuation);
if (lights.data[i].type == LIGHT_TYPE_SPOT) {
vec3 rel = normalize(position - light_pos);
diff --git a/modules/lightmapper_rd/register_types.cpp b/modules/lightmapper_rd/register_types.cpp
index 0e6d7590cc..a7b8c063fd 100644
--- a/modules/lightmapper_rd/register_types.cpp
+++ b/modules/lightmapper_rd/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,7 +30,7 @@
#include "register_types.h"
-#include "core/project_settings.h"
+#include "core/config/project_settings.h"
#include "lightmapper_rd.h"
#include "scene/3d/lightmapper.h"
diff --git a/modules/lightmapper_rd/register_types.h b/modules/lightmapper_rd/register_types.h
index b0e15a927f..622d6e37a7 100644
--- a/modules/lightmapper_rd/register_types.h
+++ b/modules/lightmapper_rd/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mbedtls/SCsub b/modules/mbedtls/SCsub
index 5f5d25a3ee..4fcbe8fb43 100755..100644
--- a/modules/mbedtls/SCsub
+++ b/modules/mbedtls/SCsub
@@ -5,8 +5,11 @@ Import("env_modules")
env_mbed_tls = env_modules.Clone()
+# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_mbedtls"]:
- # Thirdparty source files
thirdparty_sources = [
"aes.c",
"aesni.c",
@@ -96,7 +99,21 @@ if env["builtin_mbedtls"]:
env_thirdparty = env_mbed_tls.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
+
+# Godot source files
+
+module_obj = []
+
+env_mbed_tls.add_source_files(module_obj, "*.cpp")
+
+if env["tests"]:
+ env_mbed_tls.Append(CPPDEFINES=["TESTS_ENABLED"])
+ env_mbed_tls.add_source_files(module_obj, "./tests/*.cpp")
+
+env.modules_sources += module_obj
-# Module sources
-env_mbed_tls.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/mbedtls/config.py b/modules/mbedtls/config.py
index d22f9454ed..d22f9454ed 100755..100644
--- a/modules/mbedtls/config.py
+++ b/modules/mbedtls/config.py
diff --git a/modules/mbedtls/crypto_mbedtls.cpp b/modules/mbedtls/crypto_mbedtls.cpp
index 12a982df6e..73931b0365 100644
--- a/modules/mbedtls/crypto_mbedtls.cpp
+++ b/modules/mbedtls/crypto_mbedtls.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,10 +32,10 @@
#include "core/os/file_access.h"
-#include "core/engine.h"
+#include "core/config/engine.h"
+#include "core/config/project_settings.h"
#include "core/io/certs_compressed.gen.h"
#include "core/io/compression.h"
-#include "core/project_settings.h"
#ifdef TOOLS_ENABLED
#include "editor/editor_settings.h"
@@ -44,6 +44,7 @@
#define PEM_END_CRT "-----END CERTIFICATE-----\n"
#include <mbedtls/debug.h>
+#include <mbedtls/md.h>
#include <mbedtls/pem.h>
CryptoKey *CryptoKeyMbedTLS::create() {
@@ -186,6 +187,68 @@ Error X509CertificateMbedTLS::save(String p_path) {
return OK;
}
+bool HMACContextMbedTLS::is_md_type_allowed(mbedtls_md_type_t p_md_type) {
+ switch (p_md_type) {
+ case MBEDTLS_MD_SHA1:
+ case MBEDTLS_MD_SHA256:
+ return true;
+ default:
+ return false;
+ }
+}
+
+HMACContext *HMACContextMbedTLS::create() {
+ return memnew(HMACContextMbedTLS);
+}
+
+Error HMACContextMbedTLS::start(HashingContext::HashType p_hash_type, PackedByteArray p_key) {
+ ERR_FAIL_COND_V_MSG(ctx != nullptr, ERR_FILE_ALREADY_IN_USE, "HMACContext already started.");
+
+ // HMAC keys can be any size.
+ ERR_FAIL_COND_V_MSG(p_key.is_empty(), ERR_INVALID_PARAMETER, "Key must not be empty.");
+
+ hash_type = p_hash_type;
+ mbedtls_md_type_t ht = CryptoMbedTLS::md_type_from_hashtype(p_hash_type, hash_len);
+
+ bool allowed = HMACContextMbedTLS::is_md_type_allowed(ht);
+ ERR_FAIL_COND_V_MSG(!allowed, ERR_INVALID_PARAMETER, "Unsupported hash type.");
+
+ ctx = memalloc(sizeof(mbedtls_md_context_t));
+ mbedtls_md_init((mbedtls_md_context_t *)ctx);
+
+ mbedtls_md_setup((mbedtls_md_context_t *)ctx, mbedtls_md_info_from_type((mbedtls_md_type_t)ht), 1);
+ int ret = mbedtls_md_hmac_starts((mbedtls_md_context_t *)ctx, (const uint8_t *)p_key.ptr(), (size_t)p_key.size());
+ return ret ? FAILED : OK;
+}
+
+Error HMACContextMbedTLS::update(PackedByteArray p_data) {
+ ERR_FAIL_COND_V_MSG(ctx == nullptr, ERR_INVALID_DATA, "Start must be called before update.");
+
+ ERR_FAIL_COND_V_MSG(p_data.is_empty(), ERR_INVALID_PARAMETER, "Src must not be empty.");
+
+ int ret = mbedtls_md_hmac_update((mbedtls_md_context_t *)ctx, (const uint8_t *)p_data.ptr(), (size_t)p_data.size());
+ return ret ? FAILED : OK;
+}
+
+PackedByteArray HMACContextMbedTLS::finish() {
+ ERR_FAIL_COND_V_MSG(ctx == nullptr, PackedByteArray(), "Start must be called before finish.");
+ ERR_FAIL_COND_V_MSG(hash_len == 0, PackedByteArray(), "Unsupported hash type.");
+
+ PackedByteArray out;
+ out.resize(hash_len);
+
+ unsigned char *out_ptr = (unsigned char *)out.ptrw();
+ int ret = mbedtls_md_hmac_finish((mbedtls_md_context_t *)ctx, out_ptr);
+
+ mbedtls_md_free((mbedtls_md_context_t *)ctx);
+ memfree((mbedtls_md_context_t *)ctx);
+ ctx = nullptr;
+ hash_len = 0;
+
+ ERR_FAIL_COND_V_MSG(ret, PackedByteArray(), "Error received while finishing HMAC");
+ return out;
+}
+
Crypto *CryptoMbedTLS::create() {
return memnew(CryptoMbedTLS);
}
@@ -199,6 +262,7 @@ void CryptoMbedTLS::initialize_crypto() {
Crypto::_load_default_certificates = load_default_certificates;
X509CertificateMbedTLS::make_default();
CryptoKeyMbedTLS::make_default();
+ HMACContextMbedTLS::make_default();
}
void CryptoMbedTLS::finalize_crypto() {
@@ -210,6 +274,7 @@ void CryptoMbedTLS::finalize_crypto() {
}
X509CertificateMbedTLS::finalize();
CryptoKeyMbedTLS::finalize();
+ HMACContextMbedTLS::finalize();
}
CryptoMbedTLS::CryptoMbedTLS() {
@@ -313,7 +378,7 @@ PackedByteArray CryptoMbedTLS::generate_random_bytes(int p_bytes) {
return out;
}
-mbedtls_md_type_t CryptoMbedTLS::_md_type_from_hashtype(HashingContext::HashType p_hash_type, int &r_size) {
+mbedtls_md_type_t CryptoMbedTLS::md_type_from_hashtype(HashingContext::HashType p_hash_type, int &r_size) {
switch (p_hash_type) {
case HashingContext::HASH_MD5:
r_size = 16;
@@ -332,7 +397,7 @@ mbedtls_md_type_t CryptoMbedTLS::_md_type_from_hashtype(HashingContext::HashType
Vector<uint8_t> CryptoMbedTLS::sign(HashingContext::HashType p_hash_type, Vector<uint8_t> p_hash, Ref<CryptoKey> p_key) {
int size;
- mbedtls_md_type_t type = _md_type_from_hashtype(p_hash_type, size);
+ mbedtls_md_type_t type = CryptoMbedTLS::md_type_from_hashtype(p_hash_type, size);
ERR_FAIL_COND_V_MSG(type == MBEDTLS_MD_NONE, Vector<uint8_t>(), "Invalid hash type.");
ERR_FAIL_COND_V_MSG(p_hash.size() != size, Vector<uint8_t>(), "Invalid hash provided. Size must be " + itos(size));
Ref<CryptoKeyMbedTLS> key = static_cast<Ref<CryptoKeyMbedTLS>>(p_key);
@@ -350,7 +415,7 @@ Vector<uint8_t> CryptoMbedTLS::sign(HashingContext::HashType p_hash_type, Vector
bool CryptoMbedTLS::verify(HashingContext::HashType p_hash_type, Vector<uint8_t> p_hash, Vector<uint8_t> p_signature, Ref<CryptoKey> p_key) {
int size;
- mbedtls_md_type_t type = _md_type_from_hashtype(p_hash_type, size);
+ mbedtls_md_type_t type = CryptoMbedTLS::md_type_from_hashtype(p_hash_type, size);
ERR_FAIL_COND_V_MSG(type == MBEDTLS_MD_NONE, false, "Invalid hash type.");
ERR_FAIL_COND_V_MSG(p_hash.size() != size, false, "Invalid hash provided. Size must be " + itos(size));
Ref<CryptoKeyMbedTLS> key = static_cast<Ref<CryptoKeyMbedTLS>>(p_key);
diff --git a/modules/mbedtls/crypto_mbedtls.h b/modules/mbedtls/crypto_mbedtls.h
index 2a446f9d48..5ced4d136c 100644
--- a/modules/mbedtls/crypto_mbedtls.h
+++ b/modules/mbedtls/crypto_mbedtls.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,7 +32,7 @@
#define CRYPTO_MBEDTLS_H
#include "core/crypto/crypto.h"
-#include "core/resource.h"
+#include "core/io/resource.h"
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
@@ -101,12 +101,31 @@ public:
friend class SSLContextMbedTLS;
};
+class HMACContextMbedTLS : public HMACContext {
+private:
+ HashingContext::HashType hash_type;
+ int hash_len = 0;
+ void *ctx = nullptr;
+
+public:
+ static HMACContext *create();
+ static void make_default() { HMACContext::_create = create; }
+ static void finalize() { HMACContext::_create = nullptr; }
+
+ static bool is_md_type_allowed(mbedtls_md_type_t p_md_type);
+
+ virtual Error start(HashingContext::HashType p_hash_type, PackedByteArray p_key);
+ virtual Error update(PackedByteArray p_data);
+ virtual PackedByteArray finish();
+
+ HMACContextMbedTLS() {}
+};
+
class CryptoMbedTLS : public Crypto {
private:
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
static X509CertificateMbedTLS *default_certs;
- mbedtls_md_type_t _md_type_from_hashtype(HashingContext::HashType p_hash_type, int &r_size);
public:
static Crypto *create();
@@ -114,6 +133,7 @@ public:
static void finalize_crypto();
static X509CertificateMbedTLS *get_default_certificates();
static void load_default_certificates(String p_path);
+ static mbedtls_md_type_t md_type_from_hashtype(HashingContext::HashType p_hash_type, int &r_size);
virtual PackedByteArray generate_random_bytes(int p_bytes);
virtual Ref<CryptoKey> generate_rsa(int p_bytes);
diff --git a/modules/mbedtls/dtls_server_mbedtls.cpp b/modules/mbedtls/dtls_server_mbedtls.cpp
index d9961b026f..5d895d8579 100644
--- a/modules/mbedtls/dtls_server_mbedtls.cpp
+++ b/modules/mbedtls/dtls_server_mbedtls.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mbedtls/dtls_server_mbedtls.h b/modules/mbedtls/dtls_server_mbedtls.h
index d93553bf7f..9f0c9670e7 100644
--- a/modules/mbedtls/dtls_server_mbedtls.h
+++ b/modules/mbedtls/dtls_server_mbedtls.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mbedtls/packet_peer_mbed_dtls.cpp b/modules/mbedtls/packet_peer_mbed_dtls.cpp
index 8206d739ae..b2f8d668bf 100644
--- a/modules/mbedtls/packet_peer_mbed_dtls.cpp
+++ b/modules/mbedtls/packet_peer_mbed_dtls.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mbedtls/packet_peer_mbed_dtls.h b/modules/mbedtls/packet_peer_mbed_dtls.h
index b958fa3b95..0feec04c6e 100755..100644
--- a/modules/mbedtls/packet_peer_mbed_dtls.h
+++ b/modules/mbedtls/packet_peer_mbed_dtls.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mbedtls/register_types.cpp b/modules/mbedtls/register_types.cpp
index 84a27c29bd..e483030b94 100644
--- a/modules/mbedtls/register_types.cpp
+++ b/modules/mbedtls/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,6 +35,10 @@
#include "packet_peer_mbed_dtls.h"
#include "stream_peer_mbedtls.h"
+#ifdef TESTS_ENABLED
+#include "tests/test_crypto_mbedtls.h"
+#endif
+
void register_mbedtls_types() {
CryptoMbedTLS::initialize_crypto();
StreamPeerMbedTLS::initialize_ssl();
diff --git a/modules/mbedtls/register_types.h b/modules/mbedtls/register_types.h
index 90c81b1682..46ffb8522b 100755..100644
--- a/modules/mbedtls/register_types.h
+++ b/modules/mbedtls/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mbedtls/ssl_context_mbedtls.cpp b/modules/mbedtls/ssl_context_mbedtls.cpp
index a2200e0644..046f30588a 100644
--- a/modules/mbedtls/ssl_context_mbedtls.cpp
+++ b/modules/mbedtls/ssl_context_mbedtls.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mbedtls/ssl_context_mbedtls.h b/modules/mbedtls/ssl_context_mbedtls.h
index baaeb6eb85..d243185726 100644
--- a/modules/mbedtls/ssl_context_mbedtls.h
+++ b/modules/mbedtls/ssl_context_mbedtls.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,7 +35,7 @@
#include "core/os/file_access.h"
-#include "core/reference.h"
+#include "core/object/reference.h"
#include <mbedtls/config.h>
#include <mbedtls/ctr_drbg.h>
diff --git a/modules/mbedtls/stream_peer_mbedtls.cpp b/modules/mbedtls/stream_peer_mbedtls.cpp
index e9a610b7ee..1332d0923c 100644
--- a/modules/mbedtls/stream_peer_mbedtls.cpp
+++ b/modules/mbedtls/stream_peer_mbedtls.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mbedtls/stream_peer_mbedtls.h b/modules/mbedtls/stream_peer_mbedtls.h
index 68b03ae995..ccbbebe4f8 100755..100644
--- a/modules/mbedtls/stream_peer_mbedtls.h
+++ b/modules/mbedtls/stream_peer_mbedtls.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mbedtls/tests/test_crypto_mbedtls.cpp b/modules/mbedtls/tests/test_crypto_mbedtls.cpp
new file mode 100644
index 0000000000..4217497082
--- /dev/null
+++ b/modules/mbedtls/tests/test_crypto_mbedtls.cpp
@@ -0,0 +1,62 @@
+/*************************************************************************/
+/* test_crypto_mbedtls.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "modules/mbedtls/tests/test_crypto_mbedtls.h"
+
+#include "modules/mbedtls/crypto_mbedtls.h"
+#include "tests/test_macros.h"
+
+namespace TestCryptoMbedTLS {
+
+void hmac_digest_test(HashingContext::HashType ht, String expected_hex) {
+ CryptoMbedTLS crypto;
+ PackedByteArray key = String("supersecretkey").to_utf8_buffer();
+ PackedByteArray msg = String("Return of the MAC!").to_utf8_buffer();
+ PackedByteArray digest = crypto.hmac_digest(ht, key, msg);
+ String hex = String::hex_encode_buffer(digest.ptr(), digest.size());
+ CHECK(hex == expected_hex);
+}
+
+void hmac_context_digest_test(HashingContext::HashType ht, String expected_hex) {
+ HMACContextMbedTLS ctx;
+ PackedByteArray key = String("supersecretkey").to_utf8_buffer();
+ PackedByteArray msg1 = String("Return of ").to_utf8_buffer();
+ PackedByteArray msg2 = String("the MAC!").to_utf8_buffer();
+ Error err = ctx.start(ht, key);
+ CHECK(err == OK);
+ err = ctx.update(msg1);
+ CHECK(err == OK);
+ err = ctx.update(msg2);
+ CHECK(err == OK);
+ PackedByteArray digest = ctx.finish();
+ String hex = String::hex_encode_buffer(digest.ptr(), digest.size());
+ CHECK(hex == expected_hex);
+}
+} // namespace TestCryptoMbedTLS
diff --git a/modules/mbedtls/tests/test_crypto_mbedtls.h b/modules/mbedtls/tests/test_crypto_mbedtls.h
new file mode 100644
index 0000000000..b798717e52
--- /dev/null
+++ b/modules/mbedtls/tests/test_crypto_mbedtls.h
@@ -0,0 +1,61 @@
+/*************************************************************************/
+/* test_crypto_mbedtls.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_CRYPTO_MBEDTLS_H
+#define TEST_CRYPTO_MBEDTLS_H
+
+#include "core/crypto/hashing_context.h"
+
+#include "tests/test_macros.h"
+
+namespace TestCryptoMbedTLS {
+
+void hmac_digest_test(HashingContext::HashType ht, String expected_hex);
+
+TEST_CASE("[CryptoMbedTLS] HMAC digest") {
+ // SHA-256
+ hmac_digest_test(HashingContext::HashType::HASH_SHA256, "fe442023f8a7d36a810e1e7cd8a8e2816457f350a008fbf638296afa12085e59");
+
+ // SHA-1
+ hmac_digest_test(HashingContext::HashType::HASH_SHA1, "a0ac4cd68a2f4812c355983d94e8d025afe7dddf");
+}
+
+void hmac_context_digest_test(HashingContext::HashType ht, String expected_hex);
+
+TEST_CASE("[HMACContext] HMAC digest") {
+ // SHA-256
+ hmac_context_digest_test(HashingContext::HashType::HASH_SHA256, "fe442023f8a7d36a810e1e7cd8a8e2816457f350a008fbf638296afa12085e59");
+
+ // SHA-1
+ hmac_context_digest_test(HashingContext::HashType::HASH_SHA1, "a0ac4cd68a2f4812c355983d94e8d025afe7dddf");
+}
+} // namespace TestCryptoMbedTLS
+
+#endif // TEST_CRYPTO_MBEDTLS_H
diff --git a/modules/meshoptimizer/SCsub b/modules/meshoptimizer/SCsub
new file mode 100644
index 0000000000..3f86bb4f00
--- /dev/null
+++ b/modules/meshoptimizer/SCsub
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+Import("env")
+Import("env_modules")
+
+env_meshoptimizer = env_modules.Clone()
+
+# Thirdparty source files
+
+thirdparty_obj = []
+
+thirdparty_dir = "#thirdparty/meshoptimizer/"
+thirdparty_sources = [
+ "allocator.cpp",
+ "clusterizer.cpp",
+ "indexcodec.cpp",
+ "indexgenerator.cpp",
+ "overdrawanalyzer.cpp",
+ "overdrawoptimizer.cpp",
+ "simplifier.cpp",
+ "spatialorder.cpp",
+ "stripifier.cpp",
+ "vcacheanalyzer.cpp",
+ "vcacheoptimizer.cpp",
+ "vertexcodec.cpp",
+ "vertexfilter.cpp",
+ "vfetchanalyzer.cpp",
+ "vfetchoptimizer.cpp",
+]
+thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
+
+env_thirdparty = env_meshoptimizer.Clone()
+env_thirdparty.disable_warnings()
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_meshoptimizer.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/meshoptimizer/config.py b/modules/meshoptimizer/config.py
new file mode 100644
index 0000000000..82e4e43397
--- /dev/null
+++ b/modules/meshoptimizer/config.py
@@ -0,0 +1,7 @@
+def can_build(env, platform):
+ # Having this on release by default, it's small and a lot of users like to do procedural stuff
+ return True
+
+
+def configure(env):
+ pass
diff --git a/modules/meshoptimizer/register_types.cpp b/modules/meshoptimizer/register_types.cpp
new file mode 100644
index 0000000000..a03310f518
--- /dev/null
+++ b/modules/meshoptimizer/register_types.cpp
@@ -0,0 +1,47 @@
+/*************************************************************************/
+/* register_types.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "register_types.h"
+#include "scene/resources/surface_tool.h"
+#include "thirdparty/meshoptimizer/meshoptimizer.h"
+
+void register_meshoptimizer_types() {
+ SurfaceTool::optimize_vertex_cache_func = meshopt_optimizeVertexCache;
+ SurfaceTool::simplify_func = meshopt_simplify;
+ SurfaceTool::simplify_scale_func = meshopt_simplifyScale;
+ SurfaceTool::simplify_sloppy_func = meshopt_simplifySloppy;
+}
+
+void unregister_meshoptimizer_types() {
+ SurfaceTool::optimize_vertex_cache_func = nullptr;
+ SurfaceTool::simplify_func = nullptr;
+ SurfaceTool::simplify_scale_func = nullptr;
+ SurfaceTool::simplify_sloppy_func = nullptr;
+}
diff --git a/modules/meshoptimizer/register_types.h b/modules/meshoptimizer/register_types.h
new file mode 100644
index 0000000000..5b15503acd
--- /dev/null
+++ b/modules/meshoptimizer/register_types.h
@@ -0,0 +1,37 @@
+/*************************************************************************/
+/* register_types.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef MESHOPTIMIZER_REGISTER_TYPES_H
+#define MESHOPTIMIZER_REGISTER_TYPES_H
+
+void register_meshoptimizer_types();
+void unregister_meshoptimizer_types();
+
+#endif // PVR_REGISTER_TYPES_H
diff --git a/modules/minimp3/SCsub b/modules/minimp3/SCsub
new file mode 100644
index 0000000000..f4d1605d55
--- /dev/null
+++ b/modules/minimp3/SCsub
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+
+Import("env")
+Import("env_modules")
+
+env_minimp3 = env_modules.Clone()
+
+thirdparty_dir = "#thirdparty/minimp3/"
+
+# Treat minimp3 headers as system headers to avoid raising warnings. Not supported on MSVC.
+if not env.msvc:
+ env_minimp3.Append(CPPFLAGS=["-isystem", Dir(thirdparty_dir).path])
+else:
+ env_minimp3.Prepend(CPPPATH=[thirdparty_dir])
+
+# Godot's own source files
+env_minimp3.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/minimp3/audio_stream_mp3.cpp b/modules/minimp3/audio_stream_mp3.cpp
new file mode 100644
index 0000000000..8627f71987
--- /dev/null
+++ b/modules/minimp3/audio_stream_mp3.cpp
@@ -0,0 +1,231 @@
+/*************************************************************************/
+/* audio_stream_mp3.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#define MINIMP3_ONLY_MP3
+#define MINIMP3_FLOAT_OUTPUT
+#define MINIMP3_IMPLEMENTATION
+#define MINIMP3_NO_STDIO
+
+#include "audio_stream_mp3.h"
+
+#include "core/os/file_access.h"
+
+void AudioStreamPlaybackMP3::_mix_internal(AudioFrame *p_buffer, int p_frames) {
+ ERR_FAIL_COND(!active);
+
+ int todo = p_frames;
+
+ while (todo && active) {
+ mp3dec_frame_info_t frame_info;
+ mp3d_sample_t *buf_frame = nullptr;
+
+ int samples_mixed = mp3dec_ex_read_frame(mp3d, &buf_frame, &frame_info, mp3_stream->channels);
+
+ if (samples_mixed) {
+ p_buffer[p_frames - todo] = AudioFrame(buf_frame[0], buf_frame[samples_mixed - 1]);
+ --todo;
+ ++frames_mixed;
+ }
+
+ else {
+ //EOF
+ if (mp3_stream->loop) {
+ seek(mp3_stream->loop_offset);
+ loops++;
+ } else {
+ //fill remainder with silence
+ for (int i = p_frames - todo; i < p_frames; i++) {
+ p_buffer[i] = AudioFrame(0, 0);
+ }
+ active = false;
+ todo = 0;
+ }
+ }
+ }
+}
+
+float AudioStreamPlaybackMP3::get_stream_sampling_rate() {
+ return mp3_stream->sample_rate;
+}
+
+void AudioStreamPlaybackMP3::start(float p_from_pos) {
+ active = true;
+ seek(p_from_pos);
+ loops = 0;
+ _begin_resample();
+}
+
+void AudioStreamPlaybackMP3::stop() {
+ active = false;
+}
+
+bool AudioStreamPlaybackMP3::is_playing() const {
+ return active;
+}
+
+int AudioStreamPlaybackMP3::get_loop_count() const {
+ return loops;
+}
+
+float AudioStreamPlaybackMP3::get_playback_position() const {
+ return float(frames_mixed) / mp3_stream->sample_rate;
+}
+
+void AudioStreamPlaybackMP3::seek(float p_time) {
+ if (!active)
+ return;
+
+ if (p_time >= mp3_stream->get_length()) {
+ p_time = 0;
+ }
+
+ frames_mixed = uint32_t(mp3_stream->sample_rate * p_time);
+ mp3dec_ex_seek(mp3d, frames_mixed * mp3_stream->channels);
+}
+
+AudioStreamPlaybackMP3::~AudioStreamPlaybackMP3() {
+ if (mp3d) {
+ mp3dec_ex_close(mp3d);
+ memfree(mp3d);
+ }
+}
+
+Ref<AudioStreamPlayback> AudioStreamMP3::instance_playback() {
+ Ref<AudioStreamPlaybackMP3> mp3s;
+
+ ERR_FAIL_COND_V_MSG(data == nullptr, mp3s,
+ "This AudioStreamMP3 does not have an audio file assigned "
+ "to it. AudioStreamMP3 should not be created from the "
+ "inspector or with `.new()`. Instead, load an audio file.");
+
+ mp3s.instance();
+ mp3s->mp3_stream = Ref<AudioStreamMP3>(this);
+ mp3s->mp3d = (mp3dec_ex_t *)memalloc(sizeof(mp3dec_ex_t));
+
+ int errorcode = mp3dec_ex_open_buf(mp3s->mp3d, (const uint8_t *)data, data_len, MP3D_SEEK_TO_SAMPLE);
+
+ mp3s->frames_mixed = 0;
+ mp3s->active = false;
+ mp3s->loops = 0;
+
+ if (errorcode) {
+ ERR_FAIL_COND_V(errorcode, Ref<AudioStreamPlaybackMP3>());
+ }
+
+ return mp3s;
+}
+
+String AudioStreamMP3::get_stream_name() const {
+ return ""; //return stream_name;
+}
+
+void AudioStreamMP3::clear_data() {
+ if (data) {
+ memfree(data);
+ data = nullptr;
+ data_len = 0;
+ }
+}
+
+void AudioStreamMP3::set_data(const Vector<uint8_t> &p_data) {
+ int src_data_len = p_data.size();
+ const uint8_t *src_datar = p_data.ptr();
+
+ mp3dec_ex_t mp3d;
+ mp3dec_ex_open_buf(&mp3d, src_datar, src_data_len, MP3D_SEEK_TO_SAMPLE);
+
+ channels = mp3d.info.channels;
+ sample_rate = mp3d.info.hz;
+ length = float(mp3d.samples) / (sample_rate * float(channels));
+
+ mp3dec_ex_close(&mp3d);
+
+ clear_data();
+
+ data = memalloc(src_data_len);
+ copymem(data, src_datar, src_data_len);
+ data_len = src_data_len;
+}
+
+Vector<uint8_t> AudioStreamMP3::get_data() const {
+ Vector<uint8_t> vdata;
+
+ if (data_len && data) {
+ vdata.resize(data_len);
+ {
+ uint8_t *w = vdata.ptrw();
+ copymem(w, data, data_len);
+ }
+ }
+
+ return vdata;
+}
+
+void AudioStreamMP3::set_loop(bool p_enable) {
+ loop = p_enable;
+}
+
+bool AudioStreamMP3::has_loop() const {
+ return loop;
+}
+
+void AudioStreamMP3::set_loop_offset(float p_seconds) {
+ loop_offset = p_seconds;
+}
+
+float AudioStreamMP3::get_loop_offset() const {
+ return loop_offset;
+}
+
+float AudioStreamMP3::get_length() const {
+ return length;
+}
+
+void AudioStreamMP3::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_data", "data"), &AudioStreamMP3::set_data);
+ ClassDB::bind_method(D_METHOD("get_data"), &AudioStreamMP3::get_data);
+
+ ClassDB::bind_method(D_METHOD("set_loop", "enable"), &AudioStreamMP3::set_loop);
+ ClassDB::bind_method(D_METHOD("has_loop"), &AudioStreamMP3::has_loop);
+
+ ClassDB::bind_method(D_METHOD("set_loop_offset", "seconds"), &AudioStreamMP3::set_loop_offset);
+ ClassDB::bind_method(D_METHOD("get_loop_offset"), &AudioStreamMP3::get_loop_offset);
+
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_data", "get_data");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_loop", "has_loop");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "loop_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_loop_offset", "get_loop_offset");
+}
+
+AudioStreamMP3::AudioStreamMP3() {
+}
+
+AudioStreamMP3::~AudioStreamMP3() {
+ clear_data();
+}
diff --git a/modules/minimp3/audio_stream_mp3.h b/modules/minimp3/audio_stream_mp3.h
new file mode 100644
index 0000000000..de02ba6003
--- /dev/null
+++ b/modules/minimp3/audio_stream_mp3.h
@@ -0,0 +1,110 @@
+/*************************************************************************/
+/* audio_stream_mp3.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef AUDIO_STREAM_MP3_H
+#define AUDIO_STREAM_MP3_H
+
+#include "core/io/resource_loader.h"
+#include "servers/audio/audio_stream.h"
+
+#include "minimp3_ex.h"
+
+class AudioStreamMP3;
+
+class AudioStreamPlaybackMP3 : public AudioStreamPlaybackResampled {
+ GDCLASS(AudioStreamPlaybackMP3, AudioStreamPlaybackResampled);
+
+ mp3dec_ex_t *mp3d = nullptr;
+ uint32_t frames_mixed = 0;
+ bool active = false;
+ int loops = 0;
+
+ friend class AudioStreamMP3;
+
+ Ref<AudioStreamMP3> mp3_stream;
+
+protected:
+ virtual void _mix_internal(AudioFrame *p_buffer, int p_frames) override;
+ virtual float get_stream_sampling_rate() override;
+
+public:
+ virtual void start(float p_from_pos = 0.0) override;
+ virtual void stop() override;
+ virtual bool is_playing() const override;
+
+ virtual int get_loop_count() const override; //times it looped
+
+ virtual float get_playback_position() const override;
+ virtual void seek(float p_time) override;
+
+ AudioStreamPlaybackMP3() {}
+ ~AudioStreamPlaybackMP3();
+};
+
+class AudioStreamMP3 : public AudioStream {
+ GDCLASS(AudioStreamMP3, AudioStream);
+ OBJ_SAVE_TYPE(AudioStream) //children are all saved as AudioStream, so they can be exchanged
+ RES_BASE_EXTENSION("mp3str");
+
+ friend class AudioStreamPlaybackMP3;
+
+ void *data = nullptr;
+ uint32_t data_len = 0;
+
+ float sample_rate = 1;
+ int channels = 1;
+ float length = 0;
+ bool loop = false;
+ float loop_offset = 0;
+ void clear_data();
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_loop(bool p_enable);
+ bool has_loop() const;
+
+ void set_loop_offset(float p_seconds);
+ float get_loop_offset() const;
+
+ virtual Ref<AudioStreamPlayback> instance_playback() override;
+ virtual String get_stream_name() const override;
+
+ void set_data(const Vector<uint8_t> &p_data);
+ Vector<uint8_t> get_data() const;
+
+ virtual float get_length() const override;
+
+ AudioStreamMP3();
+ virtual ~AudioStreamMP3();
+};
+
+#endif // AUDIO_STREAM_MP3_H
diff --git a/modules/minimp3/config.py b/modules/minimp3/config.py
new file mode 100644
index 0000000000..bd35d099b9
--- /dev/null
+++ b/modules/minimp3/config.py
@@ -0,0 +1,16 @@
+def can_build(env, platform):
+ return True
+
+
+def configure(env):
+ pass
+
+
+def get_doc_classes():
+ return [
+ "AudioStreamMP3",
+ ]
+
+
+def get_doc_path():
+ return "doc_classes"
diff --git a/modules/minimp3/doc_classes/AudioStreamMP3.xml b/modules/minimp3/doc_classes/AudioStreamMP3.xml
new file mode 100644
index 0000000000..92e777ca0f
--- /dev/null
+++ b/modules/minimp3/doc_classes/AudioStreamMP3.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="AudioStreamMP3" inherits="AudioStream" version="4.0">
+ <brief_description>
+ MP3 audio stream driver.
+ </brief_description>
+ <description>
+ MP3 audio stream driver.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="data" type="PackedByteArray" setter="set_data" getter="get_data" default="PackedByteArray( )">
+ Contains the audio data in bytes.
+ </member>
+ <member name="loop" type="bool" setter="set_loop" getter="has_loop" default="false">
+ If [code]true[/code], the stream will automatically loop when it reaches the end.
+ </member>
+ <member name="loop_offset" type="float" setter="set_loop_offset" getter="get_loop_offset" default="0.0">
+ Time in seconds at which the stream starts after being looped.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/modules/minimp3/register_types.cpp b/modules/minimp3/register_types.cpp
new file mode 100644
index 0000000000..4ab4c743d6
--- /dev/null
+++ b/modules/minimp3/register_types.cpp
@@ -0,0 +1,52 @@
+/*************************************************************************/
+/* register_types.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "register_types.h"
+
+#include "audio_stream_mp3.h"
+
+#ifdef TOOLS_ENABLED
+#include "core/config/engine.h"
+#include "resource_importer_mp3.h"
+#endif
+
+void register_minimp3_types() {
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ Ref<ResourceImporterMP3> mp3_import;
+ mp3_import.instance();
+ ResourceFormatImporter::get_singleton()->add_importer(mp3_import);
+ }
+#endif
+ ClassDB::register_class<AudioStreamMP3>();
+}
+
+void unregister_minimp3_types() {
+}
diff --git a/modules/minimp3/register_types.h b/modules/minimp3/register_types.h
new file mode 100644
index 0000000000..96227c272e
--- /dev/null
+++ b/modules/minimp3/register_types.h
@@ -0,0 +1,37 @@
+/*************************************************************************/
+/* register_types.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef MINIMP3_REGISTER_TYPES_H
+#define MINIMP3_REGISTER_TYPES_H
+
+void register_minimp3_types();
+void unregister_minimp3_types();
+
+#endif // MINIMP3_REGISTER_TYPES_H
diff --git a/modules/minimp3/resource_importer_mp3.cpp b/modules/minimp3/resource_importer_mp3.cpp
new file mode 100644
index 0000000000..afd26fb79e
--- /dev/null
+++ b/modules/minimp3/resource_importer_mp3.cpp
@@ -0,0 +1,104 @@
+/*************************************************************************/
+/* resource_importer_mp3.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "resource_importer_mp3.h"
+
+#include "core/io/resource_saver.h"
+#include "core/os/file_access.h"
+#include "scene/resources/texture.h"
+
+String ResourceImporterMP3::get_importer_name() const {
+ return "mp3";
+}
+
+String ResourceImporterMP3::get_visible_name() const {
+ return "MP3";
+}
+
+void ResourceImporterMP3::get_recognized_extensions(List<String> *p_extensions) const {
+ p_extensions->push_back("mp3");
+}
+
+String ResourceImporterMP3::get_save_extension() const {
+ return "mp3str";
+}
+
+String ResourceImporterMP3::get_resource_type() const {
+ return "AudioStreamMP3";
+}
+
+bool ResourceImporterMP3::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
+ return true;
+}
+
+int ResourceImporterMP3::get_preset_count() const {
+ return 0;
+}
+
+String ResourceImporterMP3::get_preset_name(int p_idx) const {
+ return String();
+}
+
+void ResourceImporterMP3::get_import_options(List<ImportOption> *r_options, int p_preset) const {
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "loop"), true));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "loop_offset"), 0));
+}
+
+Error ResourceImporterMP3::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
+ 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);
+
+ size_t len = f->get_len();
+
+ Vector<uint8_t> data;
+ data.resize(len);
+ uint8_t *w = data.ptrw();
+
+ f->get_buffer(w, len);
+
+ memdelete(f);
+
+ Ref<AudioStreamMP3> mp3_stream;
+ mp3_stream.instance();
+
+ mp3_stream->set_data(data);
+ ERR_FAIL_COND_V(!mp3_stream->get_data().size(), ERR_FILE_CORRUPT);
+ mp3_stream->set_loop(loop);
+ mp3_stream->set_loop_offset(loop_offset);
+
+ return ResourceSaver::save(p_save_path + ".mp3str", mp3_stream);
+}
+
+ResourceImporterMP3::ResourceImporterMP3() {
+}
diff --git a/modules/minimp3/resource_importer_mp3.h b/modules/minimp3/resource_importer_mp3.h
new file mode 100644
index 0000000000..71b51887a2
--- /dev/null
+++ b/modules/minimp3/resource_importer_mp3.h
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* resource_importer_mp3.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef RESOURCE_IMPORTER_MP3_H
+#define RESOURCE_IMPORTER_MP3_H
+
+#include "audio_stream_mp3.h"
+#include "core/io/resource_importer.h"
+
+class ResourceImporterMP3 : public ResourceImporter {
+ GDCLASS(ResourceImporterMP3, ResourceImporter);
+
+public:
+ virtual String get_importer_name() const override;
+ virtual String get_visible_name() const override;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const override;
+ virtual String get_save_extension() const override;
+ virtual String get_resource_type() const override;
+
+ virtual int get_preset_count() const override;
+ virtual String get_preset_name(int p_idx) const override;
+
+ virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const override;
+ virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const override;
+
+ virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override;
+
+ ResourceImporterMP3();
+};
+
+#endif // RESOURCE_IMPORTER_MP3_H
diff --git a/modules/mobile_vr/mobile_vr_interface.cpp b/modules/mobile_vr/mobile_vr_interface.cpp
index a2fb443ef0..a9073ea4a0 100644
--- a/modules/mobile_vr/mobile_vr_interface.cpp
+++ b/modules/mobile_vr/mobile_vr_interface.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mobile_vr/mobile_vr_interface.h b/modules/mobile_vr/mobile_vr_interface.h
index 9b03fff777..1afa6c39b6 100644
--- a/modules/mobile_vr/mobile_vr_interface.h
+++ b/modules/mobile_vr/mobile_vr_interface.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mobile_vr/register_types.cpp b/modules/mobile_vr/register_types.cpp
index 0bb555e780..e7d33ba8a7 100644
--- a/modules/mobile_vr/register_types.cpp
+++ b/modules/mobile_vr/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mobile_vr/register_types.h b/modules/mobile_vr/register_types.h
index 33f608b6ed..9f20f252a4 100644
--- a/modules/mobile_vr/register_types.h
+++ b/modules/mobile_vr/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/SCsub b/modules/mono/SCsub
index e8f3174a0a..3b94949470 100644
--- a/modules/mono/SCsub
+++ b/modules/mono/SCsub
@@ -40,6 +40,11 @@ if env_mono["tools"] and env_mono["mono_glue"] and env_mono["build_cil"]:
godot_tools_build.build(env_mono, api_sln_cmd)
+ # Build Godot.NET.Sdk
+ import build_scripts.godot_net_sdk_build as godot_net_sdk_build
+
+ godot_net_sdk_build.build(env_mono)
+
# Add sources
env_mono.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/mono/build_scripts/godot_net_sdk_build.py b/modules/mono/build_scripts/godot_net_sdk_build.py
new file mode 100644
index 0000000000..3bfba0f0f6
--- /dev/null
+++ b/modules/mono/build_scripts/godot_net_sdk_build.py
@@ -0,0 +1,45 @@
+# Build Godot.NET.Sdk solution
+
+import os
+
+from SCons.Script import Dir
+
+
+def build_godot_net_sdk(source, target, env):
+ # source and target elements are of type SCons.Node.FS.File, hence why we convert them to str
+
+ module_dir = env["module_dir"]
+
+ solution_path = os.path.join(module_dir, "editor/Godot.NET.Sdk/Godot.NET.Sdk.sln")
+ build_config = "Release"
+
+ from .solution_builder import build_solution
+
+ extra_msbuild_args = ["/p:GodotPlatform=" + env["platform"]]
+
+ build_solution(env, solution_path, build_config, extra_msbuild_args)
+ # No need to copy targets. The Godot.NET.Sdk csproj takes care of copying them.
+
+
+def build(env_mono):
+ assert env_mono["tools"]
+
+ output_dir = Dir("#bin").abspath
+ editor_tools_dir = os.path.join(output_dir, "GodotSharp", "Tools")
+ nupkgs_dir = os.path.join(editor_tools_dir, "nupkgs")
+
+ module_dir = os.getcwd()
+
+ package_version_file = os.path.join(
+ module_dir, "editor", "Godot.NET.Sdk", "Godot.NET.Sdk", "Godot.NET.Sdk_PackageVersion.txt"
+ )
+
+ with open(package_version_file, mode="r") as f:
+ version = f.read().strip()
+
+ target_filenames = ["Godot.NET.Sdk.%s.nupkg" % version]
+
+ targets = [os.path.join(nupkgs_dir, filename) for filename in target_filenames]
+
+ cmd = env_mono.CommandNoCache(targets, [], build_godot_net_sdk, module_dir=module_dir)
+ env_mono.AlwaysBuild(cmd)
diff --git a/modules/mono/build_scripts/make_android_mono_config.py b/modules/mono/build_scripts/make_android_mono_config.py
index d276d7d886..28494bff6e 100644
--- a/modules/mono/build_scripts/make_android_mono_config.py
+++ b/modules/mono/build_scripts/make_android_mono_config.py
@@ -32,17 +32,16 @@ namespace {
static const int config_compressed_size = %d;
static const int config_uncompressed_size = %d;
static const unsigned char config_compressed_data[] = { %s };
-
} // namespace
String get_godot_android_mono_config() {
Vector<uint8_t> data;
data.resize(config_uncompressed_size);
uint8_t* w = data.ptrw();
- Compression::decompress(w.ptr(), config_uncompressed_size, config_compressed_data,
+ Compression::decompress(w, config_uncompressed_size, config_compressed_data,
config_compressed_size, Compression::MODE_DEFLATE);
String s;
- if (s.parse_utf8((const char *)w.ptr(), data.size())) {
+ if (s.parse_utf8((const char *)w, data.size())) {
ERR_FAIL_V(String());
}
return s;
diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py
index 6057004166..309abfbff7 100644
--- a/modules/mono/build_scripts/mono_configure.py
+++ b/modules/mono/build_scripts/mono_configure.py
@@ -97,6 +97,7 @@ def configure(env, env_mono):
copy_mono_root = env["copy_mono_root"]
mono_prefix = env["mono_prefix"]
+ mono_bcl = env["mono_bcl"]
mono_lib_names = ["mono-2.0-sgen", "monosgen-2.0"]
@@ -262,7 +263,8 @@ def configure(env, env_mono):
env_mono.Append(CPPDEFINES=["_REENTRANT"])
if mono_static:
- env.Append(LINKFLAGS=["-rdynamic"])
+ if not is_javascript:
+ env.Append(LINKFLAGS=["-rdynamic"])
mono_lib_file = os.path.join(mono_lib_path, "lib" + mono_lib + ".a")
@@ -397,7 +399,7 @@ def configure(env, env_mono):
if tools_enabled:
# Only supported for editor builds.
- copy_mono_root_files(env, mono_root)
+ copy_mono_root_files(env, mono_root, mono_bcl)
def make_template_dir(env, mono_root):
@@ -430,7 +432,7 @@ def make_template_dir(env, mono_root):
copy_mono_shared_libs(env, mono_root, template_mono_root_dir)
-def copy_mono_root_files(env, mono_root):
+def copy_mono_root_files(env, mono_root, mono_bcl):
from glob import glob
from shutil import copy
from shutil import rmtree
@@ -455,7 +457,7 @@ def copy_mono_root_files(env, mono_root):
# Copy framework assemblies
- mono_framework_dir = os.path.join(mono_root, "lib", "mono", "4.5")
+ mono_framework_dir = mono_bcl or os.path.join(mono_root, "lib", "mono", "4.5")
mono_framework_facades_dir = os.path.join(mono_framework_dir, "Facades")
editor_mono_framework_dir = os.path.join(editor_mono_root_dir, "lib", "mono", "4.5")
diff --git a/modules/mono/class_db_api_json.cpp b/modules/mono/class_db_api_json.cpp
index d7b2028204..553c6eca53 100644
--- a/modules/mono/class_db_api_json.cpp
+++ b/modules/mono/class_db_api_json.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,9 +32,9 @@
#ifdef DEBUG_METHODS_ENABLED
+#include "core/config/project_settings.h"
#include "core/io/json.h"
#include "core/os/file_access.h"
-#include "core/project_settings.h"
#include "core/version.h"
void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
@@ -71,7 +71,7 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
while ((k = t->method_map.next(k))) {
String name = k->operator String();
- ERR_CONTINUE(name.empty());
+ ERR_CONTINUE(name.is_empty());
if (name[0] == '_') {
continue; // Ignore non-virtual methods that start with an underscore
@@ -122,7 +122,7 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
method_dict["hint_flags"] = mb->get_hint_flags();
}
- if (!methods.empty()) {
+ if (!methods.is_empty()) {
class_dict["methods"] = methods;
}
}
@@ -149,7 +149,7 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
constant_dict["value"] = t->constant_map[F->get()];
}
- if (!constants.empty()) {
+ if (!constants.is_empty()) {
class_dict["constants"] = constants;
}
}
@@ -184,7 +184,7 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
}
}
- if (!signals.empty()) {
+ if (!signals.is_empty()) {
class_dict["signals"] = signals;
}
}
@@ -214,7 +214,7 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
property_dict["getter"] = psg->getter;
}
- if (!properties.empty()) {
+ if (!properties.is_empty()) {
class_dict["property_setget"] = properties;
}
}
@@ -233,7 +233,7 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
property_dict["usage"] = F->get().usage;
}
- if (!property_list.empty()) {
+ if (!property_list.is_empty()) {
class_dict["property_list"] = property_list;
}
}
diff --git a/modules/mono/class_db_api_json.h b/modules/mono/class_db_api_json.h
index 7f016ac3d6..6698a6260f 100644
--- a/modules/mono/class_db_api_json.h
+++ b/modules/mono/class_db_api_json.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,13 +31,13 @@
#ifndef CLASS_DB_API_JSON_H
#define CLASS_DB_API_JSON_H
-// 'core/method_bind.h' defines DEBUG_METHODS_ENABLED, but it looks like we
-// cannot include it here. That's why we include it through 'core/class_db.h'.
-#include "core/class_db.h"
+// 'core/object/method_bind.h' defines DEBUG_METHODS_ENABLED, but it looks like we
+// cannot include it here. That's why we include it through 'core/object/class_db.h'.
+#include "core/object/class_db.h"
#ifdef DEBUG_METHODS_ENABLED
-#include "core/ustring.h"
+#include "core/string/ustring.h"
void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api);
diff --git a/modules/mono/config.py b/modules/mono/config.py
index d060ae9b28..4c851a2989 100644
--- a/modules/mono/config.py
+++ b/modules/mono/config.py
@@ -11,7 +11,6 @@ def configure(env):
if platform not in supported_platforms:
raise RuntimeError("This module does not currently support building for this platform")
- env.use_ptrcall = True
env.add_module_version_string("mono")
from SCons.Script import BoolVariable, PathVariable, Variables, Help
@@ -28,6 +27,14 @@ def configure(env):
PathVariable.PathAccept,
)
)
+ envvars.Add(
+ PathVariable(
+ "mono_bcl",
+ "Path to a custom Mono BCL (Base Class Library) directory for the target platform",
+ "",
+ PathVariable.PathAccept,
+ )
+ )
envvars.Add(BoolVariable("mono_static", "Statically link Mono", default_mono_static))
envvars.Add(BoolVariable("mono_glue", "Build with the Mono glue sources", True))
envvars.Add(BoolVariable("build_cil", "Build C# solutions", True))
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index a05b38b8bf..bd29dc1876 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,6 +33,7 @@
#include <mono/metadata/threads.h>
#include <stdint.h>
+#include "core/config/project_settings.h"
#include "core/debugger/engine_debugger.h"
#include "core/debugger/script_debugger.h"
#include "core/io/json.h"
@@ -40,7 +41,6 @@
#include "core/os/mutex.h"
#include "core/os/os.h"
#include "core/os/thread.h"
-#include "core/project_settings.h"
#ifdef TOOLS_ENABLED
#include "editor/bindings_generator.h"
@@ -346,14 +346,18 @@ Ref<Script> CSharpLanguage::get_template(const String &p_class_name, const Strin
"// }\n"
"}\n";
- String base_class_name = get_base_class_name(p_base_class_name, p_class_name);
+ // Replaces all spaces in p_class_name with underscores to prevent
+ // erronous C# Script templates from being generated when the object name
+ // has spaces in it.
+ String class_name_no_spaces = p_class_name.replace(" ", "_");
+ String base_class_name = get_base_class_name(p_base_class_name, class_name_no_spaces);
script_template = script_template.replace("%BASE%", base_class_name)
- .replace("%CLASS%", p_class_name);
+ .replace("%CLASS%", class_name_no_spaces);
Ref<CSharpScript> script;
script.instance();
script->set_source_code(script_template);
- script->set_name(p_class_name);
+ script->set_name(class_name_no_spaces);
return script;
}
@@ -364,9 +368,10 @@ bool CSharpLanguage::is_using_templates() {
void CSharpLanguage::make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) {
String src = p_script->get_source_code();
- String base_class_name = get_base_class_name(p_base_class_name, p_class_name);
+ String class_name_no_spaces = p_class_name.replace(" ", "_");
+ String base_class_name = get_base_class_name(p_base_class_name, class_name_no_spaces);
src = src.replace("%BASE%", base_class_name)
- .replace("%CLASS%", p_class_name)
+ .replace("%CLASS%", class_name_no_spaces)
.replace("%TS%", _get_indentation());
p_script->set_source_code(src);
}
@@ -395,7 +400,7 @@ bool CSharpLanguage::supports_builtin_mode() const {
#ifdef TOOLS_ENABLED
static String variant_type_to_managed_name(const String &p_var_type_name) {
- if (p_var_type_name.empty()) {
+ if (p_var_type_name.is_empty()) {
return "object";
}
@@ -477,7 +482,7 @@ static String variant_type_to_managed_name(const String &p_var_type_name) {
Variant::COLOR,
Variant::STRING_NAME,
Variant::NODE_PATH,
- Variant::_RID,
+ Variant::RID,
Variant::CALLABLE
};
@@ -757,7 +762,7 @@ bool CSharpLanguage::is_assembly_reloading_needed() {
String appname = ProjectSettings::get_singleton()->get("application/config/name");
String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
- if (appname_safe.empty()) {
+ if (appname_safe.is_empty()) {
appname_safe = "UnnamedProject";
}
@@ -854,7 +859,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
to_reload.push_back(script);
- if (script->get_path().empty()) {
+ if (script->get_path().is_empty()) {
script->tied_class_name_for_reload = script->script_class->get_name_for_lookup();
script->tied_class_namespace_for_reload = script->script_class->get_namespace();
}
@@ -940,8 +945,6 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
// Use a placeholder for now to avoid losing the state when saving a scene
- obj->set_script(scr);
-
PlaceHolderScriptInstance *placeholder = scr->placeholder_instance_create(obj);
obj->set_script_instance(placeholder);
@@ -968,14 +971,13 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
for (List<Ref<CSharpScript>>::Element *E = to_reload.front(); E; E = E->next()) {
Ref<CSharpScript> script = E->get();
- if (!script->get_path().empty()) {
#ifdef TOOLS_ENABLED
- script->exports_invalidated = true;
+ script->exports_invalidated = true;
#endif
- script->signals_invalidated = true;
+ script->signals_invalidated = true;
+ if (!script->get_path().is_empty()) {
script->reload(p_soft_reload);
- script->update_exports();
if (!script->valid) {
script->pending_reload_instances.clear();
@@ -1444,7 +1446,7 @@ Map<Object *, CSharpScriptBinding>::Element *CSharpLanguage::insert_script_bindi
void CSharpLanguage::free_instance_binding_data(void *p_data) {
if (GDMono::get_singleton() == nullptr) {
#ifdef DEBUG_ENABLED
- CRASH_COND(!script_bindings.empty());
+ CRASH_COND(!script_bindings.is_empty());
#endif
// Mono runtime finalized, all the gchandle bindings were already released
return;
@@ -1950,6 +1952,7 @@ MonoObject *CSharpInstance::_internal_new_managed() {
}
void CSharpInstance::mono_object_disposed(MonoObject *p_obj) {
+ // Must make sure event signals are not left dangling
disconnect_event_signals();
#ifdef DEBUG_ENABLED
@@ -1965,6 +1968,9 @@ void CSharpInstance::mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_f
CRASH_COND(gchandle.is_released());
#endif
+ // Must make sure event signals are not left dangling
+ disconnect_event_signals();
+
r_remove_script_instance = false;
if (_unreference_owner_unsafe()) {
@@ -2224,6 +2230,9 @@ CSharpInstance::~CSharpInstance() {
destructing_script_instance = true;
+ // Must make sure event signals are not left dangling
+ disconnect_event_signals();
+
if (!gchandle.is_released()) {
if (!predelete_notified && !ref_dying) {
// This destructor is not called from the owners destructor.
@@ -2595,7 +2604,7 @@ void CSharpScript::load_script_signals(GDMonoClass *p_class, GDMonoClass *p_nati
MonoCustomAttrInfo *event_attrs = mono_custom_attrs_from_event(top->get_mono_ptr(), raw_event);
if (event_attrs) {
if (mono_custom_attrs_has_attr(event_attrs, CACHED_CLASS(SignalAttribute)->get_mono_ptr())) {
- const char *event_name = mono_event_get_name(raw_event);
+ String event_name = String::utf8(mono_event_get_name(raw_event));
found_event_signals.push_back(StringName(event_name));
}
@@ -2799,7 +2808,7 @@ int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, Manage
name_only_hint_string += ",";
}
- String enum_field_name = mono_field_get_name(field);
+ String enum_field_name = String::utf8(mono_field_get_name(field));
r_hint_string += enum_field_name;
name_only_hint_string += enum_field_name;
@@ -2955,13 +2964,24 @@ void CSharpScript::initialize_for_managed_type(Ref<CSharpScript> p_script, GDMon
CRASH_COND(p_script->native == nullptr);
+ p_script->valid = true;
+
+ update_script_class_info(p_script);
+
+#ifdef TOOLS_ENABLED
+ p_script->_update_member_info_no_exports();
+#endif
+}
+
+// Extract information about the script using the mono class.
+void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) {
GDMonoClass *base = p_script->script_class->get_parent_class();
+ // `base` should only be set if the script is a user defined type.
if (base != p_script->native) {
p_script->base = base;
}
- p_script->valid = true;
p_script->tool = p_script->script_class->has_attribute(CACHED_CLASS(ToolAttribute));
if (!p_script->tool) {
@@ -2969,7 +2989,7 @@ void CSharpScript::initialize_for_managed_type(Ref<CSharpScript> p_script, GDMon
p_script->tool = nesting_class && nesting_class->has_attribute(CACHED_CLASS(ToolAttribute));
}
-#if TOOLS_ENABLED
+#ifdef TOOLS_ENABLED
if (!p_script->tool) {
p_script->tool = p_script->script_class->get_assembly() == GDMono::get_singleton()->get_tools_assembly();
}
@@ -2996,17 +3016,74 @@ void CSharpScript::initialize_for_managed_type(Ref<CSharpScript> p_script, GDMon
p_script->script_class->fetch_methods_with_godot_api_checks(p_script->native);
- // Need to fetch method from base classes as well
+ p_script->rpc_functions.clear();
+ p_script->rpc_variables.clear();
+
GDMonoClass *top = p_script->script_class;
while (top && top != p_script->native) {
+ // Fetch methods from base classes as well
top->fetch_methods_with_godot_api_checks(p_script->native);
+
+ // Update RPC info
+ {
+ Vector<GDMonoMethod *> methods = top->get_all_methods();
+ for (int i = 0; i < methods.size(); i++) {
+ if (!methods[i]->is_static()) {
+ MultiplayerAPI::RPCMode mode = p_script->_member_get_rpc_mode(methods[i]);
+ if (MultiplayerAPI::RPC_MODE_DISABLED != mode) {
+ ScriptNetData nd;
+ nd.name = methods[i]->get_name();
+ nd.mode = mode;
+ if (-1 == p_script->rpc_functions.find(nd)) {
+ p_script->rpc_functions.push_back(nd);
+ }
+ }
+ }
+ }
+ }
+
+ {
+ Vector<GDMonoField *> fields = top->get_all_fields();
+ for (int i = 0; i < fields.size(); i++) {
+ if (!fields[i]->is_static()) {
+ MultiplayerAPI::RPCMode mode = p_script->_member_get_rpc_mode(fields[i]);
+ if (MultiplayerAPI::RPC_MODE_DISABLED != mode) {
+ ScriptNetData nd;
+ nd.name = fields[i]->get_name();
+ nd.mode = mode;
+ if (-1 == p_script->rpc_variables.find(nd)) {
+ p_script->rpc_variables.push_back(nd);
+ }
+ }
+ }
+ }
+ }
+
+ {
+ Vector<GDMonoProperty *> properties = top->get_all_properties();
+ for (int i = 0; i < properties.size(); i++) {
+ if (!properties[i]->is_static()) {
+ MultiplayerAPI::RPCMode mode = p_script->_member_get_rpc_mode(properties[i]);
+ if (MultiplayerAPI::RPC_MODE_DISABLED != mode) {
+ ScriptNetData nd;
+ nd.name = properties[i]->get_name();
+ nd.mode = mode;
+ if (-1 == p_script->rpc_variables.find(nd)) {
+ p_script->rpc_variables.push_back(nd);
+ }
+ }
+ }
+ }
+ }
+
top = top->get_parent_class();
}
+ // Sort so we are 100% that they are always the same.
+ p_script->rpc_functions.sort_custom<SortNetData>();
+ p_script->rpc_variables.sort_custom<SortNetData>();
+
p_script->load_script_signals(p_script->script_class, p_script->native);
-#ifdef TOOLS_ENABLED
- p_script->_update_member_info_no_exports();
-#endif
}
bool CSharpScript::can_instance() const {
@@ -3051,7 +3128,7 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
ERR_FAIL_COND_V_MSG(p_argcount == 0, nullptr,
"Cannot create script instance. The class '" + script_class->get_full_name() +
"' does not define a parameterless constructor." +
- (get_path().empty() ? String() : " Path: '" + get_path() + "'."));
+ (get_path().is_empty() ? String() : " Path: '" + get_path() + "'."));
ERR_FAIL_V_MSG(nullptr, "Constructor not found.");
}
@@ -3206,7 +3283,7 @@ bool CSharpScript::instance_has(const Object *p_this) const {
}
bool CSharpScript::has_source_code() const {
- return !source.empty();
+ return !source.is_empty();
}
String CSharpScript::get_source_code() const {
@@ -3305,124 +3382,15 @@ Error CSharpScript::reload(bool p_keep_state) {
print_verbose("Found class " + script_class->get_full_name() + " for script " + get_path());
#endif
- tool = script_class->has_attribute(CACHED_CLASS(ToolAttribute));
-
- if (!tool) {
- GDMonoClass *nesting_class = script_class->get_nesting_class();
- tool = nesting_class && nesting_class->has_attribute(CACHED_CLASS(ToolAttribute));
- }
-
-#if TOOLS_ENABLED
- if (!tool) {
- tool = script_class->get_assembly() == GDMono::get_singleton()->get_tools_assembly();
- }
-#endif
-
native = GDMonoUtils::get_class_native_base(script_class);
CRASH_COND(native == nullptr);
- GDMonoClass *base_class = script_class->get_parent_class();
-
- if (base_class != native) {
- base = base_class;
- }
-
-#ifdef DEBUG_ENABLED
- // For debug builds, we must fetch from all native base methods as well.
- // Native base methods must be fetched before the current class.
- // Not needed if the script class itself is a native class.
-
- if (script_class != native) {
- GDMonoClass *native_top = native;
- while (native_top) {
- native_top->fetch_methods_with_godot_api_checks(native);
-
- if (native_top == CACHED_CLASS(GodotObject)) {
- break;
- }
-
- native_top = native_top->get_parent_class();
- }
- }
-#endif
-
- script_class->fetch_methods_with_godot_api_checks(native);
+ update_script_class_info(this);
- // Need to fetch method from base classes as well
- GDMonoClass *top = script_class;
- while (top && top != native) {
- top->fetch_methods_with_godot_api_checks(native);
- top = top->get_parent_class();
- }
-
- load_script_signals(script_class, native);
_update_exports();
}
- rpc_functions.clear();
- rpc_variables.clear();
-
- GDMonoClass *top = script_class;
- while (top && top != native) {
- {
- Vector<GDMonoMethod *> methods = top->get_all_methods();
- for (int i = 0; i < methods.size(); i++) {
- if (!methods[i]->is_static()) {
- MultiplayerAPI::RPCMode mode = _member_get_rpc_mode(methods[i]);
- if (MultiplayerAPI::RPC_MODE_DISABLED != mode) {
- ScriptNetData nd;
- nd.name = methods[i]->get_name();
- nd.mode = mode;
- if (-1 == rpc_functions.find(nd)) {
- rpc_functions.push_back(nd);
- }
- }
- }
- }
- }
-
- {
- Vector<GDMonoField *> fields = top->get_all_fields();
- for (int i = 0; i < fields.size(); i++) {
- if (!fields[i]->is_static()) {
- MultiplayerAPI::RPCMode mode = _member_get_rpc_mode(fields[i]);
- if (MultiplayerAPI::RPC_MODE_DISABLED != mode) {
- ScriptNetData nd;
- nd.name = fields[i]->get_name();
- nd.mode = mode;
- if (-1 == rpc_variables.find(nd)) {
- rpc_variables.push_back(nd);
- }
- }
- }
- }
- }
-
- {
- Vector<GDMonoProperty *> properties = top->get_all_properties();
- for (int i = 0; i < properties.size(); i++) {
- if (!properties[i]->is_static()) {
- MultiplayerAPI::RPCMode mode = _member_get_rpc_mode(properties[i]);
- if (MultiplayerAPI::RPC_MODE_DISABLED != mode) {
- ScriptNetData nd;
- nd.name = properties[i]->get_name();
- nd.mode = mode;
- if (-1 == rpc_variables.find(nd)) {
- rpc_variables.push_back(nd);
- }
- }
- }
- }
- }
-
- top = top->get_parent_class();
- }
-
- // Sort so we are 100% that they are always the same.
- rpc_functions.sort_custom<SortNetData>();
- rpc_variables.sort_custom<SortNetData>();
-
return OK;
}
@@ -3616,9 +3584,9 @@ Error CSharpScript::load_source_code(const String &p_path) {
ERR_FAIL_COND_V_MSG(ferr != OK, ferr,
ferr == ERR_INVALID_DATA ?
- "Script '" + p_path + "' contains invalid unicode (UTF-8), so it was not loaded."
+ "Script '" + p_path + "' contains invalid unicode (UTF-8), so it was not loaded."
" Please ensure that scripts are saved in valid UTF-8 unicode." :
- "Failed to read file: '" + p_path + "'.");
+ "Failed to read file: '" + p_path + "'.");
#ifdef TOOLS_ENABLED
source_changed_cache = true;
@@ -3630,7 +3598,7 @@ Error CSharpScript::load_source_code(const String &p_path) {
void CSharpScript::_update_name() {
String path = get_path();
- if (!path.empty()) {
+ if (!path.is_empty()) {
name = get_path().get_file().get_basename();
}
}
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index f0b43a40f9..85edd8b9c6 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,10 +31,11 @@
#ifndef CSHARP_SCRIPT_H
#define CSHARP_SCRIPT_H
+#include "core/doc_data.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
-#include "core/script_language.h"
-#include "core/self_list.h"
+#include "core/object/script_language.h"
+#include "core/templates/self_list.h"
#include "mono_gc_handle.h"
#include "mono_gd/gd_mono.h"
@@ -164,6 +165,7 @@ private:
// Do not use unless you know what you are doing
friend void GDMonoInternals::tie_managed_to_unmanaged(MonoObject *, Object *);
static Ref<CSharpScript> create_for_managed_type(GDMonoClass *p_class, GDMonoClass *p_native);
+ static void update_script_class_info(Ref<CSharpScript> p_script);
static void initialize_for_managed_type(Ref<CSharpScript> p_script, GDMonoClass *p_class, GDMonoClass *p_native);
MultiplayerAPI::RPCMode _member_get_rpc_mode(IMonoClassMember *p_member) const;
@@ -188,6 +190,14 @@ public:
String get_source_code() const override;
void set_source_code(const String &p_code) override;
+#ifdef TOOLS_ENABLED
+ virtual const Vector<DocData::ClassDoc> &get_documentation() const override {
+ // TODO
+ static Vector<DocData::ClassDoc> docs;
+ return docs;
+ }
+#endif // TOOLS_ENABLED
+
Error reload(bool p_keep_state = false) override;
bool has_script_signal(const StringName &p_signal) const override;
@@ -287,7 +297,7 @@ public:
void mono_object_disposed(MonoObject *p_obj);
/*
- * If 'r_delete_owner' is set to true, the caller must memdelete the script instance's owner. Otherwise, ifevent_signal
+ * If 'r_delete_owner' is set to true, the caller must memdelete the script instance's owner. Otherwise, if
* 'r_remove_script_instance' is set to true, the caller must destroy the script instance by removing it from its owner.
*/
void mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_finalizer, bool &r_delete_owner, bool &r_remove_script_instance);
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj
index 86a0a4393e..8304d9e321 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj
@@ -1,13 +1,13 @@
<Project Sdk="Microsoft.Build.NoTargets/2.0.1">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
+ <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<Description>MSBuild .NET Sdk for Godot projects.</Description>
<Authors>Godot Engine contributors</Authors>
<PackageId>Godot.NET.Sdk</PackageId>
<Version>4.0.0</Version>
- <PackageVersion>4.0.0-dev2</PackageVersion>
<PackageProjectUrl>https://github.com/godotengine/godot/tree/master/modules/mono/editor/Godot.NET.Sdk</PackageProjectUrl>
<PackageType>MSBuildSdk</PackageType>
<PackageTags>MSBuildSdk</PackageTags>
@@ -19,7 +19,13 @@
<GenerateNuspecDependsOn>$(GenerateNuspecDependsOn);SetNuSpecProperties</GenerateNuspecDependsOn>
</PropertyGroup>
- <Target Name="SetNuSpecProperties" Condition=" Exists('$(NuspecFile)') ">
+ <Target Name="ReadGodotNETSdkVersion" BeforeTargets="BeforeBuild;BeforeRebuild;CoreCompile">
+ <PropertyGroup>
+ <PackageVersion>$([System.IO.File]::ReadAllText('$(ProjectDir)Godot.NET.Sdk_PackageVersion.txt').Trim())</PackageVersion>
+ </PropertyGroup>
+ </Target>
+
+ <Target Name="SetNuSpecProperties" Condition=" Exists('$(NuspecFile)') " DependsOnTargets="ReadGodotNETSdkVersion">
<PropertyGroup>
<NuspecProperties>
id=$(PackageId);
@@ -32,4 +38,13 @@
</NuspecProperties>
</PropertyGroup>
</Target>
+
+ <Target Name="CopyNupkgToSConsOutputDir" AfterTargets="Pack">
+ <PropertyGroup>
+ <GodotSourceRootPath>$(SolutionDir)\..\..\..\..\</GodotSourceRootPath>
+ <GodotOutputDataDir>$(GodotSourceRootPath)\bin\GodotSharp\</GodotOutputDataDir>
+ </PropertyGroup>
+ <Copy SourceFiles="$(OutputPath)$(PackageId).$(PackageVersion).nupkg"
+ DestinationFolder="$(GodotOutputDataDir)Tools\nupkgs\" />
+ </Target>
</Project>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk_PackageVersion.txt b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk_PackageVersion.txt
new file mode 100644
index 0000000000..34749489b9
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk_PackageVersion.txt
@@ -0,0 +1 @@
+4.0.0-dev3
diff --git a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs
index 5edf72d63e..9b7b422276 100644
--- a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs
@@ -15,14 +15,14 @@ namespace GodotTools.BuildLogger
public void Initialize(IEventSource eventSource)
{
if (null == Parameters)
- throw new LoggerException("Log directory was not set.");
+ throw new LoggerException("Log directory parameter not specified.");
var parameters = Parameters.Split(new[] { ';' });
string logDir = parameters[0];
if (string.IsNullOrEmpty(logDir))
- throw new LoggerException("Log directory was not set.");
+ throw new LoggerException("Log directory parameter is empty.");
if (parameters.Length > 1)
throw new LoggerException("Too many parameters passed.");
@@ -51,22 +51,31 @@ namespace GodotTools.BuildLogger
{
throw new LoggerException("Failed to create log file: " + ex.Message);
}
- else
- {
- // Unexpected failure
- throw;
- }
+
+ // Unexpected failure
+ throw;
}
eventSource.ProjectStarted += eventSource_ProjectStarted;
- eventSource.TaskStarted += eventSource_TaskStarted;
+ eventSource.ProjectFinished += eventSource_ProjectFinished;
eventSource.MessageRaised += eventSource_MessageRaised;
eventSource.WarningRaised += eventSource_WarningRaised;
eventSource.ErrorRaised += eventSource_ErrorRaised;
- eventSource.ProjectFinished += eventSource_ProjectFinished;
}
- void eventSource_ErrorRaised(object sender, BuildErrorEventArgs e)
+ private void eventSource_ProjectStarted(object sender, ProjectStartedEventArgs e)
+ {
+ WriteLine(e.Message);
+ indent++;
+ }
+
+ private void eventSource_ProjectFinished(object sender, ProjectFinishedEventArgs e)
+ {
+ indent--;
+ WriteLine(e.Message);
+ }
+
+ private void eventSource_ErrorRaised(object sender, BuildErrorEventArgs e)
{
string line = $"{e.File}({e.LineNumber},{e.ColumnNumber}): error {e.Code}: {e.Message}";
@@ -81,7 +90,7 @@ namespace GodotTools.BuildLogger
issuesStreamWriter.WriteLine(errorLine);
}
- void eventSource_WarningRaised(object sender, BuildWarningEventArgs e)
+ private void eventSource_WarningRaised(object sender, BuildWarningEventArgs e)
{
string line = $"{e.File}({e.LineNumber},{e.ColumnNumber}): warning {e.Code}: {e.Message}";
@@ -108,40 +117,6 @@ namespace GodotTools.BuildLogger
}
}
- private void eventSource_TaskStarted(object sender, TaskStartedEventArgs e)
- {
- // TaskStartedEventArgs adds ProjectFile, TaskFile, TaskName
- // To keep this log clean, this logger will ignore these events.
- }
-
- private void eventSource_ProjectStarted(object sender, ProjectStartedEventArgs e)
- {
- WriteLine(e.Message);
- indent++;
- }
-
- private void eventSource_ProjectFinished(object sender, ProjectFinishedEventArgs e)
- {
- indent--;
- WriteLine(e.Message);
- }
-
- /// <summary>
- /// Write a line to the log, adding the SenderName
- /// </summary>
- private void WriteLineWithSender(string line, BuildEventArgs e)
- {
- if (0 == string.Compare(e.SenderName, "MSBuild", StringComparison.OrdinalIgnoreCase))
- {
- // Well, if the sender name is MSBuild, let's leave it out for prettiness
- WriteLine(line);
- }
- else
- {
- WriteLine(e.SenderName + ": " + line);
- }
- }
-
/// <summary>
/// Write a line to the log, adding the SenderName and Message
/// (these parameters are on all MSBuild event argument objects)
diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj
index e4d6b2e010..37123ba2b2 100644
--- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj
@@ -10,6 +10,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\GodotTools.Core\GodotTools.Core.csproj" />
+ <ProjectReference Include="..\GodotTools.Shared\GodotTools.Shared.csproj" />
</ItemGroup>
<!--
The Microsoft.Build.Runtime package is too problematic so we create a MSBuild.exe stub. The workaround described
diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs
index 01d7c99662..7d49d251dd 100644
--- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs
@@ -3,14 +3,13 @@ using System.IO;
using System.Text;
using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;
+using GodotTools.Shared;
namespace GodotTools.ProjectEditor
{
public static class ProjectGenerator
{
- public const string GodotSdkVersionToUse = "4.0.0-dev2";
-
- public static string GodotSdkAttrValue => $"Godot.NET.Sdk/{GodotSdkVersionToUse}";
+ public static string GodotSdkAttrValue => $"Godot.NET.Sdk/{GeneratedGodotNupkgsVersions.GodotNETSdk}";
public static ProjectRootElement GenGameProject(string name)
{
diff --git a/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets b/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets
new file mode 100644
index 0000000000..1d382dcb43
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets
@@ -0,0 +1,36 @@
+<Project>
+ <!-- Generate C# file with the version of all the nupkgs bundled with Godot -->
+
+ <Target Name="SetPropertiesForGenerateGodotNupkgsVersions">
+ <PropertyGroup>
+ <GodotNETSdkPackageVersionFile>$(SolutionDir)..\Godot.NET.Sdk\Godot.NET.Sdk\Godot.NET.Sdk_PackageVersion.txt</GodotNETSdkPackageVersionFile>
+ <GeneratedGodotNupkgsVersionsFile>$(IntermediateOutputPath)GodotNupkgsVersions.g.cs</GeneratedGodotNupkgsVersionsFile>
+ </PropertyGroup>
+ </Target>
+
+ <Target Name="GenerateGodotNupkgsVersionsFile"
+ DependsOnTargets="PrepareForBuild;_GenerateGodotNupkgsVersionsFile"
+ BeforeTargets="BeforeCompile;CoreCompile">
+ <ItemGroup>
+ <Compile Include="$(GeneratedGodotNupkgsVersionsFile)" />
+ <FileWrites Include="$(GeneratedGodotNupkgsVersionsFile)" />
+ </ItemGroup>
+ </Target>
+ <Target Name="_GenerateGodotNupkgsVersionsFile"
+ DependsOnTargets="SetPropertiesForGenerateGodotNupkgsVersions"
+ Inputs="$(MSBuildProjectFile);@(GodotNETSdkPackageVersionFile)"
+ Outputs="$(GeneratedGodotNupkgsVersionsFile)">
+ <PropertyGroup>
+ <GenerateGodotNupkgsVersionsCode><![CDATA[
+namespace $(RootNamespace) {
+ public class GeneratedGodotNupkgsVersions {
+ public const string GodotNETSdk = "$([System.IO.File]::ReadAllText('$(GodotNETSdkPackageVersionFile)').Trim())"%3b
+ }
+}
+]]></GenerateGodotNupkgsVersionsCode>
+ </PropertyGroup>
+ <WriteLinesToFile Lines="$(GenerateGodotNupkgsVersionsCode)"
+ File="$(GeneratedGodotNupkgsVersionsFile)"
+ Overwrite="True" WriteOnlyWhenDifferent="True" />
+ </Target>
+</Project>
diff --git a/modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj b/modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj
new file mode 100644
index 0000000000..3bc1698c15
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj
@@ -0,0 +1,6 @@
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <TargetFramework>netstandard2.0</TargetFramework>
+ </PropertyGroup>
+ <Import Project="GenerateGodotNupkgsVersions.targets" />
+</Project>
diff --git a/modules/mono/editor/GodotTools/GodotTools.sln b/modules/mono/editor/GodotTools/GodotTools.sln
index ba5379e562..d3107a69db 100644
--- a/modules/mono/editor/GodotTools/GodotTools.sln
+++ b/modules/mono/editor/GodotTools/GodotTools.sln
@@ -13,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotTools.IdeMessaging", "
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotTools.OpenVisualStudio", "GodotTools.OpenVisualStudio\GodotTools.OpenVisualStudio.csproj", "{EAFFF236-FA96-4A4D-BD23-0E51EF988277}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotTools.Shared", "GodotTools.Shared\GodotTools.Shared.csproj", "{2758FFAF-8237-4CF2-B569-66BF8B3587BB}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -43,5 +45,9 @@ Global
{EAFFF236-FA96-4A4D-BD23-0E51EF988277}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EAFFF236-FA96-4A4D-BD23-0E51EF988277}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EAFFF236-FA96-4A4D-BD23-0E51EF988277}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2758FFAF-8237-4CF2-B569-66BF8B3587BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2758FFAF-8237-4CF2-B569-66BF8B3587BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2758FFAF-8237-4CF2-B569-66BF8B3587BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2758FFAF-8237-4CF2-B569-66BF8B3587BB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
diff --git a/modules/mono/editor/GodotTools/GodotTools/BottomPanel.cs b/modules/mono/editor/GodotTools/GodotTools/BottomPanel.cs
deleted file mode 100644
index 3ab669a9f3..0000000000
--- a/modules/mono/editor/GodotTools/GodotTools/BottomPanel.cs
+++ /dev/null
@@ -1,339 +0,0 @@
-using Godot;
-using System;
-using System.IO;
-using Godot.Collections;
-using GodotTools.Internals;
-using static GodotTools.Internals.Globals;
-using File = GodotTools.Utils.File;
-using Path = System.IO.Path;
-
-namespace GodotTools
-{
- public class BottomPanel : VBoxContainer
- {
- private EditorInterface editorInterface;
-
- private TabContainer panelTabs;
-
- private VBoxContainer panelBuildsTab;
-
- private ItemList buildTabsList;
- private TabContainer buildTabs;
-
- private Button warningsBtn;
- private Button errorsBtn;
- private Button viewLogBtn;
-
- private void _UpdateBuildTab(int index, int? currentTab)
- {
- var tab = (BuildTab)buildTabs.GetChild(index);
-
- string itemName = Path.GetFileNameWithoutExtension(tab.BuildInfo.Solution);
- itemName += " [" + tab.BuildInfo.Configuration + "]";
-
- buildTabsList.AddItem(itemName, tab.IconTexture);
-
- string itemTooltip = "Solution: " + tab.BuildInfo.Solution;
- itemTooltip += "\nConfiguration: " + tab.BuildInfo.Configuration;
- itemTooltip += "\nStatus: ";
-
- if (tab.BuildExited)
- itemTooltip += tab.BuildResult == BuildTab.BuildResults.Success ? "Succeeded" : "Errored";
- else
- itemTooltip += "Running";
-
- if (!tab.BuildExited || tab.BuildResult == BuildTab.BuildResults.Error)
- itemTooltip += $"\nErrors: {tab.ErrorCount}";
-
- itemTooltip += $"\nWarnings: {tab.WarningCount}";
-
- buildTabsList.SetItemTooltip(index, itemTooltip);
-
- // If this tab was already selected before the changes or if no tab was selected
- if (currentTab == null || currentTab == index)
- {
- buildTabsList.Select(index);
- _BuildTabsItemSelected(index);
- }
- }
-
- private void _UpdateBuildTabsList()
- {
- buildTabsList.Clear();
-
- int? currentTab = buildTabs.CurrentTab;
-
- if (currentTab < 0 || currentTab >= buildTabs.GetTabCount())
- currentTab = null;
-
- for (int i = 0; i < buildTabs.GetChildCount(); i++)
- _UpdateBuildTab(i, currentTab);
- }
-
- public BuildTab GetBuildTabFor(BuildInfo buildInfo)
- {
- foreach (var buildTab in new Array<BuildTab>(buildTabs.GetChildren()))
- {
- if (buildTab.BuildInfo.Equals(buildInfo))
- return buildTab;
- }
-
- var newBuildTab = new BuildTab(buildInfo);
- AddBuildTab(newBuildTab);
-
- return newBuildTab;
- }
-
- private void _BuildTabsItemSelected(int idx)
- {
- if (idx < 0 || idx >= buildTabs.GetTabCount())
- throw new IndexOutOfRangeException();
-
- buildTabs.CurrentTab = idx;
- if (!buildTabs.Visible)
- buildTabs.Visible = true;
-
- warningsBtn.Visible = true;
- errorsBtn.Visible = true;
- viewLogBtn.Visible = true;
- }
-
- private void _BuildTabsNothingSelected()
- {
- if (buildTabs.GetTabCount() != 0)
- {
- // just in case
- buildTabs.Visible = false;
-
- // This callback is called when clicking on the empty space of the list.
- // ItemList won't deselect the items automatically, so we must do it ourselves.
- buildTabsList.UnselectAll();
- }
-
- warningsBtn.Visible = false;
- errorsBtn.Visible = false;
- viewLogBtn.Visible = false;
- }
-
- private void _WarningsToggled(bool pressed)
- {
- int currentTab = buildTabs.CurrentTab;
-
- if (currentTab < 0 || currentTab >= buildTabs.GetTabCount())
- throw new InvalidOperationException("No tab selected");
-
- var buildTab = (BuildTab)buildTabs.GetChild(currentTab);
- buildTab.WarningsVisible = pressed;
- buildTab.UpdateIssuesList();
- }
-
- private void _ErrorsToggled(bool pressed)
- {
- int currentTab = buildTabs.CurrentTab;
-
- if (currentTab < 0 || currentTab >= buildTabs.GetTabCount())
- throw new InvalidOperationException("No tab selected");
-
- var buildTab = (BuildTab)buildTabs.GetChild(currentTab);
- buildTab.ErrorsVisible = pressed;
- buildTab.UpdateIssuesList();
- }
-
- public void BuildProjectPressed()
- {
- if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
- return; // No solution to build
-
- string editorScriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, "scripts_metadata.editor");
- string playerScriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, "scripts_metadata.editor_player");
-
- CsProjOperations.GenerateScriptsMetadata(GodotSharpDirs.ProjectCsProjPath, editorScriptsMetadataPath);
-
- if (File.Exists(editorScriptsMetadataPath))
- {
- try
- {
- File.Copy(editorScriptsMetadataPath, playerScriptsMetadataPath);
- }
- catch (IOException e)
- {
- GD.PushError($"Failed to copy scripts metadata file. Exception message: {e.Message}");
- return;
- }
- }
-
- bool buildSuccess = BuildManager.BuildProjectBlocking("Debug");
-
- if (!buildSuccess)
- return;
-
- // Notify running game for hot-reload
- Internal.EditorDebuggerNodeReloadScripts();
-
- // Hot-reload in the editor
- GodotSharpEditor.Instance.GetNode<HotReloadAssemblyWatcher>("HotReloadAssemblyWatcher").RestartTimer();
-
- if (Internal.IsAssembliesReloadingNeeded())
- Internal.ReloadAssemblies(softReload: false);
- }
-
- private void _ViewLogPressed()
- {
- if (!buildTabsList.IsAnythingSelected())
- return;
-
- var selectedItems = buildTabsList.GetSelectedItems();
-
- if (selectedItems.Length != 1)
- throw new InvalidOperationException($"Expected 1 selected item, got {selectedItems.Length}");
-
- int selectedItem = selectedItems[0];
-
- var buildTab = (BuildTab)buildTabs.GetTabControl(selectedItem);
-
- OS.ShellOpen(Path.Combine(buildTab.BuildInfo.LogsDirPath, BuildManager.MsBuildLogFileName));
- }
-
- public override void _Notification(int what)
- {
- base._Notification(what);
-
- if (what == EditorSettings.NotificationEditorSettingsChanged)
- {
- var editorBaseControl = editorInterface.GetBaseControl();
- panelTabs.AddThemeStyleboxOverride("panel", editorBaseControl.GetThemeStylebox("DebuggerPanel", "EditorStyles"));
- panelTabs.AddThemeStyleboxOverride("tab_fg", editorBaseControl.GetThemeStylebox("DebuggerTabFG", "EditorStyles"));
- panelTabs.AddThemeStyleboxOverride("tab_bg", editorBaseControl.GetThemeStylebox("DebuggerTabBG", "EditorStyles"));
- }
- }
-
- public void AddBuildTab(BuildTab buildTab)
- {
- buildTabs.AddChild(buildTab);
- RaiseBuildTab(buildTab);
- }
-
- public void RaiseBuildTab(BuildTab buildTab)
- {
- if (buildTab.GetParent() != buildTabs)
- throw new InvalidOperationException("Build tab is not in the tabs list");
-
- buildTabs.MoveChild(buildTab, 0);
- _UpdateBuildTabsList();
- }
-
- public void ShowBuildTab()
- {
- for (int i = 0; i < panelTabs.GetTabCount(); i++)
- {
- if (panelTabs.GetTabControl(i) == panelBuildsTab)
- {
- panelTabs.CurrentTab = i;
- GodotSharpEditor.Instance.MakeBottomPanelItemVisible(this);
- return;
- }
- }
-
- GD.PushError("Builds tab not found");
- }
-
- public override void _Ready()
- {
- base._Ready();
-
- editorInterface = GodotSharpEditor.Instance.GetEditorInterface();
-
- var editorBaseControl = editorInterface.GetBaseControl();
-
- SizeFlagsVertical = (int)SizeFlags.ExpandFill;
- SetAnchorsAndMarginsPreset(LayoutPreset.Wide);
-
- panelTabs = new TabContainer
- {
- TabAlign = TabContainer.TabAlignEnum.Left,
- RectMinSize = new Vector2(0, 228) * EditorScale,
- SizeFlagsVertical = (int)SizeFlags.ExpandFill
- };
- panelTabs.AddThemeStyleboxOverride("panel", editorBaseControl.GetThemeStylebox("DebuggerPanel", "EditorStyles"));
- panelTabs.AddThemeStyleboxOverride("tab_fg", editorBaseControl.GetThemeStylebox("DebuggerTabFG", "EditorStyles"));
- panelTabs.AddThemeStyleboxOverride("tab_bg", editorBaseControl.GetThemeStylebox("DebuggerTabBG", "EditorStyles"));
- AddChild(panelTabs);
-
- {
- // Builds tab
- panelBuildsTab = new VBoxContainer
- {
- Name = "Builds".TTR(),
- SizeFlagsHorizontal = (int)SizeFlags.ExpandFill
- };
- panelTabs.AddChild(panelBuildsTab);
-
- var toolBarHBox = new HBoxContainer {SizeFlagsHorizontal = (int)SizeFlags.ExpandFill};
- panelBuildsTab.AddChild(toolBarHBox);
-
- var buildProjectBtn = new Button
- {
- Text = "Build Project".TTR(),
- FocusMode = FocusModeEnum.None
- };
- buildProjectBtn.PressedSignal += BuildProjectPressed;
- toolBarHBox.AddChild(buildProjectBtn);
-
- toolBarHBox.AddSpacer(begin: false);
-
- warningsBtn = new Button
- {
- Text = "Warnings".TTR(),
- ToggleMode = true,
- Pressed = true,
- Visible = false,
- FocusMode = FocusModeEnum.None
- };
- warningsBtn.Toggled += _WarningsToggled;
- toolBarHBox.AddChild(warningsBtn);
-
- errorsBtn = new Button
- {
- Text = "Errors".TTR(),
- ToggleMode = true,
- Pressed = true,
- Visible = false,
- FocusMode = FocusModeEnum.None
- };
- errorsBtn.Toggled += _ErrorsToggled;
- toolBarHBox.AddChild(errorsBtn);
-
- toolBarHBox.AddSpacer(begin: false);
-
- viewLogBtn = new Button
- {
- Text = "View log".TTR(),
- FocusMode = FocusModeEnum.None,
- Visible = false
- };
- viewLogBtn.PressedSignal += _ViewLogPressed;
- toolBarHBox.AddChild(viewLogBtn);
-
- var hsc = new HSplitContainer
- {
- SizeFlagsHorizontal = (int)SizeFlags.ExpandFill,
- SizeFlagsVertical = (int)SizeFlags.ExpandFill
- };
- panelBuildsTab.AddChild(hsc);
-
- buildTabsList = new ItemList {SizeFlagsHorizontal = (int)SizeFlags.ExpandFill};
- buildTabsList.ItemSelected += _BuildTabsItemSelected;
- buildTabsList.NothingSelected += _BuildTabsNothingSelected;
- hsc.AddChild(buildTabsList);
-
- buildTabs = new TabContainer
- {
- TabAlign = TabContainer.TabAlignEnum.Left,
- SizeFlagsHorizontal = (int)SizeFlags.ExpandFill,
- TabsVisible = false
- };
- hsc.AddChild(buildTabs);
- }
- }
- }
-}
diff --git a/modules/mono/editor/GodotTools/GodotTools/BuildInfo.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs
index ab090c46e7..51055dc9b9 100644
--- a/modules/mono/editor/GodotTools/GodotTools/BuildInfo.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs
@@ -4,7 +4,7 @@ using Godot.Collections;
using GodotTools.Internals;
using Path = System.IO.Path;
-namespace GodotTools
+namespace GodotTools.Build
{
[Serializable]
public sealed class BuildInfo : Reference // TODO Remove Reference once we have proper serialization
@@ -20,7 +20,9 @@ namespace GodotTools
public override bool Equals(object obj)
{
if (obj is BuildInfo other)
- return other.Solution == Solution && other.Configuration == Configuration;
+ return other.Solution == Solution && other.Targets == Targets &&
+ other.Configuration == Configuration && other.Restore == Restore &&
+ other.CustomProperties == CustomProperties && other.LogsDirPath == LogsDirPath;
return false;
}
@@ -31,7 +33,11 @@ namespace GodotTools
{
int hash = 17;
hash = hash * 29 + Solution.GetHashCode();
+ hash = hash * 29 + Targets.GetHashCode();
hash = hash * 29 + Configuration.GetHashCode();
+ hash = hash * 29 + Restore.GetHashCode();
+ hash = hash * 29 + CustomProperties.GetHashCode();
+ hash = hash * 29 + LogsDirPath.GetHashCode();
return hash;
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/BuildManager.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs
index ff7ce97c47..b96b0c8175 100644
--- a/modules/mono/editor/GodotTools/GodotTools/BuildManager.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs
@@ -1,20 +1,18 @@
using System;
-using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
-using GodotTools.Build;
using GodotTools.Ides.Rider;
using GodotTools.Internals;
-using GodotTools.Utils;
using JetBrains.Annotations;
using static GodotTools.Internals.Globals;
using File = GodotTools.Utils.File;
+using OS = GodotTools.Utils.OS;
-namespace GodotTools
+namespace GodotTools.Build
{
public static class BuildManager
{
- private static readonly List<BuildInfo> BuildsInProgress = new List<BuildInfo>();
+ private static BuildInfo _buildInProgress;
public const string PropNameMSBuildMono = "MSBuild (Mono)";
public const string PropNameMSBuildVs = "MSBuild (VS Build Tools)";
@@ -24,6 +22,14 @@ namespace GodotTools
public const string MsBuildIssuesFileName = "msbuild_issues.csv";
public const string MsBuildLogFileName = "msbuild_log.txt";
+ public delegate void BuildLaunchFailedEventHandler(BuildInfo buildInfo, string reason);
+
+ public static event BuildLaunchFailedEventHandler BuildLaunchFailed;
+ public static event Action<BuildInfo> BuildStarted;
+ public static event Action<BuildResult> BuildFinished;
+ public static event Action<string> StdOutputReceived;
+ public static event Action<string> StdErrorReceived;
+
private static void RemoveOldIssuesFile(BuildInfo buildInfo)
{
var issuesFile = GetIssuesFilePath(buildInfo);
@@ -36,12 +42,13 @@ namespace GodotTools
private static void ShowBuildErrorDialog(string message)
{
- GodotSharpEditor.Instance.ShowErrorDialog(message, "Build error");
- GodotSharpEditor.Instance.BottomPanel.ShowBuildTab();
+ var plugin = GodotSharpEditor.Instance;
+ plugin.ShowErrorDialog(message, "Build error");
+ plugin.MakeBottomPanelItemVisible(plugin.MSBuildPanel);
}
- public static void RestartBuild(BuildTab buildTab) => throw new NotImplementedException();
- public static void StopBuild(BuildTab buildTab) => throw new NotImplementedException();
+ public static void RestartBuild(BuildOutputView buildOutputView) => throw new NotImplementedException();
+ public static void StopBuild(BuildOutputView buildOutputView) => throw new NotImplementedException();
private static string GetLogFilePath(BuildInfo buildInfo)
{
@@ -61,15 +68,14 @@ namespace GodotTools
public static bool Build(BuildInfo buildInfo)
{
- if (BuildsInProgress.Contains(buildInfo))
+ if (_buildInProgress != null)
throw new InvalidOperationException("A build is already in progress");
- BuildsInProgress.Add(buildInfo);
+ _buildInProgress = buildInfo;
try
{
- BuildTab buildTab = GodotSharpEditor.Instance.BottomPanel.GetBuildTabFor(buildInfo);
- buildTab.OnBuildStart();
+ BuildStarted?.Invoke(buildInfo);
// Required in order to update the build tasks list
Internal.GodotMainIteration();
@@ -80,44 +86,44 @@ namespace GodotTools
}
catch (IOException e)
{
- buildTab.OnBuildExecFailed($"Cannot remove issues file: {GetIssuesFilePath(buildInfo)}");
+ BuildLaunchFailed?.Invoke(buildInfo, $"Cannot remove issues file: {GetIssuesFilePath(buildInfo)}");
Console.Error.WriteLine(e);
}
try
{
- int exitCode = BuildSystem.Build(buildInfo);
+ int exitCode = BuildSystem.Build(buildInfo, StdOutputReceived, StdErrorReceived);
if (exitCode != 0)
PrintVerbose($"MSBuild exited with code: {exitCode}. Log file: {GetLogFilePath(buildInfo)}");
- buildTab.OnBuildExit(exitCode == 0 ? BuildTab.BuildResults.Success : BuildTab.BuildResults.Error);
+ BuildFinished?.Invoke(exitCode == 0 ? BuildResult.Success : BuildResult.Error);
return exitCode == 0;
}
catch (Exception e)
{
- buildTab.OnBuildExecFailed($"The build method threw an exception.\n{e.GetType().FullName}: {e.Message}");
+ BuildLaunchFailed?.Invoke(buildInfo, $"The build method threw an exception.\n{e.GetType().FullName}: {e.Message}");
Console.Error.WriteLine(e);
return false;
}
}
finally
{
- BuildsInProgress.Remove(buildInfo);
+ _buildInProgress = null;
}
}
public static async Task<bool> BuildAsync(BuildInfo buildInfo)
{
- if (BuildsInProgress.Contains(buildInfo))
+ if (_buildInProgress != null)
throw new InvalidOperationException("A build is already in progress");
- BuildsInProgress.Add(buildInfo);
+ _buildInProgress = buildInfo;
try
{
- BuildTab buildTab = GodotSharpEditor.Instance.BottomPanel.GetBuildTabFor(buildInfo);
+ BuildStarted?.Invoke(buildInfo);
try
{
@@ -125,43 +131,57 @@ namespace GodotTools
}
catch (IOException e)
{
- buildTab.OnBuildExecFailed($"Cannot remove issues file: {GetIssuesFilePath(buildInfo)}");
+ BuildLaunchFailed?.Invoke(buildInfo, $"Cannot remove issues file: {GetIssuesFilePath(buildInfo)}");
Console.Error.WriteLine(e);
}
try
{
- int exitCode = await BuildSystem.BuildAsync(buildInfo);
+ int exitCode = await BuildSystem.BuildAsync(buildInfo, StdOutputReceived, StdErrorReceived);
if (exitCode != 0)
PrintVerbose($"MSBuild exited with code: {exitCode}. Log file: {GetLogFilePath(buildInfo)}");
- buildTab.OnBuildExit(exitCode == 0 ? BuildTab.BuildResults.Success : BuildTab.BuildResults.Error);
+ BuildFinished?.Invoke(exitCode == 0 ? BuildResult.Success : BuildResult.Error);
return exitCode == 0;
}
catch (Exception e)
{
- buildTab.OnBuildExecFailed($"The build method threw an exception.\n{e.GetType().FullName}: {e.Message}");
+ BuildLaunchFailed?.Invoke(buildInfo, $"The build method threw an exception.\n{e.GetType().FullName}: {e.Message}");
Console.Error.WriteLine(e);
return false;
}
}
finally
{
- BuildsInProgress.Remove(buildInfo);
+ _buildInProgress = null;
}
}
- public static bool BuildProjectBlocking(string config, [CanBeNull] string platform = null)
+ public static bool BuildProjectBlocking(string config, [CanBeNull] string[] targets = null, [CanBeNull] string platform = null)
{
- if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
+ var buildInfo = new BuildInfo(GodotSharpDirs.ProjectSlnPath, targets ?? new[] {"Build"}, config, restore: true);
+
+ // If a platform was not specified, try determining the current one. If that fails, let MSBuild auto-detect it.
+ if (platform != null || OS.PlatformNameMap.TryGetValue(Godot.OS.GetName(), out platform))
+ buildInfo.CustomProperties.Add($"GodotTargetPlatform={platform}");
+
+ if (Internal.GodotIsRealTDouble())
+ buildInfo.CustomProperties.Add("GodotRealTIsDouble=true");
+
+ return BuildProjectBlocking(buildInfo);
+ }
+
+ private static bool BuildProjectBlocking(BuildInfo buildInfo)
+ {
+ if (!File.Exists(buildInfo.Solution))
return true; // No solution to build
// Make sure the API assemblies are up to date before building the project.
// We may not have had the chance to update the release API assemblies, and the debug ones
// may have been deleted by the user at some point after they were loaded by the Godot editor.
- string apiAssembliesUpdateError = Internal.UpdateApiAssembliesFromPrebuilt(config == "ExportRelease" ? "Release" : "Debug");
+ string apiAssembliesUpdateError = Internal.UpdateApiAssembliesFromPrebuilt(buildInfo.Configuration == "ExportRelease" ? "Release" : "Debug");
if (!string.IsNullOrEmpty(apiAssembliesUpdateError))
{
@@ -173,15 +193,6 @@ namespace GodotTools
{
pr.Step("Building project solution", 0);
- var buildInfo = new BuildInfo(GodotSharpDirs.ProjectSlnPath, targets: new[] {"Build"}, config, restore: true);
-
- // If a platform was not specified, try determining the current one. If that fails, let MSBuild auto-detect it.
- if (platform != null || OS.PlatformNameMap.TryGetValue(Godot.OS.GetName(), out platform))
- buildInfo.CustomProperties.Add($"GodotTargetPlatform={platform}");
-
- if (Internal.GodotIsRealTDouble())
- buildInfo.CustomProperties.Add("GodotRealTIsDouble=true");
-
if (!Build(buildInfo))
{
ShowBuildErrorDialog("Failed to build project solution");
@@ -197,18 +208,51 @@ namespace GodotTools
if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
return true; // No solution to build
+ try
+ {
+ // Make sure our packages are added to the fallback folder
+ NuGetUtils.AddBundledPackagesToFallbackFolder(NuGetUtils.GodotFallbackFolderPath);
+ }
+ catch (Exception e)
+ {
+ Godot.GD.PushError("Failed to setup Godot NuGet Offline Packages: " + e.Message);
+ }
+
+ GenerateEditorScriptMetadata();
+
+ if (GodotSharpEditor.Instance.SkipBuildBeforePlaying)
+ return true; // Requested play from an external editor/IDE which already built the project
+
+ return BuildProjectBlocking("Debug");
+ }
+
+ // NOTE: This will be replaced with C# source generators in 4.0
+ public static void GenerateEditorScriptMetadata()
+ {
string editorScriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, "scripts_metadata.editor");
string playerScriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, "scripts_metadata.editor_player");
CsProjOperations.GenerateScriptsMetadata(GodotSharpDirs.ProjectCsProjPath, editorScriptsMetadataPath);
- if (File.Exists(editorScriptsMetadataPath))
- File.Copy(editorScriptsMetadataPath, playerScriptsMetadataPath);
+ if (!File.Exists(editorScriptsMetadataPath))
+ return;
- if (GodotSharpEditor.Instance.SkipBuildBeforePlaying)
- return true; // Requested play from an external editor/IDE which already built the project
+ try
+ {
+ File.Copy(editorScriptsMetadataPath, playerScriptsMetadataPath);
+ }
+ catch (IOException e)
+ {
+ throw new IOException("Failed to copy scripts metadata file.", innerException: e);
+ }
+ }
- return BuildProjectBlocking("Debug");
+ // NOTE: This will be replaced with C# source generators in 4.0
+ public static string GenerateExportedGameScriptMetadata(bool isDebug)
+ {
+ string scriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, $"scripts_metadata.{(isDebug ? "debug" : "release")}");
+ CsProjOperations.GenerateScriptsMetadata(GodotSharpDirs.ProjectCsProjPath, scriptsMetadataPath);
+ return scriptsMetadataPath;
}
public static void Initialize()
@@ -254,8 +298,6 @@ namespace GodotTools
["hint"] = Godot.PropertyHint.Enum,
["hint_string"] = hintString
});
-
- EditorDef("mono/builds/print_build_output", false);
}
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
new file mode 100644
index 0000000000..1a1639aac7
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
@@ -0,0 +1,417 @@
+using Godot;
+using System;
+using Godot.Collections;
+using GodotTools.Internals;
+using JetBrains.Annotations;
+using File = GodotTools.Utils.File;
+using Path = System.IO.Path;
+
+namespace GodotTools.Build
+{
+ public class BuildOutputView : VBoxContainer, ISerializationListener
+ {
+ [Serializable]
+ private class BuildIssue : Reference // TODO Remove Reference once we have proper serialization
+ {
+ public bool Warning { get; set; }
+ public string File { get; set; }
+ public int Line { get; set; }
+ public int Column { get; set; }
+ public string Code { get; set; }
+ public string Message { get; set; }
+ public string ProjectFile { get; set; }
+ }
+
+ private readonly Array<BuildIssue> issues = new Array<BuildIssue>(); // TODO Use List once we have proper serialization
+ private ItemList issuesList;
+ private TextEdit buildLog;
+ private PopupMenu issuesListContextMenu;
+
+ private readonly object pendingBuildLogTextLock = new object();
+ [NotNull] private string pendingBuildLogText = string.Empty;
+
+ [Signal] public event Action BuildStateChanged;
+
+ public bool HasBuildExited { get; private set; } = false;
+
+ public BuildResult? BuildResult { get; private set; } = null;
+
+ public int ErrorCount { get; private set; } = 0;
+
+ public int WarningCount { get; private set; } = 0;
+
+ public bool ErrorsVisible { get; set; } = true;
+ public bool WarningsVisible { get; set; } = true;
+
+ public Texture2D BuildStateIcon
+ {
+ get
+ {
+ if (!HasBuildExited)
+ return GetThemeIcon("Stop", "EditorIcons");
+
+ if (BuildResult == Build.BuildResult.Error)
+ return GetThemeIcon("Error", "EditorIcons");
+
+ if (WarningCount > 1)
+ return GetThemeIcon("Warning", "EditorIcons");
+
+ return null;
+ }
+ }
+
+ private BuildInfo BuildInfo { get; set; }
+
+ public bool LogVisible
+ {
+ set => buildLog.Visible = value;
+ }
+
+ private void LoadIssuesFromFile(string csvFile)
+ {
+ using (var file = new Godot.File())
+ {
+ try
+ {
+ Error openError = file.Open(csvFile, Godot.File.ModeFlags.Read);
+
+ if (openError != Error.Ok)
+ return;
+
+ while (!file.EofReached())
+ {
+ string[] csvColumns = file.GetCsvLine();
+
+ if (csvColumns.Length == 1 && string.IsNullOrEmpty(csvColumns[0]))
+ return;
+
+ if (csvColumns.Length != 7)
+ {
+ GD.PushError($"Expected 7 columns, got {csvColumns.Length}");
+ continue;
+ }
+
+ var issue = new BuildIssue
+ {
+ Warning = csvColumns[0] == "warning",
+ File = csvColumns[1],
+ Line = int.Parse(csvColumns[2]),
+ Column = int.Parse(csvColumns[3]),
+ Code = csvColumns[4],
+ Message = csvColumns[5],
+ ProjectFile = csvColumns[6]
+ };
+
+ if (issue.Warning)
+ WarningCount += 1;
+ else
+ ErrorCount += 1;
+
+ issues.Add(issue);
+ }
+ }
+ finally
+ {
+ file.Close(); // Disposing it is not enough. We need to call Close()
+ }
+ }
+ }
+
+ private void IssueActivated(int idx)
+ {
+ if (idx < 0 || idx >= issuesList.GetItemCount())
+ throw new IndexOutOfRangeException("Item list index out of range");
+
+ // Get correct issue idx from issue list
+ int issueIndex = (int)(long)issuesList.GetItemMetadata(idx);
+
+ if (issueIndex < 0 || issueIndex >= issues.Count)
+ throw new IndexOutOfRangeException("Issue index out of range");
+
+ BuildIssue issue = issues[issueIndex];
+
+ if (string.IsNullOrEmpty(issue.ProjectFile) && string.IsNullOrEmpty(issue.File))
+ return;
+
+ string projectDir = issue.ProjectFile.Length > 0 ? issue.ProjectFile.GetBaseDir() : BuildInfo.Solution.GetBaseDir();
+
+ string file = Path.Combine(projectDir.SimplifyGodotPath(), issue.File.SimplifyGodotPath());
+
+ if (!File.Exists(file))
+ return;
+
+ file = ProjectSettings.LocalizePath(file);
+
+ if (file.StartsWith("res://"))
+ {
+ var script = (Script)ResourceLoader.Load(file, typeHint: Internal.CSharpLanguageType);
+
+ if (script != null && Internal.ScriptEditorEdit(script, issue.Line, issue.Column))
+ Internal.EditorNodeShowScriptScreen();
+ }
+ }
+
+ public void UpdateIssuesList()
+ {
+ issuesList.Clear();
+
+ using (var warningIcon = GetThemeIcon("Warning", "EditorIcons"))
+ using (var errorIcon = GetThemeIcon("Error", "EditorIcons"))
+ {
+ for (int i = 0; i < issues.Count; i++)
+ {
+ BuildIssue issue = issues[i];
+
+ if (!(issue.Warning ? WarningsVisible : ErrorsVisible))
+ continue;
+
+ string tooltip = string.Empty;
+ tooltip += $"Message: {issue.Message}";
+
+ if (!string.IsNullOrEmpty(issue.Code))
+ tooltip += $"\nCode: {issue.Code}";
+
+ tooltip += $"\nType: {(issue.Warning ? "warning" : "error")}";
+
+ string text = string.Empty;
+
+ if (!string.IsNullOrEmpty(issue.File))
+ {
+ text += $"{issue.File}({issue.Line},{issue.Column}): ";
+
+ tooltip += $"\nFile: {issue.File}";
+ tooltip += $"\nLine: {issue.Line}";
+ tooltip += $"\nColumn: {issue.Column}";
+ }
+
+ if (!string.IsNullOrEmpty(issue.ProjectFile))
+ tooltip += $"\nProject: {issue.ProjectFile}";
+
+ text += issue.Message;
+
+ int lineBreakIdx = text.IndexOf("\n", StringComparison.Ordinal);
+ string itemText = lineBreakIdx == -1 ? text : text.Substring(0, lineBreakIdx);
+ issuesList.AddItem(itemText, issue.Warning ? warningIcon : errorIcon);
+
+ int index = issuesList.GetItemCount() - 1;
+ issuesList.SetItemTooltip(index, tooltip);
+ issuesList.SetItemMetadata(index, i);
+ }
+ }
+ }
+
+ private void BuildLaunchFailed(BuildInfo buildInfo, string cause)
+ {
+ HasBuildExited = true;
+ BuildResult = Build.BuildResult.Error;
+
+ issuesList.Clear();
+
+ var issue = new BuildIssue {Message = cause, Warning = false};
+
+ ErrorCount += 1;
+ issues.Add(issue);
+
+ UpdateIssuesList();
+
+ EmitSignal(nameof(BuildStateChanged));
+ }
+
+ private void BuildStarted(BuildInfo buildInfo)
+ {
+ BuildInfo = buildInfo;
+ HasBuildExited = false;
+
+ issues.Clear();
+ WarningCount = 0;
+ ErrorCount = 0;
+ buildLog.Text = string.Empty;
+
+ UpdateIssuesList();
+
+ EmitSignal(nameof(BuildStateChanged));
+ }
+
+ private void BuildFinished(BuildResult result)
+ {
+ HasBuildExited = true;
+ BuildResult = result;
+
+ LoadIssuesFromFile(Path.Combine(BuildInfo.LogsDirPath, BuildManager.MsBuildIssuesFileName));
+
+ UpdateIssuesList();
+
+ EmitSignal(nameof(BuildStateChanged));
+ }
+
+ private void UpdateBuildLogText()
+ {
+ lock (pendingBuildLogTextLock)
+ {
+ buildLog.Text += pendingBuildLogText;
+ pendingBuildLogText = string.Empty;
+ ScrollToLastNonEmptyLogLine();
+ }
+ }
+
+ private void StdOutputReceived(string text)
+ {
+ lock (pendingBuildLogTextLock)
+ {
+ if (pendingBuildLogText.Length == 0)
+ CallDeferred(nameof(UpdateBuildLogText));
+ pendingBuildLogText += text + "\n";
+ }
+ }
+
+ private void StdErrorReceived(string text)
+ {
+ lock (pendingBuildLogTextLock)
+ {
+ if (pendingBuildLogText.Length == 0)
+ CallDeferred(nameof(UpdateBuildLogText));
+ pendingBuildLogText += text + "\n";
+ }
+ }
+
+ private void ScrollToLastNonEmptyLogLine()
+ {
+ int line;
+ for (line = buildLog.GetLineCount(); line > 0; line--)
+ {
+ string lineText = buildLog.GetLine(line);
+
+ if (!string.IsNullOrEmpty(lineText) || !string.IsNullOrEmpty(lineText?.Trim()))
+ break;
+ }
+
+ buildLog.CursorSetLine(line);
+ }
+
+ public void RestartBuild()
+ {
+ if (!HasBuildExited)
+ throw new InvalidOperationException("Build already started");
+
+ BuildManager.RestartBuild(this);
+ }
+
+ public void StopBuild()
+ {
+ if (!HasBuildExited)
+ throw new InvalidOperationException("Build is not in progress");
+
+ BuildManager.StopBuild(this);
+ }
+
+ private enum IssuesContextMenuOption
+ {
+ Copy
+ }
+
+ private void IssuesListContextOptionPressed(int id)
+ {
+ switch ((IssuesContextMenuOption)id)
+ {
+ case IssuesContextMenuOption.Copy:
+ {
+ // We don't allow multi-selection but just in case that changes later...
+ string text = null;
+
+ foreach (int issueIndex in issuesList.GetSelectedItems())
+ {
+ if (text != null)
+ text += "\n";
+ text += issuesList.GetItemText(issueIndex);
+ }
+
+ if (text != null)
+ DisplayServer.ClipboardSet(text);
+ break;
+ }
+ default:
+ throw new ArgumentOutOfRangeException(nameof(id), id, "Invalid issue context menu option");
+ }
+ }
+
+ private void IssuesListRmbSelected(int index, Vector2 atPosition)
+ {
+ _ = index; // Unused
+
+ issuesListContextMenu.Clear();
+ issuesListContextMenu.Size = new Vector2i(1, 1);
+
+ if (issuesList.IsAnythingSelected())
+ {
+ // Add menu entries for the selected item
+ issuesListContextMenu.AddIconItem(GetThemeIcon("ActionCopy", "EditorIcons"),
+ label: "Copy Error".TTR(), (int)IssuesContextMenuOption.Copy);
+ }
+
+ if (issuesListContextMenu.GetItemCount() > 0)
+ {
+ issuesListContextMenu.Position = (Vector2i)(issuesList.RectGlobalPosition + atPosition);
+ issuesListContextMenu.Popup();
+ }
+ }
+
+ public override void _Ready()
+ {
+ base._Ready();
+
+ SizeFlagsVertical = (int)SizeFlags.ExpandFill;
+
+ var hsc = new HSplitContainer
+ {
+ SizeFlagsHorizontal = (int)SizeFlags.ExpandFill,
+ SizeFlagsVertical = (int)SizeFlags.ExpandFill
+ };
+ AddChild(hsc);
+
+ issuesList = new ItemList
+ {
+ SizeFlagsVertical = (int)SizeFlags.ExpandFill,
+ SizeFlagsHorizontal = (int)SizeFlags.ExpandFill // Avoid being squashed by the build log
+ };
+ issuesList.ItemActivated += IssueActivated;
+ issuesList.AllowRmbSelect = true;
+ issuesList.ItemRmbSelected += IssuesListRmbSelected;
+ hsc.AddChild(issuesList);
+
+ issuesListContextMenu = new PopupMenu();
+ issuesListContextMenu.IdPressed += IssuesListContextOptionPressed;
+ issuesList.AddChild(issuesListContextMenu);
+
+ buildLog = new TextEdit
+ {
+ Readonly = true,
+ SizeFlagsVertical = (int)SizeFlags.ExpandFill,
+ SizeFlagsHorizontal = (int)SizeFlags.ExpandFill // Avoid being squashed by the issues list
+ };
+ hsc.AddChild(buildLog);
+
+ AddBuildEventListeners();
+ }
+
+ private void AddBuildEventListeners()
+ {
+ BuildManager.BuildLaunchFailed += BuildLaunchFailed;
+ BuildManager.BuildStarted += BuildStarted;
+ BuildManager.BuildFinished += BuildFinished;
+ // StdOutput/Error can be received from different threads, so we need to use CallDeferred
+ BuildManager.StdOutputReceived += StdOutputReceived;
+ BuildManager.StdErrorReceived += StdErrorReceived;
+ }
+
+ public void OnBeforeSerialize()
+ {
+ // In case it didn't update yet. We don't want to have to serialize any pending output.
+ UpdateBuildLogText();
+ }
+
+ public void OnAfterDeserialize()
+ {
+ AddBuildEventListeners(); // Re-add them
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildResult.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildResult.cs
new file mode 100644
index 0000000000..59055b60c3
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildResult.cs
@@ -0,0 +1,8 @@
+namespace GodotTools.Build
+{
+ public enum BuildResult
+ {
+ Error,
+ Success
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
index d9862ae361..bac7a2e6db 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
@@ -44,10 +44,7 @@ namespace GodotTools.Build
}
}
- private static bool PrintBuildOutput =>
- (bool)EditorSettings.GetSetting("mono/builds/print_build_output");
-
- private static Process LaunchBuild(BuildInfo buildInfo)
+ private static Process LaunchBuild(BuildInfo buildInfo, Action<string> stdOutHandler, Action<string> stdErrHandler)
{
(string msbuildPath, BuildTool buildTool) = MsBuildFinder.FindMsBuild();
@@ -58,13 +55,13 @@ namespace GodotTools.Build
var startInfo = new ProcessStartInfo(msbuildPath, compilerArgs);
- bool redirectOutput = !IsDebugMsBuildRequested() && !PrintBuildOutput;
-
- if (!redirectOutput || Godot.OS.IsStdoutVerbose())
- Console.WriteLine($"Running: \"{startInfo.FileName}\" {startInfo.Arguments}");
+ string launchMessage = $"Running: \"{startInfo.FileName}\" {startInfo.Arguments}";
+ stdOutHandler?.Invoke(launchMessage);
+ if (Godot.OS.IsStdoutVerbose())
+ Console.WriteLine(launchMessage);
- startInfo.RedirectStandardOutput = redirectOutput;
- startInfo.RedirectStandardError = redirectOutput;
+ startInfo.RedirectStandardOutput = true;
+ startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
if (UsingMonoMsBuildOnWindows)
@@ -82,20 +79,22 @@ namespace GodotTools.Build
var process = new Process {StartInfo = startInfo};
+ if (stdOutHandler != null)
+ process.OutputDataReceived += (s, e) => stdOutHandler.Invoke(e.Data);
+ if (stdErrHandler != null)
+ process.ErrorDataReceived += (s, e) => stdErrHandler.Invoke(e.Data);
+
process.Start();
- if (redirectOutput)
- {
- process.BeginOutputReadLine();
- process.BeginErrorReadLine();
- }
+ process.BeginOutputReadLine();
+ process.BeginErrorReadLine();
return process;
}
- public static int Build(BuildInfo buildInfo)
+ public static int Build(BuildInfo buildInfo, Action<string> stdOutHandler, Action<string> stdErrHandler)
{
- using (var process = LaunchBuild(buildInfo))
+ using (var process = LaunchBuild(buildInfo, stdOutHandler, stdErrHandler))
{
process.WaitForExit();
@@ -103,9 +102,9 @@ namespace GodotTools.Build
}
}
- public static async Task<int> BuildAsync(BuildInfo buildInfo)
+ public static async Task<int> BuildAsync(BuildInfo buildInfo, Action<string> stdOutHandler, Action<string> stdErrHandler)
{
- using (var process = LaunchBuild(buildInfo))
+ using (var process = LaunchBuild(buildInfo, stdOutHandler, stdErrHandler))
{
await process.WaitForExitAsync();
@@ -152,10 +151,5 @@ namespace GodotTools.Build
foreach (string env in platformEnvironmentVariables)
environmentVariables.Remove(env);
}
-
- private static bool IsDebugMsBuildRequested()
- {
- return Environment.GetEnvironmentVariable("GODOT_DEBUG_MSBUILD")?.Trim() == "1";
- }
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
new file mode 100644
index 0000000000..708ec73454
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
@@ -0,0 +1,185 @@
+using System;
+using Godot;
+using GodotTools.Internals;
+using JetBrains.Annotations;
+using static GodotTools.Internals.Globals;
+using File = GodotTools.Utils.File;
+
+namespace GodotTools.Build
+{
+ public class MSBuildPanel : VBoxContainer
+ {
+ public BuildOutputView BuildOutputView { get; private set; }
+
+ private Button errorsBtn;
+ private Button warningsBtn;
+ private Button viewLogBtn;
+
+ private void WarningsToggled(bool pressed)
+ {
+ BuildOutputView.WarningsVisible = pressed;
+ BuildOutputView.UpdateIssuesList();
+ }
+
+ private void ErrorsToggled(bool pressed)
+ {
+ BuildOutputView.ErrorsVisible = pressed;
+ BuildOutputView.UpdateIssuesList();
+ }
+
+ [UsedImplicitly]
+ public void BuildSolution()
+ {
+ if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
+ return; // No solution to build
+
+ try
+ {
+ // Make sure our packages are added to the fallback folder
+ NuGetUtils.AddBundledPackagesToFallbackFolder(NuGetUtils.GodotFallbackFolderPath);
+ }
+ catch (Exception e)
+ {
+ GD.PushError("Failed to setup Godot NuGet Offline Packages: " + e.Message);
+ }
+
+ BuildManager.GenerateEditorScriptMetadata();
+
+ if (!BuildManager.BuildProjectBlocking("Debug"))
+ return; // Build failed
+
+ // Notify running game for hot-reload
+ Internal.EditorDebuggerNodeReloadScripts();
+
+ // Hot-reload in the editor
+ GodotSharpEditor.Instance.GetNode<HotReloadAssemblyWatcher>("HotReloadAssemblyWatcher").RestartTimer();
+
+ if (Internal.IsAssembliesReloadingNeeded())
+ Internal.ReloadAssemblies(softReload: false);
+ }
+
+ [UsedImplicitly]
+ private void RebuildSolution()
+ {
+ if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
+ return; // No solution to build
+
+ try
+ {
+ // Make sure our packages are added to the fallback folder
+ NuGetUtils.AddBundledPackagesToFallbackFolder(NuGetUtils.GodotFallbackFolderPath);
+ }
+ catch (Exception e)
+ {
+ GD.PushError("Failed to setup Godot NuGet Offline Packages: " + e.Message);
+ }
+
+ BuildManager.GenerateEditorScriptMetadata();
+
+ if (!BuildManager.BuildProjectBlocking("Debug", targets: new[] {"Rebuild"}))
+ return; // Build failed
+
+ // Notify running game for hot-reload
+ Internal.EditorDebuggerNodeReloadScripts();
+
+ // Hot-reload in the editor
+ GodotSharpEditor.Instance.GetNode<HotReloadAssemblyWatcher>("HotReloadAssemblyWatcher").RestartTimer();
+
+ if (Internal.IsAssembliesReloadingNeeded())
+ Internal.ReloadAssemblies(softReload: false);
+ }
+
+ [UsedImplicitly]
+ private void CleanSolution()
+ {
+ if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
+ return; // No solution to build
+
+ BuildManager.BuildProjectBlocking("Debug", targets: new[] {"Clean"});
+ }
+
+ private void ViewLogToggled(bool pressed) => BuildOutputView.LogVisible = pressed;
+
+ private void BuildMenuOptionPressed(int id)
+ {
+ switch ((BuildMenuOptions)id)
+ {
+ case BuildMenuOptions.BuildSolution:
+ BuildSolution();
+ break;
+ case BuildMenuOptions.RebuildSolution:
+ RebuildSolution();
+ break;
+ case BuildMenuOptions.CleanSolution:
+ CleanSolution();
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(id), id, "Invalid build menu option");
+ }
+ }
+
+ private enum BuildMenuOptions
+ {
+ BuildSolution,
+ RebuildSolution,
+ CleanSolution
+ }
+
+ public override void _Ready()
+ {
+ base._Ready();
+
+ RectMinSize = new Vector2(0, 228) * EditorScale;
+ SizeFlagsVertical = (int)SizeFlags.ExpandFill;
+
+ var toolBarHBox = new HBoxContainer {SizeFlagsHorizontal = (int)SizeFlags.ExpandFill};
+ AddChild(toolBarHBox);
+
+ var buildMenuBtn = new MenuButton {Text = "Build", Icon = GetThemeIcon("Play", "EditorIcons")};
+ toolBarHBox.AddChild(buildMenuBtn);
+
+ var buildMenu = buildMenuBtn.GetPopup();
+ buildMenu.AddItem("Build Solution".TTR(), (int)BuildMenuOptions.BuildSolution);
+ buildMenu.AddItem("Rebuild Solution".TTR(), (int)BuildMenuOptions.RebuildSolution);
+ buildMenu.AddItem("Clean Solution".TTR(), (int)BuildMenuOptions.CleanSolution);
+ buildMenu.IdPressed += BuildMenuOptionPressed;
+
+ errorsBtn = new Button
+ {
+ HintTooltip = "Show Errors".TTR(),
+ Icon = GetThemeIcon("StatusError", "EditorIcons"),
+ ExpandIcon = false,
+ ToggleMode = true,
+ Pressed = true,
+ FocusMode = FocusModeEnum.None
+ };
+ errorsBtn.Toggled += ErrorsToggled;
+ toolBarHBox.AddChild(errorsBtn);
+
+ warningsBtn = new Button
+ {
+ HintTooltip = "Show Warnings".TTR(),
+ Icon = GetThemeIcon("NodeWarning", "EditorIcons"),
+ ExpandIcon = false,
+ ToggleMode = true,
+ Pressed = true,
+ FocusMode = FocusModeEnum.None
+ };
+ warningsBtn.Toggled += WarningsToggled;
+ toolBarHBox.AddChild(warningsBtn);
+
+ viewLogBtn = new Button
+ {
+ Text = "Show Output".TTR(),
+ ToggleMode = true,
+ Pressed = true,
+ FocusMode = FocusModeEnum.None
+ };
+ viewLogBtn.Toggled += ViewLogToggled;
+ toolBarHBox.AddChild(viewLogBtn);
+
+ BuildOutputView = new BuildOutputView();
+ AddChild(BuildOutputView);
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs b/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs
index 93aae2e03e..5ef55fea49 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs
@@ -31,7 +31,7 @@ namespace GodotTools.Build
string dotnetCliPath = OS.PathWhich("dotnet");
if (!string.IsNullOrEmpty(dotnetCliPath))
return (dotnetCliPath, BuildTool.DotnetCli);
- GD.PushError("Cannot find dotnet CLI executable. Fallback to MSBuild from Visual Studio.");
+ GD.PushError($"Cannot find executable for '{BuildManager.PropNameDotnetCli}'. Fallback to MSBuild from Visual Studio.");
goto case BuildTool.MsBuildVs;
}
case BuildTool.MsBuildVs:
@@ -89,7 +89,7 @@ namespace GodotTools.Build
string dotnetCliPath = OS.PathWhich("dotnet");
if (!string.IsNullOrEmpty(dotnetCliPath))
return (dotnetCliPath, BuildTool.DotnetCli);
- GD.PushError("Cannot find dotnet CLI executable. Fallback to MSBuild from Mono.");
+ GD.PushError($"Cannot find executable for '{BuildManager.PropNameDotnetCli}'. Fallback to MSBuild from Mono.");
goto case BuildTool.MsBuildMono;
}
case BuildTool.MsBuildMono:
@@ -161,7 +161,7 @@ namespace GodotTools.Build
// Try to find 15.0 with vswhere
- var envNames = Internal.GodotIs32Bits() ? new[] { "ProgramFiles", "ProgramW6432" } : new[] { "ProgramFiles(x86)", "ProgramFiles" };
+ var envNames = Internal.GodotIs32Bits() ? new[] {"ProgramFiles", "ProgramW6432"} : new[] {"ProgramFiles(x86)", "ProgramFiles"};
string vsWherePath = null;
foreach (var envName in envNames)
@@ -181,7 +181,7 @@ namespace GodotTools.Build
var outputArray = new Godot.Collections.Array<string>();
int exitCode = Godot.OS.Execute(vsWherePath, vsWhereArgs,
- blocking: true, output: (Godot.Collections.Array)outputArray);
+ output: (Godot.Collections.Array)outputArray);
if (exitCode != 0)
return string.Empty;
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs b/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs
new file mode 100644
index 0000000000..793ef7fd71
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs
@@ -0,0 +1,296 @@
+using System;
+using System.IO;
+using System.IO.Compression;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
+using System.Xml;
+using Godot;
+using GodotTools.Internals;
+using GodotTools.Shared;
+using Directory = GodotTools.Utils.Directory;
+using Environment = System.Environment;
+using File = GodotTools.Utils.File;
+
+namespace GodotTools.Build
+{
+ public static class NuGetUtils
+ {
+ public const string GodotFallbackFolderName = "Godot Offline Packages";
+
+ public static string GodotFallbackFolderPath
+ => Path.Combine(GodotSharpDirs.MonoUserDir, "GodotNuGetFallbackFolder");
+
+ private static void AddFallbackFolderToNuGetConfig(string nuGetConfigPath, string name, string path)
+ {
+ var xmlDoc = new XmlDocument();
+ xmlDoc.Load(nuGetConfigPath);
+
+ const string nuGetConfigRootName = "configuration";
+
+ var rootNode = xmlDoc.DocumentElement;
+
+ if (rootNode == null)
+ {
+ // No root node, create it
+ rootNode = xmlDoc.CreateElement(nuGetConfigRootName);
+ xmlDoc.AppendChild(rootNode);
+
+ // Since this can be considered pretty much a new NuGet.Config, add the default nuget.org source as well
+ XmlElement nugetOrgSourceEntry = xmlDoc.CreateElement("add");
+ nugetOrgSourceEntry.Attributes.Append(xmlDoc.CreateAttribute("key")).Value = "nuget.org";
+ nugetOrgSourceEntry.Attributes.Append(xmlDoc.CreateAttribute("value")).Value = "https://api.nuget.org/v3/index.json";
+ nugetOrgSourceEntry.Attributes.Append(xmlDoc.CreateAttribute("protocolVersion")).Value = "3";
+ rootNode.AppendChild(xmlDoc.CreateElement("packageSources")).AppendChild(nugetOrgSourceEntry);
+ }
+ else
+ {
+ // Check that the root node is the expected one
+ if (rootNode.Name != nuGetConfigRootName)
+ throw new Exception("Invalid root Xml node for NuGet.Config. " +
+ $"Expected '{nuGetConfigRootName}' got '{rootNode.Name}'.");
+ }
+
+ var fallbackFoldersNode = rootNode["fallbackPackageFolders"] ??
+ rootNode.AppendChild(xmlDoc.CreateElement("fallbackPackageFolders"));
+
+ // Check if it already has our fallback package folder
+ for (var xmlNode = fallbackFoldersNode.FirstChild; xmlNode != null; xmlNode = xmlNode.NextSibling)
+ {
+ if (xmlNode.NodeType != XmlNodeType.Element)
+ continue;
+
+ var xmlElement = (XmlElement)xmlNode;
+ if (xmlElement.Name == "add" &&
+ xmlElement.Attributes["key"]?.Value == name &&
+ xmlElement.Attributes["value"]?.Value == path)
+ {
+ return;
+ }
+ }
+
+ XmlElement newEntry = xmlDoc.CreateElement("add");
+ newEntry.Attributes.Append(xmlDoc.CreateAttribute("key")).Value = name;
+ newEntry.Attributes.Append(xmlDoc.CreateAttribute("value")).Value = path;
+
+ fallbackFoldersNode.AppendChild(newEntry);
+
+ xmlDoc.Save(nuGetConfigPath);
+ }
+
+ /// <summary>
+ /// Returns all the paths where the user NuGet.Config files can be found.
+ /// Does not determine whether the returned files exist or not.
+ /// </summary>
+ private static string[] GetAllUserNuGetConfigFilePaths()
+ {
+ // Where to find 'NuGet/NuGet.Config':
+ //
+ // - Mono/.NETFramework (standalone NuGet):
+ // Uses Environment.SpecialFolder.ApplicationData
+ // - Windows: '%APPDATA%'
+ // - Linux/macOS: '$HOME/.config'
+ // - CoreCLR (dotnet CLI NuGet):
+ // - Windows: '%APPDATA%'
+ // - Linux/macOS: '$DOTNET_CLI_HOME/.nuget' otherwise '$HOME/.nuget'
+
+ string applicationData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
+
+ if (Utils.OS.IsWindows)
+ {
+ // %APPDATA% for both
+ return new[] {Path.Combine(applicationData, "NuGet", "NuGet.Config")};
+ }
+
+ var paths = new string[2];
+
+ // CoreCLR (dotnet CLI NuGet)
+
+ string dotnetCliHome = Environment.GetEnvironmentVariable("DOTNET_CLI_HOME");
+ if (!string.IsNullOrEmpty(dotnetCliHome))
+ {
+ paths[0] = Path.Combine(dotnetCliHome, ".nuget", "NuGet", "NuGet.Config");
+ }
+ else
+ {
+ string home = Environment.GetEnvironmentVariable("HOME");
+ if (string.IsNullOrEmpty(home))
+ throw new InvalidOperationException("Required environment variable 'HOME' is not set.");
+ paths[0] = Path.Combine(home, ".nuget", "NuGet", "NuGet.Config");
+ }
+
+ // Mono/.NETFramework (standalone NuGet)
+
+ // ApplicationData is $HOME/.config on Linux/macOS
+ paths[1] = Path.Combine(applicationData, "NuGet", "NuGet.Config");
+
+ return paths;
+ }
+
+ // nupkg extraction
+ //
+ // Exclude: (NuGet.Client -> NuGet.Packaging.PackageHelper.ExcludePaths)
+ // package/
+ // _rels/
+ // [Content_Types].xml
+ //
+ // Don't ignore files that begin with a dot (.)
+ //
+ // The nuspec is not lower case inside the nupkg but must be made lower case when extracted.
+
+ /// <summary>
+ /// Adds the specified fallback folder to the user NuGet.Config files,
+ /// for both standalone NuGet (Mono/.NETFramework) and dotnet CLI NuGet.
+ /// </summary>
+ public static void AddFallbackFolderToUserNuGetConfigs(string name, string path)
+ {
+ foreach (string nuGetConfigPath in GetAllUserNuGetConfigFilePaths())
+ {
+ if (!System.IO.File.Exists(nuGetConfigPath))
+ {
+ // It doesn't exist, so we create a default one
+ const string defaultConfig = @"<?xml version=""1.0"" encoding=""utf-8""?>
+<configuration>
+ <packageSources>
+ <add key=""nuget.org"" value=""https://api.nuget.org/v3/index.json"" protocolVersion=""3"" />
+ </packageSources>
+</configuration>
+";
+ System.IO.File.WriteAllText(nuGetConfigPath, defaultConfig, Encoding.UTF8); // UTF-8 with BOM
+ }
+
+ AddFallbackFolderToNuGetConfig(nuGetConfigPath, name, path);
+ }
+ }
+
+ private static void AddPackageToFallbackFolder(string fallbackFolder,
+ string nupkgPath, string packageId, string packageVersion)
+ {
+ // dotnet CLI provides no command for this, but we can do it manually.
+ //
+ // - The expected structure is as follows:
+ // fallback_folder/
+ // <package.name>/<version>/
+ // <package.name>.<version>.nupkg
+ // <package.name>.<version>.nupkg.sha512
+ // <package.name>.nuspec
+ // ... extracted nupkg files (check code for excluded files) ...
+ //
+ // - <package.name> and <version> must be in lower case.
+ // - The sha512 of the nupkg is base64 encoded.
+ // - We can get the nuspec from the nupkg which is a Zip file.
+
+ string packageIdLower = packageId.ToLower();
+ string packageVersionLower = packageVersion.ToLower();
+
+ string destDir = Path.Combine(fallbackFolder, packageIdLower, packageVersionLower);
+ string nupkgDestPath = Path.Combine(destDir, $"{packageIdLower}.{packageVersionLower}.nupkg");
+ string nupkgSha512DestPath = Path.Combine(destDir, $"{packageIdLower}.{packageVersionLower}.nupkg.sha512");
+
+ if (File.Exists(nupkgDestPath) && File.Exists(nupkgSha512DestPath))
+ return; // Already added (for speed we don't check if every file is properly extracted)
+
+ Directory.CreateDirectory(destDir);
+
+ // Generate .nupkg.sha512 file
+
+ using (var alg = SHA512.Create())
+ {
+ alg.ComputeHash(File.ReadAllBytes(nupkgPath));
+ string base64Hash = Convert.ToBase64String(alg.Hash);
+ File.WriteAllText(nupkgSha512DestPath, base64Hash);
+ }
+
+ // Extract nupkg
+ ExtractNupkg(destDir, nupkgPath, packageId, packageVersion);
+
+ // Copy .nupkg
+ File.Copy(nupkgPath, nupkgDestPath);
+ }
+
+ private static readonly string[] NupkgExcludePaths =
+ {
+ "_rels/",
+ "package/",
+ "[Content_Types].xml"
+ };
+
+ private static void ExtractNupkg(string destDir, string nupkgPath, string packageId, string packageVersion)
+ {
+ // NOTE: Must use SimplifyGodotPath to make sure we don't extract files outside the destination directory.
+
+ using (var archive = ZipFile.OpenRead(nupkgPath))
+ {
+ // Extract .nuspec manually as it needs to be in lower case
+
+ var nuspecEntry = archive.GetEntry(packageId + ".nuspec");
+
+ if (nuspecEntry == null)
+ throw new InvalidOperationException($"Failed to extract package {packageId}.{packageVersion}. Could not find the nuspec file.");
+
+ nuspecEntry.ExtractToFile(Path.Combine(destDir, nuspecEntry.Name.ToLower().SimplifyGodotPath()));
+
+ // Extract the other package files
+
+ foreach (var entry in archive.Entries)
+ {
+ // NOTE: SimplifyGodotPath() removes trailing slash and backslash,
+ // so we can't use the result to check if the entry is a directory.
+
+ string entryFullName = entry.FullName.Replace('\\', '/');
+
+ // Check if the file must be ignored
+ if ( // Excluded files.
+ NupkgExcludePaths.Any(e => entryFullName.StartsWith(e, StringComparison.OrdinalIgnoreCase)) ||
+ // Nupkg hash files and nupkg metadata files on all directory.
+ entryFullName.EndsWith(".nupkg.sha512", StringComparison.OrdinalIgnoreCase) ||
+ entryFullName.EndsWith(".nupkg.metadata", StringComparison.OrdinalIgnoreCase) ||
+ // Nuspec at root level. We already extracted it previously but in lower case.
+ entryFullName.IndexOf('/') == -1 && entryFullName.EndsWith(".nuspec"))
+ {
+ continue;
+ }
+
+ string entryFullNameSimplified = entryFullName.SimplifyGodotPath();
+ string destFilePath = Path.Combine(destDir, entryFullNameSimplified);
+ bool isDir = entryFullName.EndsWith("/");
+
+ if (isDir)
+ {
+ Directory.CreateDirectory(destFilePath);
+ }
+ else
+ {
+ Directory.CreateDirectory(Path.GetDirectoryName(destFilePath));
+ entry.ExtractToFile(destFilePath, overwrite: true);
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Copies and extracts all the Godot bundled packages to the Godot NuGet fallback folder.
+ /// Does nothing if the packages were already copied.
+ /// </summary>
+ public static void AddBundledPackagesToFallbackFolder(string fallbackFolder)
+ {
+ GD.Print("Copying Godot Offline Packages...");
+
+ string nupkgsLocation = Path.Combine(GodotSharpDirs.DataEditorToolsDir, "nupkgs");
+
+ void AddPackage(string packageId, string packageVersion)
+ {
+ string nupkgPath = Path.Combine(nupkgsLocation, $"{packageId}.{packageVersion}.nupkg");
+ AddPackageToFallbackFolder(fallbackFolder, nupkgPath, packageId, packageVersion);
+ }
+
+ foreach (var (packageId, packageVersion) in PackagesToAdd)
+ AddPackage(packageId, packageVersion);
+ }
+
+ private static readonly (string packageId, string packageVersion)[] PackagesToAdd =
+ {
+ ("Godot.NET.Sdk", GeneratedGodotNupkgsVersions.GodotNETSdk)
+ };
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/BuildTab.cs b/modules/mono/editor/GodotTools/GodotTools/BuildTab.cs
deleted file mode 100644
index 8596cd24af..0000000000
--- a/modules/mono/editor/GodotTools/GodotTools/BuildTab.cs
+++ /dev/null
@@ -1,267 +0,0 @@
-using Godot;
-using System;
-using Godot.Collections;
-using GodotTools.Internals;
-using File = GodotTools.Utils.File;
-using Path = System.IO.Path;
-
-namespace GodotTools
-{
- public class BuildTab : VBoxContainer
- {
- public enum BuildResults
- {
- Error,
- Success
- }
-
- [Serializable]
- private class BuildIssue : Reference // TODO Remove Reference once we have proper serialization
- {
- public bool Warning { get; set; }
- public string File { get; set; }
- public int Line { get; set; }
- public int Column { get; set; }
- public string Code { get; set; }
- public string Message { get; set; }
- public string ProjectFile { get; set; }
- }
-
- private readonly Array<BuildIssue> issues = new Array<BuildIssue>(); // TODO Use List once we have proper serialization
- private ItemList issuesList;
-
- public bool BuildExited { get; private set; } = false;
-
- public BuildResults? BuildResult { get; private set; } = null;
-
- public int ErrorCount { get; private set; } = 0;
-
- public int WarningCount { get; private set; } = 0;
-
- public bool ErrorsVisible { get; set; } = true;
- public bool WarningsVisible { get; set; } = true;
-
- public Texture2D IconTexture
- {
- get
- {
- if (!BuildExited)
- return GetThemeIcon("Stop", "EditorIcons");
-
- if (BuildResult == BuildResults.Error)
- return GetThemeIcon("StatusError", "EditorIcons");
-
- return GetThemeIcon("StatusSuccess", "EditorIcons");
- }
- }
-
- public BuildInfo BuildInfo { get; private set; }
-
- private void _LoadIssuesFromFile(string csvFile)
- {
- using (var file = new Godot.File())
- {
- try
- {
- Error openError = file.Open(csvFile, Godot.File.ModeFlags.Read);
-
- if (openError != Error.Ok)
- return;
-
- while (!file.EofReached())
- {
- string[] csvColumns = file.GetCsvLine();
-
- if (csvColumns.Length == 1 && string.IsNullOrEmpty(csvColumns[0]))
- return;
-
- if (csvColumns.Length != 7)
- {
- GD.PushError($"Expected 7 columns, got {csvColumns.Length}");
- continue;
- }
-
- var issue = new BuildIssue
- {
- Warning = csvColumns[0] == "warning",
- File = csvColumns[1],
- Line = int.Parse(csvColumns[2]),
- Column = int.Parse(csvColumns[3]),
- Code = csvColumns[4],
- Message = csvColumns[5],
- ProjectFile = csvColumns[6]
- };
-
- if (issue.Warning)
- WarningCount += 1;
- else
- ErrorCount += 1;
-
- issues.Add(issue);
- }
- }
- finally
- {
- file.Close(); // Disposing it is not enough. We need to call Close()
- }
- }
- }
-
- private void _IssueActivated(int idx)
- {
- if (idx < 0 || idx >= issuesList.GetItemCount())
- throw new IndexOutOfRangeException("Item list index out of range");
-
- // Get correct issue idx from issue list
- int issueIndex = (int)(long)issuesList.GetItemMetadata(idx);
-
- if (issueIndex < 0 || issueIndex >= issues.Count)
- throw new IndexOutOfRangeException("Issue index out of range");
-
- BuildIssue issue = issues[issueIndex];
-
- if (string.IsNullOrEmpty(issue.ProjectFile) && string.IsNullOrEmpty(issue.File))
- return;
-
- string projectDir = issue.ProjectFile.Length > 0 ? issue.ProjectFile.GetBaseDir() : BuildInfo.Solution.GetBaseDir();
-
- string file = Path.Combine(projectDir.SimplifyGodotPath(), issue.File.SimplifyGodotPath());
-
- if (!File.Exists(file))
- return;
-
- file = ProjectSettings.LocalizePath(file);
-
- if (file.StartsWith("res://"))
- {
- var script = (Script)ResourceLoader.Load(file, typeHint: Internal.CSharpLanguageType);
-
- if (script != null && Internal.ScriptEditorEdit(script, issue.Line, issue.Column))
- Internal.EditorNodeShowScriptScreen();
- }
- }
-
- public void UpdateIssuesList()
- {
- issuesList.Clear();
-
- using (var warningIcon = GetThemeIcon("Warning", "EditorIcons"))
- using (var errorIcon = GetThemeIcon("Error", "EditorIcons"))
- {
- for (int i = 0; i < issues.Count; i++)
- {
- BuildIssue issue = issues[i];
-
- if (!(issue.Warning ? WarningsVisible : ErrorsVisible))
- continue;
-
- string tooltip = string.Empty;
- tooltip += $"Message: {issue.Message}";
-
- if (!string.IsNullOrEmpty(issue.Code))
- tooltip += $"\nCode: {issue.Code}";
-
- tooltip += $"\nType: {(issue.Warning ? "warning" : "error")}";
-
- string text = string.Empty;
-
- if (!string.IsNullOrEmpty(issue.File))
- {
- text += $"{issue.File}({issue.Line},{issue.Column}): ";
-
- tooltip += $"\nFile: {issue.File}";
- tooltip += $"\nLine: {issue.Line}";
- tooltip += $"\nColumn: {issue.Column}";
- }
-
- if (!string.IsNullOrEmpty(issue.ProjectFile))
- tooltip += $"\nProject: {issue.ProjectFile}";
-
- text += issue.Message;
-
- int lineBreakIdx = text.IndexOf("\n", StringComparison.Ordinal);
- string itemText = lineBreakIdx == -1 ? text : text.Substring(0, lineBreakIdx);
- issuesList.AddItem(itemText, issue.Warning ? warningIcon : errorIcon);
-
- int index = issuesList.GetItemCount() - 1;
- issuesList.SetItemTooltip(index, tooltip);
- issuesList.SetItemMetadata(index, i);
- }
- }
- }
-
- public void OnBuildStart()
- {
- BuildExited = false;
-
- issues.Clear();
- WarningCount = 0;
- ErrorCount = 0;
- UpdateIssuesList();
-
- GodotSharpEditor.Instance.BottomPanel.RaiseBuildTab(this);
- }
-
- public void OnBuildExit(BuildResults result)
- {
- BuildExited = true;
- BuildResult = result;
-
- _LoadIssuesFromFile(Path.Combine(BuildInfo.LogsDirPath, BuildManager.MsBuildIssuesFileName));
- UpdateIssuesList();
-
- GodotSharpEditor.Instance.BottomPanel.RaiseBuildTab(this);
- }
-
- public void OnBuildExecFailed(string cause)
- {
- BuildExited = true;
- BuildResult = BuildResults.Error;
-
- issuesList.Clear();
-
- var issue = new BuildIssue { Message = cause, Warning = false };
-
- ErrorCount += 1;
- issues.Add(issue);
-
- UpdateIssuesList();
-
- GodotSharpEditor.Instance.BottomPanel.RaiseBuildTab(this);
- }
-
- public void RestartBuild()
- {
- if (!BuildExited)
- throw new InvalidOperationException("Build already started");
-
- BuildManager.RestartBuild(this);
- }
-
- public void StopBuild()
- {
- if (!BuildExited)
- throw new InvalidOperationException("Build is not in progress");
-
- BuildManager.StopBuild(this);
- }
-
- public override void _Ready()
- {
- base._Ready();
-
- issuesList = new ItemList { SizeFlagsVertical = (int)SizeFlags.ExpandFill };
- issuesList.ItemActivated += _IssueActivated;
- AddChild(issuesList);
- }
-
- private BuildTab()
- {
- }
-
- public BuildTab(BuildInfo buildInfo)
- {
- BuildInfo = buildInfo;
- }
- }
-}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs
index 5bb8d444c2..5bb8d444c2 100755..100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
index cd188509b4..e9bb701562 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
@@ -5,6 +5,7 @@ using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
+using GodotTools.Build;
using GodotTools.Core;
using GodotTools.Internals;
using JetBrains.Annotations;
@@ -143,6 +144,8 @@ namespace GodotTools.Export
private void _ExportBeginImpl(string[] features, bool isDebug, string path, int flags)
{
+ _ = flags; // Unused
+
if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
return;
@@ -154,12 +157,10 @@ namespace GodotTools.Export
string buildConfig = isDebug ? "ExportDebug" : "ExportRelease";
- string scriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, $"scripts_metadata.{(isDebug ? "debug" : "release")}");
- CsProjOperations.GenerateScriptsMetadata(GodotSharpDirs.ProjectCsProjPath, scriptsMetadataPath);
-
+ string scriptsMetadataPath = BuildManager.GenerateExportedGameScriptMetadata(isDebug);
AddFile(scriptsMetadataPath, scriptsMetadataPath);
- if (!BuildManager.BuildProjectBlocking(buildConfig, platform))
+ if (!BuildManager.BuildProjectBlocking(buildConfig, platform: platform))
throw new Exception("Failed to build project");
// Add dependency assemblies
@@ -172,6 +173,8 @@ namespace GodotTools.Export
assemblies[projectDllName] = projectDllSrcPath;
+ string bclDir = DeterminePlatformBclDir(platform);
+
if (platform == OS.Platforms.Android)
{
string godotAndroidExtProfileDir = GetBclProfileDir("godot_android_ext");
@@ -182,8 +185,49 @@ namespace GodotTools.Export
assemblies["Mono.Android"] = monoAndroidAssemblyPath;
}
+ else if (platform == OS.Platforms.HTML5)
+ {
+ // Ideally these would be added automatically since they're referenced by the wasm BCL assemblies.
+ // However, at least in the case of 'WebAssembly.Net.Http' for some reason the BCL assemblies
+ // reference a different version even though the assembly is the same, for some weird reason.
- string bclDir = DeterminePlatformBclDir(platform);
+ var wasmFrameworkAssemblies = new[] {"WebAssembly.Bindings", "WebAssembly.Net.WebSockets"};
+
+ foreach (string thisWasmFrameworkAssemblyName in wasmFrameworkAssemblies)
+ {
+ string thisWasmFrameworkAssemblyPath = Path.Combine(bclDir, thisWasmFrameworkAssemblyName + ".dll");
+ if (!File.Exists(thisWasmFrameworkAssemblyPath))
+ throw new FileNotFoundException($"Assembly not found: '{thisWasmFrameworkAssemblyName}'", thisWasmFrameworkAssemblyPath);
+ assemblies[thisWasmFrameworkAssemblyName] = thisWasmFrameworkAssemblyPath;
+ }
+
+ // Assemblies that can have a different name in a newer version. Newer version must come first and it has priority.
+ (string newName, string oldName)[] wasmFrameworkAssembliesOneOf = new[]
+ {
+ ("System.Net.Http.WebAssemblyHttpHandler", "WebAssembly.Net.Http")
+ };
+
+ foreach (var thisWasmFrameworkAssemblyName in wasmFrameworkAssembliesOneOf)
+ {
+ string thisWasmFrameworkAssemblyPath = Path.Combine(bclDir, thisWasmFrameworkAssemblyName.newName + ".dll");
+ if (File.Exists(thisWasmFrameworkAssemblyPath))
+ {
+ assemblies[thisWasmFrameworkAssemblyName.newName] = thisWasmFrameworkAssemblyPath;
+ }
+ else
+ {
+ thisWasmFrameworkAssemblyPath = Path.Combine(bclDir, thisWasmFrameworkAssemblyName.oldName + ".dll");
+ if (!File.Exists(thisWasmFrameworkAssemblyPath))
+ {
+ throw new FileNotFoundException("Expected one of the following assemblies but none were found: " +
+ $"'{thisWasmFrameworkAssemblyName.newName}' / '{thisWasmFrameworkAssemblyName.oldName}'",
+ thisWasmFrameworkAssemblyPath);
+ }
+
+ assemblies[thisWasmFrameworkAssemblyName.oldName] = thisWasmFrameworkAssemblyPath;
+ }
+ }
+ }
var initialAssemblies = assemblies.Duplicate();
internal_GetExportedAssemblyDependencies(initialAssemblies, buildConfig, bclDir, assemblies);
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/XcodeHelper.cs b/modules/mono/editor/GodotTools/GodotTools/Export/XcodeHelper.cs
index 219b7a698a..93ef837a83 100755..100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/XcodeHelper.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/XcodeHelper.cs
@@ -27,7 +27,7 @@ namespace GodotTools.Export
{
var outputWrapper = new Godot.Collections.Array();
- int exitCode = Godot.OS.Execute("xcode-select", new string[] { "--print-path" }, blocking: true, output: outputWrapper);
+ int exitCode = Godot.OS.Execute("xcode-select", new string[] { "--print-path" }, output: outputWrapper);
if (exitCode == 0)
{
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
index 57d334b93e..58561c5097 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
@@ -4,9 +4,9 @@ using GodotTools.Export;
using GodotTools.Utils;
using System;
using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
+using GodotTools.Build;
using GodotTools.Ides;
using GodotTools.Ides.Rider;
using GodotTools.Internals;
@@ -19,7 +19,6 @@ using Path = System.IO.Path;
namespace GodotTools
{
- [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")]
public class GodotSharpEditor : EditorPlugin, ISerializationListener
{
private EditorSettings editorSettings;
@@ -37,7 +36,7 @@ namespace GodotTools
private WeakRef exportPluginWeak; // TODO Use WeakReference once we have proper serialization
- public BottomPanel BottomPanel { get; private set; }
+ public MSBuildPanel MSBuildPanel { get; private set; }
public bool SkipBuildBeforePlaying { get; set; } = false;
@@ -148,12 +147,27 @@ namespace GodotTools
case MenuOptions.AboutCSharp:
_ShowAboutDialog();
break;
+ case MenuOptions.SetupGodotNugetFallbackFolder:
+ {
+ try
+ {
+ string fallbackFolder = NuGetUtils.GodotFallbackFolderPath;
+ NuGetUtils.AddFallbackFolderToUserNuGetConfigs(NuGetUtils.GodotFallbackFolderName, fallbackFolder);
+ NuGetUtils.AddBundledPackagesToFallbackFolder(fallbackFolder);
+ }
+ catch (Exception e)
+ {
+ ShowErrorDialog("Failed to setup Godot NuGet Offline Packages: " + e.Message);
+ }
+
+ break;
+ }
default:
throw new ArgumentOutOfRangeException(nameof(id), id, "Invalid menu option");
}
}
- private void _BuildSolutionPressed()
+ private void BuildSolutionPressed()
{
if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
{
@@ -161,23 +175,22 @@ namespace GodotTools
return; // Failed to create solution
}
- Instance.BottomPanel.BuildProjectPressed();
+ Instance.MSBuildPanel.BuildSolution();
}
- public override void _Notification(int what)
+ public override void _Ready()
{
- base._Notification(what);
+ base._Ready();
- if (what == NotificationReady)
+ MSBuildPanel.BuildOutputView.BuildStateChanged += BuildStateChanged;
+
+ bool showInfoDialog = (bool)editorSettings.GetSetting("mono/editor/show_info_on_start");
+ if (showInfoDialog)
{
- bool showInfoDialog = (bool)editorSettings.GetSetting("mono/editor/show_info_on_start");
- if (showInfoDialog)
- {
- aboutDialog.Exclusive = true;
- _ShowAboutDialog();
- // Once shown a first time, it can be seen again via the Mono menu - it doesn't have to be exclusive from that time on.
- aboutDialog.Exclusive = false;
- }
+ aboutDialog.Exclusive = true;
+ _ShowAboutDialog();
+ // Once shown a first time, it can be seen again via the Mono menu - it doesn't have to be exclusive from that time on.
+ aboutDialog.Exclusive = false;
}
}
@@ -185,6 +198,7 @@ namespace GodotTools
{
CreateSln,
AboutCSharp,
+ SetupGodotNugetFallbackFolder,
}
public void ShowErrorDialog(string message, string title = "Error")
@@ -393,6 +407,12 @@ namespace GodotTools
}
}
+ private void BuildStateChanged()
+ {
+ if (bottomPanelBtn != null)
+ bottomPanelBtn.Icon = MSBuildPanel.BuildOutputView.BuildStateIcon;
+ }
+
public override void EnablePlugin()
{
base.EnablePlugin();
@@ -409,20 +429,20 @@ namespace GodotTools
errorDialog = new AcceptDialog();
editorBaseControl.AddChild(errorDialog);
- BottomPanel = new BottomPanel();
-
- bottomPanelBtn = AddControlToBottomPanel(BottomPanel, "Mono".TTR());
+ MSBuildPanel = new MSBuildPanel();
+ bottomPanelBtn = AddControlToBottomPanel(MSBuildPanel, "MSBuild".TTR());
AddChild(new HotReloadAssemblyWatcher {Name = "HotReloadAssemblyWatcher"});
menuPopup = new PopupMenu();
menuPopup.Hide();
- AddToolSubmenuItem("Mono", menuPopup);
+ AddToolSubmenuItem("C#", menuPopup);
// TODO: Remove or edit this info dialog once Mono support is no longer in alpha
{
menuPopup.AddItem("About C# support".TTR(), (int)MenuOptions.AboutCSharp);
+ menuPopup.AddItem("Setup Godot NuGet Offline Packages".TTR(), (int)MenuOptions.SetupGodotNugetFallbackFolder);
aboutDialog = new AcceptDialog();
editorBaseControl.AddChild(aboutDialog);
aboutDialog.Title = "Important: C# support is not feature-complete";
@@ -476,7 +496,7 @@ namespace GodotTools
HintTooltip = "Build solution",
FocusMode = Control.FocusModeEnum.None
};
- toolBarBuildButton.PressedSignal += _BuildSolutionPressed;
+ toolBarBuildButton.PressedSignal += BuildSolutionPressed;
AddControlToContainer(CustomControlContainer.Toolbar, toolBarBuildButton);
if (File.Exists(GodotSharpDirs.ProjectSlnPath) && File.Exists(GodotSharpDirs.ProjectCsProjPath))
@@ -532,6 +552,16 @@ namespace GodotTools
exportPlugin.RegisterExportSettings();
exportPluginWeak = WeakRef(exportPlugin);
+ try
+ {
+ // At startup we make sure NuGet.Config files have our Godot NuGet fallback folder included
+ NuGetUtils.AddFallbackFolderToUserNuGetConfigs(NuGetUtils.GodotFallbackFolderName, NuGetUtils.GodotFallbackFolderPath);
+ }
+ catch (Exception e)
+ {
+ GD.PushError("Failed to add Godot NuGet Offline Packages to NuGet.Config: " + e.Message);
+ }
+
BuildManager.Initialize();
RiderPathManager.Initialize();
@@ -570,6 +600,7 @@ namespace GodotTools
public static GodotSharpEditor Instance { get; private set; }
+ [UsedImplicitly]
private GodotSharpEditor()
{
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs
index 16f91a0925..ed25cdaa63 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs
@@ -104,7 +104,7 @@ namespace GodotTools.Ides.Rider
if (line >= 0)
{
args.Add("--line");
- args.Add(line.ToString());
+ args.Add((line + 1).ToString()); // https://github.com/JetBrains/godot-support/issues/61
}
args.Add(scriptPath);
try
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index a17c371117..38e403b2e1 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,13 +32,13 @@
#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED)
-#include "core/engine.h"
-#include "core/global_constants.h"
+#include "core/config/engine.h"
+#include "core/core_constants.h"
#include "core/io/compression.h"
#include "core/os/dir_access.h"
#include "core/os/file_access.h"
#include "core/os/os.h"
-#include "core/ucaps.h"
+#include "core/string/ucaps.h"
#include "../glue/cs_glue_version.gen.h"
#include "../godotsharp_defs.h"
@@ -97,7 +97,7 @@
#define C_METHOD_MANAGED_TO_SIGNAL C_NS_MONOMARSHAL "::signal_info_to_callable"
#define C_METHOD_MANAGED_FROM_SIGNAL C_NS_MONOMARSHAL "::callable_to_signal_info"
-#define BINDINGS_GENERATOR_VERSION UINT32_C(11)
+#define BINDINGS_GENERATOR_VERSION UINT32_C(13)
const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN("\t%0 %1_in = %1;\n");
@@ -181,11 +181,11 @@ static String snake_to_camel_case(const String &p_identifier, bool p_input_is_up
String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterface *p_itype) {
// Based on the version in EditorHelp
- if (p_bbcode.empty()) {
+ if (p_bbcode.is_empty()) {
return String();
}
- DocData *doc = EditorHelp::get_doc_data();
+ DocTools *doc = EditorHelp::get_doc_data();
String bbcode = p_bbcode;
@@ -365,7 +365,7 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
xml_output.append("</c>");
} else if (link_tag == "enum") {
StringName search_cname = !target_itype ? target_cname :
- StringName(target_itype->name + "." + (String)target_cname);
+ StringName(target_itype->name + "." + (String)target_cname);
const Map<StringName, TypeInterface>::Element *enum_match = enum_types.find(search_cname);
@@ -644,7 +644,7 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
}
int BindingsGenerator::_determine_enum_prefix(const EnumInterface &p_ienum) {
- CRASH_COND(p_ienum.constants.empty());
+ CRASH_COND(p_ienum.constants.is_empty());
const ConstantInterface &front_iconstant = p_ienum.constants.front()->get();
Vector<String> front_parts = front_iconstant.name.split("_", /* p_allow_empty: */ true);
@@ -819,7 +819,7 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
p_output.append(";");
}
- if (!global_constants.empty()) {
+ if (!global_constants.is_empty()) {
p_output.append("\n");
}
@@ -830,7 +830,7 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
for (List<EnumInterface>::Element *E = global_enums.front(); E; E = E->next()) {
const EnumInterface &ienum = E->get();
- CRASH_COND(ienum.constants.empty());
+ CRASH_COND(ienum.constants.is_empty());
String enum_proxy_name = ienum.cname.operator String();
@@ -1283,7 +1283,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
for (const List<EnumInterface>::Element *E = itype.enums.front(); E; E = E->next()) {
const EnumInterface &ienum = E->get();
- ERR_FAIL_COND_V(ienum.constants.empty(), ERR_BUG);
+ ERR_FAIL_COND_V(ienum.constants.is_empty(), ERR_BUG);
output.append(MEMBER_BEGIN "public enum ");
output.append(ienum.cname.operator String());
@@ -1368,7 +1368,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
output.append(")\n" OPEN_BLOCK_L2 "if (" BINDINGS_PTR_FIELD " == IntPtr.Zero)\n" INDENT4 BINDINGS_PTR_FIELD " = ");
output.append(itype.api_type == ClassDB::API_EDITOR ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS);
output.append("." + ctor_method);
- output.append("(this);\n" CLOSE_BLOCK_L2);
+ output.append("(this);\n" INDENT3 "_InitializeGodotScriptInstanceInternals();\n" CLOSE_BLOCK_L2);
} else {
// Hide the constructor
output.append(MEMBER_BEGIN "internal ");
@@ -1661,14 +1661,14 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
cs_in_statements += def_arg;
cs_in_statements += ";\n" INDENT3;
- icall_params += arg_type->cs_in.empty() ? arg_in : sformat(arg_type->cs_in, arg_in);
+ icall_params += arg_type->cs_in.is_empty() ? arg_in : sformat(arg_type->cs_in, arg_in);
// Apparently the name attribute must not include the @
String param_tag_name = iarg.name.begins_with("@") ? iarg.name.substr(1, iarg.name.length()) : iarg.name;
default_args_doc.append(MEMBER_BEGIN "/// <param name=\"" + param_tag_name + "\">If the parameter is null, then the default value is " + def_arg + "</param>");
} else {
- icall_params += arg_type->cs_in.empty() ? iarg.name : sformat(arg_type->cs_in, iarg.name);
+ icall_params += arg_type->cs_in.is_empty() ? iarg.name : sformat(arg_type->cs_in, iarg.name);
}
}
@@ -1714,7 +1714,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
}
if (p_imethod.is_deprecated) {
- if (p_imethod.deprecation_message.empty()) {
+ if (p_imethod.deprecation_message.is_empty()) {
WARN_PRINT("An empty deprecation message is discouraged. Method: '" + p_imethod.proxy_name + "'.");
}
@@ -1782,7 +1782,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
if (return_type->cname == name_cache.type_void) {
p_output.append(im_call + "(" + icall_params + ");\n");
- } else if (return_type->cs_out.empty()) {
+ } else if (return_type->cs_out.is_empty()) {
p_output.append("return " + im_call + "(" + icall_params + ");\n");
} else {
p_output.append(sformat(return_type->cs_out, im_call, icall_params, return_type->cs_type, return_type->im_type_out));
@@ -1839,7 +1839,7 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
}
if (p_isignal.is_deprecated) {
- if (p_isignal.deprecation_message.empty()) {
+ if (p_isignal.deprecation_message.is_empty()) {
WARN_PRINT("An empty deprecation message is discouraged. Signal: '" + p_isignal.proxy_name + "'.");
}
@@ -1999,12 +1999,12 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
#define ADD_INTERNAL_CALL_REGISTRATION(m_icall) \
{ \
- output.append("\tmono_add_internal_call("); \
+ output.append("\tGDMonoUtils::add_internal_call("); \
output.append("\"" BINDINGS_NAMESPACE "."); \
output.append(m_icall.editor_only ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS); \
output.append("::"); \
output.append(m_icall.name); \
- output.append("\", (void*)"); \
+ output.append("\", "); \
output.append(m_icall.name); \
output.append(");\n"); \
}
@@ -2263,7 +2263,7 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
}
if (!ret_void) {
- if (return_type->c_out.empty()) {
+ if (return_type->c_out.is_empty()) {
p_output.append("\treturn " C_LOCAL_RET ";\n");
} else if (return_type->ret_as_byref_arg) {
p_output.append(sformat(return_type->c_out, return_type->c_type_out, C_LOCAL_RET, return_type->name, "arg_ret"));
@@ -2426,7 +2426,7 @@ bool BindingsGenerator::_arg_default_value_is_assignable_to_type(const Variant &
case Variant::VECTOR2:
case Variant::RECT2:
case Variant::VECTOR3:
- case Variant::_RID:
+ case Variant::RID:
case Variant::ARRAY:
case Variant::DICTIONARY:
case Variant::PACKED_BYTE_ARRAY:
@@ -2585,7 +2585,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
int argc = method_info.arguments.size();
- if (method_info.name.empty()) {
+ if (method_info.name.is_empty()) {
continue;
}
@@ -2979,7 +2979,7 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
r_iarg.default_argument = "new %s()";
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF;
break;
- case Variant::_RID:
+ case Variant::RID:
ERR_FAIL_COND_V_MSG(r_iarg.type.cname != name_cache.type_RID, false,
"Parameter of type '" + String(r_iarg.type.cname) + "' cannot have a default value of type '" + String(name_cache.type_RID) + "'.");
@@ -3100,44 +3100,11 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
INSERT_INT_TYPE("sbyte", int8_t, int64_t);
INSERT_INT_TYPE("short", int16_t, int64_t);
INSERT_INT_TYPE("int", int32_t, int64_t);
+ INSERT_INT_TYPE("long", int64_t, int64_t);
INSERT_INT_TYPE("byte", uint8_t, int64_t);
INSERT_INT_TYPE("ushort", uint16_t, int64_t);
INSERT_INT_TYPE("uint", uint32_t, int64_t);
-
- itype = TypeInterface::create_value_type(String("long"));
- {
- itype.c_out = "\treturn (%0)%1;\n";
- itype.c_in = "\t%0 %1_in = (%0)*%1;\n";
- itype.c_out = "\t*%3 = (%0)%1;\n";
- itype.c_type = "int64_t";
- itype.c_arg_in = "&%s_in";
- }
- itype.c_type_in = "int64_t*";
- itype.c_type_out = "int64_t";
- itype.im_type_in = "ref " + itype.name;
- itype.im_type_out = "out " + itype.name;
- itype.cs_in = "ref %0";
- /* in cs_out, im_type_out (%3) includes the 'out ' part */
- itype.cs_out = "%0(%1, %3 argRet); return argRet;";
- itype.ret_as_byref_arg = true;
- builtin_types.insert(itype.cname, itype);
-
- itype = TypeInterface::create_value_type(String("ulong"));
- {
- itype.c_in = "\t%0 %1_in = (%0)*%1;\n";
- itype.c_out = "\t*%3 = (%0)%1;\n";
- itype.c_type = "int64_t";
- itype.c_arg_in = "&%s_in";
- }
- itype.c_type_in = "uint64_t*";
- itype.c_type_out = "uint64_t";
- itype.im_type_in = "ref " + itype.name;
- itype.im_type_out = "out " + itype.name;
- itype.cs_in = "ref %0";
- /* in cs_out, im_type_out (%3) includes the 'out ' part */
- itype.cs_out = "%0(%1, %3 argRet); return argRet;";
- itype.ret_as_byref_arg = true;
- builtin_types.insert(itype.cname, itype);
+ INSERT_INT_TYPE("ulong", uint64_t, int64_t);
}
// Floating point types
@@ -3149,20 +3116,16 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.proxy_name = "float";
{
// The expected type for 'float' in ptrcall is 'double'
- itype.c_in = "\t%0 %1_in = (%0)*%1;\n";
- itype.c_out = "\t*%3 = (%0)%1;\n";
+ itype.c_in = "\t%0 %1_in = (%0)%1;\n";
+ itype.c_out = "\treturn (%0)%1;\n";
itype.c_type = "double";
- itype.c_type_in = "float*";
+ itype.c_type_in = "float";
itype.c_type_out = "float";
itype.c_arg_in = "&%s_in";
}
itype.cs_type = itype.proxy_name;
- itype.im_type_in = "ref " + itype.proxy_name;
- itype.im_type_out = "out " + itype.proxy_name;
- itype.cs_in = "ref %0";
- /* in cs_out, im_type_out (%3) includes the 'out ' part */
- itype.cs_out = "%0(%1, %3 argRet); return argRet;";
- itype.ret_as_byref_arg = true;
+ itype.im_type_in = itype.proxy_name;
+ itype.im_type_out = itype.proxy_name;
builtin_types.insert(itype.cname, itype);
// double
@@ -3171,20 +3134,14 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.cname = itype.name;
itype.proxy_name = "double";
{
- itype.c_in = "\t%0 %1_in = (%0)*%1;\n";
- itype.c_out = "\t*%3 = (%0)%1;\n";
itype.c_type = "double";
- itype.c_type_in = "double*";
+ itype.c_type_in = "double";
itype.c_type_out = "double";
- itype.c_arg_in = "&%s_in";
+ itype.c_arg_in = "&%s";
}
itype.cs_type = itype.proxy_name;
- itype.im_type_in = "ref " + itype.proxy_name;
- itype.im_type_out = "out " + itype.proxy_name;
- itype.cs_in = "ref %0";
- /* in cs_out, im_type_out (%3) includes the 'out ' part */
- itype.cs_out = "%0(%1, %3 argRet); return argRet;";
- itype.ret_as_byref_arg = true;
+ itype.im_type_in = itype.proxy_name;
+ itype.im_type_out = itype.proxy_name;
builtin_types.insert(itype.cname, itype);
}
@@ -3399,7 +3356,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
}
void BindingsGenerator::_populate_global_constants() {
- int global_constants_count = GlobalConstants::get_global_constant_count();
+ int global_constants_count = CoreConstants::get_global_constant_count();
if (global_constants_count > 0) {
Map<String, DocData::ClassDoc>::Element *match = EditorHelp::get_doc_data()->class_list.find("@GlobalScope");
@@ -3409,7 +3366,7 @@ void BindingsGenerator::_populate_global_constants() {
const DocData::ClassDoc &global_scope_doc = match->value();
for (int i = 0; i < global_constants_count; i++) {
- String constant_name = GlobalConstants::get_global_constant_name(i);
+ String constant_name = CoreConstants::get_global_constant_name(i);
const DocData::ConstantDoc *const_doc = nullptr;
for (int j = 0; j < global_scope_doc.constants.size(); j++) {
@@ -3421,8 +3378,8 @@ void BindingsGenerator::_populate_global_constants() {
}
}
- int constant_value = GlobalConstants::get_global_constant_value(i);
- StringName enum_name = GlobalConstants::get_global_constant_enum(i);
+ int constant_value = CoreConstants::get_global_constant_value(i);
+ StringName enum_name = CoreConstants::get_global_constant_enum(i);
ConstantInterface iconstant(constant_name, snake_to_pascal_case(constant_name, true), constant_value);
iconstant.const_doc = const_doc;
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index 90c1c9f3ee..b18dfb0ec4 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,20 +31,21 @@
#ifndef BINDINGS_GENERATOR_H
#define BINDINGS_GENERATOR_H
-#include "core/class_db.h"
-#include "core/string_builder.h"
-#include "editor/doc_data.h"
+#include "core/doc_data.h"
+#include "core/object/class_db.h"
+#include "core/string/string_builder.h"
+#include "editor/doc_tools.h"
#include "editor/editor_help.h"
#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED)
-#include "core/ustring.h"
+#include "core/string/ustring.h"
class BindingsGenerator {
struct ConstantInterface {
String name;
String proxy_name;
- int value;
+ int value = 0;
const DocData::ConstantDoc *const_doc;
ConstantInterface() {}
@@ -74,7 +75,7 @@ class BindingsGenerator {
struct PropertyInterface {
StringName cname;
String proxy_name;
- int index;
+ int index = 0;
StringName setter;
StringName getter;
@@ -479,7 +480,7 @@ class BindingsGenerator {
String im_type_out; // Return type for the C# method declaration. Also used as companion of [unique_siq]
String im_sig; // Signature for the C# method declaration
String unique_sig; // Unique signature to avoid duplicates in containers
- bool editor_only;
+ bool editor_only = false;
InternalCall() {}
diff --git a/modules/mono/editor/code_completion.cpp b/modules/mono/editor/code_completion.cpp
index 942c6d26a6..bbfba83e6f 100644
--- a/modules/mono/editor/code_completion.cpp
+++ b/modules/mono/editor/code_completion.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,7 +30,7 @@
#include "code_completion.h"
-#include "core/project_settings.h"
+#include "core/config/project_settings.h"
#include "editor/editor_file_system.h"
#include "editor/editor_settings.h"
#include "scene/gui/control.h"
@@ -150,7 +150,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr
List<String> directories;
directories.push_back(dir_access->get_current_dir());
- while (!directories.empty()) {
+ while (!directories.is_empty()) {
dir_access->change_dir(directories.back()->get());
directories.pop_back();
@@ -228,6 +228,18 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr
}
}
} break;
+ case CompletionKind::THEME_FONT_SIZES: {
+ Ref<Script> script = ResourceLoader::load(p_script_file.simplify_path());
+ Node *base = _try_find_owner_node_in_tree(script);
+ if (base && Object::cast_to<Control>(base)) {
+ List<StringName> sn;
+ Theme::get_default()->get_font_size_list(base->get_class(), &sn);
+
+ for (List<StringName>::Element *E = sn.front(); E; E = E->next()) {
+ suggestions.push_back(quoted(E->get()));
+ }
+ }
+ } break;
case CompletionKind::THEME_STYLES: {
Ref<Script> script = ResourceLoader::load(p_script_file.simplify_path());
Node *base = _try_find_owner_node_in_tree(script);
@@ -246,5 +258,4 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr
return suggestions;
}
-
} // namespace gdmono
diff --git a/modules/mono/editor/code_completion.h b/modules/mono/editor/code_completion.h
index 77673b766f..7f7521672b 100644
--- a/modules/mono/editor/code_completion.h
+++ b/modules/mono/editor/code_completion.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,8 +31,8 @@
#ifndef CODE_COMPLETION_H
#define CODE_COMPLETION_H
-#include "core/ustring.h"
-#include "core/variant.h"
+#include "core/string/ustring.h"
+#include "core/variant/variant.h"
namespace gdmono {
@@ -46,11 +46,11 @@ enum class CompletionKind {
THEME_COLORS,
THEME_CONSTANTS,
THEME_FONTS,
+ THEME_FONT_SIZES,
THEME_STYLES
};
PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_script_file);
-
} // namespace gdmono
#endif // CODE_COMPLETION_H
diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp
index 68fc372959..667e4a3879 100644
--- a/modules/mono/editor/editor_internal_calls.cpp
+++ b/modules/mono/editor/editor_internal_calls.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -47,7 +47,6 @@
#include "../godotsharp_dirs.h"
#include "../mono_gd/gd_mono_marshal.h"
#include "../utils/osx_utils.h"
-#include "bindings_generator.h"
#include "code_completion.h"
#include "godotsharp_export.h"
#include "script_class_parser.h"
@@ -173,35 +172,6 @@ MonoBoolean godot_icall_EditorProgress_Step(MonoString *p_task, MonoString *p_st
return EditorNode::progress_task_step(task, state, p_step, (bool)p_force_refresh);
}
-BindingsGenerator *godot_icall_BindingsGenerator_Ctor() {
- return memnew(BindingsGenerator);
-}
-
-void godot_icall_BindingsGenerator_Dtor(BindingsGenerator *p_handle) {
- memdelete(p_handle);
-}
-
-MonoBoolean godot_icall_BindingsGenerator_LogPrintEnabled(BindingsGenerator *p_handle) {
- return p_handle->is_log_print_enabled();
-}
-
-void godot_icall_BindingsGenerator_SetLogPrintEnabled(BindingsGenerator p_handle, MonoBoolean p_enabled) {
- p_handle.set_log_print_enabled(p_enabled);
-}
-
-int32_t godot_icall_BindingsGenerator_GenerateCsApi(BindingsGenerator *p_handle, MonoString *p_output_dir) {
- String output_dir = GDMonoMarshal::mono_string_to_godot(p_output_dir);
- return p_handle->generate_cs_api(output_dir);
-}
-
-uint32_t godot_icall_BindingsGenerator_Version() {
- return BindingsGenerator::get_version();
-}
-
-uint32_t godot_icall_BindingsGenerator_CsGlueVersion() {
- return CS_GLUE_VERSION;
-}
-
int32_t godot_icall_ScriptClassParser_ParseFile(MonoString *p_filepath, MonoObject *p_classes, MonoString **r_error_str) {
*r_error_str = nullptr;
@@ -225,7 +195,7 @@ int32_t godot_icall_ScriptClassParser_ParseFile(MonoString *p_filepath, MonoObje
}
} else {
String error_str = scp.get_error();
- if (!error_str.empty()) {
+ if (!error_str.is_empty()) {
*r_error_str = GDMonoMarshal::mono_string_from_godot(error_str);
}
}
@@ -400,75 +370,66 @@ MonoBoolean godot_icall_Utils_OS_UnixFileHasExecutableAccess(MonoString *p_file_
void register_editor_internal_calls() {
// GodotSharpDirs
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResDataDir", (void *)godot_icall_GodotSharpDirs_ResDataDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResMetadataDir", (void *)godot_icall_GodotSharpDirs_ResMetadataDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResAssembliesBaseDir", (void *)godot_icall_GodotSharpDirs_ResAssembliesBaseDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResAssembliesDir", (void *)godot_icall_GodotSharpDirs_ResAssembliesDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResConfigDir", (void *)godot_icall_GodotSharpDirs_ResConfigDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempDir", (void *)godot_icall_GodotSharpDirs_ResTempDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempAssembliesBaseDir", (void *)godot_icall_GodotSharpDirs_ResTempAssembliesBaseDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempAssembliesDir", (void *)godot_icall_GodotSharpDirs_ResTempAssembliesDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoUserDir", (void *)godot_icall_GodotSharpDirs_MonoUserDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoLogsDir", (void *)godot_icall_GodotSharpDirs_MonoLogsDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoSolutionsDir", (void *)godot_icall_GodotSharpDirs_MonoSolutionsDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_BuildLogsDirs", (void *)godot_icall_GodotSharpDirs_BuildLogsDirs);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ProjectSlnPath", (void *)godot_icall_GodotSharpDirs_ProjectSlnPath);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ProjectCsProjPath", (void *)godot_icall_GodotSharpDirs_ProjectCsProjPath);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataEditorToolsDir", (void *)godot_icall_GodotSharpDirs_DataEditorToolsDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataEditorPrebuiltApiDir", (void *)godot_icall_GodotSharpDirs_DataEditorPrebuiltApiDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoEtcDir", (void *)godot_icall_GodotSharpDirs_DataMonoEtcDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoLibDir", (void *)godot_icall_GodotSharpDirs_DataMonoLibDir);
- mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoBinDir", (void *)godot_icall_GodotSharpDirs_DataMonoBinDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResDataDir", godot_icall_GodotSharpDirs_ResDataDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResMetadataDir", godot_icall_GodotSharpDirs_ResMetadataDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResAssembliesBaseDir", godot_icall_GodotSharpDirs_ResAssembliesBaseDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResAssembliesDir", godot_icall_GodotSharpDirs_ResAssembliesDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResConfigDir", godot_icall_GodotSharpDirs_ResConfigDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempDir", godot_icall_GodotSharpDirs_ResTempDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempAssembliesBaseDir", godot_icall_GodotSharpDirs_ResTempAssembliesBaseDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempAssembliesDir", godot_icall_GodotSharpDirs_ResTempAssembliesDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoUserDir", godot_icall_GodotSharpDirs_MonoUserDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoLogsDir", godot_icall_GodotSharpDirs_MonoLogsDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoSolutionsDir", godot_icall_GodotSharpDirs_MonoSolutionsDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_BuildLogsDirs", godot_icall_GodotSharpDirs_BuildLogsDirs);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ProjectSlnPath", godot_icall_GodotSharpDirs_ProjectSlnPath);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ProjectCsProjPath", godot_icall_GodotSharpDirs_ProjectCsProjPath);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataEditorToolsDir", godot_icall_GodotSharpDirs_DataEditorToolsDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataEditorPrebuiltApiDir", godot_icall_GodotSharpDirs_DataEditorPrebuiltApiDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoEtcDir", godot_icall_GodotSharpDirs_DataMonoEtcDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoLibDir", godot_icall_GodotSharpDirs_DataMonoLibDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoBinDir", godot_icall_GodotSharpDirs_DataMonoBinDir);
// EditorProgress
- mono_add_internal_call("GodotTools.Internals.EditorProgress::internal_Create", (void *)godot_icall_EditorProgress_Create);
- mono_add_internal_call("GodotTools.Internals.EditorProgress::internal_Dispose", (void *)godot_icall_EditorProgress_Dispose);
- mono_add_internal_call("GodotTools.Internals.EditorProgress::internal_Step", (void *)godot_icall_EditorProgress_Step);
-
- // BiningsGenerator
- mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_Ctor", (void *)godot_icall_BindingsGenerator_Ctor);
- mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_Dtor", (void *)godot_icall_BindingsGenerator_Dtor);
- mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_LogPrintEnabled", (void *)godot_icall_BindingsGenerator_LogPrintEnabled);
- mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_SetLogPrintEnabled", (void *)godot_icall_BindingsGenerator_SetLogPrintEnabled);
- mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_GenerateCsApi", (void *)godot_icall_BindingsGenerator_GenerateCsApi);
- mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_Version", (void *)godot_icall_BindingsGenerator_Version);
- mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_CsGlueVersion", (void *)godot_icall_BindingsGenerator_CsGlueVersion);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.EditorProgress::internal_Create", godot_icall_EditorProgress_Create);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.EditorProgress::internal_Dispose", godot_icall_EditorProgress_Dispose);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.EditorProgress::internal_Step", godot_icall_EditorProgress_Step);
// ScriptClassParser
- mono_add_internal_call("GodotTools.Internals.ScriptClassParser::internal_ParseFile", (void *)godot_icall_ScriptClassParser_ParseFile);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.ScriptClassParser::internal_ParseFile", godot_icall_ScriptClassParser_ParseFile);
// ExportPlugin
- mono_add_internal_call("GodotTools.Export.ExportPlugin::internal_GetExportedAssemblyDependencies", (void *)godot_icall_ExportPlugin_GetExportedAssemblyDependencies);
+ GDMonoUtils::add_internal_call("GodotTools.Export.ExportPlugin::internal_GetExportedAssemblyDependencies", godot_icall_ExportPlugin_GetExportedAssemblyDependencies);
// Internals
- mono_add_internal_call("GodotTools.Internals.Internal::internal_UpdateApiAssembliesFromPrebuilt", (void *)godot_icall_Internal_UpdateApiAssembliesFromPrebuilt);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_FullTemplatesDir", (void *)godot_icall_Internal_FullTemplatesDir);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_SimplifyGodotPath", (void *)godot_icall_Internal_SimplifyGodotPath);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_IsOsxAppBundleInstalled", (void *)godot_icall_Internal_IsOsxAppBundleInstalled);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_GodotIs32Bits", (void *)godot_icall_Internal_GodotIs32Bits);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_GodotIsRealTDouble", (void *)godot_icall_Internal_GodotIsRealTDouble);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_GodotMainIteration", (void *)godot_icall_Internal_GodotMainIteration);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_GetCoreApiHash", (void *)godot_icall_Internal_GetCoreApiHash);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_GetEditorApiHash", (void *)godot_icall_Internal_GetEditorApiHash);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_IsAssembliesReloadingNeeded", (void *)godot_icall_Internal_IsAssembliesReloadingNeeded);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_ReloadAssemblies", (void *)godot_icall_Internal_ReloadAssemblies);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_EditorDebuggerNodeReloadScripts", (void *)godot_icall_Internal_EditorDebuggerNodeReloadScripts);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_ScriptEditorEdit", (void *)godot_icall_Internal_ScriptEditorEdit);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_EditorNodeShowScriptScreen", (void *)godot_icall_Internal_EditorNodeShowScriptScreen);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_GetScriptsMetadataOrNothing", (void *)godot_icall_Internal_GetScriptsMetadataOrNothing);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_MonoWindowsInstallRoot", (void *)godot_icall_Internal_MonoWindowsInstallRoot);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_EditorRunPlay", (void *)godot_icall_Internal_EditorRunPlay);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_EditorRunStop", (void *)godot_icall_Internal_EditorRunStop);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_ScriptEditorDebugger_ReloadScripts", (void *)godot_icall_Internal_ScriptEditorDebugger_ReloadScripts);
- mono_add_internal_call("GodotTools.Internals.Internal::internal_CodeCompletionRequest", (void *)godot_icall_Internal_CodeCompletionRequest);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_UpdateApiAssembliesFromPrebuilt", godot_icall_Internal_UpdateApiAssembliesFromPrebuilt);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_FullTemplatesDir", godot_icall_Internal_FullTemplatesDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_SimplifyGodotPath", godot_icall_Internal_SimplifyGodotPath);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_IsOsxAppBundleInstalled", godot_icall_Internal_IsOsxAppBundleInstalled);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GodotIs32Bits", godot_icall_Internal_GodotIs32Bits);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GodotIsRealTDouble", godot_icall_Internal_GodotIsRealTDouble);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GodotMainIteration", godot_icall_Internal_GodotMainIteration);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GetCoreApiHash", godot_icall_Internal_GetCoreApiHash);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GetEditorApiHash", godot_icall_Internal_GetEditorApiHash);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_IsAssembliesReloadingNeeded", godot_icall_Internal_IsAssembliesReloadingNeeded);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_ReloadAssemblies", godot_icall_Internal_ReloadAssemblies);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_EditorDebuggerNodeReloadScripts", godot_icall_Internal_EditorDebuggerNodeReloadScripts);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_ScriptEditorEdit", godot_icall_Internal_ScriptEditorEdit);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_EditorNodeShowScriptScreen", godot_icall_Internal_EditorNodeShowScriptScreen);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GetScriptsMetadataOrNothing", godot_icall_Internal_GetScriptsMetadataOrNothing);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_MonoWindowsInstallRoot", godot_icall_Internal_MonoWindowsInstallRoot);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_EditorRunPlay", godot_icall_Internal_EditorRunPlay);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_EditorRunStop", godot_icall_Internal_EditorRunStop);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_ScriptEditorDebugger_ReloadScripts", godot_icall_Internal_ScriptEditorDebugger_ReloadScripts);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_CodeCompletionRequest", godot_icall_Internal_CodeCompletionRequest);
// Globals
- mono_add_internal_call("GodotTools.Internals.Globals::internal_EditorScale", (void *)godot_icall_Globals_EditorScale);
- mono_add_internal_call("GodotTools.Internals.Globals::internal_GlobalDef", (void *)godot_icall_Globals_GlobalDef);
- mono_add_internal_call("GodotTools.Internals.Globals::internal_EditorDef", (void *)godot_icall_Globals_EditorDef);
- mono_add_internal_call("GodotTools.Internals.Globals::internal_TTR", (void *)godot_icall_Globals_TTR);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_EditorScale", godot_icall_Globals_EditorScale);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_GlobalDef", godot_icall_Globals_GlobalDef);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_EditorDef", godot_icall_Globals_EditorDef);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_TTR", godot_icall_Globals_TTR);
// Utils.OS
- mono_add_internal_call("GodotTools.Utils.OS::GetPlatformName", (void *)godot_icall_Utils_OS_GetPlatformName);
- mono_add_internal_call("GodotTools.Utils.OS::UnixFileHasExecutableAccess", (void *)godot_icall_Utils_OS_UnixFileHasExecutableAccess);
+ GDMonoUtils::add_internal_call("GodotTools.Utils.OS::GetPlatformName", godot_icall_Utils_OS_GetPlatformName);
+ GDMonoUtils::add_internal_call("GodotTools.Utils.OS::UnixFileHasExecutableAccess", godot_icall_Utils_OS_UnixFileHasExecutableAccess);
}
diff --git a/modules/mono/editor/editor_internal_calls.h b/modules/mono/editor/editor_internal_calls.h
index ef4e639161..24080cd867 100644
--- a/modules/mono/editor/editor_internal_calls.h
+++ b/modules/mono/editor/editor_internal_calls.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp
index 2edd8c87dc..4b858c0e82 100644
--- a/modules/mono/editor/godotsharp_export.cpp
+++ b/modules/mono/editor/godotsharp_export.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,9 +32,9 @@
#include <mono/metadata/image.h>
+#include "core/config/project_settings.h"
#include "core/io/file_access_pack.h"
#include "core/os/os.h"
-#include "core/project_settings.h"
#include "../mono_gd/gd_mono.h"
#include "../mono_gd/gd_mono_assembly.h"
@@ -55,10 +55,10 @@ MonoAssemblyName *new_mono_assembly_name() {
struct AssemblyRefInfo {
String name;
- uint16_t major;
- uint16_t minor;
- uint16_t build;
- uint16_t revision;
+ uint16_t major = 0;
+ uint16_t minor = 0;
+ uint16_t build = 0;
+ uint16_t revision = 0;
};
AssemblyRefInfo get_assemblyref_name(MonoImage *p_image, int index) {
@@ -141,5 +141,4 @@ Error get_exported_assembly_dependencies(const Dictionary &p_initial_assemblies,
return OK;
}
-
} // namespace GodotSharpExport
diff --git a/modules/mono/editor/godotsharp_export.h b/modules/mono/editor/godotsharp_export.h
index 9ab57755de..0e9d689618 100644
--- a/modules/mono/editor/godotsharp_export.h
+++ b/modules/mono/editor/godotsharp_export.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,9 +31,9 @@
#ifndef GODOTSHARP_EXPORT_H
#define GODOTSHARP_EXPORT_H
-#include "core/dictionary.h"
-#include "core/error_list.h"
-#include "core/ustring.h"
+#include "core/error/error_list.h"
+#include "core/string/ustring.h"
+#include "core/variant/dictionary.h"
#include "../mono_gd/gd_mono_header.h"
@@ -43,7 +43,6 @@ Error get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String>
Error get_exported_assembly_dependencies(const Dictionary &p_initial_assemblies,
const String &p_build_config, const String &p_custom_lib_dir, Dictionary &r_assembly_dependencies);
-
} // namespace GodotSharpExport
#endif // GODOTSHARP_EXPORT_H
diff --git a/modules/mono/editor/script_class_parser.cpp b/modules/mono/editor/script_class_parser.cpp
index f7d6e7e302..e81cbe4ebd 100644
--- a/modules/mono/editor/script_class_parser.cpp
+++ b/modules/mono/editor/script_class_parser.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,8 +30,8 @@
#include "script_class_parser.h"
-#include "core/map.h"
#include "core/os/os.h"
+#include "core/templates/map.h"
#include "../utils/string_utils.h"
@@ -735,9 +735,9 @@ Error ScriptClassParser::parse_file(const String &p_filepath) {
ERR_FAIL_COND_V_MSG(ferr != OK, ferr,
ferr == ERR_INVALID_DATA ?
- "File '" + p_filepath + "' contains invalid unicode (UTF-8), so it was not loaded."
+ "File '" + p_filepath + "' contains invalid unicode (UTF-8), so it was not loaded."
" Please ensure that scripts are saved in valid UTF-8 unicode." :
- "Failed to read file: '" + p_filepath + "'.");
+ "Failed to read file: '" + p_filepath + "'.");
run_dummy_preprocessor(source, p_filepath);
diff --git a/modules/mono/editor/script_class_parser.h b/modules/mono/editor/script_class_parser.h
index d611e8fb74..75a46bb4e5 100644
--- a/modules/mono/editor/script_class_parser.h
+++ b/modules/mono/editor/script_class_parser.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,9 +31,9 @@
#ifndef SCRIPT_CLASS_PARSER_H
#define SCRIPT_CLASS_PARSER_H
-#include "core/ustring.h"
-#include "core/variant.h"
-#include "core/vector.h"
+#include "core/string/ustring.h"
+#include "core/templates/vector.h"
+#include "core/variant/variant.h"
class ScriptClassParser {
public:
@@ -45,22 +45,22 @@ public:
};
String name;
- Type type;
+ Type type = NAMESPACE_DECL;
};
struct ClassDecl {
String name;
String namespace_;
Vector<String> base;
- bool nested;
+ bool nested = false;
};
private:
String code;
- int idx;
- int line;
+ int idx = 0;
+ int line = 0;
String error_str;
- bool error;
+ bool error = false;
Variant value;
Vector<ClassDecl> classes;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
index f77d3052f4..ce613f7ef9 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
@@ -81,6 +81,11 @@ namespace Godot.Collections
return godot_icall_Array_Resize(GetPtr(), newSize);
}
+ public void Shuffle()
+ {
+ godot_icall_Array_Shuffle(GetPtr());
+ }
+
public static Array operator +(Array left, Array right)
{
return new Array(godot_icall_Array_Concatenate(left.GetPtr(), right.GetPtr()));
@@ -220,6 +225,9 @@ namespace Godot.Collections
internal extern static Error godot_icall_Array_Resize(IntPtr ptr, int newSize);
[MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static Error godot_icall_Array_Shuffle(IntPtr ptr);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_Array_Generic_GetElementTypeInfo(Type elemType, out int elemTypeEncoding, out IntPtr elemTypeClass);
[MethodImpl(MethodImplOptions.InternalCall)]
@@ -295,6 +303,11 @@ namespace Godot.Collections
return objectArray.Resize(newSize);
}
+ public void Shuffle()
+ {
+ objectArray.Shuffle();
+ }
+
public static Array<T> operator +(Array<T> left, Array<T> right)
{
return new Array<T>(left.objectArray + right.objectArray);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
index 3700a6194f..0c333d06ef 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
@@ -104,7 +104,7 @@ namespace Godot
/// <summary>
/// The HSV hue of this color, on the range 0 to 1.
/// </summary>
- /// <value>Getting is a long process, refer to the source code for details. Setting uses <see cref="FromHsv"/>.</value>
+ /// <value>Getting is a long process, refer to the source code for details. Setting uses <see cref="FromHSV"/>.</value>
public float h
{
get
@@ -145,14 +145,14 @@ namespace Godot
}
set
{
- this = FromHsv(value, s, v, a);
+ this = FromHSV(value, s, v, a);
}
}
/// <summary>
/// The HSV saturation of this color, on the range 0 to 1.
/// </summary>
- /// <value>Getting is equivalent to the ratio between the min and max RGB value. Setting uses <see cref="FromHsv"/>.</value>
+ /// <value>Getting is equivalent to the ratio between the min and max RGB value. Setting uses <see cref="FromHSV"/>.</value>
public float s
{
get
@@ -166,14 +166,14 @@ namespace Godot
}
set
{
- this = FromHsv(h, value, v, a);
+ this = FromHSV(h, value, v, a);
}
}
/// <summary>
/// The HSV value (brightness) of this color, on the range 0 to 1.
/// </summary>
- /// <value>Getting is equivalent to using `Max()` on the RGB components. Setting uses <see cref="FromHsv"/>.</value>
+ /// <value>Getting is equivalent to using `Max()` on the RGB components. Setting uses <see cref="FromHSV"/>.</value>
public float v
{
get
@@ -182,7 +182,7 @@ namespace Godot
}
set
{
- this = FromHsv(h, s, value, a);
+ this = FromHSV(h, s, value, a);
}
}
@@ -257,20 +257,6 @@ namespace Godot
}
/// <summary>
- /// Returns the most contrasting color.
- /// </summary>
- /// <returns>The most contrasting color</returns>
- public Color Contrasted()
- {
- return new Color(
- (r + 0.5f) % 1.0f,
- (g + 0.5f) % 1.0f,
- (b + 0.5f) % 1.0f,
- a
- );
- }
-
- /// <summary>
/// Returns a new color resulting from making this color darker
/// by the specified ratio (on the range of 0 to 1).
/// </summary>
@@ -351,8 +337,8 @@ namespace Godot
}
/// <summary>
- /// Returns the color's 32-bit integer in ABGR format
- /// (each byte represents a component of the ABGR profile).
+ /// Returns the color converted to an unsigned 32-bit integer in ABGR
+ /// format (each byte represents a color channel).
/// ABGR is the reversed version of the default format.
/// </summary>
/// <returns>A uint representing this color in ABGR32 format.</returns>
@@ -370,8 +356,8 @@ namespace Godot
}
/// <summary>
- /// Returns the color's 64-bit integer in ABGR format
- /// (each word represents a component of the ABGR profile).
+ /// Returns the color converted to an unsigned 64-bit integer in ABGR
+ /// format (each word represents a color channel).
/// ABGR is the reversed version of the default format.
/// </summary>
/// <returns>A ulong representing this color in ABGR64 format.</returns>
@@ -389,8 +375,8 @@ namespace Godot
}
/// <summary>
- /// Returns the color's 32-bit integer in ARGB format
- /// (each byte represents a component of the ARGB profile).
+ /// Returns the color converted to an unsigned 32-bit integer in ARGB
+ /// format (each byte represents a color channel).
/// ARGB is more compatible with DirectX, but not used much in Godot.
/// </summary>
/// <returns>A uint representing this color in ARGB32 format.</returns>
@@ -408,8 +394,8 @@ namespace Godot
}
/// <summary>
- /// Returns the color's 64-bit integer in ARGB format
- /// (each word represents a component of the ARGB profile).
+ /// Returns the color converted to an unsigned 64-bit integer in ARGB
+ /// format (each word represents a color channel).
/// ARGB is more compatible with DirectX, but not used much in Godot.
/// </summary>
/// <returns>A ulong representing this color in ARGB64 format.</returns>
@@ -427,8 +413,8 @@ namespace Godot
}
/// <summary>
- /// Returns the color's 32-bit integer in RGBA format
- /// (each byte represents a component of the RGBA profile).
+ /// Returns the color converted to an unsigned 32-bit integer in RGBA
+ /// format (each byte represents a color channel).
/// RGBA is Godot's default and recommended format.
/// </summary>
/// <returns>A uint representing this color in RGBA32 format.</returns>
@@ -446,8 +432,8 @@ namespace Godot
}
/// <summary>
- /// Returns the color's 64-bit integer in RGBA format
- /// (each word represents a component of the RGBA profile).
+ /// Returns the color converted to an unsigned 64-bit integer in RGBA
+ /// format (each word represents a color channel).
/// RGBA is Godot's default and recommended format.
/// </summary>
/// <returns>A ulong representing this color in RGBA64 format.</returns>
@@ -469,7 +455,7 @@ namespace Godot
/// </summary>
/// <param name="includeAlpha">Whether or not to include alpha. If false, the color is RGB instead of RGBA.</param>
/// <returns>A string for the HTML hexadecimal representation of this color.</returns>
- public string ToHtml(bool includeAlpha = true)
+ public string ToHTML(bool includeAlpha = true)
{
var txt = string.Empty;
@@ -486,7 +472,7 @@ namespace Godot
}
/// <summary>
- /// Constructs a color from RGBA values on the range of 0 to 1.
+ /// Constructs a color from RGBA values, typically on the range of 0 to 1.
/// </summary>
/// <param name="r">The color's red component, typically on the range of 0 to 1.</param>
/// <param name="g">The color's green component, typically on the range of 0 to 1.</param>
@@ -514,8 +500,8 @@ namespace Godot
}
/// <summary>
- /// Constructs a color from a 32-bit integer
- /// (each byte represents a component of the RGBA profile).
+ /// Constructs a color from an unsigned 32-bit integer in RGBA format
+ /// (each byte represents a color channel).
/// </summary>
/// <param name="rgba">The uint representing the color.</param>
public Color(uint rgba)
@@ -530,8 +516,8 @@ namespace Godot
}
/// <summary>
- /// Constructs a color from a 64-bit integer
- /// (each word represents a component of the RGBA profile).
+ /// Constructs a color from an unsigned 64-bit integer in RGBA format
+ /// (each word represents a color channel).
/// </summary>
/// <param name="rgba">The ulong representing the color.</param>
public Color(ulong rgba)
@@ -546,18 +532,50 @@ namespace Godot
}
/// <summary>
+ /// Constructs a color either from an HTML color code or from a
+ /// standardized color name. Supported
+ /// color names are the same as the <see cref="Colors"/> constants.
+ /// </summary>
+ /// <param name="code">The HTML color code or color name to construct from.</param>
+ public Color(string code)
+ {
+ if (HtmlIsValid(code))
+ {
+ this = FromHTML(code);
+ }
+ else
+ {
+ this = Named(code);
+ }
+ }
+
+ /// <summary>
+ /// Constructs a color either from an HTML color code or from a
+ /// standardized color name, with `alpha` on the range of 0 to 1. Supported
+ /// color names are the same as the <see cref="Colors"/> constants.
+ /// </summary>
+ /// <param name="code">The HTML color code or color name to construct from.</param>
+ /// <param name="alpha">The alpha (transparency) value, typically on the range of 0 to 1.</param>
+ public Color(string code, float alpha)
+ {
+ this = new Color(code);
+ a = alpha;
+ }
+
+ /// <summary>
/// Constructs a color from the HTML hexadecimal color string in RGBA format.
/// </summary>
/// <param name="rgba">A string for the HTML hexadecimal representation of this color.</param>
- public Color(string rgba)
+ private static Color FromHTML(string rgba)
{
+ Color c;
if (rgba.Length == 0)
{
- r = 0f;
- g = 0f;
- b = 0f;
- a = 1.0f;
- return;
+ c.r = 0f;
+ c.g = 0f;
+ c.b = 0f;
+ c.a = 1.0f;
+ return c;
}
if (rgba[0] == '#')
@@ -591,47 +609,48 @@ namespace Godot
throw new ArgumentOutOfRangeException("Invalid color code. Length is " + rgba.Length + " but a length of 6 or 8 is expected: " + rgba);
}
- a = 1.0f;
+ c.a = 1.0f;
if (isShorthand)
{
- r = ParseCol4(rgba, 0) / 15f;
- g = ParseCol4(rgba, 1) / 15f;
- b = ParseCol4(rgba, 2) / 15f;
+ c.r = ParseCol4(rgba, 0) / 15f;
+ c.g = ParseCol4(rgba, 1) / 15f;
+ c.b = ParseCol4(rgba, 2) / 15f;
if (alpha)
{
- a = ParseCol4(rgba, 3) / 15f;
+ c.a = ParseCol4(rgba, 3) / 15f;
}
}
else
{
- r = ParseCol8(rgba, 0) / 255f;
- g = ParseCol8(rgba, 2) / 255f;
- b = ParseCol8(rgba, 4) / 255f;
+ c.r = ParseCol8(rgba, 0) / 255f;
+ c.g = ParseCol8(rgba, 2) / 255f;
+ c.b = ParseCol8(rgba, 4) / 255f;
if (alpha)
{
- a = ParseCol8(rgba, 6) / 255f;
+ c.a = ParseCol8(rgba, 6) / 255f;
}
}
- if (r < 0)
+ if (c.r < 0)
{
throw new ArgumentOutOfRangeException("Invalid color code. Red part is not valid hexadecimal: " + rgba);
}
- if (g < 0)
+ if (c.g < 0)
{
throw new ArgumentOutOfRangeException("Invalid color code. Green part is not valid hexadecimal: " + rgba);
}
- if (b < 0)
+ if (c.b < 0)
{
throw new ArgumentOutOfRangeException("Invalid color code. Blue part is not valid hexadecimal: " + rgba);
}
- if (a < 0)
+ if (c.a < 0)
{
throw new ArgumentOutOfRangeException("Invalid color code. Alpha part is not valid hexadecimal: " + rgba);
}
+ return c;
}
/// <summary>
@@ -654,9 +673,8 @@ namespace Godot
/// the constants defined in <see cref="Colors"/>.
/// </summary>
/// <param name="name">The name of the color.</param>
- /// <param name="alpha">The alpha (transparency) component represented on the range of 0 to 1. Default: 1.</param>
/// <returns>The constructed color.</returns>
- public static Color ColorN(string name, float alpha = 1f)
+ private static Color Named(string name)
{
name = name.Replace(" ", String.Empty);
name = name.Replace("-", String.Empty);
@@ -670,9 +688,7 @@ namespace Godot
throw new ArgumentOutOfRangeException($"Invalid Color Name: {name}");
}
- Color color = Colors.namedColors[name];
- color.a = alpha;
- return color;
+ return Colors.namedColors[name];
}
/// <summary>
@@ -685,11 +701,11 @@ namespace Godot
/// <param name="value">The HSV value (brightness), typically on the range of 0 to 1.</param>
/// <param name="alpha">The alpha (transparency) value, typically on the range of 0 to 1.</param>
/// <returns>The constructed color.</returns>
- public static Color FromHsv(float hue, float saturation, float value, float alpha = 1.0f)
+ public static Color FromHSV(float hue, float saturation, float value, float alpha = 1.0f)
{
if (saturation == 0)
{
- // acp_hromatic (grey)
+ // Achromatic (grey)
return new Color(value, value, value, alpha);
}
@@ -729,7 +745,7 @@ namespace Godot
/// <param name="hue">Output parameter for the HSV hue.</param>
/// <param name="saturation">Output parameter for the HSV saturation.</param>
/// <param name="value">Output parameter for the HSV value.</param>
- public void ToHsv(out float hue, out float saturation, out float value)
+ public void ToHSV(out float hue, out float saturation, out float value)
{
float max = (float)Mathf.Max(r, Mathf.Max(g, b));
float min = (float)Mathf.Min(r, Mathf.Min(g, b));
@@ -791,31 +807,10 @@ namespace Godot
return ParseCol4(str, ofs) * 16 + ParseCol4(str, ofs + 1);
}
- private String ToHex32(float val)
+ private string ToHex32(float val)
{
- int v = Mathf.RoundToInt(Mathf.Clamp(val * 255, 0, 255));
-
- var ret = string.Empty;
-
- for (int i = 0; i < 2; i++)
- {
- char c;
- int lv = v & 0xF;
-
- if (lv < 10)
- {
- c = (char)('0' + lv);
- }
- else
- {
- c = (char)('a' + lv - 10);
- }
-
- v >>= 4;
- ret = c + ret;
- }
-
- return ret;
+ byte b = (byte)Mathf.RoundToInt(Mathf.Clamp(val * 255, 0, 255));
+ return b.HexEncode();
}
internal static bool HtmlIsValid(string color)
@@ -838,7 +833,8 @@ namespace Godot
}
// Check if each hex digit is valid.
- for (int i = 0; i < len; i++) {
+ for (int i = 0; i < len; i++)
+ {
if (ParseCol4(color, i) == -1)
{
return false;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
index e050d1fdd1..6699c5992c 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
@@ -39,14 +39,6 @@ namespace Godot
return val * sgn;
}
- public static FuncRef FuncRef(Object instance, StringName funcName)
- {
- var ret = new FuncRef();
- ret.SetInstance(instance);
- ret.SetFunction(funcName);
- return ret;
- }
-
public static int Hash(object var)
{
return godot_icall_GD_hash(var);
@@ -129,7 +121,12 @@ namespace Godot
public static double RandRange(double from, double to)
{
- return godot_icall_GD_rand_range(from, to);
+ return godot_icall_GD_randf_range(from, to);
+ }
+
+ public static int RandRange(int from, int to)
+ {
+ return godot_icall_GD_randi_range(from, to);
}
public static uint RandSeed(ulong seed, out ulong newSeed)
@@ -238,9 +235,11 @@ namespace Godot
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_GD_randomize();
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static double godot_icall_GD_randf_range(double from, double to);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static double godot_icall_GD_rand_range(double from, double to);
+ internal extern static int godot_icall_GD_randi_range(int from, int to);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static uint godot_icall_GD_rand_seed(ulong seed, out ulong newSeed);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
index 6eecc262d6..c3f372d415 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
@@ -618,10 +618,10 @@ namespace Godot
/// This can also be used to round a floating point
/// number to an arbitrary number of decimals.
/// </summary>
- /// <param name="s">The value to stepify.</param>
+ /// <param name="s">The value to snap.</param>
/// <param name="step">The step size to snap to.</param>
/// <returns></returns>
- public static real_t Stepify(real_t s, real_t step)
+ public static real_t Snapped(real_t s, real_t step)
{
if (step != 0f)
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
index 42610c5ef7..48582d5ad8 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
@@ -15,14 +15,13 @@ namespace Godot
public Object() : this(false)
{
if (ptr == IntPtr.Zero)
- {
ptr = godot_icall_Object_Ctor(this);
- }
- else
- {
- // This is called inside godot_icall_Object_Ctor, so we must call it as well in this case.
- godot_icall_Object_ConnectEventSignals(ptr);
- }
+ _InitializeGodotScriptInstanceInternals();
+ }
+
+ internal void _InitializeGodotScriptInstanceInternals()
+ {
+ godot_icall_Object_ConnectEventSignals(ptr);
}
internal Object(bool memoryOwn)
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs
index b33490f9cb..bd3bcb0c58 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs
@@ -120,13 +120,13 @@ namespace Godot
/// <param name="b">The destination quaternion.</param>
/// <param name="preA">A quaternion before this quaternion.</param>
/// <param name="postB">A quaternion after `b`.</param>
- /// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The interpolated quaternion.</returns>
- public Quat CubicSlerp(Quat b, Quat preA, Quat postB, real_t t)
+ public Quat CubicSlerp(Quat b, Quat preA, Quat postB, real_t weight)
{
- real_t t2 = (1.0f - t) * t * 2f;
- Quat sp = Slerp(b, t);
- Quat sq = preA.Slerpni(postB, t);
+ real_t t2 = (1.0f - weight) * weight * 2f;
+ Quat sp = Slerp(b, weight);
+ Quat sq = preA.Slerpni(postB, weight);
return sp.Slerpni(sq, t2);
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
index f7703c77cc..868c3536fe 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
@@ -52,7 +52,7 @@ namespace Godot
}
/// <summary>
- /// The area of this rect.
+ /// The area of this Rect2.
/// </summary>
/// <value>Equivalent to <see cref="GetArea()"/>.</value>
public real_t Area
@@ -64,7 +64,7 @@ namespace Godot
/// Returns a Rect2 with equivalent position and size, modified so that
/// the top-left corner is the origin and width and height are positive.
/// </summary>
- /// <returns>The modified rect.</returns>
+ /// <returns>The modified Rect2.</returns>
public Rect2 Abs()
{
Vector2 end = End;
@@ -74,10 +74,11 @@ namespace Godot
/// <summary>
/// Returns the intersection of this Rect2 and `b`.
+ /// If the rectangles do not intersect, an empty Rect2 is returned.
/// </summary>
- /// <param name="b">The other rect.</param>
- /// <returns>The clipped rect.</returns>
- public Rect2 Clip(Rect2 b)
+ /// <param name="b">The other Rect2.</param>
+ /// <returns>The intersection of this Rect2 and `b`, or an empty Rect2 if they do not intersect.</returns>
+ public Rect2 Intersection(Rect2 b)
{
var newRect = b;
@@ -101,8 +102,8 @@ namespace Godot
/// <summary>
/// Returns true if this Rect2 completely encloses another one.
/// </summary>
- /// <param name="b">The other rect that may be enclosed.</param>
- /// <returns>A bool for whether or not this rect encloses `b`.</returns>
+ /// <param name="b">The other Rect2 that may be enclosed.</param>
+ /// <returns>A bool for whether or not this Rect2 encloses `b`.</returns>
public bool Encloses(Rect2 b)
{
return b._position.x >= _position.x && b._position.y >= _position.y &&
@@ -114,7 +115,7 @@ namespace Godot
/// Returns this Rect2 expanded to include a given point.
/// </summary>
/// <param name="to">The point to include.</param>
- /// <returns>The expanded rect.</returns>
+ /// <returns>The expanded Rect2.</returns>
public Rect2 Expand(Vector2 to)
{
var expanded = this;
@@ -156,10 +157,10 @@ namespace Godot
}
/// <summary>
- /// Returns a copy of the Rect2 grown a given amount of units towards all the sides.
+ /// Returns a copy of the Rect2 grown by the specified amount on all sides.
/// </summary>
/// <param name="by">The amount to grow by.</param>
- /// <returns>The grown rect.</returns>
+ /// <returns>The grown Rect2.</returns>
public Rect2 Grow(real_t by)
{
var g = this;
@@ -173,13 +174,13 @@ namespace Godot
}
/// <summary>
- /// Returns a copy of the Rect2 grown a given amount of units towards each direction individually.
+ /// Returns a copy of the Rect2 grown by the specified amount on each side individually.
/// </summary>
- /// <param name="left">The amount to grow by on the left.</param>
- /// <param name="top">The amount to grow by on the top.</param>
- /// <param name="right">The amount to grow by on the right.</param>
- /// <param name="bottom">The amount to grow by on the bottom.</param>
- /// <returns>The grown rect.</returns>
+ /// <param name="left">The amount to grow by on the left side.</param>
+ /// <param name="top">The amount to grow by on the top side.</param>
+ /// <param name="right">The amount to grow by on the right side.</param>
+ /// <param name="bottom">The amount to grow by on the bottom side.</param>
+ /// <returns>The grown Rect2.</returns>
public Rect2 GrowIndividual(real_t left, real_t top, real_t right, real_t bottom)
{
var g = this;
@@ -193,19 +194,19 @@ namespace Godot
}
/// <summary>
- /// Returns a copy of the Rect2 grown a given amount of units towards the <see cref="Margin"/> direction.
+ /// Returns a copy of the Rect2 grown by the specified amount on the specified Side.
/// </summary>
- /// <param name="margin">The direction to grow in.</param>
+ /// <param name="side">The side to grow.</param>
/// <param name="by">The amount to grow by.</param>
- /// <returns>The grown rect.</returns>
- public Rect2 GrowMargin(Margin margin, real_t by)
+ /// <returns>The grown Rect2.</returns>
+ public Rect2 GrowSide(Side side, real_t by)
{
var g = this;
- g = g.GrowIndividual(Margin.Left == margin ? by : 0,
- Margin.Top == margin ? by : 0,
- Margin.Right == margin ? by : 0,
- Margin.Bottom == margin ? by : 0);
+ g = g.GrowIndividual(Side.Left == side ? by : 0,
+ Side.Top == side ? by : 0,
+ Side.Right == side ? by : 0,
+ Side.Bottom == side ? by : 0);
return g;
}
@@ -213,7 +214,7 @@ namespace Godot
/// <summary>
/// Returns true if the Rect2 is flat or empty, or false otherwise.
/// </summary>
- /// <returns>A bool for whether or not the rect has area.</returns>
+ /// <returns>A bool for whether or not the Rect2 has area.</returns>
public bool HasNoArea()
{
return _size.x <= 0 || _size.y <= 0;
@@ -223,7 +224,7 @@ namespace Godot
/// Returns true if the Rect2 contains a point, or false otherwise.
/// </summary>
/// <param name="point">The point to check.</param>
- /// <returns>A bool for whether or not the rect contains `point`.</returns>
+ /// <returns>A bool for whether or not the Rect2 contains `point`.</returns>
public bool HasPoint(Vector2 point)
{
if (point.x < _position.x)
@@ -246,7 +247,7 @@ namespace Godot
/// If `includeBorders` is true, they will also be considered overlapping
/// if their borders touch, even without intersection.
/// </summary>
- /// <param name="b">The other rect to check for intersections with.</param>
+ /// <param name="b">The other Rect2 to check for intersections with.</param>
/// <param name="includeBorders">Whether or not to consider borders.</param>
/// <returns>A bool for whether or not they are intersecting.</returns>
public bool Intersects(Rect2 b, bool includeBorders = false)
@@ -296,8 +297,8 @@ namespace Godot
/// <summary>
/// Returns a larger Rect2 that contains this Rect2 and `b`.
/// </summary>
- /// <param name="b">The other rect.</param>
- /// <returns>The merged rect.</returns>
+ /// <param name="b">The other Rect2.</param>
+ /// <returns>The merged Rect2.</returns>
public Rect2 Merge(Rect2 b)
{
Rect2 newRect;
@@ -387,11 +388,11 @@ namespace Godot
}
/// <summary>
- /// Returns true if this rect and `other` are approximately equal, by running
+ /// Returns true if this Rect2 and `other` are approximately equal, by running
/// <see cref="Vector2.IsEqualApprox(Vector2)"/> on each component.
/// </summary>
- /// <param name="other">The other rect to compare.</param>
- /// <returns>Whether or not the rects are approximately equal.</returns>
+ /// <param name="other">The other Rect2 to compare.</param>
+ /// <returns>Whether or not the Rect2s are approximately equal.</returns>
public bool IsEqualApprox(Rect2 other)
{
return _position.IsEqualApprox(other._position) && _size.IsEqualApprox(other.Size);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs
index 8f71c00d76..c27af74866 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs
@@ -47,7 +47,7 @@ namespace Godot
}
/// <summary>
- /// The area of this rect.
+ /// The area of this Rect2i.
/// </summary>
/// <value>Equivalent to <see cref="GetArea()"/>.</value>
public int Area
@@ -59,7 +59,7 @@ namespace Godot
/// Returns a Rect2i with equivalent position and size, modified so that
/// the top-left corner is the origin and width and height are positive.
/// </summary>
- /// <returns>The modified rect.</returns>
+ /// <returns>The modified Rect2i.</returns>
public Rect2i Abs()
{
Vector2i end = End;
@@ -69,10 +69,11 @@ namespace Godot
/// <summary>
/// Returns the intersection of this Rect2i and `b`.
+ /// If the rectangles do not intersect, an empty Rect2i is returned.
/// </summary>
- /// <param name="b">The other rect.</param>
- /// <returns>The clipped rect.</returns>
- public Rect2i Clip(Rect2i b)
+ /// <param name="b">The other Rect2i.</param>
+ /// <returns>The intersection of this Rect2i and `b`, or an empty Rect2i if they do not intersect.</returns>
+ public Rect2i Intersection(Rect2i b)
{
var newRect = b;
@@ -96,8 +97,8 @@ namespace Godot
/// <summary>
/// Returns true if this Rect2i completely encloses another one.
/// </summary>
- /// <param name="b">The other rect that may be enclosed.</param>
- /// <returns>A bool for whether or not this rect encloses `b`.</returns>
+ /// <param name="b">The other Rect2i that may be enclosed.</param>
+ /// <returns>A bool for whether or not this Rect2i encloses `b`.</returns>
public bool Encloses(Rect2i b)
{
return b._position.x >= _position.x && b._position.y >= _position.y &&
@@ -109,7 +110,7 @@ namespace Godot
/// Returns this Rect2i expanded to include a given point.
/// </summary>
/// <param name="to">The point to include.</param>
- /// <returns>The expanded rect.</returns>
+ /// <returns>The expanded Rect2i.</returns>
public Rect2i Expand(Vector2i to)
{
var expanded = this;
@@ -151,10 +152,10 @@ namespace Godot
}
/// <summary>
- /// Returns a copy of the Rect2i grown a given amount of units towards all the sides.
+ /// Returns a copy of the Rect2i grown by the specified amount on all sides.
/// </summary>
/// <param name="by">The amount to grow by.</param>
- /// <returns>The grown rect.</returns>
+ /// <returns>The grown Rect2i.</returns>
public Rect2i Grow(int by)
{
var g = this;
@@ -168,13 +169,13 @@ namespace Godot
}
/// <summary>
- /// Returns a copy of the Rect2i grown a given amount of units towards each direction individually.
+ /// Returns a copy of the Rect2i grown by the specified amount on each side individually.
/// </summary>
- /// <param name="left">The amount to grow by on the left.</param>
- /// <param name="top">The amount to grow by on the top.</param>
- /// <param name="right">The amount to grow by on the right.</param>
- /// <param name="bottom">The amount to grow by on the bottom.</param>
- /// <returns>The grown rect.</returns>
+ /// <param name="left">The amount to grow by on the left side.</param>
+ /// <param name="top">The amount to grow by on the top side.</param>
+ /// <param name="right">The amount to grow by on the right side.</param>
+ /// <param name="bottom">The amount to grow by on the bottom side.</param>
+ /// <returns>The grown Rect2i.</returns>
public Rect2i GrowIndividual(int left, int top, int right, int bottom)
{
var g = this;
@@ -188,37 +189,37 @@ namespace Godot
}
/// <summary>
- /// Returns a copy of the Rect2i grown a given amount of units towards the <see cref="Margin"/> direction.
+ /// Returns a copy of the Rect2i grown by the specified amount on the specified Side.
/// </summary>
- /// <param name="margin">The direction to grow in.</param>
+ /// <param name="side">The side to grow.</param>
/// <param name="by">The amount to grow by.</param>
- /// <returns>The grown rect.</returns>
- public Rect2i GrowMargin(Margin margin, int by)
+ /// <returns>The grown Rect2i.</returns>
+ public Rect2i GrowSide(Side side, int by)
{
var g = this;
- g = g.GrowIndividual(Margin.Left == margin ? by : 0,
- Margin.Top == margin ? by : 0,
- Margin.Right == margin ? by : 0,
- Margin.Bottom == margin ? by : 0);
+ g = g.GrowIndividual(Side.Left == side ? by : 0,
+ Side.Top == side ? by : 0,
+ Side.Right == side ? by : 0,
+ Side.Bottom == side ? by : 0);
return g;
}
/// <summary>
- /// Returns true if the Rect2 is flat or empty, or false otherwise.
+ /// Returns true if the Rect2i is flat or empty, or false otherwise.
/// </summary>
- /// <returns>A bool for whether or not the rect has area.</returns>
+ /// <returns>A bool for whether or not the Rect2i has area.</returns>
public bool HasNoArea()
{
return _size.x <= 0 || _size.y <= 0;
}
/// <summary>
- /// Returns true if the Rect2 contains a point, or false otherwise.
+ /// Returns true if the Rect2i contains a point, or false otherwise.
/// </summary>
/// <param name="point">The point to check.</param>
- /// <returns>A bool for whether or not the rect contains `point`.</returns>
+ /// <returns>A bool for whether or not the Rect2i contains `point`.</returns>
public bool HasPoint(Vector2i point)
{
if (point.x < _position.x)
@@ -241,7 +242,7 @@ namespace Godot
/// If `includeBorders` is true, they will also be considered overlapping
/// if their borders touch, even without intersection.
/// </summary>
- /// <param name="b">The other rect to check for intersections with.</param>
+ /// <param name="b">The other Rect2i to check for intersections with.</param>
/// <param name="includeBorders">Whether or not to consider borders.</param>
/// <returns>A bool for whether or not they are intersecting.</returns>
public bool Intersects(Rect2i b, bool includeBorders = false)
@@ -273,10 +274,10 @@ namespace Godot
}
/// <summary>
- /// Returns a larger Rect2i that contains this Rect2 and `b`.
+ /// Returns a larger Rect2i that contains this Rect2i and `b`.
/// </summary>
- /// <param name="b">The other rect.</param>
- /// <returns>The merged rect.</returns>
+ /// <param name="b">The other Rect2i.</param>
+ /// <returns>The merged Rect2i.</returns>
public Rect2i Merge(Rect2i b)
{
Rect2i newRect;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
index bd1dbc1229..98efa89ef0 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
@@ -97,6 +97,36 @@ namespace Godot
return b;
}
+ /// <summary>
+ /// Converts a string containing a binary number into an integer.
+ /// Binary strings can either be prefixed with `0b` or not,
+ /// and they can also start with a `-` before the optional prefix.
+ /// </summary>
+ /// <param name="instance">The string to convert.</param>
+ /// <returns>The converted string.</returns>
+ public static int BinToInt(this string instance)
+ {
+ if (instance.Length == 0)
+ {
+ return 0;
+ }
+
+ int sign = 1;
+
+ if (instance[0] == '-')
+ {
+ sign = -1;
+ instance = instance.Substring(1);
+ }
+
+ if (instance.StartsWith("0b"))
+ {
+ instance = instance.Substring(2);
+ }
+
+ return sign * Convert.ToInt32(instance, 2);;
+ }
+
// <summary>
// Return the amount of substrings in string.
// </summary>
@@ -322,6 +352,15 @@ namespace Godot
return instance.IndexOf(what, from, caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
}
+ /// <summary>Find the first occurrence of a char. Optionally, the search starting position can be passed.</summary>
+ /// <returns>The first instance of the char, or -1 if not found.</returns>
+ public static int Find(this string instance, char what, int from = 0, bool caseSensitive = true)
+ {
+ // TODO: Could be more efficient if we get a char version of `IndexOf`.
+ // See https://github.com/dotnet/runtime/issues/44116
+ return instance.IndexOf(what.ToString(), from, caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
+ }
+
/// <summary>Find the last occurrence of a substring.</summary>
/// <returns>The starting position of the substring, or -1 if not found.</returns>
public static int FindLast(this string instance, string what, bool caseSensitive = true)
@@ -393,26 +432,111 @@ namespace Godot
return instance.Substring(sep + 1);
}
+ /// <summary>
+ /// Converts the given byte array of ASCII encoded text to a string.
+ /// Faster alternative to <see cref="GetStringFromUTF8"/> if the
+ /// content is ASCII-only. Unlike the UTF-8 function this function
+ /// maps every byte to a character in the array. Multibyte sequences
+ /// will not be interpreted correctly. For parsing user input always
+ /// use <see cref="GetStringFromUTF8"/>.
+ /// </summary>
+ /// <param name="bytes">A byte array of ASCII characters (on the range of 0-127).</param>
+ /// <returns>A string created from the bytes.</returns>
+ public static string GetStringFromASCII(this byte[] bytes)
+ {
+ return Encoding.ASCII.GetString(bytes);
+ }
+
+ /// <summary>
+ /// Converts the given byte array of UTF-8 encoded text to a string.
+ /// Slower than <see cref="GetStringFromASCII"/> but supports UTF-8
+ /// encoded data. Use this function if you are unsure about the
+ /// source of the data. For user input this function
+ /// should always be preferred.
+ /// </summary>
+ /// <param name="bytes">A byte array of UTF-8 characters (a character may take up multiple bytes).</param>
+ /// <returns>A string created from the bytes.</returns>
+ public static string GetStringFromUTF8(this byte[] bytes)
+ {
+ return Encoding.UTF8.GetString(bytes);
+ }
+
// <summary>
- // Hash the string and return a 32 bits integer.
+ // Hash the string and return a 32 bits unsigned integer.
// </summary>
- public static int Hash(this string instance)
+ public static uint Hash(this string instance)
{
- int index = 0;
- int hashv = 5381;
- int c;
+ uint hash = 5381;
- while ((c = instance[index++]) != 0)
- hashv = (hashv << 5) + hashv + c; // hash * 33 + c
+ foreach(uint c in instance)
+ {
+ hash = (hash << 5) + hash + c; // hash * 33 + c
+ }
- return hashv;
+ return hash;
}
- // <summary>
- // Convert a string containing an hexadecimal number into an int.
- // </summary>
+ /// <summary>
+ /// Returns a hexadecimal representation of this byte as a string.
+ /// </summary>
+ /// <param name="b">The byte to encode.</param>
+ /// <returns>The hexadecimal representation of this byte.</returns>
+ internal static string HexEncode(this byte b)
+ {
+ var ret = string.Empty;
+
+ for (int i = 0; i < 2; i++)
+ {
+ char c;
+ int lv = b & 0xF;
+
+ if (lv < 10)
+ {
+ c = (char)('0' + lv);
+ }
+ else
+ {
+ c = (char)('a' + lv - 10);
+ }
+
+ b >>= 4;
+ ret = c + ret;
+ }
+
+ return ret;
+ }
+
+ /// <summary>
+ /// Returns a hexadecimal representation of this byte array as a string.
+ /// </summary>
+ /// <param name="bytes">The byte array to encode.</param>
+ /// <returns>The hexadecimal representation of this byte array.</returns>
+ public static string HexEncode(this byte[] bytes)
+ {
+ var ret = string.Empty;
+
+ foreach (byte b in bytes)
+ {
+ ret += b.HexEncode();
+ }
+
+ return ret;
+ }
+
+ /// <summary>
+ /// Converts a string containing a hexadecimal number into an integer.
+ /// Hexadecimal strings can either be prefixed with `0x` or not,
+ /// and they can also start with a `-` before the optional prefix.
+ /// </summary>
+ /// <param name="instance">The string to convert.</param>
+ /// <returns>The converted string.</returns>
public static int HexToInt(this string instance)
{
+ if (instance.Length == 0)
+ {
+ return 0;
+ }
+
int sign = 1;
if (instance[0] == '-')
@@ -421,10 +545,12 @@ namespace Godot
instance = instance.Substring(1);
}
- if (!instance.StartsWith("0x"))
- return 0;
+ if (instance.StartsWith("0x"))
+ {
+ instance = instance.Substring(2);
+ }
- return sign * int.Parse(instance.Substring(2), NumberStyles.HexNumber);
+ return sign * int.Parse(instance, NumberStyles.HexNumber);
}
// <summary>
@@ -630,6 +756,33 @@ namespace Godot
}
/// <summary>
+ /// Returns a copy of the string with characters removed from the left.
+ /// </summary>
+ /// <param name="instance">The string to remove characters from.</param>
+ /// <param name="chars">The characters to be removed.</param>
+ /// <returns>A copy of the string with characters removed from the left.</returns>
+ public static string LStrip(this string instance, string chars)
+ {
+ int len = instance.Length;
+ int beg;
+
+ for (beg = 0; beg < len; beg++)
+ {
+ if (chars.Find(instance[beg]) == -1)
+ {
+ break;
+ }
+ }
+
+ if (beg == 0)
+ {
+ return instance;
+ }
+
+ return instance.Substr(beg, len - beg);
+ }
+
+ /// <summary>
/// Do a simple expression match, where '*' matches zero or more arbitrary characters and '?' matches any single character except '.'.
/// </summary>
private static bool ExprMatch(this string instance, string expr, bool caseSensitive)
@@ -780,22 +933,6 @@ namespace Godot
}
// <summary>
- // Decode a percent-encoded string. See [method percent_encode].
- // </summary>
- public static string PercentDecode(this string instance)
- {
- return Uri.UnescapeDataString(instance);
- }
-
- // <summary>
- // Percent-encode a string. This is meant to encode parameters in a URL when sending a HTTP GET request and bodies of form-urlencoded POST request.
- // </summary>
- public static string PercentEncode(this string instance)
- {
- return Uri.EscapeDataString(instance);
- }
-
- // <summary>
// If the string is a path, this concatenates [code]file[/code] at the end of the string as a subpath. E.g. [code]"this/is".plus_file("path") == "this/is/path"[/code].
// </summary>
public static string PlusFile(this string instance, string file)
@@ -857,6 +994,33 @@ namespace Godot
return instance.Substring(pos, instance.Length - pos);
}
+ /// <summary>
+ /// Returns a copy of the string with characters removed from the right.
+ /// </summary>
+ /// <param name="instance">The string to remove characters from.</param>
+ /// <param name="chars">The characters to be removed.</param>
+ /// <returns>A copy of the string with characters removed from the right.</returns>
+ public static string RStrip(this string instance, string chars)
+ {
+ int len = instance.Length;
+ int end;
+
+ for (end = len - 1; end >= 0; end--)
+ {
+ if (chars.Find(instance[end]) == -1)
+ {
+ break;
+ }
+ }
+
+ if (end == len - 1)
+ {
+ return instance;
+ }
+
+ return instance.Substr(0, end + 1);
+ }
+
public static byte[] SHA256Buffer(this string instance)
{
return godot_icall_String_sha256_buffer(instance);
@@ -1030,6 +1194,33 @@ namespace Godot
return Encoding.UTF8.GetBytes(instance);
}
+ /// <summary>
+ /// Decodes a string in URL encoded format. This is meant to
+ /// decode parameters in a URL when receiving an HTTP request.
+ /// This mostly wraps around `System.Uri.UnescapeDataString()`,
+ /// but also handles `+`.
+ /// See <see cref="URIEncode"/> for encoding.
+ /// </summary>
+ /// <param name="instance">The string to decode.</param>
+ /// <returns>The unescaped string.</returns>
+ public static string URIDecode(this string instance)
+ {
+ return Uri.UnescapeDataString(instance.Replace("+", "%20"));
+ }
+
+ /// <summary>
+ /// Encodes a string to URL friendly format. This is meant to
+ /// encode parameters in a URL when sending an HTTP request.
+ /// This wraps around `System.Uri.EscapeDataString()`.
+ /// See <see cref="URIDecode"/> for decoding.
+ /// </summary>
+ /// <param name="instance">The string to encode.</param>
+ /// <returns>The escaped string.</returns>
+ public static string URIEncode(this string instance)
+ {
+ return Uri.EscapeDataString(instance);
+ }
+
// <summary>
// Return a copy of the string with special characters escaped using the XML standard.
// </summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
index 06bbe98497..bc0f81b2a7 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
@@ -221,8 +221,7 @@ namespace Godot
real_t dot = v1.Dot(v2);
- // Clamp dot to [-1, 1]
- dot = dot < -1.0f ? -1.0f : (dot > 1.0f ? 1.0f : dot);
+ dot = Mathf.Clamp(dot, -1.0f, 1.0f);
Vector2 v;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
index d536b14eac..6279ea1ace 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
@@ -194,15 +194,16 @@ namespace Godot
/// <param name="b">The destination vector.</param>
/// <param name="preA">A vector before this vector.</param>
/// <param name="postB">A vector after `b`.</param>
- /// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The interpolated vector.</returns>
- public Vector2 CubicInterpolate(Vector2 b, Vector2 preA, Vector2 postB, real_t t)
+ public Vector2 CubicInterpolate(Vector2 b, Vector2 preA, Vector2 postB, real_t weight)
{
Vector2 p0 = preA;
Vector2 p1 = this;
Vector2 p2 = b;
Vector2 p3 = postB;
+ real_t t = weight;
real_t t2 = t * t;
real_t t3 = t2 * t;
@@ -510,7 +511,7 @@ namespace Godot
/// <returns>The snapped vector.</returns>
public Vector2 Snapped(Vector2 step)
{
- return new Vector2(Mathf.Stepify(x, step.x), Mathf.Stepify(y, step.y));
+ return new Vector2(Mathf.Snapped(x, step.x), Mathf.Snapped(y, step.y));
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
index 4a4a2a43cd..42dbdf25c3 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
@@ -161,15 +161,16 @@ namespace Godot
/// <param name="b">The destination vector.</param>
/// <param name="preA">A vector before this vector.</param>
/// <param name="postB">A vector after `b`.</param>
- /// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The interpolated vector.</returns>
- public Vector3 CubicInterpolate(Vector3 b, Vector3 preA, Vector3 postB, real_t t)
+ public Vector3 CubicInterpolate(Vector3 b, Vector3 preA, Vector3 postB, real_t weight)
{
Vector3 p0 = preA;
Vector3 p1 = this;
Vector3 p2 = b;
Vector3 p3 = postB;
+ real_t t = weight;
real_t t2 = t * t;
real_t t3 = t2 * t;
@@ -512,9 +513,9 @@ namespace Godot
{
return new Vector3
(
- Mathf.Stepify(x, step.x),
- Mathf.Stepify(y, step.y),
- Mathf.Stepify(z, step.z)
+ Mathf.Snapped(x, step.x),
+ Mathf.Snapped(y, step.y),
+ Mathf.Snapped(z, step.z)
);
}
diff --git a/modules/mono/glue/arguments_vector.h b/modules/mono/glue/arguments_vector.h
index ab48904571..9ba6a05ac6 100644
--- a/modules/mono/glue/arguments_vector.h
+++ b/modules/mono/glue/arguments_vector.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp
index ebcd6d5e9c..34a96eba17 100644
--- a/modules/mono/glue/base_object_glue.cpp
+++ b/modules/mono/glue/base_object_glue.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,10 +30,9 @@
#ifdef MONO_GLUE_ENABLED
-#include "core/class_db.h"
-#include "core/object.h"
-#include "core/reference.h"
-#include "core/string_name.h"
+#include "core/object/class_db.h"
+#include "core/object/reference.h"
+#include "core/string/string_name.h"
#include "../csharp_script.h"
#include "../mono_gd/gd_mono_cache.h"
@@ -164,9 +163,9 @@ MonoObject *godot_icall_Object_weakref(Object *p_ptr) {
return GDMonoUtils::unmanaged_get_managed(wref.ptr());
}
-Error godot_icall_SignalAwaiter_connect(Object *p_source, StringName *p_signal, Object *p_target, MonoObject *p_awaiter) {
+int32_t godot_icall_SignalAwaiter_connect(Object *p_source, StringName *p_signal, Object *p_target, MonoObject *p_awaiter) {
StringName signal = p_signal ? *p_signal : StringName();
- return gd_mono_connect_signal_awaiter(p_source, signal, p_target, p_awaiter);
+ return (int32_t)gd_mono_connect_signal_awaiter(p_source, signal, p_target, p_awaiter);
}
MonoArray *godot_icall_DynamicGodotObject_SetMemberList(Object *p_ptr) {
@@ -241,18 +240,18 @@ MonoString *godot_icall_Object_ToString(Object *p_ptr) {
}
void godot_register_object_icalls() {
- mono_add_internal_call("Godot.Object::godot_icall_Object_Ctor", (void *)godot_icall_Object_Ctor);
- mono_add_internal_call("Godot.Object::godot_icall_Object_Disposed", (void *)godot_icall_Object_Disposed);
- mono_add_internal_call("Godot.Object::godot_icall_Reference_Disposed", (void *)godot_icall_Reference_Disposed);
- mono_add_internal_call("Godot.Object::godot_icall_Object_ConnectEventSignals", (void *)godot_icall_Object_ConnectEventSignals);
- mono_add_internal_call("Godot.Object::godot_icall_Object_ClassDB_get_method", (void *)godot_icall_Object_ClassDB_get_method);
- mono_add_internal_call("Godot.Object::godot_icall_Object_ToString", (void *)godot_icall_Object_ToString);
- mono_add_internal_call("Godot.Object::godot_icall_Object_weakref", (void *)godot_icall_Object_weakref);
- mono_add_internal_call("Godot.SignalAwaiter::godot_icall_SignalAwaiter_connect", (void *)godot_icall_SignalAwaiter_connect);
- mono_add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_SetMemberList", (void *)godot_icall_DynamicGodotObject_SetMemberList);
- mono_add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_InvokeMember", (void *)godot_icall_DynamicGodotObject_InvokeMember);
- mono_add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_GetMember", (void *)godot_icall_DynamicGodotObject_GetMember);
- mono_add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_SetMember", (void *)godot_icall_DynamicGodotObject_SetMember);
+ GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_Ctor", godot_icall_Object_Ctor);
+ GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_Disposed", godot_icall_Object_Disposed);
+ GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Reference_Disposed", godot_icall_Reference_Disposed);
+ GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ConnectEventSignals", godot_icall_Object_ConnectEventSignals);
+ GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ClassDB_get_method", godot_icall_Object_ClassDB_get_method);
+ GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ToString", godot_icall_Object_ToString);
+ GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_weakref", godot_icall_Object_weakref);
+ GDMonoUtils::add_internal_call("Godot.SignalAwaiter::godot_icall_SignalAwaiter_connect", godot_icall_SignalAwaiter_connect);
+ GDMonoUtils::add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_SetMemberList", godot_icall_DynamicGodotObject_SetMemberList);
+ GDMonoUtils::add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_InvokeMember", godot_icall_DynamicGodotObject_InvokeMember);
+ GDMonoUtils::add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_GetMember", godot_icall_DynamicGodotObject_GetMember);
+ GDMonoUtils::add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_SetMember", godot_icall_DynamicGodotObject_SetMember);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp
index 3313e8cb77..191f863350 100644
--- a/modules/mono/glue/collections_glue.cpp
+++ b/modules/mono/glue/collections_glue.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,7 +32,7 @@
#include <mono/metadata/exception.h>
-#include "core/array.h"
+#include "core/variant/array.h"
#include "../mono_gd/gd_mono_cache.h"
#include "../mono_gd/gd_mono_class.h"
@@ -47,7 +47,7 @@ void godot_icall_Array_Dtor(Array *ptr) {
memdelete(ptr);
}
-MonoObject *godot_icall_Array_At(Array *ptr, int index) {
+MonoObject *godot_icall_Array_At(Array *ptr, int32_t index) {
if (index < 0 || index >= ptr->size()) {
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
return nullptr;
@@ -55,7 +55,7 @@ MonoObject *godot_icall_Array_At(Array *ptr, int index) {
return GDMonoMarshal::variant_to_mono_object(ptr->operator[](index));
}
-MonoObject *godot_icall_Array_At_Generic(Array *ptr, int index, uint32_t type_encoding, GDMonoClass *type_class) {
+MonoObject *godot_icall_Array_At_Generic(Array *ptr, int32_t index, uint32_t type_encoding, GDMonoClass *type_class) {
if (index < 0 || index >= ptr->size()) {
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
return nullptr;
@@ -63,7 +63,7 @@ MonoObject *godot_icall_Array_At_Generic(Array *ptr, int index, uint32_t type_en
return GDMonoMarshal::variant_to_mono_object(ptr->operator[](index), ManagedType(type_encoding, type_class));
}
-void godot_icall_Array_SetAt(Array *ptr, int index, MonoObject *value) {
+void godot_icall_Array_SetAt(Array *ptr, int32_t index, MonoObject *value) {
if (index < 0 || index >= ptr->size()) {
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
return;
@@ -71,11 +71,11 @@ void godot_icall_Array_SetAt(Array *ptr, int index, MonoObject *value) {
ptr->operator[](index) = GDMonoMarshal::mono_object_to_variant(value);
}
-int godot_icall_Array_Count(Array *ptr) {
+int32_t godot_icall_Array_Count(Array *ptr) {
return ptr->size();
}
-int godot_icall_Array_Add(Array *ptr, MonoObject *item) {
+int32_t godot_icall_Array_Add(Array *ptr, MonoObject *item) {
ptr->append(GDMonoMarshal::mono_object_to_variant(item));
return ptr->size();
}
@@ -88,7 +88,7 @@ MonoBoolean godot_icall_Array_Contains(Array *ptr, MonoObject *item) {
return ptr->find(GDMonoMarshal::mono_object_to_variant(item)) != -1;
}
-void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int array_index) {
+void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int32_t array_index) {
unsigned int count = ptr->size();
if (mono_array_length(array) < (array_index + count)) {
@@ -129,11 +129,11 @@ Array *godot_icall_Array_Concatenate(Array *left, Array *right) {
return new_array;
}
-int godot_icall_Array_IndexOf(Array *ptr, MonoObject *item) {
+int32_t godot_icall_Array_IndexOf(Array *ptr, MonoObject *item) {
return ptr->find(GDMonoMarshal::mono_object_to_variant(item));
}
-void godot_icall_Array_Insert(Array *ptr, int index, MonoObject *item) {
+void godot_icall_Array_Insert(Array *ptr, int32_t index, MonoObject *item) {
if (index < 0 || index > ptr->size()) {
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
return;
@@ -150,7 +150,7 @@ MonoBoolean godot_icall_Array_Remove(Array *ptr, MonoObject *item) {
return false;
}
-void godot_icall_Array_RemoveAt(Array *ptr, int index) {
+void godot_icall_Array_RemoveAt(Array *ptr, int32_t index) {
if (index < 0 || index >= ptr->size()) {
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
return;
@@ -158,8 +158,12 @@ void godot_icall_Array_RemoveAt(Array *ptr, int index) {
ptr->remove(index);
}
-Error godot_icall_Array_Resize(Array *ptr, int new_size) {
- return ptr->resize(new_size);
+int32_t godot_icall_Array_Resize(Array *ptr, int32_t new_size) {
+ return (int32_t)ptr->resize(new_size);
+}
+
+void godot_icall_Array_Shuffle(Array *ptr) {
+ ptr->shuffle();
}
void godot_icall_Array_Generic_GetElementTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class) {
@@ -222,7 +226,7 @@ Array *godot_icall_Dictionary_Values(Dictionary *ptr) {
return memnew(Array(ptr->values()));
}
-int godot_icall_Dictionary_Count(Dictionary *ptr) {
+int32_t godot_icall_Dictionary_Count(Dictionary *ptr) {
return ptr->size();
}
@@ -304,46 +308,47 @@ MonoString *godot_icall_Dictionary_ToString(Dictionary *ptr) {
}
void godot_register_collections_icalls() {
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor", (void *)godot_icall_Array_Ctor);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor_MonoArray", (void *)godot_icall_Array_Ctor_MonoArray);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Dtor", (void *)godot_icall_Array_Dtor);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_At", (void *)godot_icall_Array_At);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_At_Generic", (void *)godot_icall_Array_At_Generic);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_SetAt", (void *)godot_icall_Array_SetAt);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Count", (void *)godot_icall_Array_Count);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Add", (void *)godot_icall_Array_Add);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Clear", (void *)godot_icall_Array_Clear);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Concatenate", (void *)godot_icall_Array_Concatenate);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Contains", (void *)godot_icall_Array_Contains);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_CopyTo", (void *)godot_icall_Array_CopyTo);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Duplicate", (void *)godot_icall_Array_Duplicate);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_IndexOf", (void *)godot_icall_Array_IndexOf);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Insert", (void *)godot_icall_Array_Insert);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Remove", (void *)godot_icall_Array_Remove);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_RemoveAt", (void *)godot_icall_Array_RemoveAt);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Resize", (void *)godot_icall_Array_Resize);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Generic_GetElementTypeInfo", (void *)godot_icall_Array_Generic_GetElementTypeInfo);
- mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_ToString", (void *)godot_icall_Array_ToString);
-
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Ctor", (void *)godot_icall_Dictionary_Ctor);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Dtor", (void *)godot_icall_Dictionary_Dtor);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue", (void *)godot_icall_Dictionary_GetValue);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue_Generic", (void *)godot_icall_Dictionary_GetValue_Generic);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_SetValue", (void *)godot_icall_Dictionary_SetValue);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Keys", (void *)godot_icall_Dictionary_Keys);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Values", (void *)godot_icall_Dictionary_Values);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Count", (void *)godot_icall_Dictionary_Count);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Add", (void *)godot_icall_Dictionary_Add);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Clear", (void *)godot_icall_Dictionary_Clear);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Contains", (void *)godot_icall_Dictionary_Contains);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_ContainsKey", (void *)godot_icall_Dictionary_ContainsKey);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Duplicate", (void *)godot_icall_Dictionary_Duplicate);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_RemoveKey", (void *)godot_icall_Dictionary_RemoveKey);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Remove", (void *)godot_icall_Dictionary_Remove);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue", (void *)godot_icall_Dictionary_TryGetValue);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue_Generic", (void *)godot_icall_Dictionary_TryGetValue_Generic);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Generic_GetValueTypeInfo", (void *)godot_icall_Dictionary_Generic_GetValueTypeInfo);
- mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_ToString", (void *)godot_icall_Dictionary_ToString);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor", godot_icall_Array_Ctor);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor_MonoArray", godot_icall_Array_Ctor_MonoArray);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Dtor", godot_icall_Array_Dtor);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_At", godot_icall_Array_At);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_At_Generic", godot_icall_Array_At_Generic);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_SetAt", godot_icall_Array_SetAt);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Count", godot_icall_Array_Count);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Add", godot_icall_Array_Add);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Clear", godot_icall_Array_Clear);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Concatenate", godot_icall_Array_Concatenate);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Contains", godot_icall_Array_Contains);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_CopyTo", godot_icall_Array_CopyTo);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Duplicate", godot_icall_Array_Duplicate);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_IndexOf", godot_icall_Array_IndexOf);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Insert", godot_icall_Array_Insert);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Remove", godot_icall_Array_Remove);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_RemoveAt", godot_icall_Array_RemoveAt);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Resize", godot_icall_Array_Resize);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Shuffle", godot_icall_Array_Shuffle);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Generic_GetElementTypeInfo", godot_icall_Array_Generic_GetElementTypeInfo);
+ GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_ToString", godot_icall_Array_ToString);
+
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Ctor", godot_icall_Dictionary_Ctor);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Dtor", godot_icall_Dictionary_Dtor);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue", godot_icall_Dictionary_GetValue);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue_Generic", godot_icall_Dictionary_GetValue_Generic);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_SetValue", godot_icall_Dictionary_SetValue);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Keys", godot_icall_Dictionary_Keys);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Values", godot_icall_Dictionary_Values);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Count", godot_icall_Dictionary_Count);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Add", godot_icall_Dictionary_Add);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Clear", godot_icall_Dictionary_Clear);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Contains", godot_icall_Dictionary_Contains);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_ContainsKey", godot_icall_Dictionary_ContainsKey);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Duplicate", godot_icall_Dictionary_Duplicate);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_RemoveKey", godot_icall_Dictionary_RemoveKey);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Remove", godot_icall_Dictionary_Remove);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue", godot_icall_Dictionary_TryGetValue);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue_Generic", godot_icall_Dictionary_TryGetValue_Generic);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Generic_GetValueTypeInfo", godot_icall_Dictionary_Generic_GetValueTypeInfo);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_ToString", godot_icall_Dictionary_ToString);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/gd_glue.cpp b/modules/mono/glue/gd_glue.cpp
index 5e892b616b..a2ff868f65 100644
--- a/modules/mono/glue/gd_glue.cpp
+++ b/modules/mono/glue/gd_glue.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,12 +30,12 @@
#ifdef MONO_GLUE_ENABLED
-#include "core/array.h"
#include "core/io/marshalls.h"
#include "core/os/os.h"
-#include "core/ustring.h"
-#include "core/variant.h"
-#include "core/variant_parser.h"
+#include "core/string/ustring.h"
+#include "core/variant/array.h"
+#include "core/variant/variant.h"
+#include "core/variant/variant_parser.h"
#include "../mono_gd/gd_mono_cache.h"
#include "../mono_gd/gd_mono_marshal.h"
@@ -55,7 +55,8 @@ MonoObject *godot_icall_GD_convert(MonoObject *p_what, int32_t p_type) {
Variant what = GDMonoMarshal::mono_object_to_variant(p_what);
const Variant *args[1] = { &what };
Callable::CallError ce;
- Variant ret = Variant::construct(Variant::Type(p_type), args, 1, ce);
+ Variant ret;
+ Variant::construct(Variant::Type(p_type), ret, args, 1, ce);
ERR_FAIL_COND_V(ce.error != Callable::CallError::CALL_OK, nullptr);
return GDMonoMarshal::variant_to_mono_object(ret);
}
@@ -193,7 +194,11 @@ void godot_icall_GD_randomize() {
Math::randomize();
}
-double godot_icall_GD_rand_range(double from, double to) {
+double godot_icall_GD_randf_range(double from, double to) {
+ return Math::random(from, to);
+}
+
+int32_t godot_icall_GD_randi_range(int32_t from, int32_t to) {
return Math::random(from, to);
}
@@ -284,32 +289,33 @@ MonoObject *godot_icall_DefaultGodotTaskScheduler() {
}
void godot_register_gd_icalls() {
- mono_add_internal_call("Godot.GD::godot_icall_GD_bytes2var", (void *)godot_icall_GD_bytes2var);
- mono_add_internal_call("Godot.GD::godot_icall_GD_convert", (void *)godot_icall_GD_convert);
- mono_add_internal_call("Godot.GD::godot_icall_GD_hash", (void *)godot_icall_GD_hash);
- mono_add_internal_call("Godot.GD::godot_icall_GD_instance_from_id", (void *)godot_icall_GD_instance_from_id);
- mono_add_internal_call("Godot.GD::godot_icall_GD_pusherror", (void *)godot_icall_GD_pusherror);
- mono_add_internal_call("Godot.GD::godot_icall_GD_pushwarning", (void *)godot_icall_GD_pushwarning);
- mono_add_internal_call("Godot.GD::godot_icall_GD_print", (void *)godot_icall_GD_print);
- mono_add_internal_call("Godot.GD::godot_icall_GD_printerr", (void *)godot_icall_GD_printerr);
- mono_add_internal_call("Godot.GD::godot_icall_GD_printraw", (void *)godot_icall_GD_printraw);
- mono_add_internal_call("Godot.GD::godot_icall_GD_prints", (void *)godot_icall_GD_prints);
- mono_add_internal_call("Godot.GD::godot_icall_GD_printt", (void *)godot_icall_GD_printt);
- mono_add_internal_call("Godot.GD::godot_icall_GD_randf", (void *)godot_icall_GD_randf);
- mono_add_internal_call("Godot.GD::godot_icall_GD_randi", (void *)godot_icall_GD_randi);
- mono_add_internal_call("Godot.GD::godot_icall_GD_randomize", (void *)godot_icall_GD_randomize);
- mono_add_internal_call("Godot.GD::godot_icall_GD_rand_range", (void *)godot_icall_GD_rand_range);
- mono_add_internal_call("Godot.GD::godot_icall_GD_rand_seed", (void *)godot_icall_GD_rand_seed);
- mono_add_internal_call("Godot.GD::godot_icall_GD_seed", (void *)godot_icall_GD_seed);
- mono_add_internal_call("Godot.GD::godot_icall_GD_str", (void *)godot_icall_GD_str);
- mono_add_internal_call("Godot.GD::godot_icall_GD_str2var", (void *)godot_icall_GD_str2var);
- mono_add_internal_call("Godot.GD::godot_icall_GD_type_exists", (void *)godot_icall_GD_type_exists);
- mono_add_internal_call("Godot.GD::godot_icall_GD_var2bytes", (void *)godot_icall_GD_var2bytes);
- mono_add_internal_call("Godot.GD::godot_icall_GD_var2str", (void *)godot_icall_GD_var2str);
- mono_add_internal_call("Godot.GD::godot_icall_TypeToVariantType", (void *)godot_icall_TypeToVariantType);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_bytes2var", godot_icall_GD_bytes2var);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_convert", godot_icall_GD_convert);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_hash", godot_icall_GD_hash);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_instance_from_id", godot_icall_GD_instance_from_id);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_pusherror", godot_icall_GD_pusherror);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_pushwarning", godot_icall_GD_pushwarning);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_print", godot_icall_GD_print);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_printerr", godot_icall_GD_printerr);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_printraw", godot_icall_GD_printraw);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_prints", godot_icall_GD_prints);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_printt", godot_icall_GD_printt);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randf", godot_icall_GD_randf);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randi", godot_icall_GD_randi);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randomize", godot_icall_GD_randomize);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randf_range", godot_icall_GD_randf_range);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randi_range", godot_icall_GD_randi_range);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_rand_seed", godot_icall_GD_rand_seed);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_seed", godot_icall_GD_seed);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_str", godot_icall_GD_str);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_str2var", godot_icall_GD_str2var);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_type_exists", godot_icall_GD_type_exists);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_var2bytes", godot_icall_GD_var2bytes);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_var2str", godot_icall_GD_var2str);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_TypeToVariantType", godot_icall_TypeToVariantType);
// Dispatcher
- mono_add_internal_call("Godot.Dispatcher::godot_icall_DefaultGodotTaskScheduler", (void *)godot_icall_DefaultGodotTaskScheduler);
+ GDMonoUtils::add_internal_call("Godot.Dispatcher::godot_icall_DefaultGodotTaskScheduler", godot_icall_DefaultGodotTaskScheduler);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/glue_header.h b/modules/mono/glue/glue_header.h
index c1f1936711..3db52d7c30 100644
--- a/modules/mono/glue/glue_header.h
+++ b/modules/mono/glue/glue_header.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -58,16 +58,15 @@ void godot_register_glue_header_icalls() {
// Used by the generated glue
-#include "core/array.h"
-#include "core/class_db.h"
-#include "core/dictionary.h"
-#include "core/engine.h"
-#include "core/method_bind.h"
-#include "core/node_path.h"
-#include "core/object.h"
-#include "core/reference.h"
+#include "core/config/engine.h"
+#include "core/object/class_db.h"
+#include "core/object/method_bind.h"
+#include "core/object/reference.h"
+#include "core/string/node_path.h"
+#include "core/string/ustring.h"
#include "core/typedefs.h"
-#include "core/ustring.h"
+#include "core/variant/array.h"
+#include "core/variant/dictionary.h"
#include "../mono_gd/gd_mono_class.h"
#include "../mono_gd/gd_mono_internals.h"
diff --git a/modules/mono/glue/nodepath_glue.cpp b/modules/mono/glue/nodepath_glue.cpp
index 2aa75dd309..4ddb94e1a8 100644
--- a/modules/mono/glue/nodepath_glue.cpp
+++ b/modules/mono/glue/nodepath_glue.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,8 +30,8 @@
#ifdef MONO_GLUE_ENABLED
-#include "core/node_path.h"
-#include "core/ustring.h"
+#include "core/string/node_path.h"
+#include "core/string/ustring.h"
#include "../mono_gd/gd_mono_marshal.h"
@@ -81,17 +81,17 @@ MonoBoolean godot_icall_NodePath_is_empty(NodePath *p_ptr) {
}
void godot_register_nodepath_icalls() {
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_Ctor", (void *)godot_icall_NodePath_Ctor);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_Dtor", (void *)godot_icall_NodePath_Dtor);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_operator_String", (void *)godot_icall_NodePath_operator_String);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_get_as_property_path", (void *)godot_icall_NodePath_get_as_property_path);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_get_concatenated_subnames", (void *)godot_icall_NodePath_get_concatenated_subnames);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_get_name", (void *)godot_icall_NodePath_get_name);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_get_name_count", (void *)godot_icall_NodePath_get_name_count);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_get_subname", (void *)godot_icall_NodePath_get_subname);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_get_subname_count", (void *)godot_icall_NodePath_get_subname_count);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_is_absolute", (void *)godot_icall_NodePath_is_absolute);
- mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_is_empty", (void *)godot_icall_NodePath_is_empty);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_Ctor", godot_icall_NodePath_Ctor);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_Dtor", godot_icall_NodePath_Dtor);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_operator_String", godot_icall_NodePath_operator_String);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_as_property_path", godot_icall_NodePath_get_as_property_path);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_concatenated_subnames", godot_icall_NodePath_get_concatenated_subnames);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_name", godot_icall_NodePath_get_name);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_name_count", godot_icall_NodePath_get_name_count);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_subname", godot_icall_NodePath_get_subname);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_subname_count", godot_icall_NodePath_get_subname_count);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_is_absolute", godot_icall_NodePath_is_absolute);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_is_empty", godot_icall_NodePath_is_empty);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/rid_glue.cpp b/modules/mono/glue/rid_glue.cpp
index 6d2e6b559f..f464e63a81 100644
--- a/modules/mono/glue/rid_glue.cpp
+++ b/modules/mono/glue/rid_glue.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,9 +30,9 @@
#ifdef MONO_GLUE_ENABLED
-#include "core/object.h"
-#include "core/resource.h"
-#include "core/rid.h"
+#include "core/io/resource.h"
+#include "core/object/class_db.h"
+#include "core/templates/rid.h"
#include "../mono_gd/gd_mono_marshal.h"
@@ -56,9 +56,9 @@ uint32_t godot_icall_RID_get_id(RID *p_ptr) {
}
void godot_register_rid_icalls() {
- mono_add_internal_call("Godot.RID::godot_icall_RID_Ctor", (void *)godot_icall_RID_Ctor);
- mono_add_internal_call("Godot.RID::godot_icall_RID_Dtor", (void *)godot_icall_RID_Dtor);
- mono_add_internal_call("Godot.RID::godot_icall_RID_get_id", (void *)godot_icall_RID_get_id);
+ GDMonoUtils::add_internal_call("Godot.RID::godot_icall_RID_Ctor", godot_icall_RID_Ctor);
+ GDMonoUtils::add_internal_call("Godot.RID::godot_icall_RID_Dtor", godot_icall_RID_Dtor);
+ GDMonoUtils::add_internal_call("Godot.RID::godot_icall_RID_get_id", godot_icall_RID_get_id);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/scene_tree_glue.cpp b/modules/mono/glue/scene_tree_glue.cpp
index b43daccc1b..5a6fd69db8 100644
--- a/modules/mono/glue/scene_tree_glue.cpp
+++ b/modules/mono/glue/scene_tree_glue.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,9 +30,9 @@
#ifdef MONO_GLUE_ENABLED
-#include "core/array.h"
-#include "core/class_db.h"
-#include "core/string_name.h"
+#include "core/object/class_db.h"
+#include "core/string/string_name.h"
+#include "core/variant/array.h"
#include "scene/main/node.h"
#include "scene/main/scene_tree.h"
@@ -48,7 +48,7 @@ Array *godot_icall_SceneTree_get_nodes_in_group_Generic(SceneTree *ptr, StringNa
ptr->get_nodes_in_group(*group, &nodes);
// No need to bother if the group is empty
- if (!nodes.empty()) {
+ if (!nodes.is_empty()) {
MonoType *elem_type = mono_reflection_type_get_type(refltype);
MonoClass *mono_class = mono_class_from_mono_type(elem_type);
GDMonoClass *klass = GDMono::get_singleton()->get_class(mono_class);
@@ -80,7 +80,7 @@ Array *godot_icall_SceneTree_get_nodes_in_group_Generic(SceneTree *ptr, StringNa
}
void godot_register_scene_tree_icalls() {
- mono_add_internal_call("Godot.SceneTree::godot_icall_SceneTree_get_nodes_in_group_Generic", (void *)godot_icall_SceneTree_get_nodes_in_group_Generic);
+ GDMonoUtils::add_internal_call("Godot.SceneTree::godot_icall_SceneTree_get_nodes_in_group_Generic", godot_icall_SceneTree_get_nodes_in_group_Generic);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/string_glue.cpp b/modules/mono/glue/string_glue.cpp
index 595b8d71f1..18a9221f89 100644
--- a/modules/mono/glue/string_glue.cpp
+++ b/modules/mono/glue/string_glue.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,9 +30,9 @@
#ifdef MONO_GLUE_ENABLED
-#include "core/ustring.h"
-#include "core/variant.h"
-#include "core/vector.h"
+#include "core/string/ustring.h"
+#include "core/templates/vector.h"
+#include "core/variant/variant.h"
#include "../mono_gd/gd_mono_marshal.h"
@@ -68,12 +68,12 @@ MonoString *godot_icall_String_sha256_text(MonoString *p_str) {
}
void godot_register_string_icalls() {
- mono_add_internal_call("Godot.StringExtensions::godot_icall_String_md5_buffer", (void *)godot_icall_String_md5_buffer);
- mono_add_internal_call("Godot.StringExtensions::godot_icall_String_md5_text", (void *)godot_icall_String_md5_text);
- mono_add_internal_call("Godot.StringExtensions::godot_icall_String_rfind", (void *)godot_icall_String_rfind);
- mono_add_internal_call("Godot.StringExtensions::godot_icall_String_rfindn", (void *)godot_icall_String_rfindn);
- mono_add_internal_call("Godot.StringExtensions::godot_icall_String_sha256_buffer", (void *)godot_icall_String_sha256_buffer);
- mono_add_internal_call("Godot.StringExtensions::godot_icall_String_sha256_text", (void *)godot_icall_String_sha256_text);
+ GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_md5_buffer", godot_icall_String_md5_buffer);
+ GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_md5_text", godot_icall_String_md5_text);
+ GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_rfind", godot_icall_String_rfind);
+ GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_rfindn", godot_icall_String_rfindn);
+ GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_sha256_buffer", godot_icall_String_sha256_buffer);
+ GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_sha256_text", godot_icall_String_sha256_text);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/string_name_glue.cpp b/modules/mono/glue/string_name_glue.cpp
index 4b2e88569b..f537896559 100644
--- a/modules/mono/glue/string_name_glue.cpp
+++ b/modules/mono/glue/string_name_glue.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,8 +30,8 @@
#ifdef MONO_GLUE_ENABLED
-#include "core/string_name.h"
-#include "core/ustring.h"
+#include "core/string/string_name.h"
+#include "core/string/ustring.h"
#include "../mono_gd/gd_mono_marshal.h"
@@ -53,10 +53,10 @@ MonoBoolean godot_icall_StringName_is_empty(StringName *p_ptr) {
}
void godot_register_string_name_icalls() {
- mono_add_internal_call("Godot.StringName::godot_icall_StringName_Ctor", (void *)godot_icall_StringName_Ctor);
- mono_add_internal_call("Godot.StringName::godot_icall_StringName_Dtor", (void *)godot_icall_StringName_Dtor);
- mono_add_internal_call("Godot.StringName::godot_icall_StringName_operator_String", (void *)godot_icall_StringName_operator_String);
- mono_add_internal_call("Godot.StringName::godot_icall_StringName_is_empty", (void *)godot_icall_StringName_is_empty);
+ GDMonoUtils::add_internal_call("Godot.StringName::godot_icall_StringName_Ctor", godot_icall_StringName_Ctor);
+ GDMonoUtils::add_internal_call("Godot.StringName::godot_icall_StringName_Dtor", godot_icall_StringName_Dtor);
+ GDMonoUtils::add_internal_call("Godot.StringName::godot_icall_StringName_operator_String", godot_icall_StringName_operator_String);
+ GDMonoUtils::add_internal_call("Godot.StringName::godot_icall_StringName_is_empty", godot_icall_StringName_is_empty);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/godotsharp_defs.h b/modules/mono/godotsharp_defs.h
index 7d57d0fac3..273dba52f9 100644
--- a/modules/mono/godotsharp_defs.h
+++ b/modules/mono/godotsharp_defs.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp
index df31823deb..a39a6fe381 100644
--- a/modules/mono/godotsharp_dirs.cpp
+++ b/modules/mono/godotsharp_dirs.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,9 +30,9 @@
#include "godotsharp_dirs.h"
+#include "core/config/project_settings.h"
#include "core/os/dir_access.h"
#include "core/os/os.h"
-#include "core/project_settings.h"
#ifdef TOOLS_ENABLED
#include "core/version.h"
@@ -146,7 +146,7 @@ private:
String appname = ProjectSettings::get_singleton()->get("application/config/name");
String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
- if (appname_safe.empty()) {
+ if (appname_safe.is_empty()) {
appname_safe = "UnnamedProject";
}
@@ -322,5 +322,4 @@ String get_data_mono_bin_dir() {
return _GodotSharpDirs::get_singleton().data_mono_bin_dir;
}
#endif
-
} // namespace GodotSharpDirs
diff --git a/modules/mono/godotsharp_dirs.h b/modules/mono/godotsharp_dirs.h
index 2ab4b0e309..3a3c6f980e 100644
--- a/modules/mono/godotsharp_dirs.h
+++ b/modules/mono/godotsharp_dirs.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,7 +31,7 @@
#ifndef GODOTSHARP_DIRS_H
#define GODOTSHARP_DIRS_H
-#include "core/ustring.h"
+#include "core/string/ustring.h"
namespace GodotSharpDirs {
@@ -66,7 +66,6 @@ String get_data_mono_lib_dir();
#ifdef WINDOWS_ENABLED
String get_data_mono_bin_dir();
#endif
-
} // namespace GodotSharpDirs
#endif // GODOTSHARP_DIRS_H
diff --git a/modules/mono/icons/CSharpScript.svg b/modules/mono/icons/CSharpScript.svg
index 69664ca553..0b2cc840f8 100644
--- a/modules/mono/icons/CSharpScript.svg
+++ b/modules/mono/icons/CSharpScript.svg
@@ -1,5 +1 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1036.4)">
-<path d="m6 1046.4c-1.6569 0-3 1.3431-3 3s1.3431 3 3 3h1v-2h-1c-0.55228 0-1-0.4478-1-1 0-0.5523 0.44772-1 1-1h1v-2zm1-9-0.56445 2.2578c-0.23643 0.076-0.46689 0.1692-0.68945 0.2793l-1.9883-1.1933-1.4141 1.414 1.1953 1.9942c-0.11191 0.2211-0.20723 0.4502-0.28516 0.6855l-2.2539 0.5625v2h5.2715c-0.17677-0.3037-0.27041-0.6486-0.27148-1 9.6e-6 -1.1046 0.89543-2 2-2s2 0.8954 2 2c-4.817e-4 0.3512-0.093442 0.6961-0.26953 1h5.2695v-2l-2.2578-0.5645c-0.07594-0.2357-0.1693-0.4655-0.2793-0.6875l1.1934-1.9902-1.4141-1.414-1.9941 1.1953c-0.22113-0.1119-0.45028-0.2073-0.68555-0.2852l-0.5625-2.2539zm4 9c-0.71466-1e-4 -1.3751 0.3811-1.7324 1-0.35727 0.6188-0.35727 1.3812 0 2 0.35733 0.6189 1.0178 1.0001 1.7324 1h-2v2h2c0.71466 1e-4 1.3751-0.3811 1.7324-1 0.35727-0.6188 0.35727-1.3812 0-2-0.35733-0.6189-1.0178-1.0001-1.7324-1h2v-2z" fill="#e0e0e0"/>
-</g>
-</svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 1046.4c-1.6569 0-3 1.3431-3 3s1.3431 3 3 3h1v-2h-1c-.55228 0-1-.4478-1-1 0-.5523.44772-1 1-1h1v-2zm1-9-.56445 2.2578c-.23643.076-.46689.1692-.68945.2793l-1.9883-1.1933-1.4141 1.414 1.1953 1.9942c-.11191.2211-.20723.4502-.28516.6855l-2.2539.5625v2h5.2715c-.17677-.3037-.27041-.6486-.27148-1 .0000096-1.1046.89543-2 2-2s2 .8954 2 2c-.0004817.3512-.093442.6961-.26953 1h5.2695v-2l-2.2578-.5645c-.07594-.2357-.1693-.4655-.2793-.6875l1.1934-1.9902-1.4141-1.414-1.9941 1.1953c-.22113-.1119-.45028-.2073-.68555-.2852l-.5625-2.2539zm4 9c-.71466-.0001-1.3751.3811-1.7324 1-.35727.6188-.35727 1.3812 0 2 .35733.6189 1.0178 1.0001 1.7324 1h-2v2h2c.71466.0001 1.3751-.3811 1.7324-1 .35727-.6188.35727-1.3812 0-2-.35733-.6189-1.0178-1.0001-1.7324-1h2v-2z" fill="#e0e0e0" transform="translate(0 -1036.4)"/></svg>
diff --git a/modules/mono/managed_callable.cpp b/modules/mono/managed_callable.cpp
index dbe9c7fc5d..6d868b527c 100644
--- a/modules/mono/managed_callable.cpp
+++ b/modules/mono/managed_callable.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/managed_callable.h b/modules/mono/managed_callable.h
index 4f71e14a2f..c620eee60d 100644
--- a/modules/mono/managed_callable.h
+++ b/modules/mono/managed_callable.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,9 +33,9 @@
#include <mono/metadata/object.h>
-#include "core/callable.h"
#include "core/os/mutex.h"
-#include "core/self_list.h"
+#include "core/templates/self_list.h"
+#include "core/variant/callable.h"
#include "mono_gc_handle.h"
#include "mono_gd/gd_mono_method.h"
diff --git a/modules/mono/mono_gc_handle.cpp b/modules/mono/mono_gc_handle.cpp
index 16a6875406..8583065016 100644
--- a/modules/mono/mono_gc_handle.cpp
+++ b/modules/mono/mono_gc_handle.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/mono_gc_handle.h b/modules/mono/mono_gc_handle.h
index 13cfad4654..f435aab3dd 100644
--- a/modules/mono/mono_gc_handle.h
+++ b/modules/mono/mono_gc_handle.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,7 +33,7 @@
#include <mono/jit/jit.h>
-#include "core/reference.h"
+#include "core/object/reference.h"
namespace gdmono {
@@ -42,7 +42,6 @@ enum class GCHandleType : char {
STRONG_HANDLE,
WEAK_HANDLE
};
-
}
// Manual release of the GC handle must be done when using this struct
diff --git a/modules/mono/mono_gd/android_mono_config.h b/modules/mono/mono_gd/android_mono_config.h
index 93f708bba0..9d7cfe1b7c 100644
--- a/modules/mono/mono_gd/android_mono_config.h
+++ b/modules/mono/mono_gd/android_mono_config.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,7 +33,7 @@
#ifdef ANDROID_ENABLED
-#include "core/ustring.h"
+#include "core/string/ustring.h"
// This function is defined in an auto-generated source file
String get_godot_android_mono_config();
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index cf5ac33d20..43a39a4966 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -37,12 +37,12 @@
#include <mono/metadata/mono-gc.h>
#include <mono/metadata/profiler.h>
+#include "core/config/project_settings.h"
#include "core/debugger/engine_debugger.h"
#include "core/os/dir_access.h"
#include "core/os/file_access.h"
#include "core/os/os.h"
#include "core/os/thread.h"
-#include "core/project_settings.h"
#include "../csharp_script.h"
#include "../godotsharp_dirs.h"
@@ -142,7 +142,7 @@ void gd_mono_debug_init() {
int da_timeout = GLOBAL_DEF("mono/debugger_agent/wait_timeout", 3000);
if (Engine::get_singleton()->is_editor_hint() ||
- ProjectSettings::get_singleton()->get_resource_path().empty() ||
+ ProjectSettings::get_singleton()->get_resource_path().is_empty() ||
Main::is_project_manager()) {
if (da_args.size() == 0) {
return;
@@ -201,7 +201,6 @@ MonoDomain *gd_initialize_mono_runtime() {
return mono_jit_init_version("GodotEngine.RootDomain", runtime_version);
}
#endif
-
} // namespace
void GDMono::add_mono_shared_libs_dir_to_path() {
@@ -298,7 +297,7 @@ void GDMono::determine_mono_dirs(String &r_assembly_rootdir, String &r_config_di
}
#ifdef WINDOWS_ENABLED
- if (r_assembly_rootdir.empty() || r_config_dir.empty()) {
+ if (r_assembly_rootdir.is_empty() || r_config_dir.is_empty()) {
ERR_PRINT("Cannot find Mono in the registry.");
// Assertion: if they are not set, then they weren't found in the registry
CRASH_COND(mono_reg_info.assembly_dir.length() > 0 || mono_reg_info.config_dir.length() > 0);
@@ -361,7 +360,7 @@ void GDMono::initialize() {
#ifndef TOOLS_ENABLED
// Exported games that don't use C# must still work. They likely don't ship with mscorlib.
// We only initialize the Mono runtime if we can find mscorlib. Otherwise it would crash.
- if (GDMonoAssembly::find_assembly("mscorlib.dll").empty()) {
+ if (GDMonoAssembly::find_assembly("mscorlib.dll").is_empty()) {
print_verbose("Mono: Skipping runtime initialization because 'mscorlib.dll' could not be found");
return;
}
@@ -594,8 +593,8 @@ ApiAssemblyInfo::Version ApiAssemblyInfo::Version::get_from_loaded_assembly(GDMo
ApiAssemblyInfo::Version api_assembly_version;
const char *nativecalls_name = p_api_type == ApiAssemblyInfo::API_CORE ?
- BINDINGS_CLASS_NATIVECALLS :
- BINDINGS_CLASS_NATIVECALLS_EDITOR;
+ BINDINGS_CLASS_NATIVECALLS :
+ BINDINGS_CLASS_NATIVECALLS_EDITOR;
GDMonoClass *nativecalls_klass = p_api_assembly->get_class(BINDINGS_NAMESPACE, nativecalls_name);
@@ -758,11 +757,11 @@ String GDMono::update_api_assemblies_from_prebuilt(const String &p_config, const
#define FAIL_REASON(m_out_of_sync, m_prebuilt_exists) \
( \
(m_out_of_sync ? \
- String("The assembly is invalidated ") : \
- String("The assembly was not found ")) + \
+ String("The assembly is invalidated ") : \
+ String("The assembly was not found ")) + \
(m_prebuilt_exists ? \
- String("and the prebuilt assemblies are missing.") : \
- String("and we failed to copy the prebuilt assemblies.")))
+ String("and the prebuilt assemblies are missing.") : \
+ String("and we failed to copy the prebuilt assemblies.")))
String dst_assemblies_dir = GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config);
@@ -821,8 +820,8 @@ bool GDMono::_load_core_api_assembly(LoadedApiAssembly &r_loaded_api_assembly, c
// If running the project manager, load it from the prebuilt API directory
String assembly_dir = !Main::is_project_manager() ?
- GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config) :
- GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config);
+ GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config) :
+ GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config);
String assembly_path = assembly_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll");
@@ -854,8 +853,8 @@ bool GDMono::_load_editor_api_assembly(LoadedApiAssembly &r_loaded_api_assembly,
// If running the project manager, load it from the prebuilt API directory
String assembly_dir = !Main::is_project_manager() ?
- GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config) :
- GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config);
+ GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config) :
+ GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config);
String assembly_path = assembly_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
@@ -945,7 +944,7 @@ void GDMono::_load_api_assemblies() {
// 2. Update the API assemblies
String update_error = update_api_assemblies_from_prebuilt("Debug", &core_api_assembly.out_of_sync, &editor_api_assembly.out_of_sync);
- CRASH_COND_MSG(!update_error.empty(), update_error);
+ CRASH_COND_MSG(!update_error.is_empty(), update_error);
// 3. Load the scripts domain again
Error domain_load_err = _load_scripts_domain();
@@ -999,7 +998,7 @@ bool GDMono::_load_project_assembly() {
String appname = ProjectSettings::get_singleton()->get("application/config/name");
String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
- if (appname_safe.empty()) {
+ if (appname_safe.is_empty()) {
appname_safe = "UnnamedProject";
}
diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h
index 18f7418049..5accc21f8e 100644
--- a/modules/mono/mono_gd/gd_mono.h
+++ b/modules/mono/mono_gd/gd_mono.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -283,7 +283,6 @@ public:
}
}
};
-
} // namespace gdmono
#define _GDMONO_SCOPE_DOMAIN_(m_mono_domain) \
diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp
index 6e351001d4..1fe06bfbee 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.cpp
+++ b/modules/mono/mono_gd/gd_mono_assembly.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,11 +33,11 @@
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/tokentype.h>
+#include "core/config/project_settings.h"
#include "core/io/file_access_pack.h"
-#include "core/list.h"
#include "core/os/file_access.h"
#include "core/os/os.h"
-#include "core/project_settings.h"
+#include "core/templates/list.h"
#include "../godotsharp_dirs.h"
#include "gd_mono_cache.h"
@@ -48,20 +48,20 @@ Vector<String> GDMonoAssembly::search_dirs;
void GDMonoAssembly::fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config, const String &p_custom_bcl_dir) {
String framework_dir;
- if (!p_custom_bcl_dir.empty()) {
+ if (!p_custom_bcl_dir.is_empty()) {
framework_dir = p_custom_bcl_dir;
} else if (mono_assembly_getrootdir()) {
framework_dir = String::utf8(mono_assembly_getrootdir()).plus_file("mono").plus_file("4.5");
}
- if (!framework_dir.empty()) {
+ if (!framework_dir.is_empty()) {
r_search_dirs.push_back(framework_dir);
r_search_dirs.push_back(framework_dir.plus_file("Facades"));
}
#if !defined(TOOLS_ENABLED)
String data_game_assemblies_dir = GodotSharpDirs::get_data_game_assemblies_dir();
- if (!data_game_assemblies_dir.empty()) {
+ if (!data_game_assemblies_dir.is_empty()) {
r_search_dirs.push_back(data_game_assemblies_dir);
}
#endif
@@ -72,7 +72,7 @@ void GDMonoAssembly::fill_search_dirs(Vector<String> &r_search_dirs, const Strin
r_search_dirs.push_back(GodotSharpDirs::get_res_temp_assemblies_dir());
}
- if (p_custom_config.empty()) {
+ if (p_custom_config.is_empty()) {
r_search_dirs.push_back(GodotSharpDirs::get_res_assemblies_dir());
} else {
String api_config = p_custom_config == "ExportRelease" ? "Release" : "Debug";
@@ -230,7 +230,7 @@ void GDMonoAssembly::initialize() {
MonoAssembly *GDMonoAssembly::_real_load_assembly_from(const String &p_path, bool p_refonly, MonoAssemblyName *p_aname) {
Vector<uint8_t> data = FileAccess::get_file_as_array(p_path);
- ERR_FAIL_COND_V_MSG(data.empty(), nullptr, "Could read the assembly in the specified location");
+ ERR_FAIL_COND_V_MSG(data.is_empty(), nullptr, "Could read the assembly in the specified location");
String image_filename;
@@ -379,8 +379,8 @@ GDMonoClass *GDMonoAssembly::get_class(MonoClass *p_mono_class) {
return match->value();
}
- StringName namespace_name = mono_class_get_namespace(p_mono_class);
- StringName class_name = mono_class_get_name(p_mono_class);
+ StringName namespace_name = String::utf8(mono_class_get_namespace(p_mono_class));
+ StringName class_name = String::utf8(mono_class_get_name(p_mono_class));
GDMonoClass *wrapped_class = memnew(GDMonoClass(namespace_name, class_name, p_mono_class, this));
@@ -423,7 +423,7 @@ GDMonoClass *GDMonoAssembly::get_object_derived_class(const StringName &p_class)
match = current;
}
- while (!nested_classes.empty()) {
+ while (!nested_classes.is_empty()) {
GDMonoClass *current_nested = nested_classes.front()->get();
nested_classes.pop_front();
diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h
index 63899dc9be..350fcf3210 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.h
+++ b/modules/mono/mono_gd/gd_mono_assembly.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,9 +34,9 @@
#include <mono/jit/jit.h>
#include <mono/metadata/assembly.h>
-#include "core/hash_map.h"
-#include "core/map.h"
-#include "core/ustring.h"
+#include "core/string/ustring.h"
+#include "core/templates/hash_map.h"
+#include "core/templates/map.h"
#include "gd_mono_utils.h"
class GDMonoAssembly {
diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp
index 29aef6e609..aea467660f 100644
--- a/modules/mono/mono_gd/gd_mono_cache.cpp
+++ b/modules/mono/mono_gd/gd_mono_cache.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -316,5 +316,4 @@ void update_godot_api_cache() {
cached_data.godot_api_cache_updated = true;
}
-
} // namespace GDMonoCache
diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h
index a7bbc763a7..fb75cb4b1c 100644
--- a/modules/mono/mono_gd/gd_mono_cache.h
+++ b/modules/mono/mono_gd/gd_mono_cache.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -181,7 +181,6 @@ inline void clear_corlib_cache() {
inline void clear_godot_api_cache() {
cached_data.clear_godot_api_cache();
}
-
} // namespace GDMonoCache
#define CACHED_CLASS(m_class) (GDMonoCache::cached_data.class_##m_class)
diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp
index 6575cbc1c8..f9fddd931b 100644
--- a/modules/mono/mono_gd/gd_mono_class.cpp
+++ b/modules/mono/mono_gd/gd_mono_class.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -177,7 +177,7 @@ void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base
void *iter = nullptr;
MonoMethod *raw_method = nullptr;
while ((raw_method = mono_class_get_methods(get_mono_ptr(), &iter)) != nullptr) {
- StringName name = mono_method_get_name(raw_method);
+ StringName name = String::utf8(mono_method_get_name(raw_method));
// get_method implicitly fetches methods and adds them to this->methods
GDMonoMethod *method = get_method(raw_method, name);
@@ -290,7 +290,7 @@ bool GDMonoClass::has_public_parameterless_ctor() {
return ctor && ctor->get_visibility() == IMonoClassMember::PUBLIC;
}
-GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, int p_params_count) {
+GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, uint16_t p_params_count) {
MethodKey key = MethodKey(p_name, p_params_count);
GDMonoMethod **match = methods.getptr(key);
@@ -319,7 +319,7 @@ GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method) {
MonoMethodSignature *sig = mono_method_signature(p_raw_method);
int params_count = mono_signature_get_param_count(sig);
- StringName method_name = mono_method_get_name(p_raw_method);
+ StringName method_name = String::utf8(mono_method_get_name(p_raw_method));
return get_method(p_raw_method, method_name, params_count);
}
@@ -330,7 +330,7 @@ GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName
return get_method(p_raw_method, p_name, params_count);
}
-GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName &p_name, int p_params_count) {
+GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName &p_name, uint16_t p_params_count) {
ERR_FAIL_NULL_V(p_raw_method, nullptr);
MethodKey key = MethodKey(p_name, p_params_count);
@@ -392,7 +392,7 @@ const Vector<GDMonoField *> &GDMonoClass::get_all_fields() {
void *iter = nullptr;
MonoClassField *raw_field = nullptr;
while ((raw_field = mono_class_get_fields(mono_class, &iter)) != nullptr) {
- StringName name = mono_field_get_name(raw_field);
+ StringName name = String::utf8(mono_field_get_name(raw_field));
Map<StringName, GDMonoField *>::Element *match = fields.find(name);
@@ -441,7 +441,7 @@ const Vector<GDMonoProperty *> &GDMonoClass::get_all_properties() {
void *iter = nullptr;
MonoProperty *raw_property = nullptr;
while ((raw_property = mono_class_get_properties(mono_class, &iter)) != nullptr) {
- StringName name = mono_property_get_name(raw_property);
+ StringName name = String::utf8(mono_property_get_name(raw_property));
Map<StringName, GDMonoProperty *>::Element *match = properties.find(name);
@@ -468,14 +468,14 @@ const Vector<GDMonoClass *> &GDMonoClass::get_all_delegates() {
MonoClass *raw_class = nullptr;
while ((raw_class = mono_class_get_nested_types(mono_class, &iter)) != nullptr) {
if (mono_class_is_delegate(raw_class)) {
- StringName name = mono_class_get_name(raw_class);
+ StringName name = String::utf8(mono_class_get_name(raw_class));
Map<StringName, GDMonoClass *>::Element *match = delegates.find(name);
if (match) {
delegates_list.push_back(match->get());
} else {
- GDMonoClass *delegate = memnew(GDMonoClass(mono_class_get_namespace(raw_class), mono_class_get_name(raw_class), raw_class, assembly));
+ GDMonoClass *delegate = memnew(GDMonoClass(String::utf8(mono_class_get_namespace(raw_class)), String::utf8(mono_class_get_name(raw_class)), raw_class, assembly));
delegates.insert(name, delegate);
delegates_list.push_back(delegate);
}
@@ -492,7 +492,7 @@ const Vector<GDMonoMethod *> &GDMonoClass::get_all_methods() {
void *iter = nullptr;
MonoMethod *raw_method = nullptr;
while ((raw_method = mono_class_get_methods(get_mono_ptr(), &iter)) != nullptr) {
- method_list.push_back(memnew(GDMonoMethod(mono_method_get_name(raw_method), raw_method)));
+ method_list.push_back(memnew(GDMonoMethod(String::utf8(mono_method_get_name(raw_method)), raw_method)));
}
method_list_fetched = true;
diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h
index 44b146b87c..daea75bae8 100644
--- a/modules/mono/mono_gd/gd_mono_class.h
+++ b/modules/mono/mono_gd/gd_mono_class.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,8 +31,8 @@
#ifndef GD_MONO_CLASS_H
#define GD_MONO_CLASS_H
-#include "core/map.h"
-#include "core/ustring.h"
+#include "core/string/ustring.h"
+#include "core/templates/map.h"
#include "gd_mono_field.h"
#include "gd_mono_header.h"
@@ -59,13 +59,12 @@ class GDMonoClass {
MethodKey() {}
- MethodKey(const StringName &p_name, int p_params_count) {
- name = p_name;
- params_count = p_params_count;
+ MethodKey(const StringName &p_name, uint16_t p_params_count) :
+ name(p_name), params_count(p_params_count) {
}
StringName name;
- int params_count;
+ uint16_t params_count = 0;
};
StringName namespace_name;
@@ -139,10 +138,10 @@ public:
bool implements_interface(GDMonoClass *p_interface);
bool has_public_parameterless_ctor();
- GDMonoMethod *get_method(const StringName &p_name, int p_params_count = 0);
+ GDMonoMethod *get_method(const StringName &p_name, uint16_t p_params_count = 0);
GDMonoMethod *get_method(MonoMethod *p_raw_method);
GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name);
- GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name, int p_params_count);
+ GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name, uint16_t p_params_count);
GDMonoMethod *get_method_with_desc(const String &p_description, bool p_include_namespace);
GDMonoField *get_field(const StringName &p_name);
diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp
index 563c45e71f..1d4d52dfce 100644
--- a/modules/mono/mono_gd/gd_mono_field.cpp
+++ b/modules/mono/mono_gd/gd_mono_field.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -46,29 +46,15 @@ void GDMonoField::set_value_raw(MonoObject *p_object, void *p_ptr) {
}
void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_value) {
-#define SET_FROM_STRUCT(m_type) \
- { \
- GDMonoMarshal::M_##m_type from = MARSHALLED_OUT(m_type, p_value.operator ::m_type()); \
- mono_field_set_value(p_object, mono_field, &from); \
- }
-
-#define SET_FROM_ARRAY(m_type) \
- { \
- MonoArray *managed = GDMonoMarshal::m_type##_to_mono_array(p_value.operator ::m_type()); \
- mono_field_set_value(p_object, mono_field, managed); \
- }
-
switch (type.type_encoding) {
case MONO_TYPE_BOOLEAN: {
MonoBoolean val = p_value.operator bool();
mono_field_set_value(p_object, mono_field, &val);
} break;
-
case MONO_TYPE_CHAR: {
int16_t val = p_value.operator unsigned short();
mono_field_set_value(p_object, mono_field, &val);
} break;
-
case MONO_TYPE_I1: {
int8_t val = p_value.operator signed char();
mono_field_set_value(p_object, mono_field, &val);
@@ -85,7 +71,6 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
int64_t val = p_value.operator int64_t();
mono_field_set_value(p_object, mono_field, &val);
} break;
-
case MONO_TYPE_U1: {
uint8_t val = p_value.operator unsigned char();
mono_field_set_value(p_object, mono_field, &val);
@@ -102,93 +87,92 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
uint64_t val = p_value.operator uint64_t();
mono_field_set_value(p_object, mono_field, &val);
} break;
-
case MONO_TYPE_R4: {
float val = p_value.operator float();
mono_field_set_value(p_object, mono_field, &val);
} break;
-
case MONO_TYPE_R8: {
double val = p_value.operator double();
mono_field_set_value(p_object, mono_field, &val);
} break;
-
- case MONO_TYPE_STRING: {
- if (p_value.get_type() == Variant::NIL) {
- // Otherwise, Variant -> String would return the string "Null"
- MonoString *mono_string = nullptr;
- mono_field_set_value(p_object, mono_field, mono_string);
- } else {
- MonoString *mono_string = GDMonoMarshal::mono_string_from_godot(p_value);
- mono_field_set_value(p_object, mono_field, mono_string);
- }
- } break;
-
case MONO_TYPE_VALUETYPE: {
GDMonoClass *tclass = type.type_class;
if (tclass == CACHED_CLASS(Vector2)) {
- SET_FROM_STRUCT(Vector2);
+ GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_value.operator ::Vector2());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
if (tclass == CACHED_CLASS(Vector2i)) {
- SET_FROM_STRUCT(Vector2i);
+ GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_value.operator ::Vector2i());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
if (tclass == CACHED_CLASS(Rect2)) {
- SET_FROM_STRUCT(Rect2);
+ GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_value.operator ::Rect2());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
if (tclass == CACHED_CLASS(Rect2i)) {
- SET_FROM_STRUCT(Rect2i);
+ GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_value.operator ::Rect2i());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
if (tclass == CACHED_CLASS(Transform2D)) {
- SET_FROM_STRUCT(Transform2D);
+ GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_value.operator ::Transform2D());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
if (tclass == CACHED_CLASS(Vector3)) {
- SET_FROM_STRUCT(Vector3);
+ GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_value.operator ::Vector3());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
if (tclass == CACHED_CLASS(Vector3i)) {
- SET_FROM_STRUCT(Vector3i);
+ GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_value.operator ::Vector3i());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
if (tclass == CACHED_CLASS(Basis)) {
- SET_FROM_STRUCT(Basis);
+ GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_value.operator ::Basis());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
if (tclass == CACHED_CLASS(Quat)) {
- SET_FROM_STRUCT(Quat);
+ GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_value.operator ::Quat());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
if (tclass == CACHED_CLASS(Transform)) {
- SET_FROM_STRUCT(Transform);
+ GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_value.operator ::Transform());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
if (tclass == CACHED_CLASS(AABB)) {
- SET_FROM_STRUCT(AABB);
+ GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_value.operator ::AABB());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
if (tclass == CACHED_CLASS(Color)) {
- SET_FROM_STRUCT(Color);
+ GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_value.operator ::Color());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
if (tclass == CACHED_CLASS(Plane)) {
- SET_FROM_STRUCT(Plane);
+ GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_value.operator ::Plane());
+ mono_field_set_value(p_object, mono_field, &from);
break;
}
@@ -267,118 +251,35 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
ERR_FAIL_MSG("Attempted to set the value of a field of unmarshallable type: '" + tclass->get_name() + "'.");
} break;
-
+ case MONO_TYPE_STRING: {
+ if (p_value.get_type() == Variant::NIL) {
+ // Otherwise, Variant -> String would return the string "Null"
+ MonoString *mono_string = nullptr;
+ mono_field_set_value(p_object, mono_field, mono_string);
+ } else {
+ MonoString *mono_string = GDMonoMarshal::mono_string_from_godot(p_value);
+ mono_field_set_value(p_object, mono_field, mono_string);
+ }
+ } break;
case MONO_TYPE_ARRAY:
case MONO_TYPE_SZARRAY: {
- MonoArrayType *array_type = mono_type_get_array_type(type.type_class->get_mono_type());
-
- if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) {
- SET_FROM_ARRAY(Array);
- break;
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) {
- SET_FROM_ARRAY(PackedByteArray);
- break;
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) {
- SET_FROM_ARRAY(PackedInt32Array);
- break;
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(int64_t)) {
- SET_FROM_ARRAY(PackedInt64Array);
- break;
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(float)) {
- SET_FROM_ARRAY(PackedFloat32Array);
- break;
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(double)) {
- SET_FROM_ARRAY(PackedFloat64Array);
- break;
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(String)) {
- SET_FROM_ARRAY(PackedStringArray);
- break;
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) {
- SET_FROM_ARRAY(PackedVector2Array);
- break;
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) {
- SET_FROM_ARRAY(PackedVector3Array);
- break;
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(Color)) {
- SET_FROM_ARRAY(PackedColorArray);
- break;
- }
-
- GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass);
- if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) {
- MonoArray *managed = GDMonoMarshal::Array_to_mono_array(p_value.operator ::Array(), array_type_class);
+ MonoArray *managed = GDMonoMarshal::variant_to_mono_array(p_value, type.type_class);
+ if (likely(managed != nullptr)) {
mono_field_set_value(p_object, mono_field, managed);
- break;
}
-
- ERR_FAIL_MSG("Attempted to convert Variant to a managed array of unmarshallable element type.");
} break;
-
case MONO_TYPE_CLASS: {
- GDMonoClass *type_class = type.type_class;
-
- // GodotObject
- if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
- MonoObject *managed = GDMonoUtils::unmanaged_get_managed(p_value.operator Object *());
+ MonoObject *managed = GDMonoMarshal::variant_to_mono_object_of_class(p_value, type.type_class);
+ if (likely(managed != nullptr)) {
mono_field_set_value(p_object, mono_field, managed);
- break;
}
-
- if (CACHED_CLASS(StringName) == type_class) {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator StringName());
- mono_field_set_value(p_object, mono_field, managed);
- break;
- }
-
- if (CACHED_CLASS(NodePath) == type_class) {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator NodePath());
- mono_field_set_value(p_object, mono_field, managed);
- break;
- }
-
- if (CACHED_CLASS(RID) == type_class) {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator RID());
- mono_field_set_value(p_object, mono_field, managed);
- break;
- }
-
- // Godot.Collections.Dictionary or IDictionary
- if (CACHED_CLASS(Dictionary) == type_class || type_class == CACHED_CLASS(System_Collections_IDictionary)) {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary));
- mono_field_set_value(p_object, mono_field, managed);
- break;
- }
-
- // Godot.Collections.Array or ICollection or IEnumerable
- if (CACHED_CLASS(Array) == type_class ||
- type_class == CACHED_CLASS(System_Collections_ICollection) ||
- type_class == CACHED_CLASS(System_Collections_IEnumerable)) {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
+ } break;
+ case MONO_TYPE_GENERICINST: {
+ MonoObject *managed = GDMonoMarshal::variant_to_mono_object_of_genericinst(p_value, type.type_class);
+ if (likely(managed != nullptr)) {
mono_field_set_value(p_object, mono_field, managed);
- break;
}
-
- ERR_FAIL_MSG("Attempted to set the value of a field of unmarshallable type: '" + type_class->get_name() + "'.");
} break;
-
case MONO_TYPE_OBJECT: {
// Variant
switch (p_value.get_type()) {
@@ -404,43 +305,56 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
mono_field_set_value(p_object, mono_field, mono_string);
} break;
case Variant::VECTOR2: {
- SET_FROM_STRUCT(Vector2);
+ GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_value.operator ::Vector2());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::VECTOR2I: {
- SET_FROM_STRUCT(Vector2i);
+ GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_value.operator ::Vector2i());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::RECT2: {
- SET_FROM_STRUCT(Rect2);
+ GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_value.operator ::Rect2());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::RECT2I: {
- SET_FROM_STRUCT(Rect2i);
+ GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_value.operator ::Rect2i());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::VECTOR3: {
- SET_FROM_STRUCT(Vector3);
+ GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_value.operator ::Vector3());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::VECTOR3I: {
- SET_FROM_STRUCT(Vector3i);
+ GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_value.operator ::Vector3i());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::TRANSFORM2D: {
- SET_FROM_STRUCT(Transform2D);
+ GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_value.operator ::Transform2D());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::PLANE: {
- SET_FROM_STRUCT(Plane);
+ GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_value.operator ::Plane());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::QUAT: {
- SET_FROM_STRUCT(Quat);
+ GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_value.operator ::Quat());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::AABB: {
- SET_FROM_STRUCT(AABB);
+ GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_value.operator ::AABB());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::BASIS: {
- SET_FROM_STRUCT(Basis);
+ GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_value.operator ::Basis());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::TRANSFORM: {
- SET_FROM_STRUCT(Transform);
+ GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_value.operator ::Transform());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::COLOR: {
- SET_FROM_STRUCT(Color);
+ GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_value.operator ::Color());
+ mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::STRING_NAME: {
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator StringName());
@@ -450,8 +364,8 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator NodePath());
mono_field_set_value(p_object, mono_field, managed);
} break;
- case Variant::_RID: {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator RID());
+ case Variant::RID: {
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator ::RID());
mono_field_set_value(p_object, mono_field, managed);
} break;
case Variant::OBJECT: {
@@ -475,106 +389,49 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
mono_field_set_value(p_object, mono_field, managed);
} break;
case Variant::PACKED_BYTE_ARRAY: {
- SET_FROM_ARRAY(PackedByteArray);
+ MonoArray *managed = GDMonoMarshal::PackedByteArray_to_mono_array(p_value.operator ::PackedByteArray());
+ mono_field_set_value(p_object, mono_field, managed);
} break;
case Variant::PACKED_INT32_ARRAY: {
- SET_FROM_ARRAY(PackedInt32Array);
+ MonoArray *managed = GDMonoMarshal::PackedInt32Array_to_mono_array(p_value.operator ::PackedInt32Array());
+ mono_field_set_value(p_object, mono_field, managed);
} break;
case Variant::PACKED_INT64_ARRAY: {
- SET_FROM_ARRAY(PackedInt64Array);
+ MonoArray *managed = GDMonoMarshal::PackedInt64Array_to_mono_array(p_value.operator ::PackedInt64Array());
+ mono_field_set_value(p_object, mono_field, managed);
} break;
case Variant::PACKED_FLOAT32_ARRAY: {
- SET_FROM_ARRAY(PackedFloat32Array);
+ MonoArray *managed = GDMonoMarshal::PackedFloat32Array_to_mono_array(p_value.operator ::PackedFloat32Array());
+ mono_field_set_value(p_object, mono_field, managed);
} break;
case Variant::PACKED_FLOAT64_ARRAY: {
- SET_FROM_ARRAY(PackedFloat64Array);
+ MonoArray *managed = GDMonoMarshal::PackedFloat64Array_to_mono_array(p_value.operator ::PackedFloat64Array());
+ mono_field_set_value(p_object, mono_field, managed);
} break;
case Variant::PACKED_STRING_ARRAY: {
- SET_FROM_ARRAY(PackedStringArray);
+ MonoArray *managed = GDMonoMarshal::PackedStringArray_to_mono_array(p_value.operator ::PackedStringArray());
+ mono_field_set_value(p_object, mono_field, managed);
} break;
case Variant::PACKED_VECTOR2_ARRAY: {
- SET_FROM_ARRAY(PackedVector2Array);
+ MonoArray *managed = GDMonoMarshal::PackedVector2Array_to_mono_array(p_value.operator ::PackedVector2Array());
+ mono_field_set_value(p_object, mono_field, managed);
} break;
case Variant::PACKED_VECTOR3_ARRAY: {
- SET_FROM_ARRAY(PackedVector3Array);
+ MonoArray *managed = GDMonoMarshal::PackedVector3Array_to_mono_array(p_value.operator ::PackedVector3Array());
+ mono_field_set_value(p_object, mono_field, managed);
} break;
case Variant::PACKED_COLOR_ARRAY: {
- SET_FROM_ARRAY(PackedColorArray);
+ MonoArray *managed = GDMonoMarshal::PackedColorArray_to_mono_array(p_value.operator ::PackedColorArray());
+ mono_field_set_value(p_object, mono_field, managed);
} break;
default:
break;
}
} break;
-
- case MONO_TYPE_GENERICINST: {
- MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), type.type_class->get_mono_type());
-
- // Godot.Collections.Dictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), type.type_class);
- mono_field_set_value(p_object, mono_field, managed);
- break;
- }
-
- // Godot.Collections.Array<T>
- if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), type.type_class);
- mono_field_set_value(p_object, mono_field, managed);
- break;
- }
-
- // System.Collections.Generic.Dictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) {
- MonoReflectionType *key_reftype = nullptr;
- MonoReflectionType *value_reftype = nullptr;
- GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype);
- MonoObject *managed = GDMonoMarshal::Dictionary_to_system_generic_dict(p_value.operator Dictionary(),
- type.type_class, key_reftype, value_reftype);
- mono_field_set_value(p_object, mono_field, managed);
- break;
- }
-
- // System.Collections.Generic.List<T>
- if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) {
- MonoReflectionType *elem_reftype = nullptr;
- GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype);
- MonoObject *managed = GDMonoMarshal::Array_to_system_generic_list(p_value.operator Array(),
- type.type_class, elem_reftype);
- mono_field_set_value(p_object, mono_field, managed);
- break;
- }
-
- // IDictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) {
- MonoReflectionType *key_reftype;
- MonoReflectionType *value_reftype;
- GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype);
- GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype);
-
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), godot_dict_class);
- mono_field_set_value(p_object, mono_field, managed);
- break;
- }
-
- // ICollection<T> or IEnumerable<T>
- if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) {
- MonoReflectionType *elem_reftype;
- GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype);
- GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(elem_reftype);
-
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), godot_array_class);
- mono_field_set_value(p_object, mono_field, managed);
- break;
- }
- } break;
-
default: {
ERR_PRINT("Attempted to set the value of a field of unexpected type encoding: " + itos(type.type_encoding) + ".");
} break;
}
-
-#undef SET_FROM_ARRAY_AND_BREAK
-#undef SET_FROM_STRUCT_AND_BREAK
}
MonoObject *GDMonoField::get_value(MonoObject *p_object) {
@@ -652,7 +509,7 @@ IMonoClassMember::Visibility GDMonoField::get_visibility() {
GDMonoField::GDMonoField(MonoClassField *p_mono_field, GDMonoClass *p_owner) {
owner = p_owner;
mono_field = p_mono_field;
- name = mono_field_get_name(mono_field);
+ name = String::utf8(mono_field_get_name(mono_field));
MonoType *field_type = mono_field_get_type(mono_field);
type.type_encoding = mono_type_get_type(field_type);
MonoClass *field_type_class = mono_class_from_mono_type(field_type);
diff --git a/modules/mono/mono_gd/gd_mono_field.h b/modules/mono/mono_gd/gd_mono_field.h
index 5b40b439f9..ed5078c673 100644
--- a/modules/mono/mono_gd/gd_mono_field.h
+++ b/modules/mono/mono_gd/gd_mono_field.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/mono_gd/gd_mono_header.h b/modules/mono/mono_gd/gd_mono_header.h
index 0f4f888546..483030610f 100644
--- a/modules/mono/mono_gd/gd_mono_header.h
+++ b/modules/mono/mono_gd/gd_mono_header.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,7 +31,7 @@
#ifndef GD_MONO_HEADER_H
#define GD_MONO_HEADER_H
-#include "core/int_types.h"
+#include <cstdint>
#ifdef WIN32
#define GD_MONO_STDCALL __stdcall
diff --git a/modules/mono/mono_gd/gd_mono_internals.cpp b/modules/mono/mono_gd/gd_mono_internals.cpp
index fe1c2d28dd..65e2680905 100644
--- a/modules/mono/mono_gd/gd_mono_internals.cpp
+++ b/modules/mono/mono_gd/gd_mono_internals.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -109,8 +109,6 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
CSharpInstance *csharp_instance = CSharpInstance::create_for_managed_type(unmanaged, script.ptr(), gchandle);
unmanaged->set_script_and_instance(script, csharp_instance);
-
- csharp_instance->connect_event_signals();
}
void unhandled_exception(MonoException *p_exc) {
@@ -129,5 +127,4 @@ void unhandled_exception(MonoException *p_exc) {
#endif
}
}
-
} // namespace GDMonoInternals
diff --git a/modules/mono/mono_gd/gd_mono_internals.h b/modules/mono/mono_gd/gd_mono_internals.h
index 038d17f782..34d2d35b2d 100644
--- a/modules/mono/mono_gd/gd_mono_internals.h
+++ b/modules/mono/mono_gd/gd_mono_internals.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,7 +35,7 @@
#include "../utils/macros.h"
-#include "core/object.h"
+#include "core/object/class_db.h"
namespace GDMonoInternals {
@@ -46,7 +46,6 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged);
* Use GDMonoUtils::debug_unhandled_exception(MonoException *) instead.
*/
void unhandled_exception(MonoException *p_exc);
-
} // namespace GDMonoInternals
#endif // GD_MONO_INTERNALS_H
diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp
index b8ee0204c4..e1d283242c 100644
--- a/modules/mono/mono_gd/gd_mono_log.cpp
+++ b/modules/mono/mono_gd/gd_mono_log.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -160,13 +160,13 @@ void GDMonoLog::initialize() {
OS::Date date_now = OS::get_singleton()->get_date();
OS::Time time_now = OS::get_singleton()->get_time();
- String log_file_name = str_format("%d_%02d_%02d %02d.%02d.%02d",
+ String log_file_name = str_format("%04d-%02d-%02d_%02d.%02d.%02d",
date_now.year, date_now.month, date_now.day,
time_now.hour, time_now.min, time_now.sec);
- log_file_name += str_format(" (%d)", OS::get_singleton()->get_process_id());
+ log_file_name += str_format("_%d", OS::get_singleton()->get_process_id());
- log_file_name += ".txt";
+ log_file_name += ".log";
log_file_path = logs_dir.plus_file(log_file_name);
diff --git a/modules/mono/mono_gd/gd_mono_log.h b/modules/mono/mono_gd/gd_mono_log.h
index 3a52316060..9a95e3cb0a 100644
--- a/modules/mono/mono_gd/gd_mono_log.h
+++ b/modules/mono/mono_gd/gd_mono_log.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index c460e283ea..359f6bba4d 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -204,7 +204,7 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type, bool *r_nil_is_
}
if (CACHED_CLASS(RID) == type_class) {
- return Variant::_RID;
+ return Variant::RID;
}
if (CACHED_CLASS(Dictionary) == type_class) {
@@ -311,152 +311,590 @@ bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_
return false;
}
-MonoObject *variant_to_mono_object(const Variant *p_var) {
- ManagedType type;
+MonoString *variant_to_mono_string(const Variant &p_var) {
+ if (p_var.get_type() == Variant::NIL) {
+ return nullptr; // Otherwise, Variant -> String would return the string "Null"
+ }
+ return mono_string_from_godot(p_var.operator String());
+}
+
+MonoArray *variant_to_mono_array(const Variant &p_var, GDMonoClass *p_type_class) {
+ MonoArrayType *array_type = mono_type_get_array_type(p_type_class->get_mono_type());
+
+ if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) {
+ return Array_to_mono_array(p_var.operator Array());
+ }
+
+ if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) {
+ return PackedByteArray_to_mono_array(p_var.operator PackedByteArray());
+ }
+
+ if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) {
+ return PackedInt32Array_to_mono_array(p_var.operator PackedInt32Array());
+ }
+
+ if (array_type->eklass == CACHED_CLASS_RAW(int64_t)) {
+ return PackedInt64Array_to_mono_array(p_var.operator PackedInt64Array());
+ }
+
+ if (array_type->eklass == CACHED_CLASS_RAW(float)) {
+ return PackedFloat32Array_to_mono_array(p_var.operator PackedFloat32Array());
+ }
+
+ if (array_type->eklass == CACHED_CLASS_RAW(double)) {
+ return PackedFloat64Array_to_mono_array(p_var.operator PackedFloat64Array());
+ }
+
+ if (array_type->eklass == CACHED_CLASS_RAW(String)) {
+ return PackedStringArray_to_mono_array(p_var.operator PackedStringArray());
+ }
+
+ if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) {
+ return PackedVector2Array_to_mono_array(p_var.operator PackedVector2Array());
+ }
+
+ if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) {
+ return PackedVector3Array_to_mono_array(p_var.operator PackedVector3Array());
+ }
+
+ if (array_type->eklass == CACHED_CLASS_RAW(Color)) {
+ return PackedColorArray_to_mono_array(p_var.operator PackedColorArray());
+ }
+
+ if (mono_class_is_assignable_from(CACHED_CLASS(GodotObject)->get_mono_ptr(), array_type->eklass)) {
+ return Array_to_mono_array(p_var.operator ::Array(), array_type->eklass);
+ }
+
+ ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to array of unsupported element type:" +
+ GDMonoClass::get_full_name(array_type->eklass) + "'.");
+}
+
+MonoObject *variant_to_mono_object_of_class(const Variant &p_var, GDMonoClass *p_type_class) {
+ // GodotObject
+ if (CACHED_CLASS(GodotObject)->is_assignable_from(p_type_class)) {
+ return GDMonoUtils::unmanaged_get_managed(p_var.operator Object *());
+ }
+
+ if (CACHED_CLASS(StringName) == p_type_class) {
+ return GDMonoUtils::create_managed_from(p_var.operator StringName());
+ }
+
+ if (CACHED_CLASS(NodePath) == p_type_class) {
+ return GDMonoUtils::create_managed_from(p_var.operator NodePath());
+ }
+
+ if (CACHED_CLASS(RID) == p_type_class) {
+ return GDMonoUtils::create_managed_from(p_var.operator ::RID());
+ }
+
+ // Godot.Collections.Dictionary or IDictionary
+ if (CACHED_CLASS(Dictionary) == p_type_class || CACHED_CLASS(System_Collections_IDictionary) == p_type_class) {
+ return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), CACHED_CLASS(Dictionary));
+ }
+
+ // Godot.Collections.Array or ICollection or IEnumerable
+ if (CACHED_CLASS(Array) == p_type_class ||
+ CACHED_CLASS(System_Collections_ICollection) == p_type_class ||
+ CACHED_CLASS(System_Collections_IEnumerable) == p_type_class) {
+ return GDMonoUtils::create_managed_from(p_var.operator Array(), CACHED_CLASS(Array));
+ }
+
+ ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported type: '" +
+ p_type_class->get_full_name() + "'.");
+}
+
+MonoObject *variant_to_mono_object_of_genericinst(const Variant &p_var, GDMonoClass *p_type_class) {
+ MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type_class->get_mono_type());
+
+ // Godot.Collections.Dictionary<TKey, TValue>
+ if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
+ return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), p_type_class);
+ }
- type.type_encoding = MONO_TYPE_OBJECT;
- // type.type_class is not needed when we specify the MONO_TYPE_OBJECT encoding
+ // Godot.Collections.Array<T>
+ if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
+ return GDMonoUtils::create_managed_from(p_var.operator Array(), p_type_class);
+ }
+
+ // System.Collections.Generic.Dictionary<TKey, TValue>
+ if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) {
+ MonoReflectionType *key_reftype = nullptr;
+ MonoReflectionType *value_reftype = nullptr;
+ GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype);
+ return Dictionary_to_system_generic_dict(p_var.operator Dictionary(), p_type_class, key_reftype, value_reftype);
+ }
+
+ // System.Collections.Generic.List<T>
+ if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) {
+ MonoReflectionType *elem_reftype = nullptr;
+ GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype);
+ return Array_to_system_generic_list(p_var.operator Array(), p_type_class, elem_reftype);
+ }
+
+ // IDictionary<TKey, TValue>
+ if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) {
+ MonoReflectionType *key_reftype;
+ MonoReflectionType *value_reftype;
+ GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype);
+ GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype);
+
+ return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), godot_dict_class);
+ }
+
+ // ICollection<T> or IEnumerable<T>
+ if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) {
+ MonoReflectionType *elem_reftype;
+ GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype);
+ GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(elem_reftype);
+
+ return GDMonoUtils::create_managed_from(p_var.operator Array(), godot_array_class);
+ }
- return variant_to_mono_object(p_var, type);
+ ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported generic type: '" +
+ p_type_class->get_full_name() + "'.");
+}
+
+MonoObject *variant_to_mono_object(const Variant &p_var) {
+ // Variant
+ switch (p_var.get_type()) {
+ case Variant::BOOL: {
+ MonoBoolean val = p_var.operator bool();
+ return BOX_BOOLEAN(val);
+ }
+ case Variant::INT: {
+ int64_t val = p_var.operator int64_t();
+ return BOX_INT64(val);
+ }
+ case Variant::FLOAT: {
+#ifdef REAL_T_IS_DOUBLE
+ double val = p_var.operator double();
+ return BOX_DOUBLE(val);
+#else
+ float val = p_var.operator float();
+ return BOX_FLOAT(val);
+#endif
+ }
+ case Variant::STRING:
+ return (MonoObject *)mono_string_from_godot(p_var.operator String());
+ case Variant::VECTOR2: {
+ GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var.operator ::Vector2());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from);
+ }
+ case Variant::VECTOR2I: {
+ GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_var.operator ::Vector2i());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2i), &from);
+ }
+ case Variant::RECT2: {
+ GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var.operator ::Rect2());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from);
+ }
+ case Variant::RECT2I: {
+ GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_var.operator ::Rect2i());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2i), &from);
+ }
+ case Variant::VECTOR3: {
+ GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var.operator ::Vector3());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from);
+ }
+ case Variant::VECTOR3I: {
+ GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_var.operator ::Vector3i());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3i), &from);
+ }
+ case Variant::TRANSFORM2D: {
+ GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var.operator ::Transform2D());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from);
+ }
+ case Variant::PLANE: {
+ GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var.operator ::Plane());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from);
+ }
+ case Variant::QUAT: {
+ GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var.operator ::Quat());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from);
+ }
+ case Variant::AABB: {
+ GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var.operator ::AABB());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from);
+ }
+ case Variant::BASIS: {
+ GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var.operator ::Basis());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from);
+ }
+ case Variant::TRANSFORM: {
+ GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var.operator ::Transform());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from);
+ }
+ case Variant::COLOR: {
+ GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var.operator ::Color());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from);
+ }
+ case Variant::STRING_NAME:
+ return GDMonoUtils::create_managed_from(p_var.operator StringName());
+ case Variant::NODE_PATH:
+ return GDMonoUtils::create_managed_from(p_var.operator NodePath());
+ case Variant::RID:
+ return GDMonoUtils::create_managed_from(p_var.operator ::RID());
+ case Variant::OBJECT:
+ return GDMonoUtils::unmanaged_get_managed(p_var.operator Object *());
+ case Variant::CALLABLE: {
+ GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var.operator Callable());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Callable), &from);
+ }
+ case Variant::SIGNAL: {
+ GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var.operator Signal());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(SignalInfo), &from);
+ }
+ case Variant::DICTIONARY:
+ return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), CACHED_CLASS(Dictionary));
+ case Variant::ARRAY:
+ return GDMonoUtils::create_managed_from(p_var.operator Array(), CACHED_CLASS(Array));
+ case Variant::PACKED_BYTE_ARRAY:
+ return (MonoObject *)PackedByteArray_to_mono_array(p_var.operator PackedByteArray());
+ case Variant::PACKED_INT32_ARRAY:
+ return (MonoObject *)PackedInt32Array_to_mono_array(p_var.operator PackedInt32Array());
+ case Variant::PACKED_INT64_ARRAY:
+ return (MonoObject *)PackedInt64Array_to_mono_array(p_var.operator PackedInt64Array());
+ case Variant::PACKED_FLOAT32_ARRAY:
+ return (MonoObject *)PackedFloat32Array_to_mono_array(p_var.operator PackedFloat32Array());
+ case Variant::PACKED_FLOAT64_ARRAY:
+ return (MonoObject *)PackedFloat64Array_to_mono_array(p_var.operator PackedFloat64Array());
+ case Variant::PACKED_STRING_ARRAY:
+ return (MonoObject *)PackedStringArray_to_mono_array(p_var.operator PackedStringArray());
+ case Variant::PACKED_VECTOR2_ARRAY:
+ return (MonoObject *)PackedVector2Array_to_mono_array(p_var.operator PackedVector2Array());
+ case Variant::PACKED_VECTOR3_ARRAY:
+ return (MonoObject *)PackedVector3Array_to_mono_array(p_var.operator PackedVector3Array());
+ case Variant::PACKED_COLOR_ARRAY:
+ return (MonoObject *)PackedColorArray_to_mono_array(p_var.operator PackedColorArray());
+ default:
+ return nullptr;
+ }
}
-MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_type) {
+size_t variant_get_managed_unboxed_size(const ManagedType &p_type) {
+ // This method prints no errors for unsupported types. It's called on all methods, not only
+ // those that end up being invoked with Variant parameters.
+
+ // For MonoObject* we return 0, as it doesn't need to be stored.
+ constexpr size_t zero_for_mono_object = 0;
+
+ switch (p_type.type_encoding) {
+ case MONO_TYPE_BOOLEAN:
+ return sizeof(MonoBoolean);
+ case MONO_TYPE_CHAR:
+ return sizeof(uint16_t);
+ case MONO_TYPE_I1:
+ return sizeof(int8_t);
+ case MONO_TYPE_I2:
+ return sizeof(int16_t);
+ case MONO_TYPE_I4:
+ return sizeof(int32_t);
+ case MONO_TYPE_I8:
+ return sizeof(int64_t);
+ case MONO_TYPE_U1:
+ return sizeof(uint8_t);
+ case MONO_TYPE_U2:
+ return sizeof(uint16_t);
+ case MONO_TYPE_U4:
+ return sizeof(uint32_t);
+ case MONO_TYPE_U8:
+ return sizeof(uint64_t);
+ case MONO_TYPE_R4:
+ return sizeof(float);
+ case MONO_TYPE_R8:
+ return sizeof(double);
+ case MONO_TYPE_VALUETYPE: {
+ GDMonoClass *vtclass = p_type.type_class;
+
+#define RETURN_CHECK_FOR_STRUCT(m_struct) \
+ if (vtclass == CACHED_CLASS(m_struct)) { \
+ return sizeof(M_##m_struct); \
+ }
+
+ RETURN_CHECK_FOR_STRUCT(Vector2);
+ RETURN_CHECK_FOR_STRUCT(Vector2i);
+ RETURN_CHECK_FOR_STRUCT(Rect2);
+ RETURN_CHECK_FOR_STRUCT(Rect2i);
+ RETURN_CHECK_FOR_STRUCT(Transform2D);
+ RETURN_CHECK_FOR_STRUCT(Vector3);
+ RETURN_CHECK_FOR_STRUCT(Vector3i);
+ RETURN_CHECK_FOR_STRUCT(Basis);
+ RETURN_CHECK_FOR_STRUCT(Quat);
+ RETURN_CHECK_FOR_STRUCT(Transform);
+ RETURN_CHECK_FOR_STRUCT(AABB);
+ RETURN_CHECK_FOR_STRUCT(Color);
+ RETURN_CHECK_FOR_STRUCT(Plane);
+ RETURN_CHECK_FOR_STRUCT(Callable);
+ RETURN_CHECK_FOR_STRUCT(SignalInfo);
+
+#undef RETURN_CHECK_FOR_STRUCT
+
+ if (mono_class_is_enum(vtclass->get_mono_ptr())) {
+ MonoType *enum_basetype = mono_class_enum_basetype(vtclass->get_mono_ptr());
+ switch (mono_type_get_type(enum_basetype)) {
+ case MONO_TYPE_BOOLEAN:
+ return sizeof(MonoBoolean);
+ case MONO_TYPE_CHAR:
+ return sizeof(uint16_t);
+ case MONO_TYPE_I1:
+ return sizeof(int8_t);
+ case MONO_TYPE_I2:
+ return sizeof(int16_t);
+ case MONO_TYPE_I4:
+ return sizeof(int32_t);
+ case MONO_TYPE_I8:
+ return sizeof(int64_t);
+ case MONO_TYPE_U1:
+ return sizeof(uint8_t);
+ case MONO_TYPE_U2:
+ return sizeof(uint16_t);
+ case MONO_TYPE_U4:
+ return sizeof(uint32_t);
+ case MONO_TYPE_U8:
+ return sizeof(uint64_t);
+ default: {
+ // Enum with unsupported base type. We return nullptr MonoObject* on error.
+ return zero_for_mono_object;
+ }
+ }
+ }
+
+ // Enum with unsupported value type. We return nullptr MonoObject* on error.
+ } break;
+ case MONO_TYPE_STRING:
+ return zero_for_mono_object;
+ case MONO_TYPE_ARRAY:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_GENERICINST:
+ return zero_for_mono_object;
+ case MONO_TYPE_OBJECT:
+ return zero_for_mono_object;
+ }
+
+ // Unsupported type encoding. We return nullptr MonoObject* on error.
+ return zero_for_mono_object;
+}
+
+void *variant_to_managed_unboxed(const Variant &p_var, const ManagedType &p_type, void *r_buffer, unsigned int &r_offset) {
+#define RETURN_TYPE_VAL(m_type, m_val) \
+ *reinterpret_cast<m_type *>(r_buffer) = m_val; \
+ r_offset += sizeof(m_type); \
+ return r_buffer;
+
+ switch (p_type.type_encoding) {
+ case MONO_TYPE_BOOLEAN:
+ RETURN_TYPE_VAL(MonoBoolean, (MonoBoolean)p_var.operator bool());
+ case MONO_TYPE_CHAR:
+ RETURN_TYPE_VAL(uint16_t, p_var.operator unsigned short());
+ case MONO_TYPE_I1:
+ RETURN_TYPE_VAL(int8_t, p_var.operator signed char());
+ case MONO_TYPE_I2:
+ RETURN_TYPE_VAL(int16_t, p_var.operator signed short());
+ case MONO_TYPE_I4:
+ RETURN_TYPE_VAL(int32_t, p_var.operator signed int());
+ case MONO_TYPE_I8:
+ RETURN_TYPE_VAL(int64_t, p_var.operator int64_t());
+ case MONO_TYPE_U1:
+ RETURN_TYPE_VAL(uint8_t, p_var.operator unsigned char());
+ case MONO_TYPE_U2:
+ RETURN_TYPE_VAL(uint16_t, p_var.operator unsigned short());
+ case MONO_TYPE_U4:
+ RETURN_TYPE_VAL(uint32_t, p_var.operator unsigned int());
+ case MONO_TYPE_U8:
+ RETURN_TYPE_VAL(uint64_t, p_var.operator uint64_t());
+ case MONO_TYPE_R4:
+ RETURN_TYPE_VAL(float, p_var.operator float());
+ case MONO_TYPE_R8:
+ RETURN_TYPE_VAL(double, p_var.operator double());
+ case MONO_TYPE_VALUETYPE: {
+ GDMonoClass *vtclass = p_type.type_class;
+
+#define RETURN_CHECK_FOR_STRUCT(m_struct) \
+ if (vtclass == CACHED_CLASS(m_struct)) { \
+ GDMonoMarshal::M_##m_struct from = MARSHALLED_OUT(m_struct, p_var.operator ::m_struct()); \
+ RETURN_TYPE_VAL(M_##m_struct, from); \
+ }
+
+ RETURN_CHECK_FOR_STRUCT(Vector2);
+ RETURN_CHECK_FOR_STRUCT(Vector2i);
+ RETURN_CHECK_FOR_STRUCT(Rect2);
+ RETURN_CHECK_FOR_STRUCT(Rect2i);
+ RETURN_CHECK_FOR_STRUCT(Transform2D);
+ RETURN_CHECK_FOR_STRUCT(Vector3);
+ RETURN_CHECK_FOR_STRUCT(Vector3i);
+ RETURN_CHECK_FOR_STRUCT(Basis);
+ RETURN_CHECK_FOR_STRUCT(Quat);
+ RETURN_CHECK_FOR_STRUCT(Transform);
+ RETURN_CHECK_FOR_STRUCT(AABB);
+ RETURN_CHECK_FOR_STRUCT(Color);
+ RETURN_CHECK_FOR_STRUCT(Plane);
+
+#undef RETURN_CHECK_FOR_STRUCT
+
+ if (vtclass == CACHED_CLASS(Callable)) {
+ GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var.operator Callable());
+ RETURN_TYPE_VAL(M_Callable, from);
+ }
+
+ if (vtclass == CACHED_CLASS(SignalInfo)) {
+ GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var.operator Signal());
+ RETURN_TYPE_VAL(M_SignalInfo, from);
+ }
+
+ if (mono_class_is_enum(vtclass->get_mono_ptr())) {
+ MonoType *enum_basetype = mono_class_enum_basetype(vtclass->get_mono_ptr());
+ switch (mono_type_get_type(enum_basetype)) {
+ case MONO_TYPE_BOOLEAN: {
+ MonoBoolean val = p_var.operator bool();
+ RETURN_TYPE_VAL(MonoBoolean, val);
+ }
+ case MONO_TYPE_CHAR: {
+ uint16_t val = p_var.operator unsigned short();
+ RETURN_TYPE_VAL(uint16_t, val);
+ }
+ case MONO_TYPE_I1: {
+ int8_t val = p_var.operator signed char();
+ RETURN_TYPE_VAL(int8_t, val);
+ }
+ case MONO_TYPE_I2: {
+ int16_t val = p_var.operator signed short();
+ RETURN_TYPE_VAL(int16_t, val);
+ }
+ case MONO_TYPE_I4: {
+ int32_t val = p_var.operator signed int();
+ RETURN_TYPE_VAL(int32_t, val);
+ }
+ case MONO_TYPE_I8: {
+ int64_t val = p_var.operator int64_t();
+ RETURN_TYPE_VAL(int64_t, val);
+ }
+ case MONO_TYPE_U1: {
+ uint8_t val = p_var.operator unsigned char();
+ RETURN_TYPE_VAL(uint8_t, val);
+ }
+ case MONO_TYPE_U2: {
+ uint16_t val = p_var.operator unsigned short();
+ RETURN_TYPE_VAL(uint16_t, val);
+ }
+ case MONO_TYPE_U4: {
+ uint32_t val = p_var.operator unsigned int();
+ RETURN_TYPE_VAL(uint32_t, val);
+ }
+ case MONO_TYPE_U8: {
+ uint64_t val = p_var.operator uint64_t();
+ RETURN_TYPE_VAL(uint64_t, val);
+ }
+ default: {
+ ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to enum value of unsupported base type: '" +
+ GDMonoClass::get_full_name(mono_class_from_mono_type(enum_basetype)) + "'.");
+ }
+ }
+ }
+
+ ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported value type: '" +
+ p_type.type_class->get_full_name() + "'.");
+ } break;
+#undef RETURN_TYPE_VAL
+ case MONO_TYPE_STRING:
+ return variant_to_mono_string(p_var);
+ case MONO_TYPE_ARRAY:
+ case MONO_TYPE_SZARRAY:
+ return variant_to_mono_array(p_var, p_type.type_class);
+ case MONO_TYPE_CLASS:
+ return variant_to_mono_object_of_class(p_var, p_type.type_class);
+ case MONO_TYPE_GENERICINST:
+ return variant_to_mono_object_of_genericinst(p_var, p_type.type_class);
+ case MONO_TYPE_OBJECT:
+ return variant_to_mono_object(p_var);
+ }
+
+ ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported type with encoding: " +
+ itos(p_type.type_encoding) + ".");
+}
+
+MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_type) {
switch (p_type.type_encoding) {
case MONO_TYPE_BOOLEAN: {
- MonoBoolean val = p_var->operator bool();
+ MonoBoolean val = p_var.operator bool();
return BOX_BOOLEAN(val);
}
-
case MONO_TYPE_CHAR: {
- uint16_t val = p_var->operator unsigned short();
+ uint16_t val = p_var.operator unsigned short();
return BOX_UINT16(val);
}
-
case MONO_TYPE_I1: {
- int8_t val = p_var->operator signed char();
+ int8_t val = p_var.operator signed char();
return BOX_INT8(val);
}
case MONO_TYPE_I2: {
- int16_t val = p_var->operator signed short();
+ int16_t val = p_var.operator signed short();
return BOX_INT16(val);
}
case MONO_TYPE_I4: {
- int32_t val = p_var->operator signed int();
+ int32_t val = p_var.operator signed int();
return BOX_INT32(val);
}
case MONO_TYPE_I8: {
- int64_t val = p_var->operator int64_t();
+ int64_t val = p_var.operator int64_t();
return BOX_INT64(val);
}
-
case MONO_TYPE_U1: {
- uint8_t val = p_var->operator unsigned char();
+ uint8_t val = p_var.operator unsigned char();
return BOX_UINT8(val);
}
case MONO_TYPE_U2: {
- uint16_t val = p_var->operator unsigned short();
+ uint16_t val = p_var.operator unsigned short();
return BOX_UINT16(val);
}
case MONO_TYPE_U4: {
- uint32_t val = p_var->operator unsigned int();
+ uint32_t val = p_var.operator unsigned int();
return BOX_UINT32(val);
}
case MONO_TYPE_U8: {
- uint64_t val = p_var->operator uint64_t();
+ uint64_t val = p_var.operator uint64_t();
return BOX_UINT64(val);
}
-
case MONO_TYPE_R4: {
- float val = p_var->operator float();
+ float val = p_var.operator float();
return BOX_FLOAT(val);
}
case MONO_TYPE_R8: {
- double val = p_var->operator double();
+ double val = p_var.operator double();
return BOX_DOUBLE(val);
}
-
- case MONO_TYPE_STRING: {
- if (p_var->get_type() == Variant::NIL) {
- return nullptr; // Otherwise, Variant -> String would return the string "Null"
- }
- return (MonoObject *)mono_string_from_godot(p_var->operator String());
- } break;
-
case MONO_TYPE_VALUETYPE: {
GDMonoClass *vtclass = p_type.type_class;
- if (vtclass == CACHED_CLASS(Vector2)) {
- GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var->operator ::Vector2());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from);
- }
-
- if (vtclass == CACHED_CLASS(Vector2i)) {
- GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_var->operator ::Vector2i());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2i), &from);
- }
-
- if (vtclass == CACHED_CLASS(Rect2)) {
- GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var->operator ::Rect2());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from);
- }
-
- if (vtclass == CACHED_CLASS(Rect2i)) {
- GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_var->operator ::Rect2i());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2i), &from);
- }
-
- if (vtclass == CACHED_CLASS(Transform2D)) {
- GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var->operator ::Transform2D());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from);
- }
-
- if (vtclass == CACHED_CLASS(Vector3)) {
- GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var->operator ::Vector3());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from);
- }
-
- if (vtclass == CACHED_CLASS(Vector3i)) {
- GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_var->operator ::Vector3i());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3i), &from);
- }
-
- if (vtclass == CACHED_CLASS(Basis)) {
- GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var->operator ::Basis());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from);
- }
-
- if (vtclass == CACHED_CLASS(Quat)) {
- GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var->operator ::Quat());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from);
- }
-
- if (vtclass == CACHED_CLASS(Transform)) {
- GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var->operator ::Transform());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from);
- }
-
- if (vtclass == CACHED_CLASS(AABB)) {
- GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var->operator ::AABB());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from);
- }
-
- if (vtclass == CACHED_CLASS(Color)) {
- GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var->operator ::Color());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from);
- }
+#define RETURN_CHECK_FOR_STRUCT(m_struct) \
+ if (vtclass == CACHED_CLASS(m_struct)) { \
+ GDMonoMarshal::M_##m_struct from = MARSHALLED_OUT(m_struct, p_var.operator ::m_struct()); \
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(m_struct), &from); \
+ }
- if (vtclass == CACHED_CLASS(Plane)) {
- GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var->operator ::Plane());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from);
- }
+ RETURN_CHECK_FOR_STRUCT(Vector2);
+ RETURN_CHECK_FOR_STRUCT(Vector2i);
+ RETURN_CHECK_FOR_STRUCT(Rect2);
+ RETURN_CHECK_FOR_STRUCT(Rect2i);
+ RETURN_CHECK_FOR_STRUCT(Transform2D);
+ RETURN_CHECK_FOR_STRUCT(Vector3);
+ RETURN_CHECK_FOR_STRUCT(Vector3i);
+ RETURN_CHECK_FOR_STRUCT(Basis);
+ RETURN_CHECK_FOR_STRUCT(Quat);
+ RETURN_CHECK_FOR_STRUCT(Transform);
+ RETURN_CHECK_FOR_STRUCT(AABB);
+ RETURN_CHECK_FOR_STRUCT(Color);
+ RETURN_CHECK_FOR_STRUCT(Plane);
+
+#undef RETURN_CHECK_FOR_STRUCT
if (vtclass == CACHED_CLASS(Callable)) {
- GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var->operator Callable());
+ GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var.operator Callable());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Callable), &from);
}
if (vtclass == CACHED_CLASS(SignalInfo)) {
- GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var->operator Signal());
+ GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var.operator Signal());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(SignalInfo), &from);
}
@@ -465,316 +903,84 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
MonoClass *enum_baseclass = mono_class_from_mono_type(enum_basetype);
switch (mono_type_get_type(enum_basetype)) {
case MONO_TYPE_BOOLEAN: {
- MonoBoolean val = p_var->operator bool();
+ MonoBoolean val = p_var.operator bool();
return BOX_ENUM(enum_baseclass, val);
}
case MONO_TYPE_CHAR: {
- uint16_t val = p_var->operator unsigned short();
+ uint16_t val = p_var.operator unsigned short();
return BOX_ENUM(enum_baseclass, val);
}
case MONO_TYPE_I1: {
- int8_t val = p_var->operator signed char();
+ int8_t val = p_var.operator signed char();
return BOX_ENUM(enum_baseclass, val);
}
case MONO_TYPE_I2: {
- int16_t val = p_var->operator signed short();
+ int16_t val = p_var.operator signed short();
return BOX_ENUM(enum_baseclass, val);
}
case MONO_TYPE_I4: {
- int32_t val = p_var->operator signed int();
+ int32_t val = p_var.operator signed int();
return BOX_ENUM(enum_baseclass, val);
}
case MONO_TYPE_I8: {
- int64_t val = p_var->operator int64_t();
+ int64_t val = p_var.operator int64_t();
return BOX_ENUM(enum_baseclass, val);
}
case MONO_TYPE_U1: {
- uint8_t val = p_var->operator unsigned char();
+ uint8_t val = p_var.operator unsigned char();
return BOX_ENUM(enum_baseclass, val);
}
case MONO_TYPE_U2: {
- uint16_t val = p_var->operator unsigned short();
+ uint16_t val = p_var.operator unsigned short();
return BOX_ENUM(enum_baseclass, val);
}
case MONO_TYPE_U4: {
- uint32_t val = p_var->operator unsigned int();
+ uint32_t val = p_var.operator unsigned int();
return BOX_ENUM(enum_baseclass, val);
}
case MONO_TYPE_U8: {
- uint64_t val = p_var->operator uint64_t();
+ uint64_t val = p_var.operator uint64_t();
return BOX_ENUM(enum_baseclass, val);
}
default: {
- ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to a managed enum value of unmarshallable base type.");
+ ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to enum value of unsupported base type: '" +
+ GDMonoClass::get_full_name(enum_baseclass) + "'.");
}
}
}
- } break;
-
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY: {
- MonoArrayType *array_type = mono_type_get_array_type(p_type.type_class->get_mono_type());
-
- if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) {
- return (MonoObject *)Array_to_mono_array(p_var->operator Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) {
- return (MonoObject *)PackedByteArray_to_mono_array(p_var->operator PackedByteArray());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) {
- return (MonoObject *)PackedInt32Array_to_mono_array(p_var->operator PackedInt32Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(int64_t)) {
- return (MonoObject *)PackedInt64Array_to_mono_array(p_var->operator PackedInt64Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(float)) {
- return (MonoObject *)PackedFloat32Array_to_mono_array(p_var->operator PackedFloat32Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(double)) {
- return (MonoObject *)PackedFloat64Array_to_mono_array(p_var->operator PackedFloat64Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(String)) {
- return (MonoObject *)PackedStringArray_to_mono_array(p_var->operator PackedStringArray());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) {
- return (MonoObject *)PackedVector2Array_to_mono_array(p_var->operator PackedVector2Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) {
- return (MonoObject *)PackedVector3Array_to_mono_array(p_var->operator PackedVector3Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(Color)) {
- return (MonoObject *)PackedColorArray_to_mono_array(p_var->operator PackedColorArray());
- }
-
- GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass);
- if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) {
- return (MonoObject *)Array_to_mono_array(p_var->operator Array(), array_type_class);
- }
-
- ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to a managed array of unmarshallable element type.");
- } break;
-
- case MONO_TYPE_CLASS: {
- GDMonoClass *type_class = p_type.type_class;
-
- // GodotObject
- if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
- return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *());
- }
-
- if (CACHED_CLASS(StringName) == type_class) {
- return GDMonoUtils::create_managed_from(p_var->operator StringName());
- }
-
- if (CACHED_CLASS(NodePath) == type_class) {
- return GDMonoUtils::create_managed_from(p_var->operator NodePath());
- }
-
- if (CACHED_CLASS(RID) == type_class) {
- return GDMonoUtils::create_managed_from(p_var->operator RID());
- }
-
- // Godot.Collections.Dictionary or IDictionary
- if (CACHED_CLASS(Dictionary) == type_class || CACHED_CLASS(System_Collections_IDictionary) == type_class) {
- return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
- }
- // Godot.Collections.Array or ICollection or IEnumerable
- if (CACHED_CLASS(Array) == type_class ||
- CACHED_CLASS(System_Collections_ICollection) == type_class ||
- CACHED_CLASS(System_Collections_IEnumerable) == type_class) {
- return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
- }
- } break;
- case MONO_TYPE_OBJECT: {
- // Variant
- switch (p_var->get_type()) {
- case Variant::BOOL: {
- MonoBoolean val = p_var->operator bool();
- return BOX_BOOLEAN(val);
- }
- case Variant::INT: {
- int64_t val = p_var->operator int64_t();
- return BOX_INT64(val);
- }
- case Variant::FLOAT: {
-#ifdef REAL_T_IS_DOUBLE
- double val = p_var->operator double();
- return BOX_DOUBLE(val);
-#else
- float val = p_var->operator float();
- return BOX_FLOAT(val);
-#endif
- }
- case Variant::STRING:
- return (MonoObject *)mono_string_from_godot(p_var->operator String());
- case Variant::VECTOR2: {
- GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var->operator ::Vector2());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from);
- }
- case Variant::VECTOR2I: {
- GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_var->operator ::Vector2i());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2i), &from);
- }
- case Variant::RECT2: {
- GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var->operator ::Rect2());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from);
- }
- case Variant::RECT2I: {
- GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_var->operator ::Rect2i());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2i), &from);
- }
- case Variant::VECTOR3: {
- GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var->operator ::Vector3());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from);
- }
- case Variant::VECTOR3I: {
- GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_var->operator ::Vector3i());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3i), &from);
- }
- case Variant::TRANSFORM2D: {
- GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var->operator ::Transform2D());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from);
- }
- case Variant::PLANE: {
- GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var->operator ::Plane());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from);
- }
- case Variant::QUAT: {
- GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var->operator ::Quat());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from);
- }
- case Variant::AABB: {
- GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var->operator ::AABB());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from);
- }
- case Variant::BASIS: {
- GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var->operator ::Basis());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from);
- }
- case Variant::TRANSFORM: {
- GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var->operator ::Transform());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from);
- }
- case Variant::COLOR: {
- GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var->operator ::Color());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from);
- }
- case Variant::STRING_NAME:
- return GDMonoUtils::create_managed_from(p_var->operator StringName());
- case Variant::NODE_PATH:
- return GDMonoUtils::create_managed_from(p_var->operator NodePath());
- case Variant::_RID:
- return GDMonoUtils::create_managed_from(p_var->operator RID());
- case Variant::OBJECT:
- return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *());
- case Variant::CALLABLE: {
- GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var->operator Callable());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Callable), &from);
- }
- case Variant::SIGNAL: {
- GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var->operator Signal());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(SignalInfo), &from);
- }
- case Variant::DICTIONARY:
- return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
- case Variant::ARRAY:
- return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
- case Variant::PACKED_BYTE_ARRAY:
- return (MonoObject *)PackedByteArray_to_mono_array(p_var->operator PackedByteArray());
- case Variant::PACKED_INT32_ARRAY:
- return (MonoObject *)PackedInt32Array_to_mono_array(p_var->operator PackedInt32Array());
- case Variant::PACKED_INT64_ARRAY:
- return (MonoObject *)PackedInt64Array_to_mono_array(p_var->operator PackedInt64Array());
- case Variant::PACKED_FLOAT32_ARRAY:
- return (MonoObject *)PackedFloat32Array_to_mono_array(p_var->operator PackedFloat32Array());
- case Variant::PACKED_FLOAT64_ARRAY:
- return (MonoObject *)PackedFloat64Array_to_mono_array(p_var->operator PackedFloat64Array());
- case Variant::PACKED_STRING_ARRAY:
- return (MonoObject *)PackedStringArray_to_mono_array(p_var->operator PackedStringArray());
- case Variant::PACKED_VECTOR2_ARRAY:
- return (MonoObject *)PackedVector2Array_to_mono_array(p_var->operator PackedVector2Array());
- case Variant::PACKED_VECTOR3_ARRAY:
- return (MonoObject *)PackedVector3Array_to_mono_array(p_var->operator PackedVector3Array());
- case Variant::PACKED_COLOR_ARRAY:
- return (MonoObject *)PackedColorArray_to_mono_array(p_var->operator PackedColorArray());
- default:
- return nullptr;
- }
- break;
- case MONO_TYPE_GENERICINST: {
- MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
-
- // Godot.Collections.Dictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
- return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), p_type.type_class);
- }
-
- // Godot.Collections.Array<T>
- if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
- return GDMonoUtils::create_managed_from(p_var->operator Array(), p_type.type_class);
- }
-
- // System.Collections.Generic.Dictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) {
- MonoReflectionType *key_reftype = nullptr;
- MonoReflectionType *value_reftype = nullptr;
- GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype);
- return Dictionary_to_system_generic_dict(p_var->operator Dictionary(), p_type.type_class, key_reftype, value_reftype);
- }
-
- // System.Collections.Generic.List<T>
- if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) {
- MonoReflectionType *elem_reftype = nullptr;
- GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype);
- return Array_to_system_generic_list(p_var->operator Array(), p_type.type_class, elem_reftype);
- }
-
- // IDictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) {
- MonoReflectionType *key_reftype;
- MonoReflectionType *value_reftype;
- GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype);
- GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype);
-
- return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), godot_dict_class);
- }
-
- // ICollection<T> or IEnumerable<T>
- if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) {
- MonoReflectionType *elem_reftype;
- GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype);
- GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(elem_reftype);
-
- return GDMonoUtils::create_managed_from(p_var->operator Array(), godot_array_class);
- }
- } break;
+ ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported value type: '" +
+ p_type.type_class->get_full_name() + "'.");
} break;
+ case MONO_TYPE_STRING:
+ return (MonoObject *)variant_to_mono_string(p_var);
+ case MONO_TYPE_ARRAY:
+ case MONO_TYPE_SZARRAY:
+ return (MonoObject *)variant_to_mono_array(p_var, p_type.type_class);
+ case MONO_TYPE_CLASS:
+ return variant_to_mono_object_of_class(p_var, p_type.type_class);
+ case MONO_TYPE_GENERICINST:
+ return variant_to_mono_object_of_genericinst(p_var, p_type.type_class);
+ case MONO_TYPE_OBJECT:
+ return variant_to_mono_object(p_var);
}
- ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to an unmarshallable managed type. Name: '" +
- p_type.type_class->get_name() + "' Encoding: " + itos(p_type.type_encoding) + ".");
+ ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported type with encoding: " +
+ itos(p_type.type_encoding) + ".");
}
Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type, bool p_fail_with_err = true) {
ERR_FAIL_COND_V(!p_type.type_class, Variant());
+#ifdef DEBUG_ENABLED
+ CRASH_COND_MSG(p_type.type_encoding == MONO_TYPE_OBJECT, "Type of object should be known.");
+#endif
+
switch (p_type.type_encoding) {
case MONO_TYPE_BOOLEAN:
return (bool)unbox<MonoBoolean>(p_obj);
-
case MONO_TYPE_CHAR:
return unbox<uint16_t>(p_obj);
-
case MONO_TYPE_I1:
return unbox<int8_t>(p_obj);
case MONO_TYPE_I2:
@@ -783,7 +989,6 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type
return unbox<int32_t>(p_obj);
case MONO_TYPE_I8:
return unbox<int64_t>(p_obj);
-
case MONO_TYPE_U1:
return unbox<uint8_t>(p_obj);
case MONO_TYPE_U2:
@@ -792,19 +997,10 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type
return unbox<uint32_t>(p_obj);
case MONO_TYPE_U8:
return unbox<uint64_t>(p_obj);
-
case MONO_TYPE_R4:
return unbox<float>(p_obj);
case MONO_TYPE_R8:
return unbox<double>(p_obj);
-
- case MONO_TYPE_STRING: {
- if (p_obj == nullptr) {
- return Variant(); // NIL
- }
- return mono_string_to_godot_not_null((MonoString *)p_obj);
- } break;
-
case MONO_TYPE_VALUETYPE: {
GDMonoClass *vtclass = p_type.type_class;
@@ -872,7 +1068,12 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type
return unbox<int32_t>(p_obj);
}
} break;
-
+ case MONO_TYPE_STRING: {
+ if (p_obj == nullptr) {
+ return Variant(); // NIL
+ }
+ return mono_string_to_godot_not_null((MonoString *)p_obj);
+ } break;
case MONO_TYPE_ARRAY:
case MONO_TYPE_SZARRAY: {
MonoArrayType *array_type = mono_type_get_array_type(p_type.type_class->get_mono_type());
@@ -928,7 +1129,6 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type
return Variant();
}
} break;
-
case MONO_TYPE_CLASS: {
GDMonoClass *type_class = p_type.type_class;
@@ -973,7 +1173,6 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type
return ptr ? Variant(*ptr) : Variant();
}
} break;
-
case MONO_TYPE_GENERICINST: {
MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
@@ -1005,7 +1204,7 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type
if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) {
MonoReflectionType *elem_reftype = nullptr;
GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype);
- return system_generic_list_to_Array(p_obj, p_type.type_class, elem_reftype);
+ return system_generic_list_to_Array_variant(p_obj, p_type.type_class, elem_reftype);
}
} break;
}
@@ -1052,7 +1251,7 @@ String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc) {
ManagedType type = ManagedType::from_class(mono_object_get_class(p_obj));
Variant var = GDMonoMarshal::mono_object_to_variant_no_err(p_obj, type);
- if (var.get_type() == Variant::NIL && p_obj != nullptr) {
+ if (var.get_type() == Variant::NIL) { // `&& p_obj != nullptr` but omitted because always true
// Cannot convert MonoObject* to Variant; fallback to 'ToString()'.
MonoException *exc = nullptr;
MonoString *mono_str = GDMonoUtils::object_to_string(p_obj, &exc);
@@ -1115,9 +1314,10 @@ Dictionary system_generic_dict_to_Dictionary(MonoObject *p_obj, [[maybe_unused]]
}
MonoObject *Array_to_system_generic_list(const Array &p_array, GDMonoClass *p_class, MonoReflectionType *p_elem_reftype) {
- GDMonoClass *elem_class = ManagedType::from_reftype(p_elem_reftype).type_class;
+ MonoType *elem_type = mono_reflection_type_get_type(p_elem_reftype);
+ MonoClass *elem_class = mono_class_from_mono_type(elem_type);
- String ctor_desc = ":.ctor(System.Collections.Generic.IEnumerable`1<" + elem_class->get_type_desc() + ">)";
+ String ctor_desc = ":.ctor(System.Collections.Generic.IEnumerable`1<" + GDMonoUtils::get_type_desc(elem_type) + ">)";
GDMonoMethod *ctor = p_class->get_method_with_desc(ctor_desc, true);
CRASH_COND(ctor == nullptr);
@@ -1133,15 +1333,22 @@ MonoObject *Array_to_system_generic_list(const Array &p_array, GDMonoClass *p_cl
return mono_object;
}
-Array system_generic_list_to_Array(MonoObject *p_obj, GDMonoClass *p_class, [[maybe_unused]] MonoReflectionType *p_elem_reftype) {
+Variant system_generic_list_to_Array_variant(MonoObject *p_obj, GDMonoClass *p_class, [[maybe_unused]] MonoReflectionType *p_elem_reftype) {
GDMonoMethod *to_array = p_class->get_method("ToArray", 0);
CRASH_COND(to_array == nullptr);
MonoException *exc = nullptr;
- MonoArray *mono_array = (MonoArray *)to_array->invoke_raw(p_obj, nullptr, &exc);
+ MonoObject *array = to_array->invoke_raw(p_obj, nullptr, &exc);
UNHANDLED_EXCEPTION(exc);
- return mono_array_to_Array(mono_array);
+ ERR_FAIL_NULL_V(array, Variant());
+
+ ManagedType type = ManagedType::from_class(mono_object_get_class(array));
+
+ bool result_is_array = type.type_encoding != MONO_TYPE_SZARRAY && type.type_encoding != MONO_TYPE_ARRAY;
+ ERR_FAIL_COND_V(result_is_array, Variant());
+
+ return mono_object_to_variant(array, type);
}
MonoArray *Array_to_mono_array(const Array &p_array) {
@@ -1156,9 +1363,9 @@ MonoArray *Array_to_mono_array(const Array &p_array) {
return ret;
}
-MonoArray *Array_to_mono_array(const Array &p_array, GDMonoClass *p_array_type_class) {
+MonoArray *Array_to_mono_array(const Array &p_array, MonoClass *p_array_type_class) {
int length = p_array.size();
- MonoArray *ret = mono_array_new(mono_domain_get(), p_array_type_class->get_mono_ptr(), length);
+ MonoArray *ret = mono_array_new(mono_domain_get(), p_array_type_class, length);
for (int i = 0; i < length; i++) {
MonoObject *boxed = variant_to_mono_object(p_array[i]);
@@ -1477,8 +1684,8 @@ Callable managed_to_callable(const M_Callable &p_managed_callable) {
return Callable(managed_callable);
} else {
Object *target = p_managed_callable.target ?
- unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_managed_callable.target)) :
- nullptr;
+ unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_managed_callable.target)) :
+ nullptr;
StringName *method_ptr = unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(p_managed_callable.method_string_name));
StringName method = method_ptr ? *method_ptr : StringName();
return Callable(target, method);
@@ -1523,8 +1730,8 @@ M_Callable callable_to_managed(const Callable &p_callable) {
Signal managed_to_signal_info(const M_SignalInfo &p_managed_signal) {
Object *owner = p_managed_signal.owner ?
- unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_managed_signal.owner)) :
- nullptr;
+ unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_managed_signal.owner)) :
+ nullptr;
StringName *name_ptr = unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(p_managed_signal.name_string_name));
StringName name = name_ptr ? *name_ptr : StringName();
return Signal(owner, name);
@@ -1536,5 +1743,4 @@ M_SignalInfo signal_info_to_managed(const Signal &p_signal) {
MonoObject *name_string_name_managed = GDMonoUtils::create_managed_from(p_signal.get_name());
return { owner_managed, name_string_name_managed };
}
-
} // namespace GDMonoMarshal
diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h
index a1fd975916..668809ae5d 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.h
+++ b/modules/mono/mono_gd/gd_mono_marshal.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,7 +31,7 @@
#ifndef GDMONOMARSHAL_H
#define GDMONOMARSHAL_H
-#include "core/variant.h"
+#include "core/variant/variant.h"
#include "../managed_callable.h"
#include "gd_mono.h"
@@ -90,15 +90,40 @@ _FORCE_INLINE_ MonoString *mono_string_from_godot(const String &p_string) {
// Variant
-MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_type);
-MonoObject *variant_to_mono_object(const Variant *p_var);
+size_t variant_get_managed_unboxed_size(const ManagedType &p_type);
+void *variant_to_managed_unboxed(const Variant &p_var, const ManagedType &p_type, void *r_buffer, unsigned int &r_offset);
+MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_type);
-_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant &p_var) {
- return variant_to_mono_object(&p_var);
-}
+MonoObject *variant_to_mono_object(const Variant &p_var);
+MonoArray *variant_to_mono_array(const Variant &p_var, GDMonoClass *p_type_class);
+MonoObject *variant_to_mono_object_of_class(const Variant &p_var, GDMonoClass *p_type_class);
+MonoObject *variant_to_mono_object_of_genericinst(const Variant &p_var, GDMonoClass *p_type_class);
+MonoString *variant_to_mono_string(const Variant &p_var);
+
+// These overloads were added to avoid passing a `const Variant *` to the `const Variant &`
+// parameter. That would result in the `Variant(bool)` copy constructor being called as
+// pointers are implicitly converted to bool. Implicit conversions are f-ing evil.
-_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_type) {
- return variant_to_mono_object(&p_var, p_type);
+_FORCE_INLINE_ void *variant_to_managed_unboxed(const Variant *p_var, const ManagedType &p_type, void *r_buffer, unsigned int &r_offset) {
+ return variant_to_managed_unboxed(*p_var, p_type, r_buffer, r_offset);
+}
+_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_type) {
+ return variant_to_mono_object(*p_var, p_type);
+}
+_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant *p_var) {
+ return variant_to_mono_object(*p_var);
+}
+_FORCE_INLINE_ MonoArray *variant_to_mono_array(const Variant *p_var, GDMonoClass *p_type_class) {
+ return variant_to_mono_array(*p_var, p_type_class);
+}
+_FORCE_INLINE_ MonoObject *variant_to_mono_object_of_class(const Variant *p_var, GDMonoClass *p_type_class) {
+ return variant_to_mono_object_of_class(*p_var, p_type_class);
+}
+_FORCE_INLINE_ MonoObject *variant_to_mono_object_of_genericinst(const Variant *p_var, GDMonoClass *p_type_class) {
+ return variant_to_mono_object_of_genericinst(*p_var, p_type_class);
+}
+_FORCE_INLINE_ MonoString *variant_to_mono_string(const Variant *p_var) {
+ return variant_to_mono_string(*p_var);
}
Variant mono_object_to_variant(MonoObject *p_obj);
@@ -115,12 +140,12 @@ MonoObject *Dictionary_to_system_generic_dict(const Dictionary &p_dict, GDMonoCl
Dictionary system_generic_dict_to_Dictionary(MonoObject *p_obj, GDMonoClass *p_class, MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype);
MonoObject *Array_to_system_generic_list(const Array &p_array, GDMonoClass *p_class, MonoReflectionType *p_elem_reftype);
-Array system_generic_list_to_Array(MonoObject *p_obj, GDMonoClass *p_class, MonoReflectionType *p_elem_reftype);
+Variant system_generic_list_to_Array_variant(MonoObject *p_obj, GDMonoClass *p_class, MonoReflectionType *p_elem_reftype);
// Array
MonoArray *Array_to_mono_array(const Array &p_array);
-MonoArray *Array_to_mono_array(const Array &p_array, GDMonoClass *p_array_type_class);
+MonoArray *Array_to_mono_array(const Array &p_array, MonoClass *p_array_type_class);
Array mono_array_to_Array(MonoArray *p_array);
// PackedInt32Array
@@ -271,7 +296,6 @@ static_assert(MATCHES_Vector2 && MATCHES_Rect2 && MATCHES_Transform2D && MATCHES
MATCHES_Plane && MATCHES_Vector2i && MATCHES_Rect2i && MATCHES_Vector3i);
/* clang-format on */
#endif
-
} // namespace InteropLayout
#pragma pack(push, 1)
@@ -517,7 +541,6 @@ DECL_TYPE_MARSHAL_TEMPLATES(Plane)
#define MARSHALLED_IN(m_type, m_from_ptr) (GDMonoMarshal::marshalled_in_##m_type(m_from_ptr))
#define MARSHALLED_OUT(m_type, m_from) (GDMonoMarshal::marshalled_out_##m_type(m_from))
-
} // namespace GDMonoMarshal
#endif // GDMONOMARSHAL_H
diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp
index 04f3b25a70..67aabcde10 100644
--- a/modules/mono/mono_gd/gd_mono_method.cpp
+++ b/modules/mono/mono_gd/gd_mono_method.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -75,6 +75,10 @@ void GDMonoMethod::_update_signature(MonoMethodSignature *p_method_sig) {
// clear the cache
method_info_fetched = false;
method_info = MethodInfo();
+
+ for (int i = 0; i < params_count; i++) {
+ params_buffer_size += GDMonoMarshal::variant_get_managed_unboxed_size(param_types[i]);
+ }
}
GDMonoClass *GDMonoMethod::get_enclosing_class() const {
@@ -107,14 +111,15 @@ MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params,
MonoObject *ret;
if (params_count > 0) {
- MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), params_count);
+ void **params = (void **)alloca(params_count * sizeof(void *));
+ uint8_t *buffer = (uint8_t *)alloca(params_buffer_size);
+ unsigned int offset = 0;
for (int i = 0; i < params_count; i++) {
- MonoObject *boxed_param = GDMonoMarshal::variant_to_mono_object(p_params[i], param_types[i]);
- mono_array_setref(params, i, boxed_param);
+ params[i] = GDMonoMarshal::variant_to_managed_unboxed(p_params[i], param_types[i], buffer + offset, offset);
}
- ret = GDMonoUtils::runtime_invoke_array(mono_method, p_object, params, &exc);
+ ret = GDMonoUtils::runtime_invoke(mono_method, p_object, params, &exc);
} else {
ret = GDMonoUtils::runtime_invoke(mono_method, p_object, nullptr, &exc);
}
@@ -279,16 +284,8 @@ const MethodInfo &GDMonoMethod::get_method_info() {
return method_info;
}
-GDMonoMethod::GDMonoMethod(StringName p_name, MonoMethod *p_method) {
- name = p_name;
-
- mono_method = p_method;
-
- method_info_fetched = false;
-
- attrs_fetched = false;
- attributes = nullptr;
-
+GDMonoMethod::GDMonoMethod(StringName p_name, MonoMethod *p_method) :
+ name(p_name), mono_method(p_method) {
_update_signature();
}
diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h
index f78f57dca0..c08ffe904b 100644
--- a/modules/mono/mono_gd/gd_mono_method.h
+++ b/modules/mono/mono_gd/gd_mono_method.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -38,15 +38,16 @@
class GDMonoMethod : public IMonoClassMember {
StringName name;
- int params_count;
+ uint16_t params_count;
+ unsigned int params_buffer_size = 0;
ManagedType return_type;
Vector<ManagedType> param_types;
- bool method_info_fetched;
+ bool method_info_fetched = false;
MethodInfo method_info;
- bool attrs_fetched;
- MonoCustomAttrInfo *attributes;
+ bool attrs_fetched = false;
+ MonoCustomAttrInfo *attributes = nullptr;
void _update_signature();
void _update_signature(MonoMethodSignature *p_method_sig);
@@ -72,7 +73,7 @@ public:
_FORCE_INLINE_ MonoMethod *get_mono_ptr() const { return mono_method; }
- _FORCE_INLINE_ int get_parameters_count() const { return params_count; }
+ _FORCE_INLINE_ uint16_t get_parameters_count() const { return params_count; }
_FORCE_INLINE_ ManagedType get_return_type() const { return return_type; }
MonoObject *invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc = nullptr) const;
diff --git a/modules/mono/mono_gd/gd_mono_method_thunk.h b/modules/mono/mono_gd/gd_mono_method_thunk.h
index 01f3ae342a..091d26df1d 100644
--- a/modules/mono/mono_gd/gd_mono_method_thunk.h
+++ b/modules/mono/mono_gd/gd_mono_method_thunk.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/mono_gd/gd_mono_property.cpp b/modules/mono/mono_gd/gd_mono_property.cpp
index bc3be97102..5391b7775e 100644
--- a/modules/mono/mono_gd/gd_mono_property.cpp
+++ b/modules/mono/mono_gd/gd_mono_property.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -40,7 +40,7 @@
GDMonoProperty::GDMonoProperty(MonoProperty *p_mono_property, GDMonoClass *p_owner) {
owner = p_owner;
mono_property = p_mono_property;
- name = mono_property_get_name(mono_property);
+ name = String::utf8(mono_property_get_name(mono_property));
MonoMethod *prop_method = mono_property_get_get_method(mono_property);
@@ -149,10 +149,9 @@ bool GDMonoProperty::has_setter() {
void GDMonoProperty::set_value(MonoObject *p_object, MonoObject *p_value, MonoException **r_exc) {
MonoMethod *prop_method = mono_property_get_set_method(mono_property);
- MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), 1);
- mono_array_setref(params, 0, p_value);
+ void *params[1] = { p_value };
MonoException *exc = nullptr;
- GDMonoUtils::runtime_invoke_array(prop_method, p_object, params, &exc);
+ GDMonoUtils::runtime_invoke(prop_method, p_object, params, &exc);
if (exc) {
if (r_exc) {
*r_exc = exc;
diff --git a/modules/mono/mono_gd/gd_mono_property.h b/modules/mono/mono_gd/gd_mono_property.h
index 611ac293e4..af7a2c02e5 100644
--- a/modules/mono/mono_gd/gd_mono_property.h
+++ b/modules/mono/mono_gd/gd_mono_property.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
index 3f1155f430..6e0a263c7f 100644
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,10 +35,10 @@
#include "core/debugger/engine_debugger.h"
#include "core/debugger/script_debugger.h"
+#include "core/object/reference.h"
#include "core/os/dir_access.h"
#include "core/os/mutex.h"
#include "core/os/os.h"
-#include "core/reference.h"
#ifdef TOOLS_ENABLED
#include "editor/debugger/editor_debugger_node.h"
@@ -480,6 +480,7 @@ void set_pending_exception(MonoException *p_exc) {
#else
if (get_runtime_invoke_count() == 0) {
debug_unhandled_exception(p_exc);
+ return;
}
if (!mono_runtime_set_pending_exception(p_exc, false)) {
@@ -498,13 +499,6 @@ MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, M
return ret;
}
-MonoObject *runtime_invoke_array(MonoMethod *p_method, void *p_obj, MonoArray *p_params, MonoException **r_exc) {
- GD_MONO_BEGIN_RUNTIME_INVOKE;
- MonoObject *ret = mono_runtime_invoke_array(p_method, p_obj, p_params, (MonoObject **)r_exc);
- GD_MONO_END_RUNTIME_INVOKE;
- return ret;
-}
-
MonoString *object_to_string(MonoObject *p_obj, MonoException **r_exc) {
GD_MONO_BEGIN_RUNTIME_INVOKE;
MonoString *ret = mono_object_to_string(p_obj, (MonoObject **)r_exc);
@@ -659,7 +653,6 @@ GDMonoClass *make_generic_dictionary_type(MonoReflectionType *p_key_reftype, Mon
UNHANDLED_EXCEPTION(exc);
return GDMono::get_singleton()->get_class(mono_class_from_mono_type(mono_reflection_type_get_type(reftype)));
}
-
} // namespace Marshal
ScopeThreadAttach::ScopeThreadAttach() {
@@ -679,5 +672,4 @@ StringName get_native_godot_class_name(GDMonoClass *p_class) {
StringName *ptr = GDMonoMarshal::unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(native_name_obj));
return ptr ? *ptr : StringName();
}
-
} // namespace GDMonoUtils
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
index 5958bf3cc1..9e024418e1 100644
--- a/modules/mono/mono_gd/gd_mono_utils.h
+++ b/modules/mono/mono_gd/gd_mono_utils.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -36,9 +36,12 @@
#include "../mono_gc_handle.h"
#include "../utils/macros.h"
#include "gd_mono_header.h"
+#ifdef JAVASCRIPT_ENABLED
+#include "gd_mono_wasm_m2n.h"
+#endif
-#include "core/object.h"
-#include "core/reference.h"
+#include "core/object/class_db.h"
+#include "core/object/reference.h"
#define UNHANDLED_EXCEPTION(m_exc) \
if (unlikely(m_exc != nullptr)) { \
@@ -64,7 +67,6 @@ void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoRefl
GDMonoClass *make_generic_array_type(MonoReflectionType *p_elem_reftype);
GDMonoClass *make_generic_dictionary_type(MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype);
-
} // namespace Marshal
_FORCE_INLINE_ void hash_combine(uint32_t &p_hash, const uint32_t &p_with_hash) {
@@ -136,7 +138,6 @@ _FORCE_INLINE_ int &get_runtime_invoke_count_ref() {
}
MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, MonoException **r_exc);
-MonoObject *runtime_invoke_array(MonoMethod *p_method, void *p_obj, MonoArray *p_params, MonoException **r_exc);
MonoString *object_to_string(MonoObject *p_obj, MonoException **r_exc);
@@ -157,6 +158,21 @@ private:
StringName get_native_godot_class_name(GDMonoClass *p_class);
+template <typename... P>
+void add_internal_call(const char *p_name, void (*p_func)(P...)) {
+#ifdef JAVASCRIPT_ENABLED
+ GDMonoWasmM2n::ICallTrampolines<P...>::add();
+#endif
+ mono_add_internal_call(p_name, (void *)p_func);
+}
+
+template <typename R, typename... P>
+void add_internal_call(const char *p_name, R (*p_func)(P...)) {
+#ifdef JAVASCRIPT_ENABLED
+ GDMonoWasmM2n::ICallTrampolinesR<R, P...>::add();
+#endif
+ mono_add_internal_call(p_name, (void *)p_func);
+}
} // namespace GDMonoUtils
#define NATIVE_GDMONOCLASS_NAME(m_class) (GDMonoUtils::get_native_godot_class_name(m_class))
diff --git a/modules/mono/mono_gd/gd_mono_wasm_m2n.cpp b/modules/mono/mono_gd/gd_mono_wasm_m2n.cpp
new file mode 100644
index 0000000000..a477c55456
--- /dev/null
+++ b/modules/mono/mono_gd/gd_mono_wasm_m2n.cpp
@@ -0,0 +1,79 @@
+/*************************************************************************/
+/* gd_mono_wasm_m2n.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gd_mono_wasm_m2n.h"
+
+#ifdef JAVASCRIPT_ENABLED
+
+#include "core/templates/oa_hash_map.h"
+
+typedef mono_bool (*GodotMonoM2nIcallTrampolineDispatch)(const char *cookie, void *target_func, Mono_InterpMethodArguments *margs);
+
+// This extern function is implemented in our patched version of Mono
+MONO_API void godot_mono_register_m2n_icall_trampoline_dispatch_hook(GodotMonoM2nIcallTrampolineDispatch hook);
+
+namespace GDMonoWasmM2n {
+
+struct HashMapCookieComparator {
+ static bool compare(const char *p_lhs, const char *p_rhs) {
+ return strcmp(p_lhs, p_rhs) == 0;
+ }
+};
+
+// The default hasher supports 'const char *' C Strings, but we need a custom comparator
+OAHashMap<const char *, TrampolineFunc, HashMapHasherDefault, HashMapCookieComparator> trampolines;
+
+void set_trampoline(const char *cookies, GDMonoWasmM2n::TrampolineFunc trampoline_func) {
+ trampolines.set(cookies, trampoline_func);
+}
+
+mono_bool trampoline_dispatch_hook(const char *cookie, void *target_func, Mono_InterpMethodArguments *margs) {
+ TrampolineFunc *trampoline_func = trampolines.lookup_ptr(cookie);
+
+ if (!trampoline_func) {
+ return false;
+ }
+
+ (*trampoline_func)(target_func, margs);
+ return true;
+}
+
+bool initialized = false;
+
+void lazy_initialize() {
+ // Doesn't need to be thread safe
+ if (!initialized) {
+ initialized = true;
+ godot_mono_register_m2n_icall_trampoline_dispatch_hook(&trampoline_dispatch_hook);
+ }
+}
+} // namespace GDMonoWasmM2n
+
+#endif
diff --git a/modules/mono/mono_gd/gd_mono_wasm_m2n.h b/modules/mono/mono_gd/gd_mono_wasm_m2n.h
new file mode 100644
index 0000000000..159a2ed7b6
--- /dev/null
+++ b/modules/mono/mono_gd/gd_mono_wasm_m2n.h
@@ -0,0 +1,263 @@
+/*************************************************************************/
+/* gd_mono_wasm_m2n.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GD_MONO_WASM_M2N_H
+#define GD_MONO_WASM_M2N_H
+
+#ifdef JAVASCRIPT_ENABLED
+
+#include "core/string/ustring.h"
+#include "core/typedefs.h"
+
+#include <mono/metadata/loader.h>
+#include <mono/utils/mono-publib.h>
+#include <stdexcept>
+#include <type_traits>
+
+extern "C" {
+
+struct Mono_InterpMethodArguments {
+ size_t ilen;
+ void **iargs;
+ size_t flen;
+ double *fargs;
+ void **retval;
+ size_t is_float_ret;
+ //#ifdef TARGET_WASM
+ void *sig;
+ //#endif
+};
+} // extern "C"
+
+namespace GDMonoWasmM2n {
+
+template <typename T, size_t Size>
+struct array {
+ T elems[Size];
+};
+
+template <typename T>
+constexpr char get_m2n_cookie_impl() {
+#define M2N_REG_COOKIE(m_type, m_cookie) \
+ if constexpr (std::is_same_v<m_type, T>) { \
+ return m_cookie; \
+ }
+
+ M2N_REG_COOKIE(MonoBoolean, 'I');
+ M2N_REG_COOKIE(int8_t, 'I');
+ M2N_REG_COOKIE(uint8_t, 'I');
+ M2N_REG_COOKIE(int16_t, 'I');
+ M2N_REG_COOKIE(uint16_t, 'I');
+ M2N_REG_COOKIE(int32_t, 'I');
+ M2N_REG_COOKIE(uint32_t, 'I');
+ M2N_REG_COOKIE(int64_t, 'L');
+ M2N_REG_COOKIE(uint64_t, 'L');
+ M2N_REG_COOKIE(float, 'F');
+ M2N_REG_COOKIE(double, 'D');
+
+ if constexpr (std::is_pointer_v<T>) {
+ if constexpr (sizeof(void *) == 4) {
+ return 'I';
+ } else {
+ return 'L';
+ }
+ }
+
+ if constexpr (std::is_void_v<T>) {
+ return 'V';
+ }
+
+ return 'X';
+
+#undef M2N_REG_COOKIE
+}
+
+template <typename T>
+constexpr char get_m2n_cookie() {
+ constexpr char cookie = get_m2n_cookie_impl<T>();
+ static_assert(cookie != 'X', "Type not supported in internal call signature.");
+ return cookie;
+}
+
+template <typename... T>
+constexpr array<const char, sizeof...(T) + 2> get_m2n_cookies() {
+ return array<const char, sizeof...(T) + 2>{ 'V', get_m2n_cookie<T>()..., '\0' };
+}
+
+template <typename R, typename... T>
+constexpr array<const char, sizeof...(T) + 2> get_m2n_cookies_r() {
+ return array<const char, sizeof...(T) + 2>{ get_m2n_cookie<R>(), get_m2n_cookie<T>()..., '\0' };
+}
+
+template <typename T>
+constexpr size_t calc_m2n_index(size_t &r_int_idx, size_t &r_float_idx) {
+ constexpr char cookie = get_m2n_cookie<T>();
+
+ static_assert(cookie == 'I' || cookie == 'L' || cookie == 'F' || cookie == 'D');
+
+ if constexpr (cookie == 'I' || cookie == 'L') {
+ size_t ret = r_int_idx;
+ r_int_idx += cookie == 'I' ? 1 : 2;
+ return ret;
+ } else {
+ size_t ret = r_float_idx;
+ r_float_idx += cookie == 'F' ? 1 : 2;
+ return ret;
+ }
+}
+
+template <typename... P>
+constexpr array<size_t, sizeof...(P)> get_indices_for_type() {
+ size_t int_idx = 0;
+ size_t float_idx = 0;
+ return array<size_t, sizeof...(P)>{ calc_m2n_index<P>(int_idx, float_idx)... };
+}
+
+constexpr size_t fidx(size_t p_x) {
+ if constexpr (sizeof(void *) == 4) {
+ return p_x * 2;
+ } else {
+ return p_x;
+ }
+}
+
+template <typename T>
+T m2n_arg_cast(Mono_InterpMethodArguments *p_margs, size_t p_idx) {
+ constexpr char cookie = get_m2n_cookie<T>();
+
+ static_assert(cookie == 'I' || cookie == 'L' || cookie == 'F' || cookie == 'D');
+
+ if constexpr (cookie == 'I') {
+ return (T)(size_t)p_margs->iargs[p_idx];
+ } else if constexpr (cookie == 'L') {
+ static_assert(std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t> ||
+ (sizeof(void *) == 8 && std::is_pointer_v<T>),
+ "Invalid type for cookie 'L'.");
+
+ union {
+ T l;
+ struct {
+ int32_t lo;
+ int32_t hi;
+ } pair;
+ } p;
+
+ p.pair.lo = (int32_t)(size_t)p_margs->iargs[p_idx];
+ p.pair.hi = (int32_t)(size_t)p_margs->iargs[p_idx + 1];
+
+ return p.l;
+ } else if constexpr (cookie == 'F') {
+ return *reinterpret_cast<float *>(&p_margs->fargs[fidx(p_idx)]);
+ } else if constexpr (cookie == 'D') {
+ return (T)(size_t)p_margs->fargs[p_idx];
+ }
+}
+
+template <typename... P, size_t... Is>
+void m2n_trampoline_with_idx_seq(void *p_target_func, Mono_InterpMethodArguments *p_margs, IndexSequence<Is...>) {
+ constexpr array<size_t, sizeof...(P)> indices = get_indices_for_type<P...>();
+ typedef void (*Func)(P...);
+ Func func = (Func)p_target_func;
+ func(m2n_arg_cast<P>(p_margs, indices.elems[Is])...);
+}
+
+template <typename R, typename... P, size_t... Is>
+void m2n_trampoline_with_idx_seq_r(void *p_target_func, Mono_InterpMethodArguments *p_margs, IndexSequence<Is...>) {
+ constexpr array<size_t, sizeof...(P)> indices = get_indices_for_type<P...>();
+ typedef R (*Func)(P...);
+ Func func = (Func)p_target_func;
+ R res = func(m2n_arg_cast<P>(p_margs, indices.elems[Is])...);
+ *reinterpret_cast<R *>(p_margs->retval) = res;
+}
+
+inline void m2n_trampoline_with_idx_seq_0(void *p_target_func, Mono_InterpMethodArguments *p_margs) {
+ typedef void (*Func)();
+ Func func = (Func)p_target_func;
+ func();
+}
+
+template <typename R>
+void m2n_trampoline_with_idx_seq_r0(void *p_target_func, Mono_InterpMethodArguments *p_margs) {
+ typedef R (*Func)();
+ Func func = (Func)p_target_func;
+ R res = func();
+ *reinterpret_cast<R *>(p_margs->retval) = res;
+}
+
+template <typename... P>
+void m2n_trampoline(void *p_target_func, Mono_InterpMethodArguments *p_margs) {
+ if constexpr (sizeof...(P) == 0) {
+ m2n_trampoline_with_idx_seq_0(p_target_func, p_margs);
+ } else {
+ m2n_trampoline_with_idx_seq<P...>(p_target_func, p_margs, BuildIndexSequence<sizeof...(P)>{});
+ }
+}
+
+template <typename R, typename... P>
+void m2n_trampoline_r(void *p_target_func, Mono_InterpMethodArguments *p_margs) {
+ if constexpr (sizeof...(P) == 0) {
+ m2n_trampoline_with_idx_seq_r0<R>(p_target_func, p_margs);
+ } else {
+ m2n_trampoline_with_idx_seq_r<R, P...>(p_target_func, p_margs, BuildIndexSequence<sizeof...(P)>{});
+ }
+}
+
+typedef void (*TrampolineFunc)(void *p_target_func, Mono_InterpMethodArguments *p_margs);
+
+void set_trampoline(const char *cookies, TrampolineFunc trampoline_func);
+
+void lazy_initialize();
+
+template <typename... P>
+struct ICallTrampolines {
+ static constexpr auto cookies = get_m2n_cookies<P...>();
+
+ static void add() {
+ lazy_initialize();
+ set_trampoline(cookies.elems, &m2n_trampoline<P...>);
+ }
+};
+
+template <typename R, typename... P>
+struct ICallTrampolinesR {
+ static constexpr auto cookies = get_m2n_cookies_r<R, P...>();
+
+ static void add() {
+ lazy_initialize();
+ set_trampoline(cookies.elems, &m2n_trampoline_r<R, P...>);
+ }
+};
+
+void initialize();
+} // namespace GDMonoWasmM2n
+
+#endif
+
+#endif // GD_MONO_WASM_M2N_H
diff --git a/modules/mono/mono_gd/i_mono_class_member.h b/modules/mono/mono_gd/i_mono_class_member.h
index 2e8e01c80e..36e14ba27c 100644
--- a/modules/mono/mono_gd/i_mono_class_member.h
+++ b/modules/mono/mono_gd/i_mono_class_member.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/mono_gd/managed_type.cpp b/modules/mono/mono_gd/managed_type.cpp
index 3e971efece..0acfafe841 100644
--- a/modules/mono/mono_gd/managed_type.cpp
+++ b/modules/mono/mono_gd/managed_type.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/mono_gd/managed_type.h b/modules/mono/mono_gd/managed_type.h
index 491a2f3d20..0456a9a864 100644
--- a/modules/mono/mono_gd/managed_type.h
+++ b/modules/mono/mono_gd/managed_type.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/mono_gd/support/android_support.cpp b/modules/mono/mono_gd/support/android_support.cpp
index 8bcdeec9dd..cba29d63cd 100644
--- a/modules/mono/mono_gd/support/android_support.cpp
+++ b/modules/mono/mono_gd/support/android_support.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -44,7 +44,7 @@
#endif
#include "core/os/os.h"
-#include "core/ustring.h"
+#include "core/string/ustring.h"
#include "platform/android/java_godot_wrapper.h"
#include "platform/android/os_android.h"
#include "platform/android/thread_jandroid.h"
@@ -109,7 +109,7 @@ bool jni_exception_check(JNIEnv *p_env) {
String app_native_lib_dir_cache;
String determine_app_native_lib_dir() {
- JNIEnv *env = ThreadAndroid::get_env();
+ JNIEnv *env = get_jni_env();
ScopedLocalRef<jclass> activityThreadClass(env, env->FindClass("android/app/ActivityThread"));
jmethodID currentActivityThread = env->GetStaticMethodID(activityThreadClass, "currentActivityThread", "()Landroid/app/ActivityThread;");
@@ -134,7 +134,7 @@ String determine_app_native_lib_dir() {
}
String get_app_native_lib_dir() {
- if (app_native_lib_dir_cache.empty())
+ if (app_native_lib_dir_cache.is_empty())
app_native_lib_dir_cache = determine_app_native_lib_dir();
return app_native_lib_dir_cache;
}
@@ -253,7 +253,7 @@ int32_t get_build_version_sdk_int() {
// android.os.Build.VERSION.SDK_INT
if (build_version_sdk_int == 0) {
- JNIEnv *env = ThreadAndroid::get_env();
+ JNIEnv *env = get_jni_env();
jclass versionClass = env->FindClass("android/os/Build$VERSION");
ERR_FAIL_NULL_V(versionClass, 0);
@@ -281,7 +281,7 @@ MonoBoolean _gd_mono_init_cert_store() {
// return false;
// }
- JNIEnv *env = ThreadAndroid::get_env();
+ JNIEnv *env = get_jni_env();
ScopedLocalRef<jclass> keyStoreClass(env, env->FindClass("java/security/KeyStore"));
@@ -322,7 +322,7 @@ MonoArray *_gd_mono_android_cert_store_lookup(MonoString *p_alias) {
return nullptr;
}
- JNIEnv *env = ThreadAndroid::get_env();
+ JNIEnv *env = get_jni_env();
ScopedLocalRef<jstring> js_alias(env, env->NewStringUTF(alias_utf8));
mono_free(alias_utf8);
@@ -355,8 +355,8 @@ MonoArray *_gd_mono_android_cert_store_lookup(MonoString *p_alias) {
}
void register_internal_calls() {
- mono_add_internal_call("Android.Runtime.AndroidEnvironment::_gd_mono_init_cert_store", (void *)_gd_mono_init_cert_store);
- mono_add_internal_call("Android.Runtime.AndroidEnvironment::_gd_mono_android_cert_store_lookup", (void *)_gd_mono_android_cert_store_lookup);
+ GDMonoUtils::add_internal_call("Android.Runtime.AndroidEnvironment::_gd_mono_init_cert_store", _gd_mono_init_cert_store);
+ GDMonoUtils::add_internal_call("Android.Runtime.AndroidEnvironment::_gd_mono_android_cert_store_lookup", _gd_mono_android_cert_store_lookup);
}
void initialize() {
@@ -380,14 +380,13 @@ void cleanup() {
if (godot_dl_handle)
gd_mono_android_dlclose(godot_dl_handle, nullptr);
- JNIEnv *env = ThreadAndroid::get_env();
+ JNIEnv *env = get_jni_env();
if (certStore) {
env->DeleteGlobalRef(certStore);
certStore = nullptr;
}
}
-
} // namespace support
} // namespace android
} // namespace gdmono
@@ -438,7 +437,7 @@ GD_PINVOKE_EXPORT mono_bool _monodroid_get_network_interface_up_state(const char
*r_is_up = 0;
- JNIEnv *env = ThreadAndroid::get_env();
+ JNIEnv *env = get_jni_env();
jclass networkInterfaceClass = env->FindClass("java/net/NetworkInterface");
ERR_FAIL_NULL_V(networkInterfaceClass, 0);
@@ -470,7 +469,7 @@ GD_PINVOKE_EXPORT mono_bool _monodroid_get_network_interface_supports_multicast(
*r_supports_multicast = 0;
- JNIEnv *env = ThreadAndroid::get_env();
+ JNIEnv *env = get_jni_env();
jclass networkInterfaceClass = env->FindClass("java/net/NetworkInterface");
ERR_FAIL_NULL_V(networkInterfaceClass, 0);
@@ -508,7 +507,7 @@ static void interop_get_active_network_dns_servers(char **r_dns_servers, int *dn
CRASH_COND(get_build_version_sdk_int() < 23);
#endif
- JNIEnv *env = ThreadAndroid::get_env();
+ JNIEnv *env = get_jni_env();
GodotJavaWrapper *godot_java = ((OS_Android *)OS::get_singleton())->get_godot_java();
jobject activity = godot_java->get_activity();
@@ -649,7 +648,7 @@ GD_PINVOKE_EXPORT const char *_monodroid_timezone_get_default_id() {
//
// TimeZone.getDefault().getID()
- JNIEnv *env = ThreadAndroid::get_env();
+ JNIEnv *env = get_jni_env();
ScopedLocalRef<jclass> timeZoneClass(env, env->FindClass("java/util/TimeZone"));
ERR_FAIL_NULL_V(timeZoneClass, nullptr);
diff --git a/modules/mono/mono_gd/support/android_support.h b/modules/mono/mono_gd/support/android_support.h
index dc2e6c95ed..0c5dd2764c 100755..100644
--- a/modules/mono/mono_gd/support/android_support.h
+++ b/modules/mono/mono_gd/support/android_support.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,7 +33,7 @@
#if defined(ANDROID_ENABLED)
-#include "core/ustring.h"
+#include "core/string/ustring.h"
namespace gdmono {
namespace android {
@@ -45,7 +45,6 @@ void initialize();
void cleanup();
void register_internal_calls();
-
} // namespace support
} // namespace android
} // namespace gdmono
diff --git a/modules/mono/mono_gd/support/ios_support.h b/modules/mono/mono_gd/support/ios_support.h
index e28af120e3..28a8806d0e 100755..100644
--- a/modules/mono/mono_gd/support/ios_support.h
+++ b/modules/mono/mono_gd/support/ios_support.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,7 +33,7 @@
#if defined(IPHONE_ENABLED)
-#include "core/ustring.h"
+#include "core/string/ustring.h"
namespace gdmono {
namespace ios {
@@ -41,7 +41,6 @@ namespace support {
void initialize();
void cleanup();
-
} // namespace support
} // namespace ios
} // namespace gdmono
diff --git a/modules/mono/mono_gd/support/ios_support.mm b/modules/mono/mono_gd/support/ios_support.mm
index dc23c06eba..cdee04edcf 100644
--- a/modules/mono/mono_gd/support/ios_support.mm
+++ b/modules/mono/mono_gd/support/ios_support.mm
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -72,7 +72,6 @@ void initialize() {
void cleanup() {
}
-
} // namespace support
} // namespace ios
} // namespace gdmono
diff --git a/modules/mono/register_types.cpp b/modules/mono/register_types.cpp
index 98c3ba1324..80eb47bfd4 100644
--- a/modules/mono/register_types.cpp
+++ b/modules/mono/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,7 +30,7 @@
#include "register_types.h"
-#include "core/engine.h"
+#include "core/config/engine.h"
#include "csharp_script.h"
diff --git a/modules/mono/register_types.h b/modules/mono/register_types.h
index e30d9a8abd..1a2ff004b5 100644
--- a/modules/mono/register_types.h
+++ b/modules/mono/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp
index bd67b03c8e..3aaf726fc8 100644
--- a/modules/mono/signal_awaiter_utils.cpp
+++ b/modules/mono/signal_awaiter_utils.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -48,18 +48,10 @@ Error gd_mono_connect_signal_awaiter(Object *p_source, const StringName &p_signa
}
bool SignalAwaiterCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) {
+ // Only called if both instances are of type SignalAwaiterCallable. Static cast is safe.
const SignalAwaiterCallable *a = static_cast<const SignalAwaiterCallable *>(p_a);
const SignalAwaiterCallable *b = static_cast<const SignalAwaiterCallable *>(p_b);
-
- if (a->target_id != b->target_id) {
- return false;
- }
-
- if (a->signal != b->signal) {
- return false;
- }
-
- return true;
+ return a->awaiter_handle.handle == b->awaiter_handle.handle;
}
bool SignalAwaiterCallable::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) {
@@ -109,11 +101,15 @@ void SignalAwaiterCallable::call(const Variant **p_arguments, int p_argcount, Va
"Resumed after await, but class instance is gone.");
#endif
- MonoArray *signal_args = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_argcount);
+ MonoArray *signal_args = nullptr;
- for (int i = 0; i < p_argcount; i++) {
- MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(*p_arguments[i]);
- mono_array_setref(signal_args, i, boxed);
+ if (p_argcount > 0) {
+ signal_args = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_argcount);
+
+ for (int i = 0; i < p_argcount; i++) {
+ MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(*p_arguments[i]);
+ mono_array_setref(signal_args, i, boxed);
+ }
}
MonoObject *awaiter = awaiter_handle.get_target();
diff --git a/modules/mono/signal_awaiter_utils.h b/modules/mono/signal_awaiter_utils.h
index c550315a23..4c77f8cfed 100644
--- a/modules/mono/signal_awaiter_utils.h
+++ b/modules/mono/signal_awaiter_utils.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,7 +31,7 @@
#ifndef SIGNAL_AWAITER_UTILS_H
#define SIGNAL_AWAITER_UTILS_H
-#include "core/reference.h"
+#include "core/object/reference.h"
#include "csharp_script.h"
#include "mono_gc_handle.h"
diff --git a/modules/mono/utils/macros.h b/modules/mono/utils/macros.h
index c76619cca4..4a220d89c8 100644
--- a/modules/mono/utils/macros.h
+++ b/modules/mono/utils/macros.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -64,7 +64,6 @@ public:
template <typename F>
ScopeExit<F> operator+(F p_exit_func) { return ScopeExit<F>(p_exit_func); }
};
-
} // namespace gdmono
#define SCOPE_EXIT \
diff --git a/modules/mono/utils/mono_reg_utils.cpp b/modules/mono/utils/mono_reg_utils.cpp
index a619f0b975..bb1265e959 100644
--- a/modules/mono/utils/mono_reg_utils.cpp
+++ b/modules/mono/utils/mono_reg_utils.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -173,7 +173,7 @@ String find_msbuild_tools_path() {
String output;
int exit_code;
- OS::get_singleton()->execute(vswhere_path, vswhere_args, true, nullptr, &output, &exit_code);
+ OS::get_singleton()->execute(vswhere_path, vswhere_args, &output, &exit_code);
if (exit_code == 0) {
Vector<String> lines = output.split("\n");
@@ -188,7 +188,7 @@ String find_msbuild_tools_path() {
if (key == "installationPath") {
String val = line.substr(sep_idx + 1, line.length()).strip_edges();
- ERR_BREAK(val.empty());
+ ERR_BREAK(val.is_empty());
if (!val.ends_with("\\")) {
val += "\\";
@@ -225,7 +225,6 @@ cleanup:
return msbuild_tools_path;
}
-
} // namespace MonoRegUtils
#endif // WINDOWS_ENABLED
diff --git a/modules/mono/utils/mono_reg_utils.h b/modules/mono/utils/mono_reg_utils.h
index 4ef876f2b6..0e617761ea 100644
--- a/modules/mono/utils/mono_reg_utils.h
+++ b/modules/mono/utils/mono_reg_utils.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,7 +33,7 @@
#ifdef WINDOWS_ENABLED
-#include "core/ustring.h"
+#include "core/string/ustring.h"
struct MonoRegInfo {
String version;
diff --git a/modules/mono/utils/osx_utils.cpp b/modules/mono/utils/osx_utils.cpp
index e68466b1cf..f4216c8129 100644
--- a/modules/mono/utils/osx_utils.cpp
+++ b/modules/mono/utils/osx_utils.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,7 +32,7 @@
#ifdef OSX_ENABLED
-#include "core/print_string.h"
+#include "core/string/print_string.h"
#include <CoreFoundation/CoreFoundation.h>
#include <CoreServices/CoreServices.h>
diff --git a/modules/mono/utils/osx_utils.h b/modules/mono/utils/osx_utils.h
index 55002702f8..6704f19077 100644
--- a/modules/mono/utils/osx_utils.h
+++ b/modules/mono/utils/osx_utils.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "core/ustring.h"
+#include "core/string/ustring.h"
#ifndef OSX_UTILS_H
#define OSX_UTILS_H
diff --git a/modules/mono/utils/path_utils.cpp b/modules/mono/utils/path_utils.cpp
index 5d1abd0c09..93d44628ac 100644
--- a/modules/mono/utils/path_utils.cpp
+++ b/modules/mono/utils/path_utils.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,10 +30,10 @@
#include "path_utils.h"
+#include "core/config/project_settings.h"
#include "core/os/dir_access.h"
#include "core/os/file_access.h"
#include "core/os/os.h"
-#include "core/project_settings.h"
#ifdef WINDOWS_ENABLED
#include <windows.h>
@@ -136,7 +136,7 @@ String realpath(const String &p_path) {
}
String join(const String &p_a, const String &p_b) {
- if (p_a.empty()) {
+ if (p_a.is_empty()) {
return p_b;
}
@@ -165,7 +165,7 @@ String relative_to_impl(const String &p_path, const String &p_relative_to) {
} else {
String base_dir = p_relative_to.get_base_dir();
- if (base_dir.length() <= 2 && (base_dir.empty() || base_dir.ends_with(":"))) {
+ if (base_dir.length() <= 2 && (base_dir.is_empty() || base_dir.ends_with(":"))) {
return p_path;
}
@@ -194,5 +194,4 @@ String relative_to(const String &p_path, const String &p_relative_to) {
return relative_to_impl(path_abs_norm, relative_to_abs_norm);
}
-
} // namespace path
diff --git a/modules/mono/utils/path_utils.h b/modules/mono/utils/path_utils.h
index bcd8af8bb9..82b8f95f49 100644
--- a/modules/mono/utils/path_utils.h
+++ b/modules/mono/utils/path_utils.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,8 +31,8 @@
#ifndef PATH_UTILS_H
#define PATH_UTILS_H
-#include "core/string_builder.h"
-#include "core/ustring.h"
+#include "core/string/string_builder.h"
+#include "core/string/ustring.h"
namespace path {
@@ -56,7 +56,6 @@ String abspath(const String &p_path);
String realpath(const String &p_path);
String relative_to(const String &p_path, const String &p_relative_to);
-
} // namespace path
#endif // PATH_UTILS_H
diff --git a/modules/mono/utils/string_utils.cpp b/modules/mono/utils/string_utils.cpp
index 65da4328f6..43de77005e 100644
--- a/modules/mono/utils/string_utils.cpp
+++ b/modules/mono/utils/string_utils.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -84,7 +84,6 @@ int sfind(const String &p_text, int p_from) {
return -1;
}
-
} // namespace
String sformat(const String &p_text, const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4, const Variant &p5) {
diff --git a/modules/mono/utils/string_utils.h b/modules/mono/utils/string_utils.h
index 0318fec592..3290cb38b9 100644
--- a/modules/mono/utils/string_utils.h
+++ b/modules/mono/utils/string_utils.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,8 +31,8 @@
#ifndef STRING_FORMAT_H
#define STRING_FORMAT_H
-#include "core/ustring.h"
-#include "core/variant.h"
+#include "core/string/ustring.h"
+#include "core/variant/variant.h"
#include <stdarg.h>
diff --git a/modules/ogg/SCsub b/modules/ogg/SCsub
index e768fb4ae8..e415d92498 100644
--- a/modules/ogg/SCsub
+++ b/modules/ogg/SCsub
@@ -9,6 +9,9 @@ Import("env_modules")
env_ogg = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_libogg"]:
thirdparty_dir = "#thirdparty/libogg/"
thirdparty_sources = [
@@ -21,7 +24,16 @@ if env["builtin_libogg"]:
env_thirdparty = env_ogg.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
# Godot source files
-env_ogg.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_ogg.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/ogg/register_types.cpp b/modules/ogg/register_types.cpp
index 73c691397c..b23ea65378 100644
--- a/modules/ogg/register_types.cpp
+++ b/modules/ogg/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/ogg/register_types.h b/modules/ogg/register_types.h
index 849d27bb06..49d5ed9c80 100644
--- a/modules/ogg/register_types.h
+++ b/modules/ogg/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/opensimplex/SCsub b/modules/opensimplex/SCsub
index 52d8b145ef..86d77c3dfb 100644
--- a/modules/opensimplex/SCsub
+++ b/modules/opensimplex/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_opensimplex = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
thirdparty_dir = "#thirdparty/misc/"
thirdparty_sources = [
"open-simplex-noise.c",
@@ -16,7 +19,15 @@ env_opensimplex.Prepend(CPPPATH=[thirdparty_dir])
env_thirdparty = env_opensimplex.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_opensimplex.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-# Godot's own source files
-env_opensimplex.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/opensimplex/doc_classes/NoiseTexture.xml b/modules/opensimplex/doc_classes/NoiseTexture.xml
index c06f3096de..7df261d2ba 100644
--- a/modules/opensimplex/doc_classes/NoiseTexture.xml
+++ b/modules/opensimplex/doc_classes/NoiseTexture.xml
@@ -5,7 +5,7 @@
</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 normalmap textures.
+ NoiseTexture can also generate normal map textures.
The class uses [Thread]s to generate the texture data internally, so [method Texture2D.get_data] may return [code]null[/code] if the generation process has not completed yet. In that case, you need to wait for the texture to be generated before accessing the data:
[codeblock]
var texture = preload("res://noise.tres")
@@ -18,7 +18,7 @@
<methods>
</methods>
<members>
- <member name="as_normalmap" type="bool" setter="set_as_normalmap" getter="is_normalmap" default="false">
+ <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">
diff --git a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml
index d89828037f..dcda5c2324 100644
--- a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml
+++ b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml
@@ -24,7 +24,7 @@
<tutorials>
</tutorials>
<methods>
- <method name="get_image">
+ <method name="get_image" qualifiers="const">
<return type="Image">
</return>
<argument index="0" name="width" type="int">
@@ -32,10 +32,10 @@
<argument index="1" name="height" type="int">
</argument>
<description>
- Generate a noise image with the requested [code]width[/code] and [code]height[/code], based on the current noise parameters.
+ Generate a noise image in [constant Image.FORMAT_L8] format with the requested [code]width[/code] and [code]height[/code], based on the current noise parameters.
</description>
</method>
- <method name="get_noise_1d">
+ <method name="get_noise_1d" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="x" type="float">
@@ -45,7 +45,7 @@
[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">
+ <method name="get_noise_2d" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="x" type="float">
@@ -56,7 +56,7 @@
Returns the 2D noise value [code][-1,1][/code] at the given position.
</description>
</method>
- <method name="get_noise_2dv">
+ <method name="get_noise_2dv" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="pos" type="Vector2">
@@ -65,7 +65,7 @@
Returns the 2D noise value [code][-1,1][/code] at the given position.
</description>
</method>
- <method name="get_noise_3d">
+ <method name="get_noise_3d" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="x" type="float">
@@ -78,7 +78,7 @@
Returns the 3D noise value [code][-1,1][/code] at the given position.
</description>
</method>
- <method name="get_noise_3dv">
+ <method name="get_noise_3dv" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="pos" type="Vector3">
@@ -87,7 +87,7 @@
Returns the 3D noise value [code][-1,1][/code] at the given position.
</description>
</method>
- <method name="get_noise_4d">
+ <method name="get_noise_4d" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="x" type="float">
@@ -102,13 +102,13 @@
Returns the 4D noise value [code][-1,1][/code] at the given position.
</description>
</method>
- <method name="get_seamless_image">
+ <method name="get_seamless_image" qualifiers="const">
<return type="Image">
</return>
<argument index="0" name="size" type="int">
</argument>
<description>
- Generate a tileable noise image, based on the current noise parameters. Generated seamless images are always square ([code]size[/code] × [code]size[/code]).
+ 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]).
</description>
</method>
</methods>
diff --git a/modules/opensimplex/icons/NoiseTexture.svg b/modules/opensimplex/icons/NoiseTexture.svg
index 5908c2b2d4..479684cde2 100644
--- a/modules/opensimplex/icons/NoiseTexture.svg
+++ b/modules/opensimplex/icons/NoiseTexture.svg
@@ -1,3 +1 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<path d="m2 1c-0.55228 0-1 0.44772-1 1v12c0 0.55228 0.44772 1 1 1h12c0.55228 0 1-0.44772 1-1v-12c0-0.55228-0.44772-1-1-1zm1 2h10v8h-10zm3 1v2h2v-2zm2 2v2h2v2h2v-6h-2v2zm0 2h-2v-2h-2v4h4z" fill="#e0e0e0" fill-opacity=".99608"/>
-</svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1c-.55228 0-1 .44772-1 1v12c0 .55228.44772 1 1 1h12c.55228 0 1-.44772 1-1v-12c0-.55228-.44772-1-1-1zm1 2h10v8h-10zm3 1v2h2v-2zm2 2v2h2v2h2v-6h-2v2zm0 2h-2v-2h-2v4h4z" fill="#e0e0e0" fill-opacity=".99608"/></svg>
diff --git a/modules/opensimplex/noise_texture.cpp b/modules/opensimplex/noise_texture.cpp
index 1181e69cd3..30a0ca3464 100644
--- a/modules/opensimplex/noise_texture.cpp
+++ b/modules/opensimplex/noise_texture.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,13 +34,12 @@
NoiseTexture::NoiseTexture() {
update_queued = false;
- noise_thread = nullptr;
regen_queued = false;
first_time = true;
size = Vector2i(512, 512);
seamless = false;
- as_normalmap = false;
+ as_normal_map = false;
bump_strength = 8.0;
noise = Ref<OpenSimplexNoise>();
@@ -52,10 +51,7 @@ NoiseTexture::~NoiseTexture() {
if (texture.is_valid()) {
RS::get_singleton()->free(texture);
}
- if (noise_thread) {
- Thread::wait_to_finish(noise_thread);
- memdelete(noise_thread);
- }
+ noise_thread.wait_to_finish();
}
void NoiseTexture::_bind_methods() {
@@ -68,8 +64,8 @@ void NoiseTexture::_bind_methods() {
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_as_normalmap", "as_normalmap"), &NoiseTexture::set_as_normalmap);
- ClassDB::bind_method(D_METHOD("is_normalmap"), &NoiseTexture::is_normalmap);
+ 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);
@@ -81,14 +77,14 @@ void NoiseTexture::_bind_methods() {
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, "seamless"), "set_seamless", "get_seamless");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "as_normalmap"), "set_as_normalmap", "is_normalmap");
+ 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");
}
void NoiseTexture::_validate_property(PropertyInfo &property) const {
if (property.name == "bump_strength") {
- if (!as_normalmap) {
+ if (!as_normal_map) {
property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
}
}
@@ -109,11 +105,9 @@ void NoiseTexture::_set_texture_data(const Ref<Image> &p_image) {
void NoiseTexture::_thread_done(const Ref<Image> &p_image) {
_set_texture_data(p_image);
- Thread::wait_to_finish(noise_thread);
- memdelete(noise_thread);
- noise_thread = nullptr;
+ noise_thread.wait_to_finish();
if (regen_queued) {
- noise_thread = Thread::create(_thread_function, this);
+ noise_thread.start(_thread_function, this);
regen_queued = false;
}
}
@@ -148,8 +142,8 @@ Ref<Image> NoiseTexture::_generate_texture() {
image = ref_noise->get_image(size.x, size.y);
}
- if (as_normalmap) {
- image->bumpmap_to_normalmap(bump_strength);
+ if (as_normal_map) {
+ image->bump_map_to_normal_map(bump_strength);
}
return image;
@@ -165,8 +159,8 @@ void NoiseTexture::_update_texture() {
use_thread = false;
#endif
if (use_thread) {
- if (!noise_thread) {
- noise_thread = Thread::create(_thread_function, this);
+ if (!noise_thread.is_started()) {
+ noise_thread.start(_thread_function, this);
regen_queued = false;
} else {
regen_queued = true;
@@ -225,17 +219,17 @@ bool NoiseTexture::get_seamless() {
return seamless;
}
-void NoiseTexture::set_as_normalmap(bool p_as_normalmap) {
- if (p_as_normalmap == as_normalmap) {
+void NoiseTexture::set_as_normal_map(bool p_as_normal_map) {
+ if (p_as_normal_map == as_normal_map) {
return;
}
- as_normalmap = p_as_normalmap;
+ as_normal_map = p_as_normal_map;
_queue_update();
_change_notify();
}
-bool NoiseTexture::is_normalmap() {
- return as_normalmap;
+bool NoiseTexture::is_normal_map() {
+ return as_normal_map;
}
void NoiseTexture::set_bump_strength(float p_bump_strength) {
@@ -243,7 +237,7 @@ void NoiseTexture::set_bump_strength(float p_bump_strength) {
return;
}
bump_strength = p_bump_strength;
- if (as_normalmap) {
+ if (as_normal_map) {
_queue_update();
}
}
diff --git a/modules/opensimplex/noise_texture.h b/modules/opensimplex/noise_texture.h
index 7357e54e35..170275bd2e 100644
--- a/modules/opensimplex/noise_texture.h
+++ b/modules/opensimplex/noise_texture.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,8 +33,8 @@
#include "open_simplex_noise.h"
-#include "core/image.h"
-#include "core/reference.h"
+#include "core/io/image.h"
+#include "core/object/reference.h"
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "editor/property_editor.h"
@@ -45,7 +45,7 @@ class NoiseTexture : public Texture2D {
private:
Ref<Image> data;
- Thread *noise_thread;
+ Thread noise_thread;
bool first_time;
bool update_queued;
@@ -57,7 +57,7 @@ private:
Ref<OpenSimplexNoise> noise;
Vector2i size;
bool seamless;
- bool as_normalmap;
+ bool as_normal_map;
float bump_strength;
void _thread_done(const Ref<Image> &p_image);
@@ -82,8 +82,8 @@ public:
void set_seamless(bool p_seamless);
bool get_seamless();
- void set_as_normalmap(bool p_as_normalmap);
- bool is_normalmap();
+ 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();
diff --git a/modules/opensimplex/open_simplex_noise.cpp b/modules/opensimplex/open_simplex_noise.cpp
index b08219d258..a823bcf3b8 100644
--- a/modules/opensimplex/open_simplex_noise.cpp
+++ b/modules/opensimplex/open_simplex_noise.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -63,7 +63,7 @@ void OpenSimplexNoise::set_seed(int p_seed) {
emit_changed();
}
-int OpenSimplexNoise::get_seed() {
+int OpenSimplexNoise::get_seed() const {
return seed;
}
@@ -102,9 +102,9 @@ void OpenSimplexNoise::set_lacunarity(float p_lacunarity) {
emit_changed();
}
-Ref<Image> OpenSimplexNoise::get_image(int p_width, int p_height) {
+Ref<Image> OpenSimplexNoise::get_image(int p_width, int p_height) const {
Vector<uint8_t> data;
- data.resize(p_width * p_height * 4);
+ data.resize(p_width * p_height);
uint8_t *wd8 = data.ptrw();
@@ -112,21 +112,17 @@ Ref<Image> OpenSimplexNoise::get_image(int p_width, int p_height) {
for (int j = 0; j < p_width; j++) {
float v = get_noise_2d(j, i);
v = v * 0.5 + 0.5; // Normalize [0..1]
- uint8_t value = uint8_t(CLAMP(v * 255.0, 0, 255));
- wd8[(i * p_width + j) * 4 + 0] = value;
- wd8[(i * p_width + j) * 4 + 1] = value;
- wd8[(i * p_width + j) * 4 + 2] = value;
- wd8[(i * p_width + j) * 4 + 3] = 255;
+ 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_RGBA8, data));
+ 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) {
+Ref<Image> OpenSimplexNoise::get_seamless_image(int p_size) const {
Vector<uint8_t> data;
- data.resize(p_size * p_size * 4);
+ data.resize(p_size * p_size);
uint8_t *wd8 = data.ptrw();
@@ -135,10 +131,10 @@ Ref<Image> OpenSimplexNoise::get_seamless_image(int p_size) {
float ii = (float)i / (float)p_size;
float jj = (float)j / (float)p_size;
- ii *= 2.0 * Math_PI;
- jj *= 2.0 * Math_PI;
+ ii *= Math_TAU;
+ jj *= Math_TAU;
- float radius = p_size / (2.0 * Math_PI);
+ float radius = p_size / Math_TAU;
float x = radius * Math::sin(jj);
float y = radius * Math::cos(jj);
@@ -147,15 +143,11 @@ Ref<Image> OpenSimplexNoise::get_seamless_image(int p_size) {
float v = get_noise_4d(x, y, z, w);
v = v * 0.5 + 0.5; // Normalize [0..1]
- uint8_t value = uint8_t(CLAMP(v * 255.0, 0, 255));
- wd8[(i * p_size + j) * 4 + 0] = value;
- wd8[(i * p_size + j) * 4 + 1] = value;
- wd8[(i * p_size + j) * 4 + 2] = value;
- wd8[(i * p_size + j) * 4 + 3] = 255;
+ 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_RGBA8, data));
+ Ref<Image> image = memnew(Image(p_size, p_size, false, Image::FORMAT_L8, data));
return image;
}
@@ -193,11 +185,11 @@ void OpenSimplexNoise::_bind_methods() {
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) {
+float OpenSimplexNoise::get_noise_1d(float x) const {
return get_noise_2d(x, 1.0);
}
-float OpenSimplexNoise::get_noise_2d(float x, float y) {
+float OpenSimplexNoise::get_noise_2d(float x, float y) const {
x /= period;
y /= period;
@@ -217,7 +209,7 @@ float OpenSimplexNoise::get_noise_2d(float x, float y) {
return sum / max;
}
-float OpenSimplexNoise::get_noise_3d(float x, float y, float z) {
+float OpenSimplexNoise::get_noise_3d(float x, float y, float z) const {
x /= period;
y /= period;
z /= period;
@@ -239,7 +231,7 @@ float OpenSimplexNoise::get_noise_3d(float x, float y, float z) {
return sum / max;
}
-float OpenSimplexNoise::get_noise_4d(float x, float y, float z, float w) {
+float OpenSimplexNoise::get_noise_4d(float x, float y, float z, float w) const {
x /= period;
y /= period;
z /= period;
diff --git a/modules/opensimplex/open_simplex_noise.h b/modules/opensimplex/open_simplex_noise.h
index dce62bc1f9..f18dd4d798 100644
--- a/modules/opensimplex/open_simplex_noise.h
+++ b/modules/opensimplex/open_simplex_noise.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,21 +31,21 @@
#ifndef OPEN_SIMPLEX_NOISE_H
#define OPEN_SIMPLEX_NOISE_H
-#include "core/image.h"
-#include "core/reference.h"
+#include "core/io/image.h"
+#include "core/object/reference.h"
#include "scene/resources/texture.h"
#include "thirdparty/misc/open-simplex-noise.h"
-// 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.
-#define MAX_OCTAVES 9
-
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;
@@ -61,7 +61,7 @@ public:
void _init_seeds();
void set_seed(int seed);
- int get_seed();
+ int get_seed() const;
void set_octaves(int p_octaves);
int get_octaves() const { return octaves; }
@@ -75,22 +75,22 @@ public:
void set_lacunarity(float p_lacunarity);
float get_lacunarity() const { return lacunarity; }
- Ref<Image> get_image(int p_width, int p_height);
- Ref<Image> get_seamless_image(int p_size);
+ Ref<Image> get_image(int p_width, int p_height) const;
+ Ref<Image> get_seamless_image(int p_size) const;
- float get_noise_1d(float x);
- float get_noise_2d(float x, float y);
- float get_noise_3d(float x, float y, float z);
- float get_noise_4d(float x, float y, float z, float w);
+ 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) { return open_simplex_noise2(&(contexts[octave]), x, y); }
- _FORCE_INLINE_ float _get_octave_noise_3d(int octave, float x, float y, float z) { 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) { return open_simplex_noise4(&(contexts[octave]), x, y, z, w); }
+ _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(Vector2 v) { return get_noise_2d(v.x, v.y); }
- _FORCE_INLINE_ float get_noise_3dv(Vector3 v) { return get_noise_3d(v.x, v.y, v.z); }
+ _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();
diff --git a/modules/opensimplex/register_types.cpp b/modules/opensimplex/register_types.cpp
index fef90cdce3..e9735a2cc8 100644
--- a/modules/opensimplex/register_types.cpp
+++ b/modules/opensimplex/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/opensimplex/register_types.h b/modules/opensimplex/register_types.h
index 51c6815eae..d72e37e3a3 100644
--- a/modules/opensimplex/register_types.h
+++ b/modules/opensimplex/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/opus/SCsub b/modules/opus/SCsub
index 52c61fa708..1437cd86df 100644
--- a/modules/opus/SCsub
+++ b/modules/opus/SCsub
@@ -10,6 +10,10 @@ Import("env_modules")
env_opus = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
+# Thirdparty source files
if env["builtin_opus"]:
thirdparty_dir = "#thirdparty/opus/"
@@ -233,7 +237,16 @@ if env["builtin_opus"]:
env_thirdparty = env_opus.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
+
+# Godot source files
+
+module_obj = []
+
+env_opus.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-# Module files
-env_opus.add_source_files(env.modules_sources, "register_types.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/opus/register_types.cpp b/modules/opus/register_types.cpp
index a4329e142c..02874a9a4b 100644
--- a/modules/opus/register_types.cpp
+++ b/modules/opus/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/opus/register_types.h b/modules/opus/register_types.h
index ad6e083c82..af889cf809 100644
--- a/modules/opus/register_types.h
+++ b/modules/opus/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/pvr/SCsub b/modules/pvr/SCsub
index e0baf851f1..36052cffed 100644
--- a/modules/pvr/SCsub
+++ b/modules/pvr/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_pvr = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
# Not unbundled so far since not widespread as shared library
thirdparty_dir = "#thirdparty/pvrtccompressor/"
thirdparty_sources = [
@@ -21,7 +24,15 @@ env_pvr.Prepend(CPPPATH=[thirdparty_dir])
env_thirdparty = env_pvr.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
# Godot source files
-env_pvr.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_pvr.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/pvr/image_compress_pvrtc.cpp b/modules/pvr/image_compress_pvrtc.cpp
new file mode 100644
index 0000000000..d2d8976694
--- /dev/null
+++ b/modules/pvr/image_compress_pvrtc.cpp
@@ -0,0 +1,84 @@
+/*************************************************************************/
+/* image_compress_pvrtc.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "image_compress_pvrtc.h"
+
+#include "core/io/image.h"
+#include "core/object/reference.h"
+
+#include <PvrTcEncoder.h>
+#include <RgbaBitmap.h>
+
+static void _compress_pvrtc1_4bpp(Image *p_img) {
+ Ref<Image> img = p_img->duplicate();
+
+ bool make_mipmaps = false;
+ if (!img->is_size_po2() || img->get_width() != img->get_height()) {
+ make_mipmaps = img->has_mipmaps();
+ img->resize_to_po2(true);
+ }
+ img->convert(Image::FORMAT_RGBA8);
+ if (!img->has_mipmaps() && make_mipmaps) {
+ img->generate_mipmaps();
+ }
+
+ bool use_alpha = img->detect_alpha();
+
+ Ref<Image> new_img;
+ new_img.instance();
+ new_img->create(img->get_width(), img->get_height(), img->has_mipmaps(), use_alpha ? Image::FORMAT_PVRTC1_4A : Image::FORMAT_PVRTC1_4);
+
+ Vector<uint8_t> data = new_img->get_data();
+ {
+ uint8_t *wr = data.ptrw();
+ const uint8_t *r = img->get_data().ptr();
+
+ for (int i = 0; i <= new_img->get_mipmap_count(); i++) {
+ int ofs, size, w, h;
+ img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h);
+ Javelin::RgbaBitmap bm(w, h);
+ void *dst = (void *)bm.GetData();
+ copymem(dst, &r[ofs], size);
+ Javelin::ColorRgba<unsigned char> *dp = bm.GetData();
+ for (int j = 0; j < size / 4; j++) {
+ // Red and blue colors are swapped.
+ SWAP(dp[j].r, dp[j].b);
+ }
+ new_img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h);
+ Javelin::PvrTcEncoder::EncodeRgba4Bpp(&wr[ofs], bm);
+ }
+ }
+
+ p_img->create(new_img->get_width(), new_img->get_height(), new_img->has_mipmaps(), new_img->get_format(), data);
+}
+
+void _register_pvrtc_compress_func() {
+ Image::_image_compress_pvrtc1_4bpp_func = _compress_pvrtc1_4bpp;
+}
diff --git a/modules/pvr/image_compress_pvrtc.h b/modules/pvr/image_compress_pvrtc.h
new file mode 100644
index 0000000000..985076ce4d
--- /dev/null
+++ b/modules/pvr/image_compress_pvrtc.h
@@ -0,0 +1,36 @@
+/*************************************************************************/
+/* image_compress_pvrtc.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef IMAGE_COMPRESS_PVRTC_H
+#define IMAGE_COMPRESS_PVRTC_H
+
+void _register_pvrtc_compress_func();
+
+#endif // IMAGE_COMPRESS_PVRTC_H
diff --git a/modules/pvr/register_types.cpp b/modules/pvr/register_types.cpp
index 1eb697bba3..aeac564c93 100644
--- a/modules/pvr/register_types.cpp
+++ b/modules/pvr/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,6 +30,7 @@
#include "register_types.h"
+#include "image_compress_pvrtc.h"
#include "texture_loader_pvr.h"
static Ref<ResourceFormatPVR> resource_loader_pvr;
@@ -37,6 +38,8 @@ static Ref<ResourceFormatPVR> resource_loader_pvr;
void register_pvr_types() {
resource_loader_pvr.instance();
ResourceLoader::add_resource_format_loader(resource_loader_pvr);
+
+ _register_pvrtc_compress_func();
}
void unregister_pvr_types() {
diff --git a/modules/pvr/register_types.h b/modules/pvr/register_types.h
index 8318996a46..74fcfe2ce4 100644
--- a/modules/pvr/register_types.h
+++ b/modules/pvr/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/pvr/texture_loader_pvr.cpp b/modules/pvr/texture_loader_pvr.cpp
index 050dce1aab..70a3c8b5a9 100644
--- a/modules/pvr/texture_loader_pvr.cpp
+++ b/modules/pvr/texture_loader_pvr.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,16 +29,12 @@
/*************************************************************************/
#include "texture_loader_pvr.h"
-#include "PvrTcEncoder.h"
-#include "RgbaBitmap.h"
+
#include "core/os/file_access.h"
-#include <string.h>
-#include <new>
static void _pvrtc_decompress(Image *p_img);
enum PVRFLags {
-
PVR_HAS_MIPMAPS = 0x00000100,
PVR_TWIDDLED = 0x00000200,
PVR_NORMAL_MAP = 0x00000400,
@@ -48,7 +44,6 @@ enum PVRFLags {
PVR_VOLUME_TEXTURES = 0x00004000,
PVR_HAS_ALPHA = 0x00008000,
PVR_VFLIP = 0x00010000
-
};
RES ResourceFormatPVR::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
@@ -113,11 +108,11 @@ RES ResourceFormatPVR::load(const String &p_path, const String &p_original_path,
switch (flags & 0xFF) {
case 0x18:
case 0xC:
- format = (flags & PVR_HAS_ALPHA) ? Image::FORMAT_PVRTC2A : Image::FORMAT_PVRTC2;
+ format = (flags & PVR_HAS_ALPHA) ? Image::FORMAT_PVRTC1_2A : Image::FORMAT_PVRTC1_2;
break;
case 0x19:
case 0xD:
- format = (flags & PVR_HAS_ALPHA) ? Image::FORMAT_PVRTC4A : Image::FORMAT_PVRTC4;
+ format = (flags & PVR_HAS_ALPHA) ? Image::FORMAT_PVRTC1_4A : Image::FORMAT_PVRTC1_4;
break;
case 0x16:
format = Image::FORMAT_L8;
@@ -158,7 +153,7 @@ RES ResourceFormatPVR::load(const String &p_path, const String &p_original_path,
}
Ref<Image> image = memnew(Image(width, height, mipmaps, format, data));
- ERR_FAIL_COND_V(image->empty(), RES());
+ ERR_FAIL_COND_V(image->is_empty(), RES());
Ref<ImageTexture> texture = memnew(ImageTexture);
texture->create_from_image(image);
@@ -185,53 +180,8 @@ String ResourceFormatPVR::get_resource_type(const String &p_path) const {
return "";
}
-static void _compress_pvrtc4(Image *p_img) {
- Ref<Image> img = p_img->duplicate();
-
- bool make_mipmaps = false;
- if (!img->is_size_po2() || img->get_width() != img->get_height()) {
- make_mipmaps = img->has_mipmaps();
- img->resize_to_po2(true);
- }
- img->convert(Image::FORMAT_RGBA8);
- if (!img->has_mipmaps() && make_mipmaps) {
- img->generate_mipmaps();
- }
-
- bool use_alpha = img->detect_alpha();
-
- Ref<Image> new_img;
- new_img.instance();
- new_img->create(img->get_width(), img->get_height(), img->has_mipmaps(), use_alpha ? Image::FORMAT_PVRTC4A : Image::FORMAT_PVRTC4);
-
- Vector<uint8_t> data = new_img->get_data();
- {
- uint8_t *wr = data.ptrw();
- const uint8_t *r = img->get_data().ptr();
-
- for (int i = 0; i <= new_img->get_mipmap_count(); i++) {
- int ofs, size, w, h;
- img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h);
- Javelin::RgbaBitmap bm(w, h);
- void *dst = (void *)bm.GetData();
- copymem(dst, &r[ofs], size);
- Javelin::ColorRgba<unsigned char> *dp = bm.GetData();
- for (int j = 0; j < size / 4; j++) {
- /* red and blue colors are swapped. */
- SWAP(dp[j].r, dp[j].b);
- }
- new_img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h);
- Javelin::PvrTcEncoder::EncodeRgba4Bpp(&wr[ofs], bm);
- }
- }
-
- p_img->create(new_img->get_width(), new_img->get_height(), new_img->has_mipmaps(), new_img->get_format(), data);
-}
-
ResourceFormatPVR::ResourceFormatPVR() {
Image::_image_decompress_pvrtc = _pvrtc_decompress;
- Image::_image_compress_pvrtc4_func = _compress_pvrtc4;
- Image::_image_compress_pvrtc2_func = _compress_pvrtc4;
}
/////////////////////////////////////////////////////////
@@ -637,9 +587,9 @@ static void decompress_pvrtc(PVRTCBlock *p_comp_img, const int p_2bit, const int
}
static void _pvrtc_decompress(Image *p_img) {
- ERR_FAIL_COND(p_img->get_format() != Image::FORMAT_PVRTC2 && p_img->get_format() != Image::FORMAT_PVRTC2A && p_img->get_format() != Image::FORMAT_PVRTC4 && p_img->get_format() != Image::FORMAT_PVRTC4A);
+ ERR_FAIL_COND(p_img->get_format() != Image::FORMAT_PVRTC1_2 && p_img->get_format() != Image::FORMAT_PVRTC1_2A && p_img->get_format() != Image::FORMAT_PVRTC1_4 && p_img->get_format() != Image::FORMAT_PVRTC1_4A);
- bool _2bit = (p_img->get_format() == Image::FORMAT_PVRTC2 || p_img->get_format() == Image::FORMAT_PVRTC2A);
+ bool _2bit = (p_img->get_format() == Image::FORMAT_PVRTC1_2 || p_img->get_format() == Image::FORMAT_PVRTC1_2A);
Vector<uint8_t> data = p_img->get_data();
const uint8_t *r = data.ptr();
diff --git a/modules/pvr/texture_loader_pvr.h b/modules/pvr/texture_loader_pvr.h
index 07ef129689..da425c3237 100644
--- a/modules/pvr/texture_loader_pvr.h
+++ b/modules/pvr/texture_loader_pvr.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/regex/SCsub b/modules/regex/SCsub
index 2afacc1d9c..deb9db7591 100644
--- a/modules/regex/SCsub
+++ b/modules/regex/SCsub
@@ -5,6 +5,10 @@ Import("env_modules")
env_regex = env_modules.Clone()
+# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_pcre2"]:
thirdparty_dir = "#thirdparty/pcre2/src/"
thirdparty_flags = ["PCRE2_STATIC", "HAVE_CONFIG_H", "SUPPORT_UNICODE"]
@@ -52,11 +56,21 @@ if env["builtin_pcre2"]:
env_pcre2 = env_regex.Clone()
env_pcre2.disable_warnings()
env_pcre2["OBJSUFFIX"] = "_" + width + env_pcre2["OBJSUFFIX"]
- env_pcre2.add_source_files(env.modules_sources, thirdparty_sources)
env_pcre2.Append(CPPDEFINES=[("PCRE2_CODE_UNIT_WIDTH", width)])
+ env_pcre2.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
pcre2_builtin("16")
pcre2_builtin("32")
+
+# Godot source files
+
+module_obj = []
+
env_regex.Append(CPPDEFINES=[("PCRE2_CODE_UNIT_WIDTH", 0)])
-env_regex.add_source_files(env.modules_sources, "*.cpp")
+env_regex.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/regex/doc_classes/RegEx.xml b/modules/regex/doc_classes/RegEx.xml
index 312275842a..b21f5d1e7a 100644
--- a/modules/regex/doc_classes/RegEx.xml
+++ b/modules/regex/doc_classes/RegEx.xml
@@ -39,8 +39,8 @@
var regex = RegEx.new()
regex.compile("\\S+") # Negated whitespace character class.
var results = []
- for match in regex.search_all("One Two \n\tThree"):
- results.push_back(match.get_string())
+ for result in regex.search_all("One Two \n\tThree"):
+ results.push_back(result.get_string())
# The `results` array now contains "One", "Two", "Three".
[/codeblock]
[b]Note:[/b] Godot's regex implementation is based on the [url=https://www.pcre.org/]PCRE2[/url] library. You can view the full pattern reference [url=https://www.pcre.org/current/doc/html/pcre2pattern.html]here[/url].
diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp
index c10a276eae..fe8136ef35 100644
--- a/modules/regex/regex.cpp
+++ b/modules/regex/regex.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/regex/regex.h b/modules/regex/regex.h
index 52b49c783e..46505855d7 100644
--- a/modules/regex/regex.h
+++ b/modules/regex/regex.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,12 +31,12 @@
#ifndef REGEX_H
#define REGEX_H
-#include "core/array.h"
-#include "core/dictionary.h"
-#include "core/map.h"
-#include "core/reference.h"
-#include "core/ustring.h"
-#include "core/vector.h"
+#include "core/object/reference.h"
+#include "core/string/ustring.h"
+#include "core/templates/map.h"
+#include "core/templates/vector.h"
+#include "core/variant/array.h"
+#include "core/variant/dictionary.h"
class RegExMatch : public Reference {
GDCLASS(RegExMatch, Reference);
@@ -83,7 +83,6 @@ protected:
public:
void clear();
Error compile(const String &p_pattern);
- void _init(const String &p_pattern = "");
Ref<RegExMatch> search(const String &p_subject, int p_offset = 0, int p_end = -1) const;
Array search_all(const String &p_subject, int p_offset = 0, int p_end = -1) const;
diff --git a/modules/regex/register_types.cpp b/modules/regex/register_types.cpp
index 5d4aeba2d7..82f3eaf707 100644
--- a/modules/regex/register_types.cpp
+++ b/modules/regex/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,7 +29,7 @@
/*************************************************************************/
#include "register_types.h"
-#include "core/class_db.h"
+#include "core/object/class_db.h"
#include "regex.h"
void register_regex_types() {
diff --git a/modules/regex/register_types.h b/modules/regex/register_types.h
index cf377cdf5f..fe94cde954 100644
--- a/modules/regex/register_types.h
+++ b/modules/regex/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/regex/tests/test_regex.h b/modules/regex/tests/test_regex.h
new file mode 100644
index 0000000000..c2d303b435
--- /dev/null
+++ b/modules/regex/tests/test_regex.h
@@ -0,0 +1,164 @@
+/*************************************************************************/
+/* test_regex.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_REGEX_H
+#define TEST_REGEX_H
+
+#include "core/string/ustring.h"
+#include "modules/regex/regex.h"
+
+#include "tests/test_macros.h"
+
+namespace TestRegEx {
+
+TEST_CASE("[RegEx] Initialization") {
+ const String pattern = "(?<vowel>[aeiou])";
+
+ RegEx re1(pattern);
+ CHECK(re1.is_valid());
+ CHECK(re1.get_pattern() == pattern);
+ CHECK(re1.get_group_count() == 1);
+
+ Array names = re1.get_names();
+ CHECK(names.size() == 1);
+ CHECK(names[0] == "vowel");
+
+ RegEx re2;
+ CHECK(re2.is_valid() == false);
+ CHECK(re2.compile(pattern) == OK);
+ CHECK(re2.is_valid());
+
+ CHECK(re1.get_pattern() == re2.get_pattern());
+ CHECK(re1.get_group_count() == re2.get_group_count());
+
+ names = re2.get_names();
+ CHECK(names.size() == 1);
+ CHECK(names[0] == "vowel");
+}
+
+TEST_CASE("[RegEx] Clearing") {
+ RegEx re("Godot");
+ REQUIRE(re.is_valid());
+ re.clear();
+ CHECK(re.is_valid() == false);
+}
+
+TEST_CASE("[RegEx] Searching") {
+ const String s = "Searching";
+ const String vowels = "[aeiou]{1,2}";
+ const String numerics = "\\d";
+
+ RegEx re(vowels);
+ REQUIRE(re.is_valid());
+
+ Ref<RegExMatch> match = re.search(s);
+ REQUIRE(match != nullptr);
+ CHECK(match->get_string(0) == "ea");
+
+ match = re.search(s, 2, 4);
+ REQUIRE(match != nullptr);
+ CHECK(match->get_string(0) == "a");
+
+ const Array all_results = re.search_all(s);
+ CHECK(all_results.size() == 2);
+ match = all_results[0];
+ REQUIRE(match != nullptr);
+ CHECK(match->get_string(0) == "ea");
+ match = all_results[1];
+ REQUIRE(match != nullptr);
+ CHECK(match->get_string(0) == "i");
+
+ CHECK(re.compile(numerics) == OK);
+ CHECK(re.is_valid());
+ CHECK(re.search(s) == nullptr);
+ CHECK(re.search_all(s).size() == 0);
+}
+
+TEST_CASE("[RegEx] Substitution") {
+ String s = "Double all the vowels.";
+
+ RegEx re("(?<vowel>[aeiou])");
+ REQUIRE(re.is_valid());
+ CHECK(re.sub(s, "$0$vowel", true) == "Doouublee aall thee vooweels.");
+}
+
+TEST_CASE("[RegEx] Uninitialized use") {
+ const String s = "Godot";
+
+ RegEx re;
+ ERR_PRINT_OFF;
+ CHECK(re.search(s) == nullptr);
+ CHECK(re.search_all(s).size() == 0);
+ CHECK(re.sub(s, "") == "");
+ CHECK(re.get_group_count() == 0);
+ CHECK(re.get_names().size() == 0);
+ ERR_PRINT_ON
+}
+
+TEST_CASE("[RegEx] Empty Pattern") {
+ const String s = "Godot";
+
+ RegEx re;
+ CHECK(re.compile("") == OK);
+ CHECK(re.is_valid());
+}
+
+TEST_CASE("[RegEx] Invalid offset") {
+ const String s = "Godot";
+
+ RegEx re("o");
+ REQUIRE(re.is_valid());
+ CHECK(re.search(s, -1) == nullptr);
+ CHECK(re.search_all(s, -1).size() == 0);
+ CHECK(re.sub(s, "", true, -1) == "");
+}
+
+TEST_CASE("[RegEx] Invalid end position") {
+ const String s = "Godot";
+
+ RegEx re("o");
+ REQUIRE(re.is_valid());
+ Ref<RegExMatch> match = re.search(s, 0, 10);
+ CHECK(match->get_string(0) == "o");
+
+ const Array all_results = re.search_all(s, 0, 10);
+ CHECK(all_results.size() == 2);
+ match = all_results[0];
+ REQUIRE(match != nullptr);
+ CHECK(match->get_string(0) == String("o"));
+ match = all_results[1];
+ REQUIRE(match != nullptr);
+ CHECK(match->get_string(0) == String("o"));
+
+ CHECK(re.sub(s, "", true, 0, 10) == "Gdt");
+}
+} // namespace TestRegEx
+
+#endif // TEST_REGEX_H
diff --git a/modules/register_module_types.h b/modules/register_module_types.h
index acd9fc7c97..2cff8c54c4 100644
--- a/modules/register_module_types.h
+++ b/modules/register_module_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/squish/SCsub b/modules/squish/SCsub
index b31032403f..c9e29911d8 100644
--- a/modules/squish/SCsub
+++ b/modules/squish/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_squish = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_squish"]:
thirdparty_dir = "#thirdparty/squish/"
thirdparty_sources = [
@@ -26,7 +29,16 @@ if env["builtin_squish"]:
env_thirdparty = env_squish.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
# Godot source files
-env_squish.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_squish.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/squish/image_compress_squish.cpp b/modules/squish/image_compress_squish.cpp
index c510779317..cce08034df 100644
--- a/modules/squish/image_compress_squish.cpp
+++ b/modules/squish/image_compress_squish.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/squish/image_compress_squish.h b/modules/squish/image_compress_squish.h
index 19e6d57474..301d30fcf1 100644
--- a/modules/squish/image_compress_squish.h
+++ b/modules/squish/image_compress_squish.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,7 +31,7 @@
#ifndef IMAGE_COMPRESS_SQUISH_H
#define IMAGE_COMPRESS_SQUISH_H
-#include "core/image.h"
+#include "core/io/image.h"
void image_compress_squish(Image *p_image, float p_lossy_quality, Image::UsedChannels p_channels);
void image_decompress_squish(Image *p_image);
diff --git a/modules/squish/register_types.cpp b/modules/squish/register_types.cpp
index ad28aff058..451e9d8e93 100644
--- a/modules/squish/register_types.cpp
+++ b/modules/squish/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/squish/register_types.h b/modules/squish/register_types.h
index ab56c54d4a..0f87d64333 100644
--- a/modules/squish/register_types.h
+++ b/modules/squish/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/stb_vorbis/SCsub b/modules/stb_vorbis/SCsub
index 266c87c802..8fddb23dc8 100644
--- a/modules/stb_vorbis/SCsub
+++ b/modules/stb_vorbis/SCsub
@@ -6,11 +6,22 @@ Import("env_modules")
env_stb_vorbis = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
thirdparty_sources = ["#thirdparty/misc/stb_vorbis.c"]
env_thirdparty = env_stb_vorbis.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_stb_vorbis.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-# Godot's own source files
-env_stb_vorbis.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
index 346833ab9c..4b2be47e74 100644
--- a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
+++ b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -124,7 +124,10 @@ AudioStreamPlaybackOGGVorbis::~AudioStreamPlaybackOGGVorbis() {
Ref<AudioStreamPlayback> AudioStreamOGGVorbis::instance_playback() {
Ref<AudioStreamPlaybackOGGVorbis> ovs;
- ERR_FAIL_COND_V(data == nullptr, ovs);
+ ERR_FAIL_COND_V_MSG(data == nullptr, ovs,
+ "This AudioStreamOGGVorbis does not have an audio file assigned "
+ "to it. AudioStreamOGGVorbis should not be created from the "
+ "inspector or with `.new()`. Instead, load an audio file.");
ovs.instance();
ovs->vorbis_stream = Ref<AudioStreamOGGVorbis>(this);
diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.h b/modules/stb_vorbis/audio_stream_ogg_vorbis.h
index 5070f2a078..efc8fc6c27 100644
--- a/modules/stb_vorbis/audio_stream_ogg_vorbis.h
+++ b/modules/stb_vorbis/audio_stream_ogg_vorbis.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/stb_vorbis/register_types.cpp b/modules/stb_vorbis/register_types.cpp
index 6669d30278..6f7eb53bc8 100644
--- a/modules/stb_vorbis/register_types.cpp
+++ b/modules/stb_vorbis/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,7 +33,7 @@
#include "audio_stream_ogg_vorbis.h"
#ifdef TOOLS_ENABLED
-#include "core/engine.h"
+#include "core/config/engine.h"
#include "resource_importer_ogg_vorbis.h"
#endif
diff --git a/modules/stb_vorbis/register_types.h b/modules/stb_vorbis/register_types.h
index f5a1dd31bc..d36d87606c 100644
--- a/modules/stb_vorbis/register_types.h
+++ b/modules/stb_vorbis/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp b/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp
index d68d050d34..ec1c30783a 100644
--- a/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp
+++ b/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/stb_vorbis/resource_importer_ogg_vorbis.h b/modules/stb_vorbis/resource_importer_ogg_vorbis.h
index 47f0039328..60fe3381fb 100644
--- a/modules/stb_vorbis/resource_importer_ogg_vorbis.h
+++ b/modules/stb_vorbis/resource_importer_ogg_vorbis.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/svg/SCsub b/modules/svg/SCsub
index 0bfba34fe5..c7228a8d0b 100644
--- a/modules/svg/SCsub
+++ b/modules/svg/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_svg = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
thirdparty_dir = "#thirdparty/nanosvg/"
thirdparty_sources = [
"nanosvg.cc",
@@ -16,7 +19,15 @@ env_svg.Prepend(CPPPATH=[thirdparty_dir])
env_thirdparty = env_svg.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_svg.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-# Godot's own source files
-env_svg.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp
index 8ca4452ac9..6ce3e4b4b3 100644
--- a/modules/svg/image_loader_svg.cpp
+++ b/modules/svg/image_loader_svg.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/svg/image_loader_svg.h b/modules/svg/image_loader_svg.h
index ecaba5052b..e64175b172 100644
--- a/modules/svg/image_loader_svg.h
+++ b/modules/svg/image_loader_svg.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,7 +32,7 @@
#define IMAGE_LOADER_SVG_H
#include "core/io/image_loader.h"
-#include "core/ustring.h"
+#include "core/string/ustring.h"
/**
@author Daniel Ramirez <djrmuv@gmail.com>
diff --git a/modules/svg/register_types.cpp b/modules/svg/register_types.cpp
index 9fbefd2cfe..1a611184d2 100644
--- a/modules/svg/register_types.cpp
+++ b/modules/svg/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/svg/register_types.h b/modules/svg/register_types.h
index a3d914e0cb..106ac9056f 100644
--- a/modules/svg/register_types.h
+++ b/modules/svg/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub
new file mode 100644
index 0000000000..3589c8546d
--- /dev/null
+++ b/modules/text_server_adv/SCsub
@@ -0,0 +1,501 @@
+#!/usr/bin/env python
+
+Import("env")
+Import("env_modules")
+
+env_text_server_adv = env_modules.Clone()
+
+
+def make_icu_data(target, source, env):
+ import os
+
+ 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: http://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()
+ import os.path
+
+ 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")
+
+
+# Thirdparty source files
+
+thirdparty_obj = []
+
+if env["builtin_harfbuzz"]:
+ env_harfbuzz = env_modules.Clone()
+ env_harfbuzz.disable_warnings()
+
+ thirdparty_dir = "#thirdparty/harfbuzz/"
+ thirdparty_sources = [
+ "src/hb-aat-layout.cc",
+ "src/hb-aat-map.cc",
+ "src/hb-blob.cc",
+ "src/hb-buffer-serialize.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-ft.cc",
+ #'src/hb-gdi.cc',
+ #'src/hb-glib.cc',
+ #'src/hb-gobject-structs.cc',
+ "src/hb-graphite2.cc",
+ "src/hb-icu.cc",
+ "src/hb-map.cc",
+ "src/hb-number.cc",
+ "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-thai.cc",
+ "src/hb-ot-shape-complex-use-table.cc",
+ "src/hb-ot-shape-complex-use.cc",
+ "src/hb-ot-shape-complex-vowel-constraints.cc",
+ "src/hb-ot-shape-fallback.cc",
+ "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'
+ ]
+ thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
+
+ env_harfbuzz.Append(
+ CPPPATH=[
+ "#thirdparty/harfbuzz/src",
+ "#thirdparty/freetype/include",
+ "#thirdparty/graphite/include",
+ "#thirdparty/icu4c/common/",
+ ]
+ )
+
+ if env["platform"] == "android" or env["platform"] == "linuxbsd" or env["platform"] == "server":
+ env_harfbuzz.Append(CCFLAGS=["-DHAVE_PTHREAD"])
+
+ if env["platform"] == "javascript":
+ if env["threads_enabled"]:
+ env_harfbuzz.Append(CCFLAGS=["-DHAVE_PTHREAD"])
+ else:
+ env_harfbuzz.Append(CCFLAGS=["-DHB_NO_MT"])
+
+ env_harfbuzz.Append(
+ CCFLAGS=[
+ "-DHAVE_ICU_BUILTIN",
+ "-DHAVE_ICU",
+ "-DHAVE_FREETYPE",
+ "-DHAVE_GRAPHITE2",
+ "-DGRAPHITE2_STATIC",
+ ]
+ )
+
+ lib = env_harfbuzz.add_library("harfbuzz_builtin", thirdparty_sources)
+ thirdparty_obj += lib
+
+ # Needs to be appended to arrive after libscene in the linker call,
+ # but we don't want it to arrive *after* system libs, so manual hack
+ # LIBS contains first SCons Library objects ("SCons.Node.FS.File object")
+ # and then plain strings for system library. We insert between the two.
+ inserted = False
+ for idx, linklib in enumerate(env["LIBS"]):
+ if isinstance(linklib, (str, bytes)): # first system lib such as "X11", otherwise SCons lib object
+ env["LIBS"].insert(idx, lib)
+ inserted = True
+ break
+ if not inserted:
+ env.Append(LIBS=[lib])
+
+
+if env["builtin_graphite"]:
+ env_graphite = env_modules.Clone()
+ env_graphite.disable_warnings()
+
+ thirdparty_dir = "#thirdparty/graphite/"
+ thirdparty_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 not env_graphite.msvc:
+ thirdparty_sources += ["src/direct_machine.cpp"]
+ else:
+ thirdparty_sources += ["src/call_machine.cpp"]
+
+ thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
+
+ env_graphite.Append(CPPPATH=["#thirdparty/graphite/src", "#thirdparty/graphite/include"])
+ env_graphite.Append(
+ CCFLAGS=[
+ "-DGRAPHITE2_STATIC",
+ "-DGRAPHITE2_NTRACING",
+ "-DGRAPHITE2_NFILEFACE",
+ ]
+ )
+
+ lib = env_graphite.add_library("graphite_builtin", thirdparty_sources)
+ thirdparty_obj += lib
+
+ # Needs to be appended to arrive after libscene in the linker call,
+ # but we don't want it to arrive *after* system libs, so manual hack
+ # LIBS contains first SCons Library objects ("SCons.Node.FS.File object")
+ # and then plain strings for system library. We insert between the two.
+ inserted = False
+ for idx, linklib in enumerate(env["LIBS"]):
+ if isinstance(linklib, (str, bytes)): # first system lib such as "X11", otherwise SCons lib object
+ env["LIBS"].insert(idx, lib)
+ inserted = True
+ break
+ if not inserted:
+ env.Append(LIBS=[lib])
+
+
+if env["builtin_icu"]:
+ env_icu = env_modules.Clone()
+ env_icu.disable_warnings()
+
+ thirdparty_dir = "#thirdparty/icu4c/"
+ thirdparty_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/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/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_sources = [thirdparty_dir + file for file in thirdparty_sources]
+
+ icu_data_name = "icudt68l.dat"
+
+ 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)
+ 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",
+ "-DICU_DATA_NAME=" + icu_data_name,
+ ]
+ )
+ env_text_server_adv.Append(
+ CXXFLAGS=[
+ "-DICU_DATA_NAME=" + icu_data_name,
+ ]
+ )
+
+ lib = env_icu.add_library("icu_builtin", thirdparty_sources)
+ thirdparty_obj += lib
+
+ # Needs to be appended to arrive after libscene in the linker call,
+ # but we don't want it to arrive *after* system libs, so manual hack
+ # LIBS contains first SCons Library objects ("SCons.Node.FS.File object")
+ # and then plain strings for system library. We insert between the two.
+ inserted = False
+ for idx, linklib in enumerate(env["LIBS"]):
+ if isinstance(linklib, (str, bytes)): # first system lib such as "X11", otherwise SCons lib object
+ env["LIBS"].insert(idx, lib)
+ inserted = True
+ break
+ if not inserted:
+ env.Append(LIBS=[lib])
+
+
+# Godot source files
+
+module_obj = []
+
+if env_text_server_adv["tools"]:
+ env_text_server_adv.Append(CXXFLAGS=["-DICU_STATIC_DATA"])
+
+env_text_server_adv.Append(
+ CPPPATH=[
+ "#thirdparty/harfbuzz/src",
+ "#thirdparty/freetype/include",
+ "#thirdparty/graphite/include",
+ "#thirdparty/icu4c/common/",
+ ]
+)
+
+env_text_server_adv.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/text_server_adv/bitmap_font_adv.cpp b/modules/text_server_adv/bitmap_font_adv.cpp
new file mode 100644
index 0000000000..51cc242348
--- /dev/null
+++ b/modules/text_server_adv/bitmap_font_adv.cpp
@@ -0,0 +1,580 @@
+/*************************************************************************/
+/* bitmap_font_adv.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "bitmap_font_adv.h"
+
+/*************************************************************************/
+/* hb_bmp_font_t HarfBuzz Bitmap font interface */
+/*************************************************************************/
+
+struct hb_bmp_font_t {
+ BitmapFontDataAdvanced *face = nullptr;
+ float font_size = 0;
+ bool unref = false; /* Whether to destroy bm_face when done. */
+};
+
+static hb_bmp_font_t *_hb_bmp_font_create(BitmapFontDataAdvanced *p_face, float p_font_size, bool p_unref) {
+ hb_bmp_font_t *bm_font = reinterpret_cast<hb_bmp_font_t *>(calloc(1, sizeof(hb_bmp_font_t)));
+
+ if (!bm_font) {
+ return nullptr;
+ }
+
+ bm_font->face = p_face;
+ bm_font->font_size = p_font_size;
+ bm_font->unref = p_unref;
+
+ return bm_font;
+}
+
+static void _hb_bmp_font_destroy(void *data) {
+ hb_bmp_font_t *bm_font = reinterpret_cast<hb_bmp_font_t *>(data);
+ free(bm_font);
+}
+
+static hb_bool_t hb_bmp_get_nominal_glyph(hb_font_t *font, void *font_data, hb_codepoint_t unicode, hb_codepoint_t *glyph, void *user_data) {
+ const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(font_data);
+
+ if (!bm_font->face) {
+ return false;
+ }
+
+ if (!bm_font->face->has_char(unicode)) {
+ if (bm_font->face->has_char(0xF000u + unicode)) {
+ *glyph = 0xF000u + unicode;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ *glyph = unicode;
+ return true;
+}
+
+static hb_position_t hb_bmp_get_glyph_h_advance(hb_font_t *font, void *font_data, hb_codepoint_t glyph, void *user_data) {
+ const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(font_data);
+
+ if (!bm_font->face) {
+ return 0;
+ }
+
+ if (!bm_font->face->has_char(glyph)) {
+ return 0;
+ }
+
+ return bm_font->face->get_advance(glyph, bm_font->font_size).x * 64;
+}
+
+static hb_position_t hb_bmp_get_glyph_v_advance(hb_font_t *font, void *font_data, hb_codepoint_t glyph, void *user_data) {
+ const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(font_data);
+
+ if (!bm_font->face) {
+ return 0;
+ }
+
+ if (!bm_font->face->has_char(glyph)) {
+ return 0;
+ }
+
+ return -bm_font->face->get_advance(glyph, bm_font->font_size).y * 64;
+}
+
+static hb_position_t hb_bmp_get_glyph_h_kerning(hb_font_t *font, void *font_data, hb_codepoint_t left_glyph, hb_codepoint_t right_glyph, void *user_data) {
+ const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(font_data);
+
+ if (!bm_font->face) {
+ return 0;
+ }
+
+ if (!bm_font->face->has_char(left_glyph)) {
+ return 0;
+ }
+
+ if (!bm_font->face->has_char(right_glyph)) {
+ return 0;
+ }
+
+ return bm_font->face->get_kerning(left_glyph, right_glyph, bm_font->font_size).x * 64;
+}
+
+static hb_bool_t hb_bmp_get_glyph_v_origin(hb_font_t *font, void *font_data, hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y, void *user_data) {
+ const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(font_data);
+
+ if (!bm_font->face) {
+ return false;
+ }
+
+ if (!bm_font->face->has_char(glyph)) {
+ return false;
+ }
+
+ *x = bm_font->face->get_advance(glyph, bm_font->font_size).x * 32;
+ *y = bm_font->face->get_ascent(bm_font->font_size) * 64;
+
+ return true;
+}
+
+static hb_bool_t hb_bmp_get_glyph_extents(hb_font_t *font, void *font_data, hb_codepoint_t glyph, hb_glyph_extents_t *extents, void *user_data) {
+ const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(font_data);
+
+ if (!bm_font->face) {
+ return false;
+ }
+
+ if (!bm_font->face->has_char(glyph)) {
+ return false;
+ }
+
+ extents->x_bearing = 0;
+ extents->y_bearing = 0;
+ extents->width = bm_font->face->get_size(glyph, bm_font->font_size).x * 64;
+ extents->height = bm_font->face->get_size(glyph, bm_font->font_size).y * 64;
+
+ return true;
+}
+
+static hb_bool_t hb_bmp_get_font_h_extents(hb_font_t *font, void *font_data, hb_font_extents_t *metrics, void *user_data) {
+ const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(font_data);
+
+ if (!bm_font->face) {
+ return false;
+ }
+
+ metrics->ascender = bm_font->face->get_ascent(bm_font->font_size);
+ metrics->descender = bm_font->face->get_descent(bm_font->font_size);
+ metrics->line_gap = 0;
+
+ return true;
+}
+
+static hb_font_funcs_t *funcs = nullptr;
+void hb_bmp_create_font_funcs() {
+ funcs = hb_font_funcs_create();
+
+ hb_font_funcs_set_font_h_extents_func(funcs, hb_bmp_get_font_h_extents, nullptr, nullptr);
+ //hb_font_funcs_set_font_v_extents_func (funcs, hb_bmp_get_font_v_extents, nullptr, nullptr);
+ hb_font_funcs_set_nominal_glyph_func(funcs, hb_bmp_get_nominal_glyph, nullptr, nullptr);
+ //hb_font_funcs_set_variation_glyph_func (funcs, hb_bmp_get_variation_glyph, nullptr, nullptr);
+ hb_font_funcs_set_glyph_h_advance_func(funcs, hb_bmp_get_glyph_h_advance, nullptr, nullptr);
+ hb_font_funcs_set_glyph_v_advance_func(funcs, hb_bmp_get_glyph_v_advance, nullptr, nullptr);
+ //hb_font_funcs_set_glyph_h_origin_func(funcs, hb_bmp_get_glyph_h_origin, nullptr, nullptr);
+ hb_font_funcs_set_glyph_v_origin_func(funcs, hb_bmp_get_glyph_v_origin, nullptr, nullptr);
+ hb_font_funcs_set_glyph_h_kerning_func(funcs, hb_bmp_get_glyph_h_kerning, nullptr, nullptr);
+ //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_bmp_get_glyph_v_kerning, nullptr, nullptr);
+ hb_font_funcs_set_glyph_extents_func(funcs, hb_bmp_get_glyph_extents, nullptr, nullptr);
+ //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_bmp_get_glyph_contour_point, nullptr, nullptr);
+ //hb_font_funcs_set_glyph_name_func (funcs, hb_bmp_get_glyph_name, nullptr, nullptr);
+ //hb_font_funcs_set_glyph_from_name_func (funcs, hb_bmp_get_glyph_from_name, nullptr, nullptr);
+
+ hb_font_funcs_make_immutable(funcs);
+}
+
+void hb_bmp_free_font_funcs() {
+ if (funcs != nullptr) {
+ hb_font_funcs_destroy(funcs);
+ funcs = nullptr;
+ }
+}
+
+static void _hb_bmp_font_set_funcs(hb_font_t *p_font, BitmapFontDataAdvanced *p_face, int p_size, bool p_unref) {
+ hb_font_set_funcs(p_font, funcs, _hb_bmp_font_create(p_face, p_size, p_unref), _hb_bmp_font_destroy);
+}
+
+hb_font_t *hb_bmp_font_create(BitmapFontDataAdvanced *p_face, int p_size, hb_destroy_func_t p_destroy) {
+ hb_font_t *font;
+ hb_face_t *face = hb_face_create(nullptr, 0);
+
+ font = hb_font_create(face);
+ hb_face_destroy(face);
+ _hb_bmp_font_set_funcs(font, p_face, p_size, false);
+ return font;
+}
+
+/*************************************************************************/
+/* BitmapFontDataAdvanced */
+/*************************************************************************/
+
+Error BitmapFontDataAdvanced::load_from_file(const String &p_filename, int p_base_size) {
+ _THREAD_SAFE_METHOD_
+ //fnt format used by angelcode bmfont
+ //http://www.angelcode.com/products/bmfont/
+
+ FileAccess *f = FileAccess::open(p_filename, FileAccess::READ);
+ ERR_FAIL_COND_V_MSG(!f, ERR_FILE_NOT_FOUND, "Can't open font: " + p_filename + ".");
+
+ while (true) {
+ String line = f->get_line();
+
+ int delimiter = line.find(" ");
+ String type = line.substr(0, delimiter);
+ int pos = delimiter + 1;
+ Map<String, String> keys;
+
+ while (pos < line.size() && line[pos] == ' ') {
+ pos++;
+ }
+
+ while (pos < line.size()) {
+ int eq = line.find("=", pos);
+ if (eq == -1) {
+ break;
+ }
+ String key = line.substr(pos, eq - pos);
+ int end = -1;
+ String value;
+ if (line[eq + 1] == '"') {
+ end = line.find("\"", eq + 2);
+ if (end == -1) {
+ break;
+ }
+ value = line.substr(eq + 2, end - 1 - eq - 1);
+ pos = end + 1;
+ } else {
+ end = line.find(" ", eq + 1);
+ if (end == -1) {
+ end = line.size();
+ }
+ value = line.substr(eq + 1, end - eq);
+ pos = end;
+ }
+
+ while (pos < line.size() && line[pos] == ' ') {
+ pos++;
+ }
+
+ keys[key] = value;
+ }
+
+ if (type == "info") {
+ if (keys.has("size")) {
+ base_size = keys["size"].to_int();
+ }
+ } else if (type == "common") {
+ if (keys.has("lineHeight")) {
+ height = keys["lineHeight"].to_int();
+ }
+ if (keys.has("base")) {
+ ascent = keys["base"].to_int();
+ }
+ } else if (type == "page") {
+ if (keys.has("file")) {
+ String base_dir = p_filename.get_base_dir();
+ String file = base_dir.plus_file(keys["file"]);
+ if (RenderingServer::get_singleton() != nullptr) {
+ Ref<Texture2D> tex = ResourceLoader::load(file);
+ if (tex.is_null()) {
+ ERR_PRINT("Can't load font texture!");
+ } else {
+ ERR_FAIL_COND_V_MSG(tex.is_null(), ERR_FILE_CANT_READ, "It's not a reference to a valid Texture object.");
+ textures.push_back(tex);
+ }
+ }
+ }
+ } else if (type == "char") {
+ Character c;
+ char32_t idx = 0;
+ if (keys.has("id")) {
+ idx = keys["id"].to_int();
+ }
+ if (keys.has("x")) {
+ c.rect.position.x = keys["x"].to_int();
+ }
+ if (keys.has("y")) {
+ c.rect.position.y = keys["y"].to_int();
+ }
+ if (keys.has("width")) {
+ c.rect.size.width = keys["width"].to_int();
+ }
+ if (keys.has("height")) {
+ c.rect.size.height = keys["height"].to_int();
+ }
+ if (keys.has("xoffset")) {
+ c.align.x = keys["xoffset"].to_int();
+ }
+ if (keys.has("yoffset")) {
+ c.align.y = keys["yoffset"].to_int();
+ }
+ if (keys.has("page")) {
+ c.texture_idx = keys["page"].to_int();
+ }
+ if (keys.has("xadvance")) {
+ c.advance.x = keys["xadvance"].to_int();
+ }
+ if (keys.has("yadvance")) {
+ c.advance.x = keys["yadvance"].to_int();
+ }
+ if (c.advance.x < 0) {
+ c.advance.x = c.rect.size.width + 1;
+ }
+ if (c.advance.y < 0) {
+ c.advance.y = c.rect.size.height + 1;
+ }
+ char_map[idx] = c;
+ } else if (type == "kerning") {
+ KerningPairKey kpk;
+ float k = 0;
+ if (keys.has("first")) {
+ kpk.A = keys["first"].to_int();
+ }
+ if (keys.has("second")) {
+ kpk.B = keys["second"].to_int();
+ }
+ if (keys.has("amount")) {
+ k = keys["amount"].to_int();
+ }
+ kerning_map[kpk] = k;
+ }
+
+ if (f->eof_reached()) {
+ break;
+ }
+ }
+ if (base_size == 0) {
+ base_size = height;
+ }
+
+ valid = true;
+
+ memdelete(f);
+ return OK;
+}
+
+Error BitmapFontDataAdvanced::load_from_memory(const uint8_t *p_data, size_t p_size, int p_base_size) {
+ _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND_V(p_data == nullptr, ERR_CANT_CREATE);
+ ERR_FAIL_COND_V(p_size != sizeof(TextServer::BitmapFontData), ERR_CANT_CREATE);
+
+ const TextServer::BitmapFontData *data = (const TextServer::BitmapFontData *)p_data;
+
+ if (RenderingServer::get_singleton() != nullptr) {
+ Ref<Image> image = memnew(Image(data->img));
+ Ref<ImageTexture> tex = memnew(ImageTexture);
+ tex->create_from_image(image);
+
+ textures.push_back(tex);
+ }
+
+ for (int i = 0; i < data->charcount; i++) {
+ const int *c = &data->char_rects[i * 8];
+
+ Character chr;
+ chr.rect.position.x = c[1];
+ chr.rect.position.y = c[2];
+ chr.rect.size.x = c[3];
+ chr.rect.size.y = c[4];
+ if (c[7] < 0) {
+ chr.advance.x = c[3];
+ } else {
+ chr.advance.x = c[7];
+ }
+ chr.align = Vector2(c[6], c[5]);
+ char_map[c[0]] = chr;
+ }
+
+ for (int i = 0; i < data->kerning_count; i++) {
+ KerningPairKey kpk;
+ kpk.A = data->kernings[i * 3 + 0];
+ kpk.B = data->kernings[i * 3 + 1];
+
+ if (data->kernings[i * 3 + 2] == 0 && kerning_map.has(kpk)) {
+ kerning_map.erase(kpk);
+ } else {
+ kerning_map[kpk] = data->kernings[i * 3 + 2];
+ }
+ }
+
+ height = data->height;
+ ascent = data->ascent;
+
+ base_size = p_base_size;
+ if (base_size == 0) {
+ base_size = height;
+ }
+
+ valid = true;
+
+ return OK;
+}
+
+float BitmapFontDataAdvanced::get_height(int p_size) const {
+ ERR_FAIL_COND_V(!valid, 0.f);
+ return height * (float(p_size) / float(base_size));
+}
+
+float BitmapFontDataAdvanced::get_ascent(int p_size) const {
+ ERR_FAIL_COND_V(!valid, 0.f);
+ return ascent * (float(p_size) / float(base_size));
+}
+
+float BitmapFontDataAdvanced::get_descent(int p_size) const {
+ ERR_FAIL_COND_V(!valid, 0.f);
+ return (height - ascent) * (float(p_size) / float(base_size));
+}
+
+float BitmapFontDataAdvanced::get_underline_position(int p_size) const {
+ ERR_FAIL_COND_V(!valid, 0.f);
+ return 2 * (float(p_size) / float(base_size));
+}
+
+float BitmapFontDataAdvanced::get_underline_thickness(int p_size) const {
+ ERR_FAIL_COND_V(!valid, 0.f);
+ return 1 * (float(p_size) / float(base_size));
+}
+
+void BitmapFontDataAdvanced::set_distance_field_hint(bool p_distance_field) {
+ distance_field_hint = p_distance_field;
+}
+
+bool BitmapFontDataAdvanced::get_distance_field_hint() const {
+ return distance_field_hint;
+}
+
+float BitmapFontDataAdvanced::get_base_size() const {
+ return base_size;
+}
+
+hb_font_t *BitmapFontDataAdvanced::get_hb_handle(int p_size) {
+ _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND_V(!valid, nullptr);
+ if (!cache.has(p_size)) {
+ cache[p_size] = hb_bmp_font_create(this, p_size, nullptr);
+ }
+ return cache[p_size];
+}
+
+bool BitmapFontDataAdvanced::has_char(char32_t p_char) const {
+ _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND_V(!valid, false);
+ return char_map.has(p_char);
+}
+
+String BitmapFontDataAdvanced::get_supported_chars() const {
+ _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND_V(!valid, String());
+ String chars;
+ const uint32_t *k = nullptr;
+ while ((k = char_map.next(k))) {
+ chars += char32_t(*k);
+ }
+ return chars;
+}
+
+Vector2 BitmapFontDataAdvanced::get_advance(uint32_t p_char, int p_size) const {
+ _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND_V(!valid, Vector2());
+ const Character *c = char_map.getptr(p_char);
+ ERR_FAIL_COND_V(c == nullptr, Vector2());
+
+ return c->advance * (float(p_size) / float(base_size));
+}
+
+Vector2 BitmapFontDataAdvanced::get_align(uint32_t p_char, int p_size) const {
+ _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND_V(!valid, Vector2());
+ const Character *c = char_map.getptr(p_char);
+ ERR_FAIL_COND_V(c == nullptr, Vector2());
+
+ return c->align * (float(p_size) / float(base_size));
+}
+
+Vector2 BitmapFontDataAdvanced::get_size(uint32_t p_char, int p_size) const {
+ _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND_V(!valid, Vector2());
+ const Character *c = char_map.getptr(p_char);
+ ERR_FAIL_COND_V(c == nullptr, Vector2());
+
+ return c->rect.size * (float(p_size) / float(base_size));
+}
+
+Vector2 BitmapFontDataAdvanced::get_kerning(uint32_t p_char, uint32_t p_next, int p_size) const {
+ _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND_V(!valid, Vector2());
+ KerningPairKey kpk;
+ kpk.A = p_char;
+ kpk.B = p_next;
+
+ const Map<KerningPairKey, int>::Element *E = kerning_map.find(kpk);
+ if (E) {
+ return Vector2(-E->get() * (float(p_size) / float(base_size)), 0.f);
+ } else {
+ return Vector2();
+ }
+}
+
+Vector2 BitmapFontDataAdvanced::draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const {
+ _THREAD_SAFE_METHOD_
+ if (p_index == 0) {
+ return Vector2();
+ }
+ ERR_FAIL_COND_V(!valid, Vector2());
+ const Character *c = char_map.getptr(p_index);
+
+ ERR_FAIL_COND_V(c == nullptr, Vector2());
+ ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), Vector2());
+ if (c->texture_idx != -1) {
+ Point2i cpos = p_pos;
+ cpos += c->align * (float(p_size) / float(base_size));
+ cpos.y -= ascent * (float(p_size) / float(base_size));
+ if (RenderingServer::get_singleton() != nullptr) {
+ //if (distance_field_hint) { // Not implemented.
+ // RenderingServer::get_singleton()->canvas_item_set_distance_field_mode(p_canvas, true);
+ //}
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, c->rect.size * (float(p_size) / float(base_size))), textures[c->texture_idx]->get_rid(), c->rect, p_color, false, false);
+ //if (distance_field_hint) {
+ // RenderingServer::get_singleton()->canvas_item_set_distance_field_mode(p_canvas, false);
+ //}
+ }
+ }
+
+ return c->advance * (float(p_size) / float(base_size));
+}
+
+Vector2 BitmapFontDataAdvanced::draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const {
+ _THREAD_SAFE_METHOD_
+ if (p_index == 0) {
+ return Vector2();
+ }
+ ERR_FAIL_COND_V(!valid, Vector2());
+ const Character *c = char_map.getptr(p_index);
+
+ ERR_FAIL_COND_V(c == nullptr, Vector2());
+ ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), Vector2());
+
+ // Not supported, return advance for compatibility.
+
+ return c->advance * (float(p_size) / float(base_size));
+}
+
+BitmapFontDataAdvanced::~BitmapFontDataAdvanced() {
+ for (Map<float, hb_font_t *>::Element *E = cache.front(); E; E = E->next()) {
+ hb_font_destroy(E->get());
+ }
+}
diff --git a/modules/text_server_adv/bitmap_font_adv.h b/modules/text_server_adv/bitmap_font_adv.h
new file mode 100644
index 0000000000..c314f1b087
--- /dev/null
+++ b/modules/text_server_adv/bitmap_font_adv.h
@@ -0,0 +1,118 @@
+/*************************************************************************/
+/* bitmap_font_adv.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef BITMAP_FONT_ADV_H
+#define BITMAP_FONT_ADV_H
+
+#include "font_adv.h"
+
+void hb_bmp_create_font_funcs();
+void hb_bmp_free_font_funcs();
+
+struct BitmapFontDataAdvanced : public FontDataAdvanced {
+ _THREAD_SAFE_CLASS_
+
+private:
+ Vector<Ref<Texture2D>> textures;
+
+ struct Character {
+ int texture_idx = 0;
+ Rect2 rect;
+ Vector2 align;
+ Vector2 advance = Vector2(-1, -1);
+ };
+
+ struct KerningPairKey {
+ union {
+ struct {
+ uint32_t A, B;
+ };
+
+ uint64_t pair = 0;
+ };
+
+ _FORCE_INLINE_ bool operator<(const KerningPairKey &p_r) const { return pair < p_r.pair; }
+ };
+
+ HashMap<uint32_t, Character> char_map;
+ Map<KerningPairKey, int> kerning_map;
+ Map<float, hb_font_t *> cache;
+
+ float height = 0.f;
+ float ascent = 0.f;
+ float base_size = 0.f;
+ bool distance_field_hint = false;
+
+public:
+ virtual void clear_cache() override{};
+
+ virtual Error load_from_file(const String &p_filename, int p_base_size) override;
+ virtual Error load_from_memory(const uint8_t *p_data, size_t p_size, int p_base_size) override;
+
+ virtual float get_height(int p_size) const override;
+ virtual float get_ascent(int p_size) const override;
+ virtual float get_descent(int p_size) const override;
+
+ virtual float get_underline_position(int p_size) const override;
+ virtual float get_underline_thickness(int p_size) const override;
+
+ virtual void set_antialiased(bool p_antialiased) override{};
+ virtual bool get_antialiased() const override { return false; };
+
+ virtual void set_hinting(TextServer::Hinting p_hinting) override{};
+ virtual TextServer::Hinting get_hinting() const override { return TextServer::HINTING_NONE; };
+
+ virtual void set_distance_field_hint(bool p_distance_field) override;
+ virtual bool get_distance_field_hint() const override;
+
+ virtual void set_force_autohinter(bool p_enabeld) override{};
+ virtual bool get_force_autohinter() const override { return false; };
+
+ virtual bool has_outline() const override { return false; };
+ virtual float get_base_size() const override;
+
+ virtual hb_font_t *get_hb_handle(int p_size) override;
+
+ virtual bool has_char(char32_t p_char) const override;
+ virtual String get_supported_chars() const override;
+
+ virtual Vector2 get_advance(uint32_t p_char, int p_size) const override;
+ Vector2 get_align(uint32_t p_char, int p_size) const;
+ Vector2 get_size(uint32_t p_char, int p_size) const;
+ virtual Vector2 get_kerning(uint32_t p_char, uint32_t p_next, int p_size) const override;
+ virtual uint32_t get_glyph_index(char32_t p_char, char32_t p_variation_selector) const override { return (uint32_t)p_char; };
+
+ virtual Vector2 draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const override;
+ virtual Vector2 draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const override;
+
+ virtual ~BitmapFontDataAdvanced();
+};
+
+#endif // BITMAP_FONT_ADV_H
diff --git a/modules/text_server_adv/config.py b/modules/text_server_adv/config.py
new file mode 100644
index 0000000000..22482fce24
--- /dev/null
+++ b/modules/text_server_adv/config.py
@@ -0,0 +1,6 @@
+def can_build(env, platform):
+ return env.module_check_dependencies("text_server_adv", ["freetype"])
+
+
+def configure(env):
+ pass
diff --git a/modules/text_server_adv/dynamic_font_adv.cpp b/modules/text_server_adv/dynamic_font_adv.cpp
new file mode 100644
index 0000000000..5a16158c0f
--- /dev/null
+++ b/modules/text_server_adv/dynamic_font_adv.cpp
@@ -0,0 +1,1003 @@
+/*************************************************************************/
+/* dynamic_font_adv.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "dynamic_font_adv.h"
+
+#include FT_STROKER_H
+#include FT_ADVANCES_H
+#include FT_MULTIPLE_MASTERS_H
+
+DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size(int p_size, int p_outline_size) {
+ ERR_FAIL_COND_V(!valid, nullptr);
+ ERR_FAIL_COND_V(p_size < 0 || p_size > UINT16_MAX, nullptr);
+ ERR_FAIL_COND_V(p_outline_size < 0 || p_outline_size > UINT16_MAX, nullptr);
+
+ CacheID id;
+ id.size = p_size;
+ id.outline_size = p_outline_size;
+
+ DataAtSize *fds = nullptr;
+ Map<CacheID, DataAtSize *>::Element *E = nullptr;
+ if (p_outline_size != 0) {
+ E = size_cache_outline.find(id);
+ } else {
+ E = size_cache.find(id);
+ }
+
+ if (E != nullptr) {
+ fds = E->get();
+ } else {
+ if (font_mem == nullptr && font_path != String()) {
+ if (!font_mem_cache.is_empty()) {
+ font_mem = font_mem_cache.ptr();
+ font_mem_size = font_mem_cache.size();
+ } else {
+ FileAccess *f = FileAccess::open(font_path, FileAccess::READ);
+ if (!f) {
+ ERR_FAIL_V_MSG(nullptr, "Cannot open font file '" + font_path + "'.");
+ }
+
+ size_t len = f->get_len();
+ font_mem_cache.resize(len);
+ f->get_buffer(font_mem_cache.ptrw(), len);
+ font_mem = font_mem_cache.ptr();
+ font_mem_size = len;
+ f->close();
+ }
+ }
+
+ int error = 0;
+ fds = memnew(DataAtSize);
+ if (font_mem) {
+ memset(&fds->stream, 0, sizeof(FT_StreamRec));
+ fds->stream.base = (unsigned char *)font_mem;
+ fds->stream.size = font_mem_size;
+ fds->stream.pos = 0;
+
+ FT_Open_Args fargs;
+ memset(&fargs, 0, sizeof(FT_Open_Args));
+ fargs.memory_base = (unsigned char *)font_mem;
+ fargs.memory_size = font_mem_size;
+ fargs.flags = FT_OPEN_MEMORY;
+ fargs.stream = &fds->stream;
+ error = FT_Open_Face(library, &fargs, 0, &fds->face);
+
+ } else {
+ memdelete(fds);
+ ERR_FAIL_V_MSG(nullptr, "DynamicFont uninitialized.");
+ }
+
+ if (error == FT_Err_Unknown_File_Format) {
+ memdelete(fds);
+ ERR_FAIL_V_MSG(nullptr, "Unknown font format.");
+ } else if (error) {
+ memdelete(fds);
+ ERR_FAIL_V_MSG(nullptr, "Error loading font.");
+ }
+
+ oversampling = TS->font_get_oversampling();
+
+ if (FT_HAS_COLOR(fds->face) && fds->face->num_fixed_sizes > 0) {
+ int best_match = 0;
+ int diff = ABS(p_size - ((int64_t)fds->face->available_sizes[0].width));
+ fds->scale_color_font = float(p_size * oversampling) / fds->face->available_sizes[0].width;
+ for (int i = 1; i < fds->face->num_fixed_sizes; i++) {
+ int ndiff = ABS(p_size - ((int64_t)fds->face->available_sizes[i].width));
+ if (ndiff < diff) {
+ best_match = i;
+ diff = ndiff;
+ fds->scale_color_font = float(p_size * oversampling) / fds->face->available_sizes[i].width;
+ }
+ }
+ FT_Select_Size(fds->face, best_match);
+ } else {
+ FT_Set_Pixel_Sizes(fds->face, 0, p_size * oversampling);
+ }
+
+ fds->size = p_size;
+ fds->ascent = (fds->face->size->metrics.ascender / 64.0) / oversampling * fds->scale_color_font;
+ fds->descent = (-fds->face->size->metrics.descender / 64.0) / oversampling * fds->scale_color_font;
+ fds->underline_position = -fds->face->underline_position / 64.0 / oversampling * fds->scale_color_font;
+ fds->underline_thickness = fds->face->underline_thickness / 64.0 / oversampling * fds->scale_color_font;
+
+ //Load os2 TTF pable
+ fds->os2 = (TT_OS2 *)FT_Get_Sfnt_Table(fds->face, FT_SFNT_OS2);
+
+ fds->hb_handle = hb_ft_font_create(fds->face, nullptr);
+ if (fds->hb_handle == nullptr) {
+ memdelete(fds);
+ ERR_FAIL_V_MSG(nullptr, "Error loading HB font.");
+ }
+
+ if (p_outline_size != 0) {
+ size_cache_outline[id] = fds;
+ } else {
+ size_cache[id] = fds;
+ }
+
+ // Write variations.
+ if (fds->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
+ FT_MM_Var *amaster;
+
+ FT_Get_MM_Var(fds->face, &amaster);
+
+ Vector<hb_variation_t> hb_vars;
+ Vector<FT_Fixed> coords;
+ coords.resize(amaster->num_axis);
+
+ FT_Get_Var_Design_Coordinates(fds->face, coords.size(), coords.ptrw());
+
+ for (FT_UInt i = 0; i < amaster->num_axis; i++) {
+ hb_variation_t var;
+
+ // Reset to default.
+ var.tag = amaster->axis[i].tag;
+ var.value = (double)amaster->axis[i].def / 65536.f;
+ coords.write[i] = amaster->axis[i].def;
+
+ if (variations.has(var.tag)) {
+ var.value = variations[var.tag];
+ coords.write[i] = CLAMP(variations[var.tag] * 65536.f, amaster->axis[i].minimum, amaster->axis[i].maximum);
+ }
+
+ hb_vars.push_back(var);
+ }
+
+ FT_Set_Var_Design_Coordinates(fds->face, coords.size(), coords.ptrw());
+ hb_font_set_variations(fds->hb_handle, hb_vars.is_empty() ? nullptr : &hb_vars[0], hb_vars.size());
+
+ FT_Done_MM_Var(library, amaster);
+ }
+ }
+ return fds;
+}
+
+Dictionary DynamicFontDataAdvanced::get_variation_list() const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(base_size);
+ if (fds == nullptr) {
+ return Dictionary();
+ }
+
+ Dictionary ret;
+ // Read variations.
+ if (fds->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
+ FT_MM_Var *amaster;
+
+ FT_Get_MM_Var(fds->face, &amaster);
+
+ for (FT_UInt i = 0; i < amaster->num_axis; i++) {
+ ret[(int32_t)amaster->axis[i].tag] = Vector3i(amaster->axis[i].minimum / 65536, amaster->axis[i].maximum / 65536, amaster->axis[i].def / 65536);
+ }
+
+ FT_Done_MM_Var(library, amaster);
+ }
+ return ret;
+}
+
+void DynamicFontDataAdvanced::set_variation(const String &p_name, double p_value) {
+ _THREAD_SAFE_METHOD_
+ int32_t tag = TS->name_to_tag(p_name);
+ if (!variations.has(tag) || (variations[tag] != p_value)) {
+ variations[tag] = p_value;
+ clear_cache();
+ }
+}
+
+double DynamicFontDataAdvanced::get_variation(const String &p_name) const {
+ _THREAD_SAFE_METHOD_
+ int32_t tag = TS->name_to_tag(p_name);
+ if (!variations.has(tag)) {
+ return 0.f;
+ }
+ return variations[tag];
+}
+
+Dictionary DynamicFontDataAdvanced::get_feature_list() const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(base_size);
+ if (fds == nullptr) {
+ return Dictionary();
+ }
+
+ Dictionary out;
+ // Read feature flags.
+ unsigned int count = hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, NULL, NULL);
+ if (count != 0) {
+ hb_tag_t *feature_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));
+ hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, &count, feature_tags);
+ for (unsigned int i = 0; i < count; i++) {
+ out[feature_tags[i]] = 1;
+ }
+ memfree(feature_tags);
+ }
+ count = hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, NULL, NULL);
+ if (count != 0) {
+ hb_tag_t *feature_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));
+ hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, &count, feature_tags);
+ for (unsigned int i = 0; i < count; i++) {
+ out[feature_tags[i]] = 1;
+ }
+ memfree(feature_tags);
+ }
+
+ return out;
+}
+
+DynamicFontDataAdvanced::TexturePosition DynamicFontDataAdvanced::find_texture_pos_for_glyph(DynamicFontDataAdvanced::DataAtSize *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height) {
+ TexturePosition ret;
+ ret.index = -1;
+
+ int mw = p_width;
+ int mh = p_height;
+
+ for (int i = 0; i < p_data->textures.size(); i++) {
+ const CharTexture &ct = p_data->textures[i];
+
+ if (RenderingServer::get_singleton() != nullptr) {
+ if (ct.texture->get_format() != p_image_format) {
+ continue;
+ }
+ }
+
+ if (mw > ct.texture_size || mh > ct.texture_size) { //too big for this texture
+ continue;
+ }
+
+ ret.y = 0x7FFFFFFF;
+ ret.x = 0;
+
+ for (int j = 0; j < ct.texture_size - mw; j++) {
+ int max_y = 0;
+
+ for (int k = j; k < j + mw; k++) {
+ int y = ct.offsets[k];
+ if (y > max_y) {
+ max_y = y;
+ }
+ }
+
+ if (max_y < ret.y) {
+ ret.y = max_y;
+ ret.x = j;
+ }
+ }
+
+ if (ret.y == 0x7FFFFFFF || ret.y + mh > ct.texture_size) {
+ continue; //fail, could not fit it here
+ }
+
+ ret.index = i;
+ break;
+ }
+
+ if (ret.index == -1) {
+ //could not find texture to fit, create one
+ ret.x = 0;
+ ret.y = 0;
+
+ int texsize = MAX(p_data->size * oversampling * 8, 256);
+ if (mw > texsize) {
+ texsize = mw; //special case, adapt to it?
+ }
+ if (mh > texsize) {
+ texsize = mh; //special case, adapt to it?
+ }
+
+ texsize = next_power_of_2(texsize);
+
+ texsize = MIN(texsize, 4096);
+
+ CharTexture tex;
+ tex.texture_size = texsize;
+ tex.imgdata.resize(texsize * texsize * p_color_size); //grayscale alpha
+
+ {
+ //zero texture
+ uint8_t *w = tex.imgdata.ptrw();
+ ERR_FAIL_COND_V(texsize * texsize * p_color_size > tex.imgdata.size(), ret);
+ // Initialize the texture to all-white pixels to prevent artifacts when the
+ // font is displayed at a non-default scale with filtering enabled.
+ if (p_color_size == 2) {
+ for (int i = 0; i < texsize * texsize * p_color_size; i += 2) { // FORMAT_LA8
+ w[i + 0] = 255;
+ w[i + 1] = 0;
+ }
+ } else if (p_color_size == 4) {
+ for (int i = 0; i < texsize * texsize * p_color_size; i += 4) { // FORMAT_RGBA8
+ w[i + 0] = 255;
+ w[i + 1] = 255;
+ w[i + 2] = 255;
+ w[i + 3] = 0;
+ }
+ } else {
+ ERR_FAIL_V(ret);
+ }
+ }
+ tex.offsets.resize(texsize);
+ for (int i = 0; i < texsize; i++) { //zero offsets
+ tex.offsets.write[i] = 0;
+ }
+
+ p_data->textures.push_back(tex);
+ ret.index = p_data->textures.size() - 1;
+ }
+
+ return ret;
+}
+
+DynamicFontDataAdvanced::Character DynamicFontDataAdvanced::Character::not_found() {
+ Character ch;
+ return ch;
+}
+
+DynamicFontDataAdvanced::Character DynamicFontDataAdvanced::bitmap_to_character(DynamicFontDataAdvanced::DataAtSize *p_data, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance) {
+ int w = bitmap.width;
+ int h = bitmap.rows;
+
+ int mw = w + rect_margin * 2;
+ int mh = h + rect_margin * 2;
+
+ ERR_FAIL_COND_V(mw > 4096, Character::not_found());
+ ERR_FAIL_COND_V(mh > 4096, Character::not_found());
+
+ 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;
+
+ TexturePosition tex_pos = find_texture_pos_for_glyph(p_data, color_size, require_format, mw, mh);
+ ERR_FAIL_COND_V(tex_pos.index < 0, Character::not_found());
+
+ //fit character in char texture
+
+ CharTexture &tex = p_data->textures.write[tex_pos.index];
+
+ {
+ uint8_t *wr = tex.imgdata.ptrw();
+
+ for (int i = 0; i < h; i++) {
+ for (int j = 0; j < w; j++) {
+ int ofs = ((i + tex_pos.y + rect_margin) * tex.texture_size + j + tex_pos.x + rect_margin) * color_size;
+ ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), Character::not_found());
+ switch (bitmap.pixel_mode) {
+ case FT_PIXEL_MODE_MONO: {
+ int byte = i * bitmap.pitch + (j >> 3);
+ int bit = 1 << (7 - (j % 8));
+ wr[ofs + 0] = 255; //grayscale as 1
+ wr[ofs + 1] = (bitmap.buffer[byte] & bit) ? 255 : 0;
+ } break;
+ case FT_PIXEL_MODE_GRAY:
+ wr[ofs + 0] = 255; //grayscale as 1
+ wr[ofs + 1] = bitmap.buffer[i * bitmap.pitch + j];
+ break;
+ case FT_PIXEL_MODE_BGRA: {
+ int ofs_color = i * bitmap.pitch + (j << 2);
+ wr[ofs + 2] = bitmap.buffer[ofs_color + 0];
+ wr[ofs + 1] = bitmap.buffer[ofs_color + 1];
+ wr[ofs + 0] = bitmap.buffer[ofs_color + 2];
+ wr[ofs + 3] = bitmap.buffer[ofs_color + 3];
+ } break;
+ // TODO: FT_PIXEL_MODE_LCD
+ default:
+ ERR_FAIL_V_MSG(Character::not_found(), "Font uses unsupported pixel format: " + itos(bitmap.pixel_mode) + ".");
+ break;
+ }
+ }
+ }
+ }
+
+ //blit to image and texture
+ {
+ if (RenderingServer::get_singleton() != nullptr) {
+ Ref<Image> img = memnew(Image(tex.texture_size, tex.texture_size, 0, require_format, tex.imgdata));
+
+ if (tex.texture.is_null()) {
+ tex.texture.instance();
+ tex.texture->create_from_image(img);
+ } else {
+ tex.texture->update(img); //update
+ }
+ }
+ }
+
+ // update height array
+ for (int k = tex_pos.x; k < tex_pos.x + mw; k++) {
+ tex.offsets.write[k] = tex_pos.y + mh;
+ }
+
+ Character chr;
+ chr.align = (Vector2(xofs, -yofs) * p_data->scale_color_font / oversampling).round();
+ chr.advance = (advance * p_data->scale_color_font / oversampling).round();
+ chr.texture_idx = tex_pos.index;
+ chr.found = true;
+
+ chr.rect_uv = Rect2(tex_pos.x + rect_margin, tex_pos.y + rect_margin, w, h);
+ chr.rect = chr.rect_uv;
+ chr.rect.position /= oversampling;
+ chr.rect.size *= (p_data->scale_color_font / oversampling);
+ return chr;
+}
+
+void DynamicFontDataAdvanced::update_glyph(int p_size, uint32_t p_index) {
+ DataAtSize *fds = get_data_for_size(p_size, false);
+ ERR_FAIL_COND(fds == nullptr);
+
+ if (fds->glyph_map.has(p_index)) {
+ return;
+ }
+
+ Character character = Character::not_found();
+ FT_GlyphSlot slot = fds->face->glyph;
+
+ if (p_index == 0) {
+ fds->glyph_map[p_index] = character;
+ return;
+ }
+
+ int ft_hinting;
+ switch (hinting) {
+ case TextServer::HINTING_NONE:
+ ft_hinting = FT_LOAD_NO_HINTING;
+ break;
+ case TextServer::HINTING_LIGHT:
+ ft_hinting = FT_LOAD_TARGET_LIGHT;
+ break;
+ default:
+ ft_hinting = FT_LOAD_TARGET_NORMAL;
+ break;
+ }
+
+ FT_Fixed v, h;
+ FT_Get_Advance(fds->face, p_index, FT_HAS_COLOR(fds->face) ? FT_LOAD_COLOR : FT_LOAD_DEFAULT | (force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0) | ft_hinting, &h);
+ FT_Get_Advance(fds->face, p_index, FT_HAS_COLOR(fds->face) ? FT_LOAD_COLOR : FT_LOAD_DEFAULT | (force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0) | ft_hinting | FT_LOAD_VERTICAL_LAYOUT, &v);
+
+ int error = FT_Load_Glyph(fds->face, p_index, FT_HAS_COLOR(fds->face) ? FT_LOAD_COLOR : FT_LOAD_DEFAULT | (force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0) | ft_hinting);
+ if (error) {
+ fds->glyph_map[p_index] = character;
+ return;
+ }
+
+ error = FT_Render_Glyph(fds->face->glyph, antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
+ if (!error) {
+ character = bitmap_to_character(fds, slot->bitmap, slot->bitmap_top, slot->bitmap_left, Vector2((h + (1 << 9)) >> 10, (v + (1 << 9)) >> 10) / 64.0);
+ }
+
+ fds->glyph_map[p_index] = character;
+}
+
+void DynamicFontDataAdvanced::update_glyph_outline(int p_size, int p_outline_size, uint32_t p_index) {
+ DataAtSize *fds = get_data_for_size(p_size, p_outline_size);
+ ERR_FAIL_COND(fds == nullptr);
+
+ if (fds->glyph_map.has(p_index)) {
+ return;
+ }
+
+ Character character = Character::not_found();
+ if (p_index == 0) {
+ fds->glyph_map[p_index] = character;
+ return;
+ }
+
+ int error = FT_Load_Glyph(fds->face, p_index, FT_LOAD_NO_BITMAP | (force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
+ if (error) {
+ fds->glyph_map[p_index] = character;
+ return;
+ }
+
+ FT_Stroker stroker;
+ if (FT_Stroker_New(library, &stroker) != 0) {
+ fds->glyph_map[p_index] = character;
+ return;
+ }
+
+ FT_Stroker_Set(stroker, (int)(p_outline_size * oversampling * 64.0), FT_STROKER_LINECAP_BUTT, FT_STROKER_LINEJOIN_ROUND, 0);
+ FT_Glyph glyph;
+ FT_BitmapGlyph glyph_bitmap;
+
+ if (FT_Get_Glyph(fds->face->glyph, &glyph) != 0) {
+ goto cleanup_stroker;
+ }
+ if (FT_Glyph_Stroke(&glyph, stroker, 1) != 0) {
+ goto cleanup_glyph;
+ }
+ if (FT_Glyph_To_Bitmap(&glyph, antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO, nullptr, 1) != 0) {
+ goto cleanup_glyph;
+ }
+
+ glyph_bitmap = (FT_BitmapGlyph)glyph;
+ character = bitmap_to_character(fds, glyph_bitmap->bitmap, glyph_bitmap->top, glyph_bitmap->left, Vector2());
+
+cleanup_glyph:
+ FT_Done_Glyph(glyph);
+cleanup_stroker:
+ FT_Stroker_Done(stroker);
+
+ fds->glyph_map[p_index] = character;
+}
+
+void DynamicFontDataAdvanced::clear_cache() {
+ _THREAD_SAFE_METHOD_
+ for (Map<CacheID, DataAtSize *>::Element *E = size_cache.front(); E; E = E->next()) {
+ memdelete(E->get());
+ }
+ size_cache.clear();
+ for (Map<CacheID, DataAtSize *>::Element *E = size_cache_outline.front(); E; E = E->next()) {
+ memdelete(E->get());
+ }
+ size_cache_outline.clear();
+}
+
+Error DynamicFontDataAdvanced::load_from_file(const String &p_filename, int p_base_size) {
+ _THREAD_SAFE_METHOD_
+ if (library == nullptr) {
+ int error = FT_Init_FreeType(&library);
+ ERR_FAIL_COND_V_MSG(error != 0, ERR_CANT_CREATE, "Error initializing FreeType.");
+ }
+ clear_cache();
+
+ font_path = p_filename;
+ base_size = p_base_size;
+
+ valid = true;
+ DataAtSize *fds = get_data_for_size(base_size); // load base size.
+ if (fds == nullptr) {
+ valid = false;
+ ERR_FAIL_V(ERR_CANT_CREATE);
+ }
+
+ return OK;
+}
+
+Error DynamicFontDataAdvanced::load_from_memory(const uint8_t *p_data, size_t p_size, int p_base_size) {
+ _THREAD_SAFE_METHOD_
+ if (library == nullptr) {
+ int error = FT_Init_FreeType(&library);
+ ERR_FAIL_COND_V_MSG(error != 0, ERR_CANT_CREATE, "Error initializing FreeType.");
+ }
+ clear_cache();
+
+ font_mem = p_data;
+ font_mem_size = p_size;
+ base_size = p_base_size;
+
+ valid = true;
+ DataAtSize *fds = get_data_for_size(base_size); // load base size.
+ if (fds == nullptr) {
+ valid = false;
+ ERR_FAIL_V(ERR_CANT_CREATE);
+ }
+
+ return OK;
+}
+
+float DynamicFontDataAdvanced::get_height(int p_size) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(p_size);
+ ERR_FAIL_COND_V(fds == nullptr, 0.f);
+ return fds->ascent + fds->descent;
+}
+
+float DynamicFontDataAdvanced::get_ascent(int p_size) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(p_size);
+ ERR_FAIL_COND_V(fds == nullptr, 0.f);
+ return fds->ascent;
+}
+
+float DynamicFontDataAdvanced::get_descent(int p_size) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(p_size);
+ ERR_FAIL_COND_V(fds == nullptr, 0.f);
+ return fds->descent;
+}
+
+float DynamicFontDataAdvanced::get_underline_position(int p_size) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(p_size);
+ ERR_FAIL_COND_V(fds == nullptr, 0.f);
+ return fds->underline_position;
+}
+
+float DynamicFontDataAdvanced::get_underline_thickness(int p_size) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(p_size);
+ ERR_FAIL_COND_V(fds == nullptr, 0.f);
+ return fds->underline_thickness;
+}
+
+bool DynamicFontDataAdvanced::is_script_supported(uint32_t p_script) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(base_size);
+ ERR_FAIL_COND_V(fds == nullptr, false);
+
+ unsigned int count = hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, NULL, NULL);
+ if (count != 0) {
+ hb_tag_t *script_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));
+ hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, &count, script_tags);
+ for (unsigned int i = 0; i < count; i++) {
+ if (p_script == script_tags[i]) {
+ memfree(script_tags);
+ return true;
+ }
+ }
+ memfree(script_tags);
+ }
+ count = hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, NULL, NULL);
+ if (count != 0) {
+ hb_tag_t *script_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));
+ hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, &count, script_tags);
+ for (unsigned int i = 0; i < count; i++) {
+ if (p_script == script_tags[i]) {
+ memfree(script_tags);
+ return true;
+ }
+ }
+ memfree(script_tags);
+ }
+
+ if (!fds->os2) {
+ return false;
+ }
+
+ switch (p_script) {
+ case HB_SCRIPT_COMMON:
+ return (fds->os2->ulUnicodeRange1 & 1L << 4) || (fds->os2->ulUnicodeRange1 & 1L << 5) || (fds->os2->ulUnicodeRange1 & 1L << 6) || (fds->os2->ulUnicodeRange1 & 1L << 31) || (fds->os2->ulUnicodeRange2 & 1L << 0) || (fds->os2->ulUnicodeRange2 & 1L << 1) || (fds->os2->ulUnicodeRange2 & 1L << 2) || (fds->os2->ulUnicodeRange2 & 1L << 3) || (fds->os2->ulUnicodeRange2 & 1L << 4) || (fds->os2->ulUnicodeRange2 & 1L << 5) || (fds->os2->ulUnicodeRange2 & 1L << 6) || (fds->os2->ulUnicodeRange2 & 1L << 7) || (fds->os2->ulUnicodeRange2 & 1L << 8) || (fds->os2->ulUnicodeRange2 & 1L << 9) || (fds->os2->ulUnicodeRange2 & 1L << 10) || (fds->os2->ulUnicodeRange2 & 1L << 11) || (fds->os2->ulUnicodeRange2 & 1L << 12) || (fds->os2->ulUnicodeRange2 & 1L << 13) || (fds->os2->ulUnicodeRange2 & 1L << 14) || (fds->os2->ulUnicodeRange2 & 1L << 15) || (fds->os2->ulUnicodeRange2 & 1L << 30) || (fds->os2->ulUnicodeRange3 & 1L << 0) || (fds->os2->ulUnicodeRange3 & 1L << 1) || (fds->os2->ulUnicodeRange3 & 1L << 2) || (fds->os2->ulUnicodeRange3 & 1L << 4) || (fds->os2->ulUnicodeRange3 & 1L << 5) || (fds->os2->ulUnicodeRange3 & 1L << 18) || (fds->os2->ulUnicodeRange3 & 1L << 24) || (fds->os2->ulUnicodeRange3 & 1L << 25) || (fds->os2->ulUnicodeRange3 & 1L << 26) || (fds->os2->ulUnicodeRange3 & 1L << 27) || (fds->os2->ulUnicodeRange3 & 1L << 28) || (fds->os2->ulUnicodeRange4 & 1L << 3) || (fds->os2->ulUnicodeRange4 & 1L << 6) || (fds->os2->ulUnicodeRange4 & 1L << 15) || (fds->os2->ulUnicodeRange4 & 1L << 23) || (fds->os2->ulUnicodeRange4 & 1L << 24) || (fds->os2->ulUnicodeRange4 & 1L << 26);
+ case HB_SCRIPT_LATIN:
+ return (fds->os2->ulUnicodeRange1 & 1L << 0) || (fds->os2->ulUnicodeRange1 & 1L << 1) || (fds->os2->ulUnicodeRange1 & 1L << 2) || (fds->os2->ulUnicodeRange1 & 1L << 3) || (fds->os2->ulUnicodeRange1 & 1L << 29);
+ case HB_SCRIPT_GREEK:
+ return (fds->os2->ulUnicodeRange1 & 1L << 7) || (fds->os2->ulUnicodeRange1 & 1L << 30);
+ case HB_SCRIPT_COPTIC:
+ return (fds->os2->ulUnicodeRange1 & 1L << 8);
+ case HB_SCRIPT_CYRILLIC:
+ return (fds->os2->ulUnicodeRange1 & 1L << 9);
+ case HB_SCRIPT_ARMENIAN:
+ return (fds->os2->ulUnicodeRange1 & 1L << 10);
+ case HB_SCRIPT_HEBREW:
+ return (fds->os2->ulUnicodeRange1 & 1L << 11);
+ case HB_SCRIPT_VAI:
+ return (fds->os2->ulUnicodeRange1 & 1L << 12);
+ case HB_SCRIPT_ARABIC:
+ return (fds->os2->ulUnicodeRange1 & 1L << 13) || (fds->os2->ulUnicodeRange2 & 1L << 31) || (fds->os2->ulUnicodeRange3 & 1L << 3);
+ case HB_SCRIPT_NKO:
+ return (fds->os2->ulUnicodeRange1 & 1L << 14);
+ case HB_SCRIPT_DEVANAGARI:
+ return (fds->os2->ulUnicodeRange1 & 1L << 15);
+ case HB_SCRIPT_BENGALI:
+ return (fds->os2->ulUnicodeRange1 & 1L << 16);
+ case HB_SCRIPT_GURMUKHI:
+ return (fds->os2->ulUnicodeRange1 & 1L << 17);
+ case HB_SCRIPT_GUJARATI:
+ return (fds->os2->ulUnicodeRange1 & 1L << 18);
+ case HB_SCRIPT_ORIYA:
+ return (fds->os2->ulUnicodeRange1 & 1L << 19);
+ case HB_SCRIPT_TAMIL:
+ return (fds->os2->ulUnicodeRange1 & 1L << 20);
+ case HB_SCRIPT_TELUGU:
+ return (fds->os2->ulUnicodeRange1 & 1L << 21);
+ case HB_SCRIPT_KANNADA:
+ return (fds->os2->ulUnicodeRange1 & 1L << 22);
+ case HB_SCRIPT_MALAYALAM:
+ return (fds->os2->ulUnicodeRange1 & 1L << 23);
+ case HB_SCRIPT_THAI:
+ return (fds->os2->ulUnicodeRange1 & 1L << 24);
+ case HB_SCRIPT_LAO:
+ return (fds->os2->ulUnicodeRange1 & 1L << 25);
+ case HB_SCRIPT_GEORGIAN:
+ return (fds->os2->ulUnicodeRange1 & 1L << 26);
+ case HB_SCRIPT_BALINESE:
+ return (fds->os2->ulUnicodeRange1 & 1L << 27);
+ case HB_SCRIPT_HANGUL:
+ return (fds->os2->ulUnicodeRange1 & 1L << 28) || (fds->os2->ulUnicodeRange2 & 1L << 20) || (fds->os2->ulUnicodeRange2 & 1L << 24);
+ case HB_SCRIPT_HAN:
+ return (fds->os2->ulUnicodeRange2 & 1L << 21) || (fds->os2->ulUnicodeRange2 & 1L << 22) || (fds->os2->ulUnicodeRange2 & 1L << 23) || (fds->os2->ulUnicodeRange2 & 1L << 26) || (fds->os2->ulUnicodeRange2 & 1L << 27) || (fds->os2->ulUnicodeRange2 & 1L << 29);
+ case HB_SCRIPT_HIRAGANA:
+ return (fds->os2->ulUnicodeRange2 & 1L << 17);
+ case HB_SCRIPT_KATAKANA:
+ return (fds->os2->ulUnicodeRange2 & 1L << 18);
+ case HB_SCRIPT_BOPOMOFO:
+ return (fds->os2->ulUnicodeRange2 & 1L << 19);
+ case HB_SCRIPT_TIBETAN:
+ return (fds->os2->ulUnicodeRange3 & 1L << 6);
+ case HB_SCRIPT_SYRIAC:
+ return (fds->os2->ulUnicodeRange3 & 1L << 7);
+ case HB_SCRIPT_THAANA:
+ return (fds->os2->ulUnicodeRange3 & 1L << 8);
+ case HB_SCRIPT_SINHALA:
+ return (fds->os2->ulUnicodeRange3 & 1L << 9);
+ case HB_SCRIPT_MYANMAR:
+ return (fds->os2->ulUnicodeRange3 & 1L << 10);
+ case HB_SCRIPT_ETHIOPIC:
+ return (fds->os2->ulUnicodeRange3 & 1L << 11);
+ case HB_SCRIPT_CHEROKEE:
+ return (fds->os2->ulUnicodeRange3 & 1L << 12);
+ case HB_SCRIPT_CANADIAN_SYLLABICS:
+ return (fds->os2->ulUnicodeRange3 & 1L << 13);
+ case HB_SCRIPT_OGHAM:
+ return (fds->os2->ulUnicodeRange3 & 1L << 14);
+ case HB_SCRIPT_RUNIC:
+ return (fds->os2->ulUnicodeRange3 & 1L << 15);
+ case HB_SCRIPT_KHMER:
+ return (fds->os2->ulUnicodeRange3 & 1L << 16);
+ case HB_SCRIPT_MONGOLIAN:
+ return (fds->os2->ulUnicodeRange3 & 1L << 17);
+ case HB_SCRIPT_YI:
+ return (fds->os2->ulUnicodeRange3 & 1L << 19);
+ case HB_SCRIPT_HANUNOO:
+ case HB_SCRIPT_TAGBANWA:
+ case HB_SCRIPT_BUHID:
+ case HB_SCRIPT_TAGALOG:
+ return (fds->os2->ulUnicodeRange3 & 1L << 20);
+ case HB_SCRIPT_OLD_ITALIC:
+ return (fds->os2->ulUnicodeRange3 & 1L << 21);
+ case HB_SCRIPT_GOTHIC:
+ return (fds->os2->ulUnicodeRange3 & 1L << 22);
+ case HB_SCRIPT_DESERET:
+ return (fds->os2->ulUnicodeRange3 & 1L << 23);
+ case HB_SCRIPT_LIMBU:
+ return (fds->os2->ulUnicodeRange3 & 1L << 29);
+ case HB_SCRIPT_TAI_LE:
+ return (fds->os2->ulUnicodeRange3 & 1L << 30);
+ case HB_SCRIPT_NEW_TAI_LUE:
+ return (fds->os2->ulUnicodeRange3 & 1L << 31);
+ case HB_SCRIPT_BUGINESE:
+ return (fds->os2->ulUnicodeRange4 & 1L << 0);
+ case HB_SCRIPT_GLAGOLITIC:
+ return (fds->os2->ulUnicodeRange4 & 1L << 1);
+ case HB_SCRIPT_TIFINAGH:
+ return (fds->os2->ulUnicodeRange4 & 1L << 2);
+ case HB_SCRIPT_SYLOTI_NAGRI:
+ return (fds->os2->ulUnicodeRange4 & 1L << 4);
+ case HB_SCRIPT_LINEAR_B:
+ return (fds->os2->ulUnicodeRange4 & 1L << 5);
+ case HB_SCRIPT_UGARITIC:
+ return (fds->os2->ulUnicodeRange4 & 1L << 7);
+ case HB_SCRIPT_OLD_PERSIAN:
+ return (fds->os2->ulUnicodeRange4 & 1L << 8);
+ case HB_SCRIPT_SHAVIAN:
+ return (fds->os2->ulUnicodeRange4 & 1L << 9);
+ case HB_SCRIPT_OSMANYA:
+ return (fds->os2->ulUnicodeRange4 & 1L << 10);
+ case HB_SCRIPT_CYPRIOT:
+ return (fds->os2->ulUnicodeRange4 & 1L << 11);
+ case HB_SCRIPT_KHAROSHTHI:
+ return (fds->os2->ulUnicodeRange4 & 1L << 12);
+ case HB_SCRIPT_TAI_VIET:
+ return (fds->os2->ulUnicodeRange4 & 1L << 13);
+ case HB_SCRIPT_CUNEIFORM:
+ return (fds->os2->ulUnicodeRange4 & 1L << 14);
+ case HB_SCRIPT_SUNDANESE:
+ return (fds->os2->ulUnicodeRange4 & 1L << 16);
+ case HB_SCRIPT_LEPCHA:
+ return (fds->os2->ulUnicodeRange4 & 1L << 17);
+ case HB_SCRIPT_OL_CHIKI:
+ return (fds->os2->ulUnicodeRange4 & 1L << 18);
+ case HB_SCRIPT_SAURASHTRA:
+ return (fds->os2->ulUnicodeRange4 & 1L << 19);
+ case HB_SCRIPT_KAYAH_LI:
+ return (fds->os2->ulUnicodeRange4 & 1L << 20);
+ case HB_SCRIPT_REJANG:
+ return (fds->os2->ulUnicodeRange4 & 1L << 21);
+ case HB_SCRIPT_CHAM:
+ return (fds->os2->ulUnicodeRange4 & 1L << 22);
+ case HB_SCRIPT_ANATOLIAN_HIEROGLYPHS:
+ return (fds->os2->ulUnicodeRange4 & 1L << 25);
+ default:
+ return false;
+ };
+}
+
+void DynamicFontDataAdvanced::set_antialiased(bool p_antialiased) {
+ if (antialiased != p_antialiased) {
+ clear_cache();
+ antialiased = p_antialiased;
+ }
+}
+
+bool DynamicFontDataAdvanced::get_antialiased() const {
+ return antialiased;
+}
+
+void DynamicFontDataAdvanced::set_force_autohinter(bool p_enabled) {
+ if (force_autohinter != p_enabled) {
+ clear_cache();
+ force_autohinter = p_enabled;
+ }
+}
+
+bool DynamicFontDataAdvanced::get_force_autohinter() const {
+ return force_autohinter;
+}
+
+void DynamicFontDataAdvanced::set_hinting(TextServer::Hinting p_hinting) {
+ if (hinting != p_hinting) {
+ clear_cache();
+ hinting = p_hinting;
+ }
+}
+
+TextServer::Hinting DynamicFontDataAdvanced::get_hinting() const {
+ return hinting;
+}
+
+bool DynamicFontDataAdvanced::has_outline() const {
+ return true;
+}
+
+float DynamicFontDataAdvanced::get_base_size() const {
+ return base_size;
+}
+
+String DynamicFontDataAdvanced::get_supported_chars() const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(base_size);
+ ERR_FAIL_COND_V(fds == nullptr, String());
+
+ String chars;
+
+ FT_UInt gindex;
+ FT_ULong charcode = FT_Get_First_Char(fds->face, &gindex);
+ while (gindex != 0) {
+ if (charcode != 0) {
+ chars += char32_t(charcode);
+ }
+ charcode = FT_Get_Next_Char(fds->face, charcode, &gindex);
+ }
+
+ return chars;
+}
+
+float DynamicFontDataAdvanced::get_font_scale(int p_size) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(p_size);
+ ERR_FAIL_COND_V(fds == nullptr, 1.0f);
+
+ return fds->scale_color_font / oversampling;
+}
+
+bool DynamicFontDataAdvanced::has_char(char32_t p_char) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(base_size);
+ ERR_FAIL_COND_V(fds == nullptr, false);
+
+ const_cast<DynamicFontDataAdvanced *>(this)->update_glyph(base_size, FT_Get_Char_Index(fds->face, p_char));
+ Character ch = fds->glyph_map[FT_Get_Char_Index(fds->face, p_char)];
+
+ return (ch.found);
+}
+
+hb_font_t *DynamicFontDataAdvanced::get_hb_handle(int p_size) {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = get_data_for_size(p_size);
+ ERR_FAIL_COND_V(fds == nullptr, nullptr);
+
+ return fds->hb_handle;
+}
+
+uint32_t DynamicFontDataAdvanced::get_glyph_index(char32_t p_char, char32_t p_variation_selector) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(base_size);
+ ERR_FAIL_COND_V(fds == nullptr, 0);
+
+ if (p_variation_selector == 0x0000) {
+ return FT_Get_Char_Index(fds->face, p_char);
+ } else {
+ return FT_Face_GetCharVariantIndex(fds->face, p_char, p_variation_selector);
+ }
+}
+
+Vector2 DynamicFontDataAdvanced::get_advance(uint32_t p_index, int p_size) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(p_size);
+ ERR_FAIL_COND_V(fds == nullptr, Vector2());
+
+ const_cast<DynamicFontDataAdvanced *>(this)->update_glyph(p_size, p_index);
+ Character ch = fds->glyph_map[p_index];
+
+ return ch.advance;
+}
+
+Vector2 DynamicFontDataAdvanced::get_kerning(uint32_t p_char, uint32_t p_next, int p_size) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(p_size);
+ ERR_FAIL_COND_V(fds == nullptr, Vector2());
+
+ FT_Vector delta;
+ FT_Get_Kerning(fds->face, p_char, p_next, FT_KERNING_DEFAULT, &delta);
+ return Vector2(delta.x, delta.y);
+}
+
+Vector2 DynamicFontDataAdvanced::draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(p_size);
+ ERR_FAIL_COND_V(fds == nullptr, Vector2());
+
+ const_cast<DynamicFontDataAdvanced *>(this)->update_glyph(p_size, p_index);
+ Character ch = fds->glyph_map[p_index];
+
+ Vector2 advance;
+ if (ch.found) {
+ ERR_FAIL_COND_V(ch.texture_idx < -1 || ch.texture_idx >= fds->textures.size(), Vector2());
+
+ if (ch.texture_idx != -1) {
+ Point2i cpos = p_pos;
+ cpos += ch.align;
+ Color modulate = p_color;
+ if (FT_HAS_COLOR(fds->face)) {
+ modulate.r = modulate.g = modulate.b = 1.0;
+ }
+ if (RenderingServer::get_singleton() != nullptr) {
+ RID texture = fds->textures[ch.texture_idx].texture->get_rid();
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, ch.rect.size), texture, ch.rect_uv, modulate, false, false);
+ }
+ }
+
+ advance = ch.advance;
+ }
+
+ return advance;
+}
+
+Vector2 DynamicFontDataAdvanced::draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(p_size, p_outline_size);
+ ERR_FAIL_COND_V(fds == nullptr, Vector2());
+
+ const_cast<DynamicFontDataAdvanced *>(this)->update_glyph_outline(p_size, p_outline_size, p_index);
+ Character ch = fds->glyph_map[p_index];
+
+ Vector2 advance;
+ if (ch.found) {
+ ERR_FAIL_COND_V(ch.texture_idx < -1 || ch.texture_idx >= fds->textures.size(), Vector2());
+
+ if (ch.texture_idx != -1) {
+ Point2i cpos = p_pos;
+ cpos += ch.align;
+ Color modulate = p_color;
+ if (FT_HAS_COLOR(fds->face)) {
+ modulate.r = modulate.g = modulate.b = 1.0;
+ }
+ if (RenderingServer::get_singleton() != nullptr) {
+ RID texture = fds->textures[ch.texture_idx].texture->get_rid();
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, ch.rect.size), texture, ch.rect_uv, modulate, false, false);
+ }
+ }
+
+ advance = ch.advance;
+ }
+
+ return advance;
+}
+
+DynamicFontDataAdvanced::~DynamicFontDataAdvanced() {
+ clear_cache();
+ if (library != nullptr) {
+ FT_Done_FreeType(library);
+ }
+}
diff --git a/modules/text_server_adv/dynamic_font_adv.h b/modules/text_server_adv/dynamic_font_adv.h
new file mode 100644
index 0000000000..c35dd9390b
--- /dev/null
+++ b/modules/text_server_adv/dynamic_font_adv.h
@@ -0,0 +1,191 @@
+/*************************************************************************/
+/* dynamic_font_adv.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef DYNAMIC_FONT_ADV_H
+#define DYNAMIC_FONT_ADV_H
+
+#include "font_adv.h"
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_TRUETYPE_TABLES_H
+
+#include <hb-ft.h>
+#include <hb-ot.h>
+
+struct DynamicFontDataAdvanced : public FontDataAdvanced {
+ _THREAD_SAFE_CLASS_
+
+private:
+ struct CharTexture {
+ Vector<uint8_t> imgdata;
+ int texture_size = 0;
+ Vector<int> offsets;
+ Ref<ImageTexture> texture;
+ };
+
+ struct Character {
+ bool found = false;
+ int texture_idx = 0;
+ Rect2 rect;
+ Rect2 rect_uv;
+ Vector2 align;
+ Vector2 advance = Vector2(-1, -1);
+
+ static Character not_found();
+ };
+
+ struct TexturePosition {
+ int index = 0;
+ int x = 0;
+ int y = 0;
+ };
+
+ struct CacheID {
+ union {
+ struct {
+ uint32_t size : 16;
+ uint32_t outline_size : 16;
+ };
+ uint32_t key;
+ };
+ bool operator<(CacheID right) const {
+ return key < right.key;
+ }
+ CacheID() {
+ key = 0;
+ }
+ };
+
+ struct DataAtSize {
+ FT_Face face = nullptr;
+ TT_OS2 *os2 = nullptr;
+ FT_StreamRec stream;
+
+ int size = 0;
+ float scale_color_font = 1.f;
+ float ascent = 0;
+ float descent = 0;
+ float underline_position = 0;
+ float underline_thickness = 0;
+
+ Vector<CharTexture> textures;
+ HashMap<uint32_t, Character> glyph_map;
+
+ hb_font_t *hb_handle = nullptr;
+ ~DataAtSize() {
+ if (hb_handle != nullptr) {
+ hb_font_destroy(hb_handle);
+ }
+ if (face != nullptr) {
+ FT_Done_Face(face);
+ }
+ }
+ };
+
+ FT_Library library = nullptr;
+
+ // Source data.
+ const uint8_t *font_mem = nullptr;
+ int font_mem_size = 0;
+ String font_path;
+ Vector<uint8_t> font_mem_cache;
+
+ Map<int32_t, double> variations;
+
+ float rect_margin = 1.f;
+ int base_size = 16;
+ float oversampling = 1.f;
+ bool antialiased = true;
+ bool force_autohinter = false;
+ TextServer::Hinting hinting = TextServer::HINTING_LIGHT;
+
+ Map<CacheID, DataAtSize *> size_cache;
+ Map<CacheID, DataAtSize *> size_cache_outline;
+
+ DataAtSize *get_data_for_size(int p_size, int p_outline_size = 0);
+
+ TexturePosition find_texture_pos_for_glyph(DataAtSize *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height);
+ Character bitmap_to_character(DataAtSize *p_data, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance);
+ _FORCE_INLINE_ void update_glyph(int p_size, uint32_t p_index);
+ _FORCE_INLINE_ void update_glyph_outline(int p_size, int p_outline_size, uint32_t p_index);
+
+public:
+ virtual void clear_cache() override;
+
+ virtual Error load_from_file(const String &p_filename, int p_base_size) override;
+ virtual Error load_from_memory(const uint8_t *p_data, size_t p_size, int p_base_size) override;
+
+ virtual float get_height(int p_size) const override;
+ virtual float get_ascent(int p_size) const override;
+ virtual float get_descent(int p_size) const override;
+
+ virtual Dictionary get_feature_list() const override;
+ virtual Dictionary get_variation_list() const override;
+
+ virtual void set_variation(const String &p_name, double p_value) override;
+ virtual double get_variation(const String &p_name) const override;
+
+ virtual float get_underline_position(int p_size) const override;
+ virtual float get_underline_thickness(int p_size) const override;
+
+ virtual void set_antialiased(bool p_antialiased) override;
+ virtual bool get_antialiased() const override;
+
+ virtual void set_hinting(TextServer::Hinting p_hinting) override;
+ virtual TextServer::Hinting get_hinting() const override;
+
+ virtual void set_force_autohinter(bool p_enabled) override;
+ virtual bool get_force_autohinter() const override;
+
+ virtual void set_distance_field_hint(bool p_distance_field) override{};
+ virtual bool get_distance_field_hint() const override { return false; };
+
+ virtual bool has_outline() const override;
+ virtual float get_base_size() const override;
+
+ virtual bool is_script_supported(uint32_t p_script) const override;
+
+ virtual bool has_char(char32_t p_char) const override;
+ virtual String get_supported_chars() const override;
+ virtual float get_font_scale(int p_size) const override;
+
+ virtual hb_font_t *get_hb_handle(int p_size) override;
+ virtual uint32_t get_glyph_index(char32_t p_char, char32_t p_variation_selector) const override;
+ virtual Vector2 get_advance(uint32_t p_index, int p_size) const override;
+ virtual Vector2 get_kerning(uint32_t p_char, uint32_t p_next, int p_size) const override;
+
+ virtual Vector2 draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const override;
+ virtual Vector2 draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const override;
+
+ virtual ~DynamicFontDataAdvanced() override;
+};
+
+#endif // DYNAMIC_FONT_ADV_H
diff --git a/modules/text_server_adv/font_adv.h b/modules/text_server_adv/font_adv.h
new file mode 100644
index 0000000000..4bbd2dd4bf
--- /dev/null
+++ b/modules/text_server_adv/font_adv.h
@@ -0,0 +1,94 @@
+/*************************************************************************/
+/* font_adv.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef FONT_ADV_H
+#define FONT_ADV_H
+
+#include "servers/text_server.h"
+
+#include <hb.h>
+
+struct FontDataAdvanced {
+ Map<String, bool> lang_support_overrides;
+ Map<String, bool> script_support_overrides;
+ bool valid = false;
+
+ virtual void clear_cache() = 0;
+
+ virtual Error load_from_file(const String &p_filename, int p_base_size) = 0;
+ virtual Error load_from_memory(const uint8_t *p_data, size_t p_size, int p_base_size) = 0;
+
+ virtual float get_height(int p_size) const = 0;
+ virtual float get_ascent(int p_size) const = 0;
+ virtual float get_descent(int p_size) const = 0;
+
+ virtual Dictionary get_feature_list() const { return Dictionary(); };
+ virtual Dictionary get_variation_list() const { return Dictionary(); };
+
+ virtual void set_variation(const String &p_name, double p_value){};
+ virtual double get_variation(const String &p_name) const { return 0; };
+
+ virtual float get_underline_position(int p_size) const = 0;
+ virtual float get_underline_thickness(int p_size) const = 0;
+
+ virtual void set_antialiased(bool p_antialiased) = 0;
+ virtual bool get_antialiased() const = 0;
+
+ virtual void set_hinting(TextServer::Hinting p_hinting) = 0;
+ virtual TextServer::Hinting get_hinting() const = 0;
+
+ virtual void set_distance_field_hint(bool p_distance_field) = 0;
+ virtual bool get_distance_field_hint() const = 0;
+
+ virtual void set_force_autohinter(bool p_enabeld) = 0;
+ virtual bool get_force_autohinter() const = 0;
+
+ virtual bool has_outline() const = 0;
+ virtual float get_base_size() const = 0;
+
+ virtual bool is_lang_supported(const String &p_lang) const { return false; };
+ virtual bool is_script_supported(uint32_t p_script) const { return false; };
+
+ virtual bool has_char(char32_t p_char) const = 0;
+ virtual String get_supported_chars() const = 0;
+ virtual float get_font_scale(int p_size) const { return 1.0f; };
+
+ virtual hb_font_t *get_hb_handle(int p_size) = 0;
+ virtual uint32_t get_glyph_index(char32_t p_char, char32_t p_variation_selector) const = 0;
+ virtual Vector2 get_advance(uint32_t p_char, int p_size) const = 0;
+ virtual Vector2 get_kerning(uint32_t p_char, uint32_t p_next, int p_size) const = 0;
+
+ virtual Vector2 draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const = 0;
+ virtual Vector2 draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const = 0;
+
+ virtual ~FontDataAdvanced(){};
+};
+
+#endif // FONT_ADV_H
diff --git a/modules/text_server_adv/icu_data/icudata_stub.cpp b/modules/text_server_adv/icu_data/icudata_stub.cpp
new file mode 100644
index 0000000000..187001f33a
--- /dev/null
+++ b/modules/text_server_adv/icu_data/icudata_stub.cpp
@@ -0,0 +1,63 @@
+/*************************************************************************/
+/* icudata_stub.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "unicode/udata.h"
+#include "unicode/utypes.h"
+#include "unicode/uversion.h"
+
+typedef struct {
+ uint16_t header_size;
+ uint8_t magic_1, magic_2;
+ UDataInfo info;
+ char padding[8];
+ uint32_t count, reserved;
+ int fake_name_and_data[4];
+} ICU_data_header;
+
+extern "C" U_EXPORT const ICU_data_header U_ICUDATA_ENTRY_POINT = {
+ 32,
+ 0xDA, 0x27,
+ { sizeof(UDataInfo),
+ 0,
+#if U_IS_BIG_ENDIAN
+ 1,
+#else
+ 0,
+#endif
+ U_CHARSET_FAMILY,
+ sizeof(UChar),
+ 0,
+ { 0x54, 0x6F, 0x43, 0x50 },
+ { 1, 0, 0, 0 },
+ { 0, 0, 0, 0 } },
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ 0, 0,
+ { 0, 0, 0, 0 }
+};
diff --git a/modules/arkit/register_types.cpp b/modules/text_server_adv/register_types.cpp
index 91069ab364..abefa83b9b 100644
--- a/modules/arkit/register_types.cpp
+++ b/modules/text_server_adv/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,16 +30,14 @@
#include "register_types.h"
-#include "arkit_interface.h"
+#include "text_server_adv.h"
-void register_arkit_types() {
- // does it make sense to register the class?
+void preregister_text_server_adv_types() {
+ TextServerAdvanced::register_server();
+}
- Ref<ARKitInterface> arkit_interface;
- arkit_interface.instance();
- XRServer::get_singleton()->add_interface(arkit_interface);
+void register_text_server_adv_types() {
}
-void unregister_arkit_types() {
- // should clean itself up nicely :)
+void unregister_text_server_adv_types() {
}
diff --git a/modules/text_server_adv/register_types.h b/modules/text_server_adv/register_types.h
new file mode 100644
index 0000000000..ddd1190f40
--- /dev/null
+++ b/modules/text_server_adv/register_types.h
@@ -0,0 +1,40 @@
+/*************************************************************************/
+/* register_types.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEXT_SERVER_ADV_REGISTER_TYPES_H
+#define TEXT_SERVER_ADV_REGISTER_TYPES_H
+
+#define MODULE_TEXT_SERVER_ADV_HAS_PREREGISTER
+
+void preregister_text_server_adv_types();
+void register_text_server_adv_types();
+void unregister_text_server_adv_types();
+
+#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
new file mode 100644
index 0000000000..8f23bb9e02
--- /dev/null
+++ b/modules/text_server_adv/script_iterator.cpp
@@ -0,0 +1,110 @@
+/*************************************************************************/
+/* script_iterator.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "script_iterator.h"
+
+bool ScriptIterator::same_script(int32_t p_script_one, int32_t p_script_two) {
+ return p_script_one <= USCRIPT_INHERITED || p_script_two <= USCRIPT_INHERITED || p_script_one == p_script_two;
+}
+
+ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length) {
+ struct ParenStackEntry {
+ int pair_index;
+ UScriptCode script_code;
+ };
+
+ if (p_start >= p_length) {
+ p_start = p_length - 1;
+ }
+
+ if (p_start < 0) {
+ p_start = 0;
+ }
+
+ ParenStackEntry paren_stack[128];
+
+ int script_start;
+ int script_end = p_start;
+ UScriptCode script_code;
+ int paren_sp = -1;
+ int start_sp = paren_sp;
+ UErrorCode err = U_ZERO_ERROR;
+ const char32_t *str = p_string.ptr();
+
+ do {
+ script_code = USCRIPT_COMMON;
+ for (script_start = script_end; script_end < p_length; script_end++) {
+ UChar32 ch = str[script_end];
+ UScriptCode sc = uscript_getScript(ch, &err);
+ if (U_FAILURE(err)) {
+ ERR_FAIL_MSG(u_errorName(err));
+ }
+ if (u_getIntPropertyValue(ch, UCHAR_BIDI_PAIRED_BRACKET_TYPE) != U_BPT_NONE) {
+ if (u_getIntPropertyValue(ch, UCHAR_BIDI_PAIRED_BRACKET_TYPE) == U_BPT_OPEN) {
+ paren_stack[++paren_sp].pair_index = ch;
+ paren_stack[paren_sp].script_code = script_code;
+ } else if (paren_sp >= 0) {
+ UChar32 paired_ch = u_getBidiPairedBracket(ch);
+ while (paren_sp >= 0 && paren_stack[paren_sp].pair_index != paired_ch) {
+ paren_sp -= 1;
+ }
+ if (paren_sp < start_sp)
+ start_sp = paren_sp;
+ if (paren_sp >= 0)
+ sc = paren_stack[paren_sp].script_code;
+ }
+ }
+
+ if (same_script(script_code, sc)) {
+ if (script_code <= USCRIPT_INHERITED && sc > USCRIPT_INHERITED) {
+ script_code = sc;
+ while (start_sp < paren_sp) {
+ paren_stack[++start_sp].script_code = script_code;
+ }
+ }
+ if ((u_getIntPropertyValue(ch, UCHAR_BIDI_PAIRED_BRACKET_TYPE) == U_BPT_CLOSE) && paren_sp >= 0) {
+ paren_sp -= 1;
+ if (start_sp >= 0) {
+ start_sp -= 1;
+ }
+ }
+ } else {
+ break;
+ }
+ }
+
+ ScriptRange rng;
+ rng.script = hb_icu_script_to_script(script_code);
+ rng.start = script_start;
+ rng.end = script_end;
+
+ script_ranges.push_back(rng);
+ } while (script_end < p_length);
+}
diff --git a/modules/text_server_adv/script_iterator.h b/modules/text_server_adv/script_iterator.h
new file mode 100644
index 0000000000..ad476f7c75
--- /dev/null
+++ b/modules/text_server_adv/script_iterator.h
@@ -0,0 +1,61 @@
+/*************************************************************************/
+/* script_iterator.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef SCRIPT_ITERATOR_H
+#define SCRIPT_ITERATOR_H
+
+#include "servers/text_server.h"
+
+#include <unicode/uchar.h>
+#include <unicode/uloc.h>
+#include <unicode/uscript.h>
+#include <unicode/ustring.h>
+#include <unicode/utypes.h>
+
+#include <hb-icu.h>
+#include <hb.h>
+
+class ScriptIterator {
+public:
+ struct ScriptRange {
+ int start;
+ int end;
+ hb_script_t script;
+ };
+ Vector<ScriptRange> script_ranges;
+
+private:
+ static bool same_script(int32_t p_script_one, int32_t p_script_two);
+
+public:
+ ScriptIterator(const String &p_string, int p_start, int p_length);
+};
+
+#endif //SCRIPT_ITERATOR_H
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
new file mode 100644
index 0000000000..8e4771685d
--- /dev/null
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -0,0 +1,2579 @@
+/*************************************************************************/
+/* text_server_adv.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "text_server_adv.h"
+#include "bitmap_font_adv.h"
+#include "dynamic_font_adv.h"
+
+#include "core/string/translation.h"
+
+#ifdef ICU_STATIC_DATA
+#include "thirdparty/icu4c/icudata.gen.h"
+#endif
+
+_FORCE_INLINE_ bool is_ain(char32_t p_chr) {
+ return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_AIN;
+}
+
+_FORCE_INLINE_ bool is_alef(char32_t p_chr) {
+ return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_ALEF;
+}
+
+_FORCE_INLINE_ bool is_beh(char32_t p_chr) {
+ int32_t prop = u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP);
+ return (prop == U_JG_BEH) || (prop == U_JG_NOON) || (prop == U_JG_AFRICAN_NOON) || (prop == U_JG_NYA) || (prop == U_JG_YEH) || (prop == U_JG_FARSI_YEH);
+}
+
+_FORCE_INLINE_ bool is_dal(char32_t p_chr) {
+ return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_DAL;
+}
+
+_FORCE_INLINE_ bool is_feh(char32_t p_chr) {
+ return (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_FEH) || (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_AFRICAN_FEH);
+}
+
+_FORCE_INLINE_ bool is_gaf(char32_t p_chr) {
+ return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_GAF;
+}
+
+_FORCE_INLINE_ bool is_heh(char32_t p_chr) {
+ return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_HEH;
+}
+
+_FORCE_INLINE_ bool is_kaf(char32_t p_chr) {
+ return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_KAF;
+}
+
+_FORCE_INLINE_ bool is_lam(char32_t p_chr) {
+ return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_LAM;
+}
+
+_FORCE_INLINE_ bool is_qaf(char32_t p_chr) {
+ return (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_QAF) || (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_AFRICAN_QAF);
+}
+
+_FORCE_INLINE_ bool is_reh(char32_t p_chr) {
+ return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_REH;
+}
+
+_FORCE_INLINE_ bool is_seen_sad(char32_t p_chr) {
+ return (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_SAD) || (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_SEEN);
+}
+
+_FORCE_INLINE_ bool is_tah(char32_t p_chr) {
+ return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_TAH;
+}
+
+_FORCE_INLINE_ bool is_teh_marbuta(char32_t p_chr) {
+ return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_TEH_MARBUTA;
+}
+
+_FORCE_INLINE_ bool is_yeh(char32_t p_chr) {
+ int32_t prop = u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP);
+ return (prop == U_JG_YEH) || (prop == U_JG_FARSI_YEH) || (prop == U_JG_YEH_BARREE) || (prop == U_JG_BURUSHASKI_YEH_BARREE) || (prop == U_JG_YEH_WITH_TAIL);
+}
+
+_FORCE_INLINE_ bool is_waw(char32_t p_chr) {
+ return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_WAW;
+}
+
+_FORCE_INLINE_ bool is_transparent(char32_t p_chr) {
+ return u_getIntPropertyValue(p_chr, UCHAR_JOINING_TYPE) == U_JT_TRANSPARENT;
+}
+
+_FORCE_INLINE_ bool is_ligature(char32_t p_chr, char32_t p_nchr) {
+ return (is_lam(p_chr) && is_alef(p_nchr));
+}
+
+_FORCE_INLINE_ bool is_connected_to_prev(char32_t p_chr, char32_t p_pchr) {
+ int32_t prop = u_getIntPropertyValue(p_pchr, UCHAR_JOINING_TYPE);
+ return (prop != U_JT_RIGHT_JOINING) && (prop != U_JT_NON_JOINING) ? !is_ligature(p_pchr, p_chr) : false;
+}
+
+_FORCE_INLINE_ bool is_control(char32_t p_char) {
+ return (p_char <= 0x001f) || (p_char >= 0x007f && p_char <= 0x009F);
+}
+
+_FORCE_INLINE_ bool is_whitespace(char32_t p_char) {
+ return (p_char == 0x0020) || (p_char == 0x00A0) || (p_char == 0x1680) || (p_char >= 0x2000 && p_char <= 0x200a) || (p_char == 0x202f) || (p_char == 0x205f) || (p_char == 0x3000) || (p_char == 0x2028) || (p_char == 0x2029) || (p_char >= 0x0009 && p_char <= 0x000d) || (p_char == 0x0085);
+}
+
+_FORCE_INLINE_ bool is_linebreak(char32_t p_char) {
+ return (p_char >= 0x000a && p_char <= 0x000d) || (p_char == 0x0085) || (p_char == 0x2028) || (p_char == 0x2029);
+}
+
+/*************************************************************************/
+
+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;
+
+bool TextServerAdvanced::has_feature(Feature p_feature) {
+ return (interface_features & p_feature) == p_feature;
+}
+
+String TextServerAdvanced::get_name() const {
+ return interface_name;
+}
+
+void TextServerAdvanced::free(RID p_rid) {
+ _THREAD_SAFE_METHOD_
+ if (font_owner.owns(p_rid)) {
+ FontDataAdvanced *fd = font_owner.getornull(p_rid);
+ font_owner.free(p_rid);
+ memdelete(fd);
+ } else if (shaped_owner.owns(p_rid)) {
+ ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_rid);
+ shaped_owner.free(p_rid);
+ memdelete(sd);
+ }
+}
+
+bool TextServerAdvanced::has(RID p_rid) {
+ _THREAD_SAFE_METHOD_
+ return font_owner.owns(p_rid) || shaped_owner.owns(p_rid);
+}
+
+bool TextServerAdvanced::load_support_data(const String &p_filename) {
+ _THREAD_SAFE_METHOD_
+
+#ifdef ICU_STATIC_DATA
+ if (icu_data == nullptr) {
+ UErrorCode err = U_ZERO_ERROR;
+ u_init(&err); // Do not check for errors, since we only load part the of data.
+ icu_data = (uint8_t *)&U_ICUDATA_ENTRY_POINT;
+ }
+#else
+ if (icu_data == nullptr) {
+ String filename = (p_filename.is_empty()) ? String("res://") + _MKSTR(ICU_DATA_NAME) : p_filename;
+
+ FileAccess *f = FileAccess::open(filename, FileAccess::READ);
+ if (!f) {
+ return false;
+ }
+
+ UErrorCode err = U_ZERO_ERROR;
+
+ // ICU data found.
+ size_t len = f->get_len();
+ icu_data = (uint8_t *)memalloc(len);
+ f->get_buffer(icu_data, len);
+ f->close();
+ memdelete(f);
+
+ udata_setCommonData(icu_data, &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));
+ }
+ }
+#endif
+ return true;
+}
+
+#ifdef TOOLS_ENABLED
+
+bool TextServerAdvanced::save_support_data(const String &p_filename) {
+ _THREAD_SAFE_METHOD_
+#ifdef ICU_STATIC_DATA
+
+ // Store data to the res file if it's available.
+ FileAccess *f = FileAccess::open(p_filename, FileAccess::WRITE);
+ if (!f) {
+ return false;
+ }
+ f->store_buffer(U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE);
+ f->close();
+ memdelete(f);
+ return true;
+
+#else
+ return false;
+#endif
+}
+
+#endif
+
+bool TextServerAdvanced::is_locale_right_to_left(const String &p_locale) {
+ String l = p_locale.get_slicec('_', 0);
+ if ((l == "ar") || (l == "dv") || (l == "he") || (l == "fa") || (l == "ff") || (l == "ku") || (l == "ur")) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+struct FeatureInfo {
+ int32_t tag;
+ String name;
+};
+
+static FeatureInfo feature_set[] = {
+ // Registred OpenType feature tags.
+ { HB_TAG('a', 'a', 'l', 't'), "access_all_alternates" },
+ { HB_TAG('a', 'b', 'v', 'f'), "above_base_forms" },
+ { HB_TAG('a', 'b', 'v', 'm'), "above_base_mark_positioning" },
+ { HB_TAG('a', 'b', 'v', 's'), "above_base_substitutions" },
+ { HB_TAG('a', 'f', 'r', 'c'), "alternative_fractions" },
+ { HB_TAG('a', 'k', 'h', 'n'), "akhands" },
+ { HB_TAG('b', 'l', 'w', 'f'), "below_base_forms" },
+ { HB_TAG('b', 'l', 'w', 'm'), "below_base_mark_positioning" },
+ { HB_TAG('b', 'l', 'w', 's'), "below_base_substitutions" },
+ { HB_TAG('c', 'a', 'l', 't'), "contextual_alternates" },
+ { HB_TAG('c', 'a', 's', 'e'), "case_sensitive_forms" },
+ { HB_TAG('c', 'c', 'm', 'p'), "glyph_composition" },
+ { HB_TAG('c', 'f', 'a', 'r'), "conjunct_form_after_ro" },
+ { HB_TAG('c', 'j', 'c', 't'), "conjunct_forms" },
+ { HB_TAG('c', 'l', 'i', 'g'), "contextual_ligatures" },
+ { HB_TAG('c', 'p', 'c', 't'), "centered_cjk_punctuation" },
+ { HB_TAG('c', 'p', 's', 'p'), "capital_spacing" },
+ { HB_TAG('c', 's', 'w', 'h'), "contextual_swash" },
+ { HB_TAG('c', 'u', 'r', 's'), "cursive_positioning" },
+ { HB_TAG('c', 'v', '0', '1'), "character_variant_01" },
+ { HB_TAG('c', 'v', '0', '2'), "character_variant_02" },
+ { HB_TAG('c', 'v', '0', '3'), "character_variant_03" },
+ { HB_TAG('c', 'v', '0', '4'), "character_variant_04" },
+ { HB_TAG('c', 'v', '0', '5'), "character_variant_05" },
+ { HB_TAG('c', 'v', '0', '6'), "character_variant_06" },
+ { HB_TAG('c', 'v', '0', '7'), "character_variant_07" },
+ { HB_TAG('c', 'v', '0', '8'), "character_variant_08" },
+ { HB_TAG('c', 'v', '0', '9'), "character_variant_09" },
+ { HB_TAG('c', 'v', '1', '0'), "character_variant_10" },
+ { HB_TAG('c', 'v', '1', '1'), "character_variant_11" },
+ { HB_TAG('c', 'v', '1', '2'), "character_variant_12" },
+ { HB_TAG('c', 'v', '1', '3'), "character_variant_13" },
+ { HB_TAG('c', 'v', '1', '4'), "character_variant_14" },
+ { HB_TAG('c', 'v', '1', '5'), "character_variant_15" },
+ { HB_TAG('c', 'v', '1', '6'), "character_variant_16" },
+ { HB_TAG('c', 'v', '1', '7'), "character_variant_17" },
+ { HB_TAG('c', 'v', '1', '8'), "character_variant_18" },
+ { HB_TAG('c', 'v', '1', '9'), "character_variant_19" },
+ { HB_TAG('c', 'v', '2', '0'), "character_variant_20" },
+ { HB_TAG('c', 'v', '2', '1'), "character_variant_21" },
+ { HB_TAG('c', 'v', '2', '2'), "character_variant_22" },
+ { HB_TAG('c', 'v', '2', '3'), "character_variant_23" },
+ { HB_TAG('c', 'v', '2', '4'), "character_variant_24" },
+ { HB_TAG('c', 'v', '2', '5'), "character_variant_25" },
+ { HB_TAG('c', 'v', '2', '6'), "character_variant_26" },
+ { HB_TAG('c', 'v', '2', '7'), "character_variant_27" },
+ { HB_TAG('c', 'v', '2', '8'), "character_variant_28" },
+ { HB_TAG('c', 'v', '2', '9'), "character_variant_29" },
+ { HB_TAG('c', 'v', '3', '0'), "character_variant_30" },
+ { HB_TAG('c', 'v', '3', '1'), "character_variant_31" },
+ { HB_TAG('c', 'v', '3', '2'), "character_variant_32" },
+ { HB_TAG('c', 'v', '3', '3'), "character_variant_33" },
+ { HB_TAG('c', 'v', '3', '4'), "character_variant_34" },
+ { HB_TAG('c', 'v', '3', '5'), "character_variant_35" },
+ { HB_TAG('c', 'v', '3', '6'), "character_variant_36" },
+ { HB_TAG('c', 'v', '3', '7'), "character_variant_37" },
+ { HB_TAG('c', 'v', '3', '8'), "character_variant_38" },
+ { HB_TAG('c', 'v', '3', '9'), "character_variant_39" },
+ { HB_TAG('c', 'v', '4', '0'), "character_variant_40" },
+ { HB_TAG('c', 'v', '4', '1'), "character_variant_41" },
+ { HB_TAG('c', 'v', '4', '2'), "character_variant_42" },
+ { HB_TAG('c', 'v', '4', '3'), "character_variant_43" },
+ { HB_TAG('c', 'v', '4', '4'), "character_variant_44" },
+ { HB_TAG('c', 'v', '4', '5'), "character_variant_45" },
+ { HB_TAG('c', 'v', '4', '6'), "character_variant_46" },
+ { HB_TAG('c', 'v', '4', '7'), "character_variant_47" },
+ { HB_TAG('c', 'v', '4', '8'), "character_variant_48" },
+ { HB_TAG('c', 'v', '4', '9'), "character_variant_49" },
+ { HB_TAG('c', 'v', '5', '0'), "character_variant_50" },
+ { HB_TAG('c', 'v', '5', '1'), "character_variant_51" },
+ { HB_TAG('c', 'v', '5', '2'), "character_variant_52" },
+ { HB_TAG('c', 'v', '5', '3'), "character_variant_53" },
+ { HB_TAG('c', 'v', '5', '4'), "character_variant_54" },
+ { HB_TAG('c', 'v', '5', '5'), "character_variant_55" },
+ { HB_TAG('c', 'v', '5', '6'), "character_variant_56" },
+ { HB_TAG('c', 'v', '5', '7'), "character_variant_57" },
+ { HB_TAG('c', 'v', '5', '8'), "character_variant_58" },
+ { HB_TAG('c', 'v', '5', '9'), "character_variant_59" },
+ { HB_TAG('c', 'v', '6', '0'), "character_variant_60" },
+ { HB_TAG('c', 'v', '6', '1'), "character_variant_61" },
+ { HB_TAG('c', 'v', '6', '2'), "character_variant_62" },
+ { HB_TAG('c', 'v', '6', '3'), "character_variant_63" },
+ { HB_TAG('c', 'v', '6', '4'), "character_variant_64" },
+ { HB_TAG('c', 'v', '6', '5'), "character_variant_65" },
+ { HB_TAG('c', 'v', '6', '6'), "character_variant_66" },
+ { HB_TAG('c', 'v', '6', '7'), "character_variant_67" },
+ { HB_TAG('c', 'v', '6', '8'), "character_variant_68" },
+ { HB_TAG('c', 'v', '6', '9'), "character_variant_69" },
+ { HB_TAG('c', 'v', '7', '0'), "character_variant_70" },
+ { HB_TAG('c', 'v', '7', '1'), "character_variant_71" },
+ { HB_TAG('c', 'v', '7', '2'), "character_variant_72" },
+ { HB_TAG('c', 'v', '7', '3'), "character_variant_73" },
+ { HB_TAG('c', 'v', '7', '4'), "character_variant_74" },
+ { HB_TAG('c', 'v', '7', '5'), "character_variant_75" },
+ { HB_TAG('c', 'v', '7', '6'), "character_variant_76" },
+ { HB_TAG('c', 'v', '7', '7'), "character_variant_77" },
+ { HB_TAG('c', 'v', '7', '8'), "character_variant_78" },
+ { HB_TAG('c', 'v', '7', '9'), "character_variant_79" },
+ { HB_TAG('c', 'v', '8', '0'), "character_variant_80" },
+ { HB_TAG('c', 'v', '8', '1'), "character_variant_81" },
+ { HB_TAG('c', 'v', '8', '2'), "character_variant_82" },
+ { HB_TAG('c', 'v', '8', '3'), "character_variant_83" },
+ { HB_TAG('c', 'v', '8', '4'), "character_variant_84" },
+ { HB_TAG('c', 'v', '8', '5'), "character_variant_85" },
+ { HB_TAG('c', 'v', '8', '6'), "character_variant_86" },
+ { HB_TAG('c', 'v', '8', '7'), "character_variant_87" },
+ { HB_TAG('c', 'v', '8', '8'), "character_variant_88" },
+ { HB_TAG('c', 'v', '8', '9'), "character_variant_89" },
+ { HB_TAG('c', 'v', '9', '0'), "character_variant_90" },
+ { HB_TAG('c', 'v', '9', '1'), "character_variant_91" },
+ { HB_TAG('c', 'v', '9', '2'), "character_variant_92" },
+ { HB_TAG('c', 'v', '9', '3'), "character_variant_93" },
+ { HB_TAG('c', 'v', '9', '4'), "character_variant_94" },
+ { HB_TAG('c', 'v', '9', '5'), "character_variant_95" },
+ { HB_TAG('c', 'v', '9', '6'), "character_variant_96" },
+ { HB_TAG('c', 'v', '9', '7'), "character_variant_97" },
+ { HB_TAG('c', 'v', '9', '8'), "character_variant_98" },
+ { HB_TAG('c', 'v', '9', '9'), "character_variant_99" },
+ { HB_TAG('c', '2', 'p', 'c'), "petite_capitals_from_capitals" },
+ { HB_TAG('c', '2', 's', 'c'), "small_capitals_from_capitals" },
+ { HB_TAG('d', 'i', 's', 't'), "distances" },
+ { HB_TAG('d', 'l', 'i', 'g'), "discretionary_ligatures" },
+ { HB_TAG('d', 'n', 'o', 'm'), "denominators" },
+ { HB_TAG('d', 't', 'l', 's'), "dotless_forms" },
+ { HB_TAG('e', 'x', 'p', 't'), "expert_forms" },
+ { HB_TAG('f', 'a', 'l', 't'), "final_glyph_on_line_alternates" },
+ { HB_TAG('f', 'i', 'n', '2'), "terminal_forms_2" },
+ { HB_TAG('f', 'i', 'n', '3'), "terminal_forms_3" },
+ { HB_TAG('f', 'i', 'n', 'a'), "terminal_forms" },
+ { HB_TAG('f', 'l', 'a', 'c'), "flattened_accent_forms" },
+ { HB_TAG('f', 'r', 'a', 'c'), "fractions" },
+ { HB_TAG('f', 'w', 'i', 'd'), "full_widths" },
+ { HB_TAG('h', 'a', 'l', 'f'), "half_forms" },
+ { HB_TAG('h', 'a', 'l', 'n'), "halant_forms" },
+ { HB_TAG('h', 'a', 'l', 't'), "alternate_half_widths" },
+ { HB_TAG('h', 'i', 's', 't'), "historical_forms" },
+ { HB_TAG('h', 'k', 'n', 'a'), "horizontal_kana_alternates" },
+ { HB_TAG('h', 'l', 'i', 'g'), "historical_ligatures" },
+ { HB_TAG('h', 'n', 'g', 'l'), "hangul" },
+ { HB_TAG('h', 'o', 'j', 'o'), "hojo_kanji_forms" },
+ { HB_TAG('h', 'w', 'i', 'd'), "half_widths" },
+ { HB_TAG('i', 'n', 'i', 't'), "initial_forms" },
+ { HB_TAG('i', 's', 'o', 'l'), "isolated_forms" },
+ { HB_TAG('i', 't', 'a', 'l'), "italics" },
+ { HB_TAG('j', 'a', 'l', 't'), "justification_alternates" },
+ { HB_TAG('j', 'p', '7', '8'), "jis78_forms" },
+ { HB_TAG('j', 'p', '8', '3'), "jis83_forms" },
+ { HB_TAG('j', 'p', '9', '0'), "jis90_forms" },
+ { HB_TAG('j', 'p', '0', '4'), "jis2004_forms" },
+ { HB_TAG('k', 'e', 'r', 'n'), "kerning" },
+ { HB_TAG('l', 'f', 'b', 'd'), "left_bounds" },
+ { HB_TAG('l', 'i', 'g', 'a'), "standard_ligatures" },
+ { HB_TAG('l', 'j', 'm', 'o'), "leading_jamo_forms" },
+ { HB_TAG('l', 'n', 'u', 'm'), "lining_figures" },
+ { HB_TAG('l', 'o', 'c', 'l'), "localized_forms" },
+ { HB_TAG('l', 't', 'r', 'a'), "left_to_right_alternates" },
+ { HB_TAG('l', 't', 'r', 'm'), "left_to_right_mirrored_forms" },
+ { HB_TAG('m', 'a', 'r', 'k'), "mark_positioning" },
+ { HB_TAG('m', 'e', 'd', '2'), "medial_forms_2" },
+ { HB_TAG('m', 'e', 'd', 'i'), "medial_forms" },
+ { HB_TAG('m', 'g', 'r', 'k'), "mathematical_greek" },
+ { HB_TAG('m', 'k', 'm', 'k'), "mark_to_mark_positioning" },
+ { HB_TAG('m', 's', 'e', 't'), "mark_positioning_via_substitution" },
+ { HB_TAG('n', 'a', 'l', 't'), "alternate_annotation_forms" },
+ { HB_TAG('n', 'l', 'c', 'k'), "nlc_kanji_forms" },
+ { HB_TAG('n', 'u', 'k', 't'), "nukta_forms" },
+ { HB_TAG('n', 'u', 'm', 'r'), "numerators" },
+ { HB_TAG('o', 'n', 'u', 'm'), "oldstyle_figures" },
+ { HB_TAG('o', 'p', 'b', 'd'), "optical_bounds" },
+ { HB_TAG('o', 'r', 'd', 'n'), "ordinals" },
+ { HB_TAG('o', 'r', 'n', 'm'), "ornaments" },
+ { HB_TAG('p', 'a', 'l', 't'), "proportional_alternate_widths" },
+ { HB_TAG('p', 'c', 'a', 'p'), "petite_capitals" },
+ { HB_TAG('p', 'k', 'n', 'a'), "proportional_kana" },
+ { HB_TAG('p', 'n', 'u', 'm'), "proportional_figures" },
+ { HB_TAG('p', 'r', 'e', 'f'), "pre_base_forms" },
+ { HB_TAG('p', 'r', 'e', 's'), "pre_base_substitutions" },
+ { HB_TAG('p', 's', 't', 'f'), "post_base_forms" },
+ { HB_TAG('p', 's', 't', 's'), "post_base_substitutions" },
+ { HB_TAG('p', 'w', 'i', 'd'), "proportional_widths" },
+ { HB_TAG('q', 'w', 'i', 'd'), "quarter_widths" },
+ { HB_TAG('r', 'a', 'n', 'd'), "randomize" },
+ { HB_TAG('r', 'c', 'l', 't'), "required_contextual_alternates" },
+ { HB_TAG('r', 'k', 'r', 'f'), "rakar_forms" },
+ { HB_TAG('r', 'l', 'i', 'g'), "required_ligatures" },
+ { HB_TAG('r', 'p', 'h', 'f'), "reph_forms" },
+ { HB_TAG('r', 't', 'b', 'd'), "right_bounds" },
+ { HB_TAG('r', 't', 'l', 'a'), "right_to_left_alternates" },
+ { HB_TAG('r', 't', 'l', 'm'), "right_to_left_mirrored_forms" },
+ { HB_TAG('r', 'u', 'b', 'y'), "ruby_notation_forms" },
+ { HB_TAG('r', 'v', 'r', 'n'), "required_variation_alternates" },
+ { HB_TAG('s', 'a', 'l', 't'), "stylistic_alternates" },
+ { HB_TAG('s', 'i', 'n', 'f'), "scientific_inferiors" },
+ { HB_TAG('s', 'i', 'z', 'e'), "optical_size" },
+ { HB_TAG('s', 'm', 'c', 'p'), "small_capitals" },
+ { HB_TAG('s', 'm', 'p', 'l'), "simplified_forms" },
+ { HB_TAG('s', 's', '0', '1'), "stylistic_set_01" },
+ { HB_TAG('s', 's', '0', '2'), "stylistic_set_02" },
+ { HB_TAG('s', 's', '0', '3'), "stylistic_set_03" },
+ { HB_TAG('s', 's', '0', '4'), "stylistic_set_04" },
+ { HB_TAG('s', 's', '0', '5'), "stylistic_set_05" },
+ { HB_TAG('s', 's', '0', '6'), "stylistic_set_06" },
+ { HB_TAG('s', 's', '0', '7'), "stylistic_set_07" },
+ { HB_TAG('s', 's', '0', '8'), "stylistic_set_08" },
+ { HB_TAG('s', 's', '0', '9'), "stylistic_set_09" },
+ { HB_TAG('s', 's', '1', '0'), "stylistic_set_10" },
+ { HB_TAG('s', 's', '1', '1'), "stylistic_set_11" },
+ { HB_TAG('s', 's', '1', '2'), "stylistic_set_12" },
+ { HB_TAG('s', 's', '1', '3'), "stylistic_set_13" },
+ { HB_TAG('s', 's', '1', '4'), "stylistic_set_14" },
+ { HB_TAG('s', 's', '1', '5'), "stylistic_set_15" },
+ { HB_TAG('s', 's', '1', '6'), "stylistic_set_16" },
+ { HB_TAG('s', 's', '1', '7'), "stylistic_set_17" },
+ { HB_TAG('s', 's', '1', '8'), "stylistic_set_18" },
+ { HB_TAG('s', 's', '1', '9'), "stylistic_set_19" },
+ { HB_TAG('s', 's', '2', '0'), "stylistic_set_20" },
+ { HB_TAG('s', 's', 't', 'y'), "math_script_style_alternates" },
+ { HB_TAG('s', 't', 'c', 'h'), "stretching_glyph_decomposition" },
+ { HB_TAG('s', 'u', 'b', 's'), "subscript" },
+ { HB_TAG('s', 'u', 'p', 's'), "superscript" },
+ { HB_TAG('s', 'w', 's', 'h'), "swash" },
+ { HB_TAG('t', 'i', 't', 'l'), "titling" },
+ { HB_TAG('t', 'j', 'm', 'o'), "trailing_jamo_forms" },
+ { HB_TAG('t', 'n', 'a', 'm'), "traditional_name_forms" },
+ { HB_TAG('t', 'n', 'u', 'm'), "tabular_figures" },
+ { HB_TAG('t', 'r', 'a', 'd'), "traditional_forms" },
+ { HB_TAG('t', 'w', 'i', 'd'), "third_widths" },
+ { HB_TAG('u', 'n', 'i', 'c'), "unicase" },
+ { HB_TAG('v', 'a', 'l', 't'), "alternate_vertical_metrics" },
+ { HB_TAG('v', 'a', 't', 'u'), "vattu_variants" },
+ { HB_TAG('v', 'e', 'r', 't'), "vertical_writing" },
+ { HB_TAG('v', 'h', 'a', 'l'), "alternate_vertical_half_metrics" },
+ { HB_TAG('v', 'j', 'm', 'o'), "vowel_jamo_forms" },
+ { HB_TAG('v', 'k', 'n', 'a'), "vertical_kana_alternates" },
+ { HB_TAG('v', 'k', 'r', 'n'), "vertical_kerning" },
+ { HB_TAG('v', 'p', 'a', 'l'), "proportional_alternate_vertical_metrics" },
+ { HB_TAG('v', 'r', 't', '2'), "vertical_alternates_and_rotation" },
+ { HB_TAG('v', 'r', 't', 'r'), "vertical_alternates_for_rotation" },
+ { HB_TAG('z', 'e', 'r', 'o'), "slashed_zero" },
+ // Registred OpenType variation tags.
+ { HB_TAG('i', 't', 'a', 'l'), "italic" },
+ { HB_TAG('o', 'p', 's', 'z'), "optical_size" },
+ { HB_TAG('s', 'l', 'n', 't'), "slant" },
+ { HB_TAG('w', 'd', 't', 'h'), "width" },
+ { HB_TAG('w', 'g', 'h', 't'), "weight" },
+ { 0, String() },
+};
+
+int32_t TextServerAdvanced::name_to_tag(const String &p_name) {
+ for (int i = 0; feature_set[i].tag != 0; i++) {
+ if (feature_set[i].name == p_name) {
+ return feature_set[i].tag;
+ }
+ }
+
+ // No readable name, use tag string.
+ return hb_tag_from_string(p_name.replace("custom_", "").ascii().get_data(), -1);
+}
+
+String TextServerAdvanced::tag_to_name(int32_t p_tag) {
+ for (int i = 0; feature_set[i].tag != 0; i++) {
+ if (feature_set[i].tag == p_tag) {
+ return feature_set[i].name;
+ }
+ }
+
+ // No readable name, use tag string.
+ char name[5];
+ memset(name, 0, 5);
+ hb_tag_to_string(p_tag, name);
+ return String("custom_") + String(name);
+}
+
+/*************************************************************************/
+/* Font interface */
+/*************************************************************************/
+
+RID TextServerAdvanced::create_font_system(const String &p_name, int p_base_size) {
+ ERR_FAIL_V_MSG(RID(), "System fonts are not supported by this text server.");
+}
+
+RID TextServerAdvanced::create_font_resource(const String &p_filename, int p_base_size) {
+ _THREAD_SAFE_METHOD_
+ FontDataAdvanced *fd = nullptr;
+ if (p_filename.get_extension() == "ttf" || p_filename.get_extension() == "otf" || p_filename.get_extension() == "woff") {
+ fd = memnew(DynamicFontDataAdvanced);
+ } else if (p_filename.get_extension() == "fnt" || p_filename.get_extension() == "font") {
+ fd = memnew(BitmapFontDataAdvanced);
+ } else {
+ return RID();
+ }
+
+ Error err = fd->load_from_file(p_filename, p_base_size);
+ if (err != OK) {
+ memdelete(fd);
+ return RID();
+ }
+
+ return font_owner.make_rid(fd);
+}
+
+RID TextServerAdvanced::create_font_memory(const uint8_t *p_data, size_t p_size, const String &p_type, int p_base_size) {
+ _THREAD_SAFE_METHOD_
+ FontDataAdvanced *fd = nullptr;
+ if (p_type == "ttf" || p_type == "otf" || p_type == "woff") {
+ fd = memnew(DynamicFontDataAdvanced);
+ } else if (p_type == "fnt" || p_type == "font") {
+ fd = memnew(BitmapFontDataAdvanced);
+ } else {
+ return RID();
+ }
+
+ Error err = fd->load_from_memory(p_data, p_size, p_base_size);
+ if (err != OK) {
+ memdelete(fd);
+ return RID();
+ }
+
+ return font_owner.make_rid(fd);
+}
+
+float TextServerAdvanced::font_get_height(RID p_font, int p_size) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, 0.f);
+ return fd->get_height(p_size);
+}
+
+float TextServerAdvanced::font_get_ascent(RID p_font, int p_size) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, 0.f);
+ return fd->get_ascent(p_size);
+}
+
+float TextServerAdvanced::font_get_descent(RID p_font, int p_size) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, 0.f);
+ return fd->get_descent(p_size);
+}
+
+float TextServerAdvanced::font_get_underline_position(RID p_font, int p_size) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, 0.f);
+ return fd->get_underline_position(p_size);
+}
+
+float TextServerAdvanced::font_get_underline_thickness(RID p_font, int p_size) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, 0.f);
+ return fd->get_underline_thickness(p_size);
+}
+
+void TextServerAdvanced::font_set_antialiased(RID p_font, bool p_antialiased) {
+ _THREAD_SAFE_METHOD_
+ FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->set_antialiased(p_antialiased);
+}
+
+Dictionary TextServerAdvanced::font_get_feature_list(RID p_font) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, Dictionary());
+ return fd->get_feature_list();
+}
+
+bool TextServerAdvanced::font_get_antialiased(RID p_font) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, false);
+ return fd->get_antialiased();
+}
+
+Dictionary TextServerAdvanced::font_get_variation_list(RID p_font) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, Dictionary());
+ return fd->get_variation_list();
+}
+
+void TextServerAdvanced::font_set_variation(RID p_font, const String &p_name, double p_value) {
+ _THREAD_SAFE_METHOD_
+ FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->set_variation(p_name, p_value);
+}
+
+double TextServerAdvanced::font_get_variation(RID p_font, const String &p_name) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, 0);
+ return fd->get_variation(p_name);
+}
+
+void TextServerAdvanced::font_set_distance_field_hint(RID p_font, bool p_distance_field) {
+ _THREAD_SAFE_METHOD_
+ FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->set_distance_field_hint(p_distance_field);
+}
+
+bool TextServerAdvanced::font_get_distance_field_hint(RID p_font) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, false);
+ return fd->get_distance_field_hint();
+}
+
+void TextServerAdvanced::font_set_hinting(RID p_font, TextServer::Hinting p_hinting) {
+ _THREAD_SAFE_METHOD_
+ FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->set_hinting(p_hinting);
+}
+
+TextServer::Hinting TextServerAdvanced::font_get_hinting(RID p_font) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, TextServer::HINTING_NONE);
+ return fd->get_hinting();
+}
+
+void TextServerAdvanced::font_set_force_autohinter(RID p_font, bool p_enabeld) {
+ _THREAD_SAFE_METHOD_
+ FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->set_force_autohinter(p_enabeld);
+}
+
+bool TextServerAdvanced::font_get_force_autohinter(RID p_font) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, false);
+ return fd->get_force_autohinter();
+}
+
+bool TextServerAdvanced::font_has_char(RID p_font, char32_t p_char) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, false);
+ return fd->has_char(p_char);
+}
+
+String TextServerAdvanced::font_get_supported_chars(RID p_font) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, String());
+ return fd->get_supported_chars();
+}
+
+bool TextServerAdvanced::font_has_outline(RID p_font) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, false);
+ return fd->has_outline();
+}
+
+float TextServerAdvanced::font_get_base_size(RID p_font) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, 0.f);
+ return fd->get_base_size();
+}
+
+bool TextServerAdvanced::font_is_language_supported(RID p_font, const String &p_language) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, false);
+ if (fd->lang_support_overrides.has(p_language)) {
+ return fd->lang_support_overrides[p_language];
+ } else {
+ Vector<String> tags = p_language.replace("-", "_").split("_");
+ if (tags.size() > 0) {
+ if (fd->lang_support_overrides.has(tags[0])) {
+ return fd->lang_support_overrides[tags[0]];
+ }
+ }
+ return fd->is_lang_supported(p_language);
+ }
+}
+
+void TextServerAdvanced::font_set_language_support_override(RID p_font, const String &p_language, bool p_supported) {
+ _THREAD_SAFE_METHOD_
+ FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->lang_support_overrides[p_language] = p_supported;
+}
+
+bool TextServerAdvanced::font_get_language_support_override(RID p_font, const String &p_language) {
+ _THREAD_SAFE_METHOD_
+ FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, false);
+ return fd->lang_support_overrides[p_language];
+}
+
+void TextServerAdvanced::font_remove_language_support_override(RID p_font, const String &p_language) {
+ _THREAD_SAFE_METHOD_
+ FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->lang_support_overrides.erase(p_language);
+}
+
+Vector<String> TextServerAdvanced::font_get_language_support_overrides(RID p_font) {
+ _THREAD_SAFE_METHOD_
+ FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, Vector<String>());
+ Vector<String> ret;
+ for (Map<String, bool>::Element *E = fd->lang_support_overrides.front(); E; E = E->next()) {
+ ret.push_back(E->key());
+ }
+ return ret;
+}
+
+bool TextServerAdvanced::font_is_script_supported(RID p_font, const String &p_script) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, false);
+ if (fd->script_support_overrides.has(p_script)) {
+ return fd->script_support_overrides[p_script];
+ } else {
+ hb_script_t scr = hb_script_from_string(p_script.ascii().get_data(), -1);
+ return fd->is_script_supported(scr);
+ }
+}
+
+void TextServerAdvanced::font_set_script_support_override(RID p_font, const String &p_script, bool p_supported) {
+ _THREAD_SAFE_METHOD_
+ FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->script_support_overrides[p_script] = p_supported;
+}
+
+bool TextServerAdvanced::font_get_script_support_override(RID p_font, const String &p_script) {
+ _THREAD_SAFE_METHOD_
+ FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, false);
+ return fd->script_support_overrides[p_script];
+}
+
+void TextServerAdvanced::font_remove_script_support_override(RID p_font, const String &p_script) {
+ _THREAD_SAFE_METHOD_
+ FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->script_support_overrides.erase(p_script);
+}
+
+Vector<String> TextServerAdvanced::font_get_script_support_overrides(RID p_font) {
+ _THREAD_SAFE_METHOD_
+ FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, Vector<String>());
+ Vector<String> ret;
+ for (Map<String, bool>::Element *E = fd->script_support_overrides.front(); E; E = E->next()) {
+ ret.push_back(E->key());
+ }
+ return ret;
+}
+
+uint32_t TextServerAdvanced::font_get_glyph_index(RID p_font, char32_t p_char, char32_t p_variation_selector) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, 0);
+ return fd->get_glyph_index(p_char, p_variation_selector);
+}
+
+Vector2 TextServerAdvanced::font_get_glyph_advance(RID p_font, uint32_t p_index, int p_size) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, Vector2());
+ return fd->get_advance(p_index, p_size);
+}
+
+Vector2 TextServerAdvanced::font_get_glyph_kerning(RID p_font, uint32_t p_index_a, uint32_t p_index_b, int p_size) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, Vector2());
+ return fd->get_kerning(p_index_a, p_index_b, p_size);
+}
+
+Vector2 TextServerAdvanced::font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, Vector2());
+ return fd->draw_glyph(p_canvas, p_size, p_pos, p_index, p_color);
+}
+
+Vector2 TextServerAdvanced::font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, Vector2());
+ return fd->draw_glyph_outline(p_canvas, p_size, p_outline_size, p_pos, p_index, p_color);
+}
+
+float TextServerAdvanced::font_get_oversampling() const {
+ return oversampling;
+}
+
+void TextServerAdvanced::font_set_oversampling(float p_oversampling) {
+ _THREAD_SAFE_METHOD_
+ if (oversampling != p_oversampling) {
+ oversampling = p_oversampling;
+ List<RID> fonts;
+ font_owner.get_owned_list(&fonts);
+ for (List<RID>::Element *E = fonts.front(); E; E = E->next()) {
+ font_owner.getornull(E->get())->clear_cache();
+ }
+
+ List<RID> text_bufs;
+ shaped_owner.get_owned_list(&text_bufs);
+ for (List<RID>::Element *E = text_bufs.front(); E; E = E->next()) {
+ invalidate(shaped_owner.getornull(E->get()));
+ }
+ }
+}
+
+Vector<String> TextServerAdvanced::get_system_fonts() const {
+ return Vector<String>();
+}
+
+/*************************************************************************/
+/* Shaped text buffer interface */
+/*************************************************************************/
+
+int TextServerAdvanced::_convert_pos(const ShapedTextDataAdvanced *p_sd, int p_pos) const {
+ int32_t limit = p_pos;
+ if (p_sd->text.length() != p_sd->utf16.length()) {
+ const UChar *data = p_sd->utf16.ptr();
+ for (int i = 0; i < p_pos; i++) {
+ if (U16_IS_LEAD(data[i])) {
+ limit--;
+ }
+ }
+ }
+ return limit;
+}
+
+int TextServerAdvanced::_convert_pos_inv(const ShapedTextDataAdvanced *p_sd, int p_pos) const {
+ int32_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) {
+ limit++;
+ }
+ }
+ }
+ return limit;
+}
+
+void TextServerAdvanced::invalidate(TextServerAdvanced::ShapedTextDataAdvanced *p_shaped) {
+ p_shaped->valid = false;
+ 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->glyphs.clear();
+ p_shaped->glyphs_logical.clear();
+ p_shaped->utf16 = Char16String();
+ if (p_shaped->script_iter != nullptr) {
+ memdelete(p_shaped->script_iter);
+ p_shaped->script_iter = nullptr;
+ }
+ for (int i = 0; i < p_shaped->bidi_iter.size(); i++) {
+ ubidi_close(p_shaped->bidi_iter[i]);
+ }
+ p_shaped->bidi_iter.clear();
+}
+
+void TextServerAdvanced::full_copy(ShapedTextDataAdvanced *p_shaped) {
+ ShapedTextDataAdvanced *parent = shaped_owner.getornull(p_shaped->parent);
+
+ for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = parent->objects.front(); E; E = E->next()) {
+ if (E->get().pos >= p_shaped->start && E->get().pos < p_shaped->end) {
+ p_shaped->objects[E->key()] = E->get();
+ }
+ }
+
+ for (int k = 0; k < parent->spans.size(); k++) {
+ ShapedTextDataAdvanced::Span span = parent->spans[k];
+ if (span.start >= p_shaped->end || span.end <= p_shaped->start) {
+ continue;
+ }
+ span.start = MAX(p_shaped->start, span.start);
+ span.end = MIN(p_shaped->end, span.end);
+ p_shaped->spans.push_back(span);
+ }
+
+ p_shaped->parent = RID();
+}
+
+RID TextServerAdvanced::create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextDataAdvanced *sd = memnew(ShapedTextDataAdvanced);
+ sd->hb_buffer = hb_buffer_create();
+ sd->direction = p_direction;
+ sd->orientation = p_orientation;
+ return shaped_owner.make_rid(sd);
+}
+
+void TextServerAdvanced::shaped_text_clear(RID p_shaped) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND(!sd);
+
+ sd->parent = RID();
+ sd->start = 0;
+ sd->end = 0;
+ sd->text = String();
+ sd->spans.clear();
+ sd->objects.clear();
+ sd->bidi_override.clear();
+ invalidate(sd);
+}
+
+void TextServerAdvanced::shaped_text_set_direction(RID p_shaped, TextServer::Direction p_direction) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND(!sd);
+
+ if (sd->direction != p_direction) {
+ if (sd->parent != RID()) {
+ full_copy(sd);
+ }
+ sd->direction = p_direction;
+ invalidate(sd);
+ }
+}
+
+TextServer::Direction TextServerAdvanced::shaped_text_get_direction(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, TextServer::DIRECTION_LTR);
+ return sd->direction;
+}
+
+void TextServerAdvanced::shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND(!sd);
+ if (sd->parent != RID()) {
+ full_copy(sd);
+ }
+ sd->bidi_override = p_override;
+ invalidate(sd);
+}
+
+void TextServerAdvanced::shaped_text_set_orientation(RID p_shaped, TextServer::Orientation p_orientation) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND(!sd);
+ if (sd->orientation != p_orientation) {
+ if (sd->parent != RID()) {
+ full_copy(sd);
+ }
+ sd->orientation = p_orientation;
+ invalidate(sd);
+ }
+}
+
+void TextServerAdvanced::shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND(!sd);
+ ERR_FAIL_COND(sd->parent != RID());
+ if (sd->preserve_invalid != p_enabled) {
+ sd->preserve_invalid = p_enabled;
+ invalidate(sd);
+ }
+}
+
+bool TextServerAdvanced::shaped_text_get_preserve_invalid(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, false);
+ return sd->preserve_invalid;
+}
+
+void TextServerAdvanced::shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND(!sd);
+ if (sd->preserve_control != p_enabled) {
+ if (sd->parent != RID()) {
+ full_copy(sd);
+ }
+ sd->preserve_control = p_enabled;
+ invalidate(sd);
+ }
+}
+
+bool TextServerAdvanced::shaped_text_get_preserve_control(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, false);
+ return sd->preserve_control;
+}
+
+TextServer::Orientation TextServerAdvanced::shaped_text_get_orientation(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, TextServer::ORIENTATION_HORIZONTAL);
+ return sd->orientation;
+}
+
+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) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, false);
+ ERR_FAIL_COND_V(p_size <= 0, false);
+
+ if (p_text.is_empty()) {
+ return true;
+ }
+
+ if (sd->parent != RID()) {
+ full_copy(sd);
+ }
+
+ ShapedTextDataAdvanced::Span span;
+ span.start = sd->text.length();
+ span.end = span.start + p_text.length();
+ span.fonts = p_fonts; // Do not pre-sort, spans will be divided to subruns later.
+ span.font_size = p_size;
+ span.language = p_language;
+ span.features = p_opentype_features;
+
+ sd->spans.push_back(span);
+ sd->text += p_text;
+ sd->end += p_text.length();
+ invalidate(sd);
+
+ return true;
+}
+
+bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align, int p_length) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, false);
+ ERR_FAIL_COND_V(p_key == Variant(), false);
+ ERR_FAIL_COND_V(sd->objects.has(p_key), false);
+
+ if (sd->parent != RID()) {
+ full_copy(sd);
+ }
+
+ ShapedTextDataAdvanced::Span span;
+ span.start = sd->text.length();
+ span.end = span.start + p_length;
+ span.embedded_key = p_key;
+
+ ShapedTextDataAdvanced::EmbeddedObject obj;
+ obj.inline_align = p_inline_align;
+ obj.rect.size = p_size;
+ obj.pos = span.start;
+
+ sd->spans.push_back(span);
+ sd->text += String::chr(0xfffc).repeat(p_length);
+ sd->end += p_length;
+ sd->objects[p_key] = obj;
+ invalidate(sd);
+
+ return true;
+}
+
+bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, false);
+ ERR_FAIL_COND_V(!sd->objects.has(p_key), false);
+ sd->objects[p_key].rect.size = p_size;
+ sd->objects[p_key].inline_align = p_inline_align;
+ if (sd->valid) {
+ // Recalc string metrics.
+ sd->ascent = 0;
+ sd->descent = 0;
+ sd->width = 0;
+ sd->upos = 0;
+ sd->uthk = 0;
+ int sd_size = sd->glyphs.size();
+
+ for (int i = 0; i < sd_size; i++) {
+ Glyph gl = sd->glyphs[i];
+ Variant key;
+ if (gl.count == 1) {
+ for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
+ if (E->get().pos == gl.start) {
+ key = E->key();
+ break;
+ }
+ }
+ }
+ if (key != Variant()) {
+ if (sd->orientation == ORIENTATION_HORIZONTAL) {
+ sd->objects[key].rect.position.x = sd->width;
+ sd->width += sd->objects[key].rect.size.x;
+ switch (sd->objects[key].inline_align) {
+ case VALIGN_TOP: {
+ sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y);
+ } break;
+ case VALIGN_CENTER: {
+ sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.y / 2));
+ sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.y / 2));
+ } break;
+ case VALIGN_BOTTOM: {
+ sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y);
+ } break;
+ }
+ sd->glyphs.write[i].advance = sd->objects[key].rect.size.x;
+ } else {
+ sd->objects[key].rect.position.y = sd->width;
+ sd->width += sd->objects[key].rect.size.y;
+ switch (sd->objects[key].inline_align) {
+ case VALIGN_TOP: {
+ sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x);
+ } break;
+ case VALIGN_CENTER: {
+ sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.x / 2));
+ sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.x / 2));
+ } break;
+ case VALIGN_BOTTOM: {
+ sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x);
+ } break;
+ }
+ sd->glyphs.write[i].advance = sd->objects[key].rect.size.y;
+ }
+ } else {
+ const FontDataAdvanced *fd = font_owner.getornull(gl.font_rid);
+ if (fd != nullptr) {
+ if (sd->orientation == ORIENTATION_HORIZONTAL) {
+ sd->ascent = MAX(sd->ascent, MAX(fd->get_ascent(gl.font_size), -gl.y_off));
+ sd->descent = MAX(sd->descent, MAX(fd->get_descent(gl.font_size), gl.y_off));
+ } else {
+ sd->ascent = MAX(sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
+ sd->descent = MAX(sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
+ }
+ sd->upos = MAX(sd->upos, font_get_underline_position(gl.font_rid, gl.font_size));
+ sd->uthk = MAX(sd->uthk, font_get_underline_thickness(gl.font_rid, gl.font_size));
+ } else if (sd->preserve_invalid || (sd->preserve_control && is_control(gl.index))) {
+ // Glyph not found, replace with hex code box.
+ if (sd->orientation == ORIENTATION_HORIZONTAL) {
+ sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
+ sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
+ } 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->width += gl.advance * gl.repeat;
+ }
+ }
+
+ // Align embedded objects to baseline.
+ for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
+ if ((E->get().pos >= sd->start) && (E->get().pos < sd->end)) {
+ if (sd->orientation == ORIENTATION_HORIZONTAL) {
+ switch (E->get().inline_align) {
+ case VALIGN_TOP: {
+ E->get().rect.position.y = -sd->ascent;
+ } break;
+ case VALIGN_CENTER: {
+ E->get().rect.position.y = -(E->get().rect.size.y / 2);
+ } break;
+ case VALIGN_BOTTOM: {
+ E->get().rect.position.y = sd->descent - E->get().rect.size.y;
+ } break;
+ }
+ } else {
+ switch (E->get().inline_align) {
+ case VALIGN_TOP: {
+ E->get().rect.position.x = -sd->ascent;
+ } break;
+ case VALIGN_CENTER: {
+ E->get().rect.position.x = -(E->get().rect.size.x / 2);
+ } break;
+ case VALIGN_BOTTOM: {
+ E->get().rect.position.x = sd->descent - E->get().rect.size.x;
+ } break;
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_length) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, RID());
+ if (sd->parent != RID()) {
+ return shaped_text_substr(sd->parent, p_start, p_length);
+ }
+ if (!sd->valid) {
+ const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
+ }
+ ERR_FAIL_COND_V(p_start < 0 || p_length < 0, RID());
+ ERR_FAIL_COND_V(sd->start > p_start || sd->end < p_start, RID());
+ ERR_FAIL_COND_V(sd->end < p_start + p_length, RID());
+
+ ShapedTextDataAdvanced *new_sd = memnew(ShapedTextDataAdvanced);
+
+ new_sd->hb_buffer = hb_buffer_create();
+ new_sd->parent = p_shaped;
+ new_sd->start = p_start;
+ new_sd->end = p_start + p_length;
+
+ new_sd->orientation = sd->orientation;
+ new_sd->direction = sd->direction;
+ new_sd->para_direction = sd->para_direction;
+ new_sd->line_breaks_valid = sd->line_breaks_valid;
+ new_sd->justification_ops_valid = sd->justification_ops_valid;
+ new_sd->sort_valid = false;
+ new_sd->upos = sd->upos;
+ new_sd->uthk = sd->uthk;
+
+ if (p_length > 0) {
+ new_sd->text = sd->text.substr(p_start, p_length);
+ new_sd->utf16 = new_sd->text.utf16();
+ new_sd->script_iter = memnew(ScriptIterator(new_sd->text, 0, new_sd->text.length()));
+
+ int sd_size = sd->glyphs.size();
+ const Glyph *sd_glyphs = sd->glyphs.ptr();
+ const FontDataAdvanced *fd = nullptr;
+ RID prev_rid = RID();
+
+ for (int ov = 0; ov < sd->bidi_override.size(); ov++) {
+ UErrorCode err = U_ZERO_ERROR;
+
+ if (sd->bidi_override[ov].x >= p_start + p_length || sd->bidi_override[ov].y <= p_start) {
+ continue;
+ }
+ int start = _convert_pos_inv(sd, MAX(0, p_start - sd->bidi_override[ov].x));
+ int end = _convert_pos_inv(sd, MIN(p_start + p_length, sd->bidi_override[ov].y) - sd->bidi_override[ov].x);
+
+ ERR_FAIL_COND_V_MSG((start < 0 || end - start > new_sd->utf16.length()), RID(), "Invalid BiDi override range.");
+
+ //Create temporary line bidi & shape
+ UBiDi *bidi_iter = ubidi_openSized(end - start, 0, &err);
+ ERR_FAIL_COND_V_MSG(U_FAILURE(err), RID(), u_errorName(err));
+ ubidi_setLine(sd->bidi_iter[ov], start, end, bidi_iter, &err);
+ if (U_FAILURE(err)) {
+ ubidi_close(bidi_iter);
+ ERR_FAIL_V_MSG(RID(), u_errorName(err));
+ }
+ new_sd->bidi_iter.push_back(bidi_iter);
+
+ err = U_ZERO_ERROR;
+ int bidi_run_count = ubidi_countRuns(bidi_iter, &err);
+ ERR_FAIL_COND_V_MSG(U_FAILURE(err), RID(), u_errorName(err));
+ for (int i = 0; i < bidi_run_count; i++) {
+ int32_t _bidi_run_start = 0;
+ int32_t _bidi_run_length = 0;
+ ubidi_getVisualRun(bidi_iter, i, &_bidi_run_start, &_bidi_run_length);
+
+ int32_t bidi_run_start = _convert_pos(sd, sd->bidi_override[ov].x + start + _bidi_run_start);
+ int32_t bidi_run_end = _convert_pos(sd, sd->bidi_override[ov].x + start + _bidi_run_start + _bidi_run_length);
+
+ for (int j = 0; j < sd_size; j++) {
+ if ((sd_glyphs[j].start >= bidi_run_start) && (sd_glyphs[j].end <= bidi_run_end)) {
+ // Copy glyphs.
+ Glyph gl = sd_glyphs[j];
+ Variant key;
+ bool find_embedded = false;
+ if (gl.count == 1) {
+ for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
+ if (E->get().pos == gl.start) {
+ find_embedded = true;
+ key = E->key();
+ new_sd->objects[key] = E->get();
+ break;
+ }
+ }
+ }
+ if (find_embedded) {
+ if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
+ new_sd->objects[key].rect.position.x = new_sd->width;
+ new_sd->width += new_sd->objects[key].rect.size.x;
+ switch (new_sd->objects[key].inline_align) {
+ case VALIGN_TOP: {
+ new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y);
+ } break;
+ case VALIGN_CENTER: {
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.y / 2));
+ new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.y / 2));
+ } break;
+ case VALIGN_BOTTOM: {
+ new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y);
+ } break;
+ }
+ } else {
+ new_sd->objects[key].rect.position.y = new_sd->width;
+ new_sd->width += new_sd->objects[key].rect.size.y;
+ switch (new_sd->objects[key].inline_align) {
+ case VALIGN_TOP: {
+ new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x);
+ } break;
+ case VALIGN_CENTER: {
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.x / 2));
+ new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.x / 2));
+ } break;
+ case VALIGN_BOTTOM: {
+ new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x);
+ } break;
+ }
+ }
+ } else {
+ if (prev_rid != gl.font_rid) {
+ fd = font_owner.getornull(gl.font_rid);
+ prev_rid = gl.font_rid;
+ }
+ if (fd != nullptr) {
+ if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
+ new_sd->ascent = MAX(new_sd->ascent, MAX(fd->get_ascent(gl.font_size), -gl.y_off));
+ new_sd->descent = MAX(new_sd->descent, MAX(fd->get_descent(gl.font_size), gl.y_off));
+ } else {
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
+ new_sd->descent = MAX(new_sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
+ }
+ } else if (new_sd->preserve_invalid || (new_sd->preserve_control && is_control(gl.index))) {
+ // Glyph not found, replace with hex code box.
+ if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
+ new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
+ } 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->width += gl.advance * gl.repeat;
+ }
+ new_sd->glyphs.push_back(gl);
+ }
+ }
+ }
+ }
+
+ // Align embedded objects to baseline.
+ for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = new_sd->objects.front(); E; E = E->next()) {
+ if ((E->get().pos >= new_sd->start) && (E->get().pos < new_sd->end)) {
+ if (sd->orientation == ORIENTATION_HORIZONTAL) {
+ switch (E->get().inline_align) {
+ case VALIGN_TOP: {
+ E->get().rect.position.y = -new_sd->ascent;
+ } break;
+ case VALIGN_CENTER: {
+ E->get().rect.position.y = -(E->get().rect.size.y / 2);
+ } break;
+ case VALIGN_BOTTOM: {
+ E->get().rect.position.y = new_sd->descent - E->get().rect.size.y;
+ } break;
+ }
+ } else {
+ switch (E->get().inline_align) {
+ case VALIGN_TOP: {
+ E->get().rect.position.x = -new_sd->ascent;
+ } break;
+ case VALIGN_CENTER: {
+ E->get().rect.position.x = -(E->get().rect.size.x / 2);
+ } break;
+ case VALIGN_BOTTOM: {
+ E->get().rect.position.x = new_sd->descent - E->get().rect.size.x;
+ } break;
+ }
+ }
+ }
+ }
+ }
+
+ new_sd->valid = true;
+
+ return shaped_owner.make_rid(new_sd);
+}
+
+RID TextServerAdvanced::shaped_text_get_parent(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, RID());
+ return sd->parent;
+}
+
+float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width, uint8_t /*JustificationFlag*/ p_jst_flags) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, 0.f);
+ if (!sd->valid) {
+ const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
+ }
+ if (!sd->justification_ops_valid) {
+ const_cast<TextServerAdvanced *>(this)->shaped_text_update_justification_ops(p_shaped);
+ }
+
+ int start_pos = 0;
+ int end_pos = sd->glyphs.size() - 1;
+
+ if ((p_jst_flags & JUSTIFICATION_AFTER_LAST_TAB) == JUSTIFICATION_AFTER_LAST_TAB) {
+ int start, end, delta;
+ if (sd->para_direction == DIRECTION_LTR) {
+ start = sd->glyphs.size() - 1;
+ end = -1;
+ delta = -1;
+ } else {
+ start = 0;
+ end = sd->glyphs.size();
+ delta = +1;
+ }
+
+ for (int i = start; i != end; i += delta) {
+ if ((sd->glyphs[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
+ if (sd->para_direction == DIRECTION_LTR) {
+ start_pos = i;
+ break;
+ } else {
+ end_pos = i;
+ break;
+ }
+ }
+ }
+ }
+
+ if ((p_jst_flags & JUSTIFICATION_TRIM_EDGE_SPACES) == JUSTIFICATION_TRIM_EDGE_SPACES) {
+ while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
+ sd->width -= sd->glyphs[start_pos].advance * sd->glyphs[start_pos].repeat;
+ sd->glyphs.write[start_pos].advance = 0;
+ start_pos += sd->glyphs[start_pos].count;
+ }
+ while ((start_pos < end_pos) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
+ sd->width -= sd->glyphs[end_pos].advance * sd->glyphs[end_pos].repeat;
+ sd->glyphs.write[end_pos].advance = 0;
+ end_pos -= sd->glyphs[end_pos].count;
+ }
+ }
+
+ int space_count = 0;
+ int elongation_count = 0;
+ for (int i = start_pos; i <= end_pos; i++) {
+ const Glyph &gl = sd->glyphs[i];
+ if (gl.count > 0) {
+ if ((gl.flags & GRAPHEME_IS_ELONGATION) == GRAPHEME_IS_ELONGATION) {
+ elongation_count++;
+ }
+ if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) {
+ space_count++;
+ }
+ }
+ }
+
+ if ((elongation_count > 0) && ((p_jst_flags & JUSTIFICATION_KASHIDA) == JUSTIFICATION_KASHIDA)) {
+ float delta_width_per_kashida = (p_width - sd->width) / elongation_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_ELONGATION) == GRAPHEME_IS_ELONGATION) && (gl.advance > 0)) {
+ int count = delta_width_per_kashida / gl.advance;
+ int prev_count = gl.repeat;
+ if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {
+ gl.repeat = count;
+ } else {
+ gl.repeat = count + 1;
+ }
+ sd->width += (gl.repeat - prev_count) * gl.advance;
+ }
+ }
+ }
+ }
+
+ if ((space_count > 0) && ((p_jst_flags & JUSTIFICATION_WORD_BOUND) == JUSTIFICATION_WORD_BOUND)) {
+ float delta_width_per_space = (p_width - sd->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;
+ if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {
+ gl.advance = Math::round(MAX(gl.advance + delta_width_per_space, 0.f));
+ } else {
+ gl.advance = Math::round(MAX(gl.advance + delta_width_per_space, 0.05 * gl.font_size));
+ }
+ sd->width += (gl.advance - old_adv);
+ }
+ }
+ }
+ }
+
+ return sd->width;
+}
+
+float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<float> &p_tab_stops) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, 0.f);
+ if (!sd->valid) {
+ const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
+ }
+ if (!sd->line_breaks_valid) {
+ const_cast<TextServerAdvanced *>(this)->shaped_text_update_breaks(p_shaped);
+ }
+
+ int tab_index = 0;
+ float off = 0.f;
+
+ int start, end, delta;
+ if (sd->para_direction == DIRECTION_LTR) {
+ start = 0;
+ end = sd->glyphs.size();
+ delta = +1;
+ } else {
+ start = sd->glyphs.size() - 1;
+ end = -1;
+ delta = -1;
+ }
+
+ Glyph *gl = sd->glyphs.ptrw();
+
+ for (int i = start; i != end; i += delta) {
+ if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
+ float tab_off = 0.f;
+ while (tab_off <= off) {
+ tab_off += p_tab_stops[tab_index];
+ tab_index++;
+ if (tab_index >= p_tab_stops.size()) {
+ tab_index = 0;
+ }
+ }
+ float old_adv = gl[i].advance;
+ gl[i].advance = tab_off - off;
+ sd->width += gl[i].advance - old_adv;
+ off = 0;
+ continue;
+ }
+ off += gl[i].advance * gl[i].repeat;
+ }
+
+ return 0.f;
+}
+
+bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, false);
+ if (!sd->valid) {
+ shaped_text_shape(p_shaped);
+ }
+
+ if (sd->line_breaks_valid) {
+ return true; // Noting to do.
+ }
+
+ const UChar *data = sd->utf16.ptr();
+
+ HashMap<int, bool> breaks;
+ UErrorCode err = U_ZERO_ERROR;
+ int i = 0;
+ while (i < sd->spans.size()) {
+ String language = sd->spans[i].language;
+ int r_start = sd->spans[i].start;
+ while (i + 1 < sd->spans.size() && language == sd->spans[i + 1].language) {
+ i++;
+ }
+ int r_end = sd->spans[i].end;
+ UBreakIterator *bi = ubrk_open(UBRK_LINE, language.ascii().get_data(), data + _convert_pos_inv(sd, r_start), _convert_pos_inv(sd, r_end - r_start), &err);
+ if (U_FAILURE(err)) {
+ //No data loaded - use fallback.
+ for (int j = r_start; j < r_end; j++) {
+ char32_t c = sd->text[j - sd->start];
+ if (is_whitespace(c)) {
+ breaks[j] = false;
+ }
+ if (is_linebreak(c)) {
+ breaks[j] = true;
+ }
+ }
+ } else {
+ while (ubrk_next(bi) != UBRK_DONE) {
+ int pos = _convert_pos(sd, ubrk_current(bi)) + r_start - 1;
+ if (pos != r_end) {
+ if ((ubrk_getRuleStatus(bi) >= UBRK_LINE_HARD) && (ubrk_getRuleStatus(bi) < UBRK_LINE_HARD_LIMIT)) {
+ breaks[pos] = true;
+ } else if ((ubrk_getRuleStatus(bi) >= UBRK_LINE_SOFT) && (ubrk_getRuleStatus(bi) < UBRK_LINE_SOFT_LIMIT)) {
+ breaks[pos] = false;
+ }
+ }
+ }
+ }
+ ubrk_close(bi);
+ i++;
+ }
+
+ sd->sort_valid = false;
+ sd->glyphs_logical.clear();
+ int sd_size = sd->glyphs.size();
+ const char32_t *ch = sd->text.ptr();
+ Glyph *sd_glyphs = sd->glyphs.ptrw();
+
+ for (i = 0; i < sd_size; i++) {
+ if (sd_glyphs[i].count > 0) {
+ char32_t c = ch[sd_glyphs[i].start - sd->start];
+ if (c == 0xfffc) {
+ continue;
+ }
+ if (c == 0x0009 || c == 0x000b) {
+ sd_glyphs[i].flags |= GRAPHEME_IS_TAB;
+ }
+ if (is_whitespace(c)) {
+ sd_glyphs[i].flags |= GRAPHEME_IS_SPACE;
+ }
+ if (u_ispunct(c)) {
+ sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION;
+ }
+ if (breaks.has(sd->glyphs[i].start)) {
+ if (breaks[sd->glyphs[i].start]) {
+ sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_HARD;
+ } else {
+ if (is_whitespace(c)) {
+ sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT;
+ } else {
+ TextServer::Glyph gl;
+ gl.start = sd_glyphs[i].start;
+ gl.end = sd_glyphs[i].end;
+ gl.count = 1;
+ gl.font_rid = sd_glyphs[i].font_rid;
+ gl.font_size = sd_glyphs[i].font_size;
+ gl.flags = GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL;
+ sd->glyphs.insert(i + sd_glyphs[i].count, gl); // insert after
+
+ // Update write pointer and size.
+ sd_size = sd->glyphs.size();
+ sd_glyphs = sd->glyphs.ptrw();
+
+ i += sd_glyphs[i].count;
+ continue;
+ }
+ }
+ }
+
+ i += (sd_glyphs[i].count - 1);
+ }
+ }
+
+ sd->line_breaks_valid = true;
+
+ 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;
+ int8_t priority = 100;
+ int i = p_start;
+
+ char32_t pc = 0;
+
+ while ((p_end > p_start) && is_transparent(p_data[p_end - 1])) {
+ p_end--;
+ }
+
+ while (i < p_end) {
+ uint32_t c = p_data[i];
+
+ if (c == 0x0640) {
+ kashida_pos = i;
+ priority = 0;
+ }
+ if (priority >= 1 && i < p_end - 1) {
+ if (is_seen_sad(c) && (p_data[i + 1] != 0x200C)) {
+ kashida_pos = i;
+ priority = 1;
+ }
+ }
+ if (priority >= 2 && i > p_start) {
+ if (is_teh_marbuta(c) || is_dal(c) || (is_heh(c) && i == p_end - 1)) {
+ if (is_connected_to_prev(c, pc)) {
+ kashida_pos = i - 1;
+ priority = 2;
+ }
+ }
+ }
+ if (priority >= 3 && i > p_start) {
+ if (is_alef(c) || ((is_lam(c) || is_tah(c) || is_kaf(c) || is_gaf(c)) && i == p_end - 1)) {
+ if (is_connected_to_prev(c, pc)) {
+ kashida_pos = i - 1;
+ priority = 3;
+ }
+ }
+ }
+ if (priority >= 4 && i > p_start && i < p_end - 1) {
+ if (is_beh(c)) {
+ if (is_reh(p_data[i + 1]) || is_yeh(p_data[i + 1])) {
+ if (is_connected_to_prev(c, pc)) {
+ kashida_pos = i - 1;
+ priority = 4;
+ }
+ }
+ }
+ }
+ if (priority >= 5 && i > p_start) {
+ if (is_waw(c) || ((is_ain(c) || is_qaf(c) || is_feh(c)) && i == p_end - 1)) {
+ if (is_connected_to_prev(c, pc)) {
+ kashida_pos = i - 1;
+ priority = 5;
+ }
+ }
+ }
+ if (priority >= 6 && i > p_start) {
+ if (is_reh(c)) {
+ if (is_connected_to_prev(c, pc)) {
+ kashida_pos = i - 1;
+ priority = 6;
+ }
+ }
+ }
+ if (!is_transparent(c))
+ pc = c;
+ i++;
+ }
+
+ return kashida_pos;
+}
+
+bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, false);
+ if (!sd->valid) {
+ shaped_text_shape(p_shaped);
+ }
+ if (!sd->line_breaks_valid) {
+ shaped_text_update_breaks(p_shaped);
+ }
+
+ if (sd->justification_ops_valid) {
+ return true; // Noting to do.
+ }
+
+ const UChar *data = sd->utf16.ptr();
+ int32_t data_size = sd->utf16.length();
+
+ Map<int, bool> jstops;
+
+ // Use ICU word iterator and custom kashida detection.
+ UErrorCode err = U_ZERO_ERROR;
+ UBreakIterator *bi = ubrk_open(UBRK_WORD, "", data, data_size, &err);
+ if (U_FAILURE(err)) {
+ // No data - use fallback
+ int limit = 0;
+ for (int i = 0; i < sd->text.length(); i++) {
+ if (is_whitespace(data[i])) {
+ int ks = _generate_kashida_justification_opportunies(sd->text, limit, i) + sd->start;
+ if (ks != -1) {
+ jstops[ks] = true;
+ }
+ limit = i + 1;
+ }
+ }
+ int ks = _generate_kashida_justification_opportunies(sd->text, limit, sd->text.length()) + sd->start;
+ if (ks != -1) {
+ jstops[ks] = true;
+ }
+ } else {
+ int limit = 0;
+ while (ubrk_next(bi) != UBRK_DONE) {
+ if (ubrk_getRuleStatus(bi) != UBRK_WORD_NONE) {
+ int i = _convert_pos(sd, ubrk_current(bi));
+ jstops[i + sd->start] = false;
+ int ks = _generate_kashida_justification_opportunies(sd->text, limit, i);
+ if (ks != -1) {
+ jstops[ks + sd->start] = true;
+ }
+ limit = i;
+ }
+ }
+ ubrk_close(bi);
+ }
+
+ sd->sort_valid = false;
+ sd->glyphs_logical.clear();
+ int sd_size = sd->glyphs.size();
+
+ if (jstops.size() > 0) {
+ for (int i = 0; i < sd_size; i++) {
+ if (sd->glyphs[i].count > 0) {
+ if (jstops.has(sd->glyphs[i].start)) {
+ char32_t c = sd->text[sd->glyphs[i].start - sd->start];
+ if (c == 0xfffc) {
+ continue;
+ }
+ if (jstops[sd->glyphs[i].start]) {
+ if (c == 0x0640) {
+ sd->glyphs.write[i].flags |= GRAPHEME_IS_ELONGATION;
+ } else {
+ if (sd->glyphs[i].font_rid != RID()) {
+ TextServer::Glyph gl = _shape_single_glyph(sd, 0x0640, HB_SCRIPT_ARABIC, HB_DIRECTION_RTL, sd->glyphs[i].font_rid, sd->glyphs[i].font_size);
+ if ((gl.flags & GRAPHEME_IS_VALID) == GRAPHEME_IS_VALID) {
+ gl.start = sd->glyphs[i].start;
+ gl.end = sd->glyphs[i].end;
+ gl.repeat = 0;
+ gl.count = 1;
+ if (sd->orientation == ORIENTATION_HORIZONTAL) {
+ gl.y_off = sd->glyphs[i].y_off;
+ } else {
+ gl.x_off = sd->glyphs[i].x_off;
+ }
+ gl.flags |= GRAPHEME_IS_ELONGATION | GRAPHEME_IS_VIRTUAL;
+ sd->glyphs.insert(i, gl);
+ i++;
+ }
+ }
+ }
+ } else if (!is_whitespace(c)) {
+ TextServer::Glyph gl;
+ gl.start = sd->glyphs[i].start;
+ gl.end = sd->glyphs[i].end;
+ gl.count = 1;
+ gl.font_rid = sd->glyphs[i].font_rid;
+ gl.font_size = sd->glyphs[i].font_size;
+ gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_VIRTUAL;
+ sd->glyphs.insert(i + sd->glyphs[i].count, gl); // insert after
+ i += sd->glyphs[i].count;
+ continue;
+ }
+ }
+ }
+ }
+ }
+
+ sd->justification_ops_valid = true;
+ return sd->justification_ops_valid;
+}
+
+TextServer::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) {
+ FontDataAdvanced *fd = font_owner.getornull(p_font);
+ hb_font_t *hb_font = fd->get_hb_handle(p_font_size);
+
+ hb_buffer_clear_contents(p_sd->hb_buffer);
+ hb_buffer_set_direction(p_sd->hb_buffer, p_direction);
+ hb_buffer_set_flags(p_sd->hb_buffer, (hb_buffer_flags_t)(HB_BUFFER_FLAG_DEFAULT));
+ hb_buffer_set_script(p_sd->hb_buffer, p_script);
+ hb_buffer_add_utf32(p_sd->hb_buffer, (const uint32_t *)&p_char, 1, 0, 1);
+
+ hb_shape(hb_font, p_sd->hb_buffer, nullptr, 0);
+
+ unsigned int glyph_count = 0;
+ hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(p_sd->hb_buffer, &glyph_count);
+ hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(p_sd->hb_buffer, &glyph_count);
+
+ // Process glyphs.
+ TextServer::Glyph gl;
+
+ if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
+ gl.flags |= TextServer::GRAPHEME_IS_RTL;
+ }
+
+ gl.font_rid = p_font;
+ gl.font_size = p_font_size;
+
+ if (glyph_count > 0) {
+ if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
+ gl.advance = Math::round(glyph_pos[0].x_advance / (64.0 / fd->get_font_scale(p_font_size)));
+ } else {
+ gl.advance = -Math::round(glyph_pos[0].y_advance / (64.0 / fd->get_font_scale(p_font_size)));
+ }
+ gl.count = 1;
+
+ gl.index = glyph_info[0].codepoint;
+ gl.x_off = Math::round(glyph_pos[0].x_offset / (64.0 / fd->get_font_scale(p_font_size)));
+ gl.y_off = -Math::round(glyph_pos[0].y_offset / (64.0 / fd->get_font_scale(p_font_size)));
+
+ if ((glyph_info[0].codepoint != 0) || !u_isgraph(p_char)) {
+ gl.flags |= GRAPHEME_IS_VALID;
+ }
+ }
+ return gl;
+}
+
+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) {
+ FontDataAdvanced *fd = nullptr;
+ if (p_fb_index < p_fonts.size()) {
+ fd = font_owner.getornull(p_fonts[p_fb_index]);
+ }
+
+ int fs = p_sd->spans[p_span].font_size;
+ if (fd == nullptr) {
+ // Add fallback glyphs
+ for (int i = p_start; i < p_end; i++) {
+ if (p_sd->preserve_invalid || (p_sd->preserve_control && is_control(p_sd->text[i]))) {
+ TextServer::Glyph gl;
+ gl.start = i;
+ gl.end = i + 1;
+ gl.count = 1;
+ gl.index = p_sd->text[i];
+ gl.font_size = fs;
+ gl.font_rid = RID();
+ if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
+ gl.flags |= TextServer::GRAPHEME_IS_RTL;
+ }
+ if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
+ gl.advance = get_hex_code_box_size(fs, gl.index).x;
+ p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).y * 0.75f));
+ p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).y * 0.25f));
+ } 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->width += gl.advance;
+
+ p_sd->glyphs.push_back(gl);
+ }
+ }
+ return;
+ }
+
+ hb_font_t *hb_font = fd->get_hb_handle(fs);
+ ERR_FAIL_COND(hb_font == nullptr);
+
+ hb_buffer_clear_contents(p_sd->hb_buffer);
+ hb_buffer_set_direction(p_sd->hb_buffer, p_direction);
+ if (p_sd->preserve_control) {
+ hb_buffer_set_flags(p_sd->hb_buffer, (hb_buffer_flags_t)(HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES | (p_start == 0 ? HB_BUFFER_FLAG_BOT : 0) | (p_end == p_sd->text.length() ? HB_BUFFER_FLAG_EOT : 0)));
+ } else {
+ hb_buffer_set_flags(p_sd->hb_buffer, (hb_buffer_flags_t)(HB_BUFFER_FLAG_DEFAULT | (p_start == 0 ? HB_BUFFER_FLAG_BOT : 0) | (p_end == p_sd->text.length() ? HB_BUFFER_FLAG_EOT : 0)));
+ }
+ hb_buffer_set_script(p_sd->hb_buffer, p_script);
+
+ if (p_sd->spans[p_span].language != String()) {
+ hb_language_t lang = hb_language_from_string(p_sd->spans[p_span].language.ascii().get_data(), -1);
+ hb_buffer_set_language(p_sd->hb_buffer, lang);
+ }
+
+ hb_buffer_add_utf32(p_sd->hb_buffer, (const uint32_t *)p_sd->text.ptr(), p_sd->text.length(), p_start, p_end - p_start);
+
+ Vector<hb_feature_t> ftrs;
+ for (const Variant *ftr = p_sd->spans[p_span].features.next(nullptr); ftr != nullptr; ftr = p_sd->spans[p_span].features.next(ftr)) {
+ double values = p_sd->spans[p_span].features[*ftr];
+ if (values >= 0) {
+ hb_feature_t feature;
+ feature.tag = *ftr;
+ feature.value = values;
+ feature.start = 0;
+ feature.end = -1;
+ ftrs.push_back(feature);
+ }
+ }
+ hb_shape(hb_font, p_sd->hb_buffer, ftrs.is_empty() ? nullptr : &ftrs[0], ftrs.size());
+
+ unsigned int glyph_count = 0;
+ hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(p_sd->hb_buffer, &glyph_count);
+ hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(p_sd->hb_buffer, &glyph_count);
+
+ // Process glyphs.
+ if (glyph_count > 0) {
+ TextServer::Glyph *w = (TextServer::Glyph *)memalloc(glyph_count * sizeof(TextServer::Glyph));
+
+ int end = (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) ? p_end : 0;
+ uint32_t last_cluster_id = UINT32_MAX;
+ unsigned int last_cluster_index = 0;
+ bool last_cluster_valid = true;
+
+ for (unsigned int i = 0; i < glyph_count; i++) {
+ if ((i > 0) && (last_cluster_id != glyph_info[i].cluster)) {
+ if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
+ end = w[last_cluster_index].start;
+ } else {
+ for (unsigned int j = last_cluster_index; j < i; j++) {
+ w[j].end = glyph_info[i].cluster;
+ }
+ }
+ if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
+ w[last_cluster_index].flags |= TextServer::GRAPHEME_IS_RTL;
+ }
+ if (last_cluster_valid) {
+ w[last_cluster_index].flags |= GRAPHEME_IS_VALID;
+ }
+ w[last_cluster_index].count = i - last_cluster_index;
+ last_cluster_index = i;
+ last_cluster_valid = true;
+ }
+
+ last_cluster_id = glyph_info[i].cluster;
+
+ TextServer::Glyph &gl = w[i];
+ gl = TextServer::Glyph();
+
+ gl.start = glyph_info[i].cluster;
+ gl.end = end;
+ gl.count = 0;
+
+ gl.font_rid = p_fonts[p_fb_index];
+ gl.font_size = fs;
+
+ gl.index = glyph_info[i].codepoint;
+ if (gl.index != 0) {
+ if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
+ gl.advance = Math::round(glyph_pos[i].x_advance / (64.0 / fd->get_font_scale(fs)));
+ } else {
+ gl.advance = -Math::round(glyph_pos[i].y_advance / (64.0 / fd->get_font_scale(fs)));
+ }
+ gl.x_off = Math::round(glyph_pos[i].x_offset / (64.0 / fd->get_font_scale(fs)));
+ gl.y_off = -Math::round(glyph_pos[i].y_offset / (64.0 / fd->get_font_scale(fs)));
+ }
+
+ if (p_sd->preserve_control) {
+ last_cluster_valid = last_cluster_valid && ((glyph_info[i].codepoint != 0) || is_whitespace(p_sd->text[glyph_info[i].cluster]) || is_linebreak(p_sd->text[glyph_info[i].cluster]));
+ } else {
+ last_cluster_valid = last_cluster_valid && ((glyph_info[i].codepoint != 0) || !u_isgraph(p_sd->text[glyph_info[i].cluster]));
+ }
+ }
+ if (p_direction == HB_DIRECTION_LTR || p_direction == HB_DIRECTION_TTB) {
+ for (unsigned int j = last_cluster_index; j < glyph_count; j++) {
+ w[j].end = p_end;
+ }
+ }
+ w[last_cluster_index].count = glyph_count - last_cluster_index;
+ if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
+ w[last_cluster_index].flags |= TextServer::GRAPHEME_IS_RTL;
+ }
+ if (last_cluster_valid) {
+ w[last_cluster_index].flags |= GRAPHEME_IS_VALID;
+ }
+
+ //Fallback.
+ int failed_subrun_start = p_end + 1;
+ int failed_subrun_end = p_start;
+
+ for (unsigned int i = 0; i < glyph_count; i++) {
+ if ((w[i].flags & GRAPHEME_IS_VALID) == GRAPHEME_IS_VALID) {
+ if (failed_subrun_start != p_end + 1) {
+ _shape_run(p_sd, failed_subrun_start, failed_subrun_end, p_script, p_direction, p_fonts, p_span, p_fb_index + 1);
+ failed_subrun_start = p_end + 1;
+ failed_subrun_end = p_start;
+ }
+ for (int j = 0; j < w[i].count; j++) {
+ if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
+ 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 {
+ p_sd->ascent = MAX(p_sd->ascent, Math::round(fd->get_advance(w[i + j].index, fs).x * 0.5));
+ p_sd->descent = MAX(p_sd->descent, Math::round(fd->get_advance(w[i + j].index, fs).x * 0.5));
+ }
+ p_sd->width += w[i + j].advance;
+ p_sd->glyphs.push_back(w[i + j]);
+ }
+ } else {
+ if (failed_subrun_start >= w[i].start) {
+ failed_subrun_start = w[i].start;
+ }
+ if (failed_subrun_end <= w[i].end) {
+ failed_subrun_end = w[i].end;
+ }
+ }
+ i += w[i].count - 1;
+ }
+ memfree(w);
+ if (failed_subrun_start != p_end + 1) {
+ _shape_run(p_sd, failed_subrun_start, failed_subrun_end, p_script, p_direction, p_fonts, p_span, p_fb_index + 1);
+ }
+ p_sd->ascent = MAX(p_sd->ascent, fd->get_ascent(fs));
+ p_sd->descent = MAX(p_sd->descent, fd->get_descent(fs));
+ p_sd->upos = MAX(p_sd->upos, fd->get_underline_position(fs));
+ p_sd->uthk = MAX(p_sd->uthk, fd->get_underline_thickness(fs));
+ }
+}
+
+bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, false);
+
+ if (sd->valid) {
+ return true;
+ }
+
+ if (sd->parent != RID()) {
+ full_copy(sd);
+ }
+ invalidate(sd);
+
+ if (sd->text.length() == 0) {
+ sd->valid = true;
+ return true;
+ }
+
+ sd->utf16 = sd->text.utf16();
+ const UChar *data = sd->utf16.ptr();
+
+ // Create script iterator.
+ if (sd->script_iter == nullptr) {
+ sd->script_iter = memnew(ScriptIterator(sd->text, 0, sd->text.length()));
+ }
+
+ if (sd->bidi_override.is_empty()) {
+ sd->bidi_override.push_back(Vector2i(0, sd->end));
+ }
+
+ for (int ov = 0; ov < sd->bidi_override.size(); ov++) {
+ // Create BiDi iterator.
+ int start = _convert_pos_inv(sd, sd->bidi_override[ov].x);
+ int end = _convert_pos_inv(sd, sd->bidi_override[ov].y);
+
+ ERR_FAIL_COND_V_MSG((start < 0 || end - start > sd->utf16.length()), false, "Invalid BiDi override range.");
+
+ UErrorCode err = U_ZERO_ERROR;
+ UBiDi *bidi_iter = ubidi_openSized(end, 0, &err);
+ ERR_FAIL_COND_V_MSG(U_FAILURE(err), false, u_errorName(err));
+
+ switch (sd->direction) {
+ case DIRECTION_LTR: {
+ ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_LTR, nullptr, &err);
+ sd->para_direction = DIRECTION_LTR;
+ } break;
+ case DIRECTION_RTL: {
+ ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_RTL, nullptr, &err);
+ sd->para_direction = DIRECTION_RTL;
+ } break;
+ case DIRECTION_AUTO: {
+ UBiDiDirection direction = ubidi_getBaseDirection(data + start, end - start);
+ if (direction != UBIDI_NEUTRAL) {
+ ubidi_setPara(bidi_iter, data + start, end - start, direction, nullptr, &err);
+ sd->para_direction = (direction == UBIDI_RTL) ? DIRECTION_RTL : DIRECTION_LTR;
+ } else {
+ ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_DEFAULT_LTR, nullptr, &err);
+ sd->para_direction = DIRECTION_LTR;
+ }
+ } break;
+ }
+ ERR_FAIL_COND_V_MSG(U_FAILURE(err), false, u_errorName(err));
+ sd->bidi_iter.push_back(bidi_iter);
+
+ err = U_ZERO_ERROR;
+ int bidi_run_count = ubidi_countRuns(bidi_iter, &err);
+ ERR_FAIL_COND_V_MSG(U_FAILURE(err), false, u_errorName(err));
+ for (int i = 0; i < bidi_run_count; i++) {
+ int32_t _bidi_run_start = 0;
+ int32_t _bidi_run_length = 0;
+ hb_direction_t bidi_run_direction = HB_DIRECTION_INVALID;
+ bool is_rtl = (ubidi_getVisualRun(bidi_iter, i, &_bidi_run_start, &_bidi_run_length) == UBIDI_LTR);
+ switch (sd->orientation) {
+ case ORIENTATION_HORIZONTAL: {
+ if (is_rtl) {
+ bidi_run_direction = HB_DIRECTION_LTR;
+ } else {
+ bidi_run_direction = HB_DIRECTION_RTL;
+ }
+ } break;
+ case ORIENTATION_VERTICAL: {
+ if (is_rtl) {
+ bidi_run_direction = HB_DIRECTION_TTB;
+ } else {
+ bidi_run_direction = HB_DIRECTION_BTT;
+ }
+ }
+ }
+
+ int32_t bidi_run_start = _convert_pos(sd, sd->bidi_override[ov].x + _bidi_run_start);
+ int32_t bidi_run_end = _convert_pos(sd, sd->bidi_override[ov].x + _bidi_run_start + _bidi_run_length);
+
+ // Shape runs.
+
+ int scr_from = (is_rtl) ? 0 : sd->script_iter->script_ranges.size() - 1;
+ int scr_to = (is_rtl) ? sd->script_iter->script_ranges.size() : -1;
+ int scr_delta = (is_rtl) ? +1 : -1;
+
+ for (int j = scr_from; j != scr_to; j += scr_delta) {
+ if ((sd->script_iter->script_ranges[j].start < bidi_run_end) && (sd->script_iter->script_ranges[j].end > bidi_run_start)) {
+ int32_t script_run_start = MAX(sd->script_iter->script_ranges[j].start, bidi_run_start);
+ int32_t script_run_end = MIN(sd->script_iter->script_ranges[j].end, bidi_run_end);
+ char scr_buffer[5] = { 0, 0, 0, 0, 0 };
+ hb_tag_to_string(hb_script_to_iso15924_tag(sd->script_iter->script_ranges[j].script), scr_buffer);
+ String script = String(scr_buffer);
+
+ int spn_from = (is_rtl) ? 0 : sd->spans.size() - 1;
+ int spn_to = (is_rtl) ? sd->spans.size() : -1;
+ int spn_delta = (is_rtl) ? +1 : -1;
+
+ for (int k = spn_from; k != spn_to; k += spn_delta) {
+ const ShapedTextDataAdvanced::Span &span = sd->spans[k];
+ if (span.start >= script_run_end || span.end <= script_run_start) {
+ continue;
+ }
+ if (span.embedded_key != Variant()) {
+ // Embedded object.
+ if (sd->orientation == ORIENTATION_HORIZONTAL) {
+ sd->objects[span.embedded_key].rect.position.x = sd->width;
+ sd->width += sd->objects[span.embedded_key].rect.size.x;
+ switch (sd->objects[span.embedded_key].inline_align) {
+ case VALIGN_TOP: {
+ sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y);
+ } break;
+ case VALIGN_CENTER: {
+ sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2));
+ sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2));
+ } break;
+ case VALIGN_BOTTOM: {
+ sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y);
+ } break;
+ }
+ } else {
+ sd->objects[span.embedded_key].rect.position.y = sd->width;
+ sd->width += sd->objects[span.embedded_key].rect.size.y;
+ switch (sd->objects[span.embedded_key].inline_align) {
+ case VALIGN_TOP: {
+ sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x);
+ } break;
+ case VALIGN_CENTER: {
+ sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2));
+ sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2));
+ } break;
+ case VALIGN_BOTTOM: {
+ sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x);
+ } break;
+ }
+ }
+ Glyph gl;
+ gl.start = span.start;
+ gl.end = span.end;
+ gl.count = 1;
+ gl.flags = GRAPHEME_IS_VALID | GRAPHEME_IS_VIRTUAL;
+ if (sd->orientation == ORIENTATION_HORIZONTAL) {
+ gl.advance = sd->objects[span.embedded_key].rect.size.x;
+ } else {
+ gl.advance = sd->objects[span.embedded_key].rect.size.y;
+ }
+ sd->glyphs.push_back(gl);
+ } else {
+ Vector<RID> fonts;
+ // Push fonts with the language and script support first.
+ for (int l = 0; l < span.fonts.size(); l++) {
+ if ((font_is_language_supported(span.fonts[l], span.language)) && (font_is_script_supported(span.fonts[l], script))) {
+ fonts.push_back(sd->spans[k].fonts[l]);
+ }
+ }
+ // Push fonts with the script support.
+ for (int l = 0; l < sd->spans[k].fonts.size(); l++) {
+ if (!(font_is_language_supported(span.fonts[l], span.language)) && (font_is_script_supported(span.fonts[l], script))) {
+ fonts.push_back(sd->spans[k].fonts[l]);
+ }
+ }
+ // Push the rest valid fonts.
+ for (int l = 0; l < sd->spans[k].fonts.size(); l++) {
+ if (!(font_is_language_supported(span.fonts[l], span.language)) && !(font_is_script_supported(span.fonts[l], script))) {
+ fonts.push_back(sd->spans[k].fonts[l]);
+ }
+ }
+ _shape_run(sd, MAX(sd->spans[k].start, script_run_start), MIN(sd->spans[k].end, script_run_end), sd->script_iter->script_ranges[j].script, bidi_run_direction, fonts, k, 0);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Align embedded objects to baseline.
+ for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
+ if (sd->orientation == ORIENTATION_HORIZONTAL) {
+ switch (E->get().inline_align) {
+ case VALIGN_TOP: {
+ E->get().rect.position.y = -sd->ascent;
+ } break;
+ case VALIGN_CENTER: {
+ E->get().rect.position.y = -(E->get().rect.size.y / 2);
+ } break;
+ case VALIGN_BOTTOM: {
+ E->get().rect.position.y = sd->descent - E->get().rect.size.y;
+ } break;
+ }
+ } else {
+ switch (E->get().inline_align) {
+ case VALIGN_TOP: {
+ E->get().rect.position.x = -sd->ascent;
+ } break;
+ case VALIGN_CENTER: {
+ E->get().rect.position.x = -(E->get().rect.size.x / 2);
+ } break;
+ case VALIGN_BOTTOM: {
+ E->get().rect.position.x = sd->descent - E->get().rect.size.x;
+ } break;
+ }
+ }
+ }
+
+ sd->valid = true;
+ return sd->valid;
+}
+
+bool TextServerAdvanced::shaped_text_is_ready(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, false);
+ return sd->valid;
+}
+
+Vector<TextServer::Glyph> TextServerAdvanced::shaped_text_get_glyphs(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, Vector<TextServer::Glyph>());
+ if (!sd->valid) {
+ const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
+ }
+ return sd->glyphs;
+}
+
+Vector2i TextServerAdvanced::shaped_text_get_range(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, Vector2i());
+ return Vector2(sd->start, sd->end);
+}
+
+Vector<TextServer::Glyph> TextServerAdvanced::shaped_text_sort_logical(RID p_shaped) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, Vector<TextServer::Glyph>());
+ if (!sd->valid) {
+ const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
+ }
+
+ if (!sd->sort_valid) {
+ sd->glyphs_logical = sd->glyphs;
+ sd->glyphs_logical.sort_custom<TextServer::GlyphCompare>();
+ sd->sort_valid = true;
+ }
+
+ return sd->glyphs_logical;
+}
+
+Array TextServerAdvanced::shaped_text_get_objects(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ Array ret;
+ const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, ret);
+ for (const Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
+ ret.push_back(E->key());
+ }
+
+ return ret;
+}
+
+Rect2 TextServerAdvanced::shaped_text_get_object_rect(RID p_shaped, Variant p_key) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, Rect2());
+ ERR_FAIL_COND_V(!sd->objects.has(p_key), Rect2());
+ if (!sd->valid) {
+ const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
+ }
+ return sd->objects[p_key].rect;
+}
+
+Size2 TextServerAdvanced::shaped_text_get_size(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, Size2());
+ if (!sd->valid) {
+ const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
+ }
+ if (sd->orientation == TextServer::ORIENTATION_HORIZONTAL) {
+ return Size2(sd->width, sd->ascent + sd->descent);
+ } else {
+ return Size2(sd->ascent + sd->descent, sd->width);
+ }
+}
+
+float TextServerAdvanced::shaped_text_get_ascent(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, 0.f);
+ if (!sd->valid) {
+ const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
+ }
+ return sd->ascent;
+}
+
+float TextServerAdvanced::shaped_text_get_descent(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, 0.f);
+ if (!sd->valid) {
+ const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
+ }
+ return sd->descent;
+}
+
+float TextServerAdvanced::shaped_text_get_width(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, 0.f);
+ if (!sd->valid) {
+ const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
+ }
+ return sd->width;
+}
+
+float TextServerAdvanced::shaped_text_get_underline_position(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, 0.f);
+ if (!sd->valid) {
+ const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
+ }
+
+ return sd->upos;
+}
+
+float TextServerAdvanced::shaped_text_get_underline_thickness(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, 0.f);
+ if (!sd->valid) {
+ const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
+ }
+
+ return sd->uthk;
+}
+
+struct num_system_data {
+ String lang;
+ String digits;
+ String percent_sign;
+ String exp;
+};
+
+static num_system_data num_systems[]{
+ { "ar,ar_AR,ar_BH,ar_DJ,ar_EG,ar_ER,ar_IL,ar_IQ,ar_JO,ar_KM,ar_KW,ar_LB,ar_MR,ar_OM,ar_PS,ar_QA,ar_SA,ar_SD,ar_SO,ar_SS,ar_SY,ar_TD,ar_YE", U"٠١٢٣٤٥٦٧٨٩٫", U"٪", U"اس" },
+ { "fa,ks,pa_Arab,ps,ug,ur_IN,ur,uz_Arab", U"۰۱۲۳۴۵۶۷۸۹٫", U"٪", U"اس" },
+ { "as,bn,mni", U"০১২৩৪৫৬৭৮৯.", U"%", U"e" },
+ { "mr,ne", U"०१२३४५६७८९.", U"%", U"e" },
+ { "dz", U"༠༡༢༣༤༥༦༧༨༩.", U"%", U"e" },
+ { "sat", U"᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙.", U"%", U"e" },
+ { "my", U"၀၁၂၃၄၅၆၇၈၉.", U"%", U"e" },
+ { String(), String(), String(), String() },
+};
+
+String TextServerAdvanced::format_number(const String &p_string, const String &p_language) const {
+ _THREAD_SAFE_METHOD_
+ String lang = (p_language == "") ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
+
+ String res = p_string;
+ for (int i = 0; num_systems[i].lang != String(); i++) {
+ Vector<String> langs = num_systems[i].lang.split(",");
+ if (langs.has(lang)) {
+ if (num_systems[i].digits == String()) {
+ return p_string;
+ }
+ 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++) {
+ if (data[j] >= 0x30 && data[j] <= 0x39) {
+ data[j] = num_systems[i].digits[data[j] - 0x30];
+ } else if (data[j] == '.' || data[j] == ',') {
+ data[j] = num_systems[i].digits[10];
+ }
+ }
+ break;
+ }
+ }
+ return res;
+}
+
+String TextServerAdvanced::parse_number(const String &p_string, const String &p_language) const {
+ _THREAD_SAFE_METHOD_
+ String lang = (p_language == "") ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
+
+ String res = p_string;
+ for (int i = 0; num_systems[i].lang != String(); i++) {
+ Vector<String> langs = num_systems[i].lang.split(",");
+ if (langs.has(lang)) {
+ if (num_systems[i].digits == String()) {
+ return p_string;
+ }
+ res.replace(num_systems[i].exp, "e");
+ char32_t *data = res.ptrw();
+ for (int j = 0; j < res.size(); j++) {
+ if (data[j] == num_systems[i].digits[10]) {
+ data[j] = '.';
+ } else {
+ for (int k = 0; k < 10; k++) {
+ if (data[j] == num_systems[i].digits[k]) {
+ data[j] = 0x30 + k;
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ return res;
+}
+
+String TextServerAdvanced::percent_sign(const String &p_language) const {
+ _THREAD_SAFE_METHOD_
+ String lang = (p_language == "") ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
+
+ for (int i = 0; num_systems[i].lang != String(); i++) {
+ Vector<String> langs = num_systems[i].lang.split(",");
+ if (langs.has(lang)) {
+ if (num_systems[i].percent_sign == String()) {
+ return "%";
+ }
+ return num_systems[i].percent_sign;
+ }
+ }
+ return "%";
+}
+
+TextServer *TextServerAdvanced::create_func(Error &r_error, void *p_user_data) {
+ r_error = OK;
+ return memnew(TextServerAdvanced());
+}
+
+void TextServerAdvanced::register_server() {
+ TextServerManager::register_create_function(interface_name, interface_features, create_func, nullptr);
+}
+
+TextServerAdvanced::TextServerAdvanced() {
+ hb_bmp_create_font_funcs();
+}
+
+TextServerAdvanced::~TextServerAdvanced() {
+ hb_bmp_free_font_funcs();
+ 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
new file mode 100644
index 0000000000..89fae477f9
--- /dev/null
+++ b/modules/text_server_adv/text_server_adv.h
@@ -0,0 +1,248 @@
+/*************************************************************************/
+/* text_server_adv.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEXT_SERVER_ADV_H
+#define TEXT_SERVER_ADV_H
+
+/*************************************************************************/
+/* ICU/HarfBuzz/Graphite backed Text Server implementation with BiDi, */
+/* shaping and advanced font features support. */
+/*************************************************************************/
+
+#include "servers/text_server.h"
+
+#include "core/templates/rid_owner.h"
+#include "scene/resources/texture.h"
+#include "script_iterator.h"
+
+#include <unicode/ubidi.h>
+#include <unicode/ubrk.h>
+#include <unicode/uchar.h>
+#include <unicode/uclean.h>
+#include <unicode/udata.h>
+#include <unicode/uiter.h>
+#include <unicode/uloc.h>
+#include <unicode/uscript.h>
+#include <unicode/ustring.h>
+#include <unicode/utypes.h>
+
+#include <hb-icu.h>
+#include <hb.h>
+
+#include "font_adv.h"
+
+class TextServerAdvanced : public TextServer {
+ GDCLASS(TextServerAdvanced, TextServer);
+ _THREAD_SAFE_CLASS_
+
+ static String interface_name;
+ static uint32_t interface_features;
+
+ uint8_t *icu_data = nullptr;
+
+ struct ShapedTextDataAdvanced : public ShapedTextData {
+ /* Intermediate data */
+ Char16String utf16;
+ Vector<UBiDi *> bidi_iter;
+ Vector<Vector2i> bidi_override;
+ ScriptIterator *script_iter = nullptr;
+ hb_buffer_t *hb_buffer = nullptr;
+
+ ~ShapedTextDataAdvanced() {
+ for (int i = 0; i < bidi_iter.size(); i++) {
+ ubidi_close(bidi_iter[i]);
+ }
+ if (script_iter) {
+ memdelete(script_iter);
+ }
+ if (hb_buffer) {
+ hb_buffer_destroy(hb_buffer);
+ }
+ }
+ };
+
+ float oversampling = 1.f;
+ mutable RID_PtrOwner<FontDataAdvanced> font_owner;
+ mutable RID_PtrOwner<ShapedTextDataAdvanced> shaped_owner;
+
+ int _convert_pos(const ShapedTextDataAdvanced *p_sd, int p_pos) const;
+ int _convert_pos_inv(const ShapedTextDataAdvanced *p_sd, int p_pos) 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);
+ TextServer::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);
+
+protected:
+ static void _bind_methods(){};
+
+ void full_copy(ShapedTextDataAdvanced *p_shaped);
+ void invalidate(ShapedTextDataAdvanced *p_shaped);
+
+public:
+ virtual bool has_feature(Feature p_feature) override;
+ virtual String get_name() const override;
+
+ virtual void free(RID p_rid) override;
+ virtual bool has(RID p_rid) override;
+ virtual bool load_support_data(const String &p_filename) override;
+
+#ifdef TOOLS_ENABLED
+ virtual String get_support_data_filename() override { return _MKSTR(ICU_DATA_NAME); };
+ virtual String get_support_data_info() override { return String("ICU break iteration data (") + _MKSTR(ICU_DATA_NAME) + String(")."); };
+ virtual bool save_support_data(const String &p_filename) override;
+#endif
+
+ virtual bool is_locale_right_to_left(const String &p_locale) override;
+
+ virtual int32_t name_to_tag(const String &p_name) override;
+ virtual String tag_to_name(int32_t p_tag) override;
+
+ /* Font interface */
+ virtual RID create_font_system(const String &p_name, int p_base_size = 16) override;
+ virtual RID create_font_resource(const String &p_filename, int p_base_size = 16) override;
+ virtual RID create_font_memory(const uint8_t *p_data, size_t p_size, const String &p_type, int p_base_size = 16) override;
+
+ virtual float font_get_height(RID p_font, int p_size) const override;
+ virtual float font_get_ascent(RID p_font, int p_size) const override;
+ virtual float font_get_descent(RID p_font, int p_size) const override;
+
+ virtual float font_get_underline_position(RID p_font, int p_size) const override;
+ virtual float font_get_underline_thickness(RID p_font, int p_size) const override;
+
+ virtual void font_set_antialiased(RID p_font, bool p_antialiased) override;
+ virtual bool font_get_antialiased(RID p_font) const override;
+
+ virtual Dictionary font_get_feature_list(RID p_font) const override;
+ virtual Dictionary font_get_variation_list(RID p_font) const override;
+
+ virtual void font_set_variation(RID p_font, const String &p_name, double p_value) override;
+ virtual double font_get_variation(RID p_font, const String &p_name) const override;
+
+ virtual void font_set_hinting(RID p_font, Hinting p_hinting) override;
+ virtual Hinting font_get_hinting(RID p_font) const override;
+
+ virtual void font_set_distance_field_hint(RID p_font, bool p_distance_field) override;
+ virtual bool font_get_distance_field_hint(RID p_font) const override;
+
+ virtual void font_set_force_autohinter(RID p_font, bool p_enabeld) override;
+ virtual bool font_get_force_autohinter(RID p_font) const override;
+
+ virtual bool font_has_char(RID p_font, char32_t p_char) const override;
+ virtual String font_get_supported_chars(RID p_font) const override;
+
+ virtual bool font_has_outline(RID p_font) const override;
+ virtual float font_get_base_size(RID p_font) const override;
+
+ virtual bool font_is_language_supported(RID p_font, const String &p_language) const override;
+ virtual void font_set_language_support_override(RID p_font, const String &p_language, bool p_supported) override;
+ virtual bool font_get_language_support_override(RID p_font, const String &p_language) override;
+ virtual void font_remove_language_support_override(RID p_font, const String &p_language) override;
+ Vector<String> font_get_language_support_overrides(RID p_font) override;
+
+ virtual bool font_is_script_supported(RID p_font, const String &p_script) const override;
+ virtual void font_set_script_support_override(RID p_font, const String &p_script, bool p_supported) override;
+ virtual bool font_get_script_support_override(RID p_font, const String &p_script) override;
+ virtual void font_remove_script_support_override(RID p_font, const String &p_script) override;
+ Vector<String> font_get_script_support_overrides(RID p_font) override;
+
+ virtual uint32_t font_get_glyph_index(RID p_font, char32_t p_char, char32_t p_variation_selector = 0x0000) const override;
+ virtual Vector2 font_get_glyph_advance(RID p_font, uint32_t p_index, int p_size) const override;
+ virtual Vector2 font_get_glyph_kerning(RID p_font, uint32_t p_index_a, uint32_t p_index_b, int p_size) const override;
+
+ virtual Vector2 font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
+ virtual Vector2 font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
+
+ virtual float font_get_oversampling() const override;
+ virtual void font_set_oversampling(float p_oversampling) override;
+
+ virtual Vector<String> get_system_fonts() const 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_set_direction(RID p_shaped, Direction p_direction = DIRECTION_AUTO) override;
+ virtual Direction shaped_text_get_direction(RID p_shaped) const override;
+
+ virtual void shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) 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(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(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(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 = "") override;
+ virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1) override;
+ virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER) 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 float shaped_text_fit_to_width(RID p_shaped, float p_width, uint8_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override;
+ virtual float shaped_text_tab_align(RID p_shaped, const Vector<float> &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_is_ready(RID p_shaped) const override;
+
+ virtual Vector<Glyph> shaped_text_get_glyphs(RID p_shaped) const override;
+
+ virtual Vector2i shaped_text_get_range(RID p_shaped) const override;
+
+ virtual Vector<Glyph> shaped_text_sort_logical(RID p_shaped) 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(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 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;
+
+ static TextServer *create_func(Error &r_error, void *p_user_data);
+ static void register_server();
+
+ TextServerAdvanced();
+ ~TextServerAdvanced();
+};
+
+#endif // TEXT_SERVER_ADV_H
diff --git a/modules/text_server_fb/SCsub b/modules/text_server_fb/SCsub
new file mode 100644
index 0000000000..03eccbe7bd
--- /dev/null
+++ b/modules/text_server_fb/SCsub
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+
+Import("env")
+Import("env_modules")
+
+env_text_server_fb = env_modules.Clone()
+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/bitmap_font_fb.cpp b/modules/text_server_fb/bitmap_font_fb.cpp
new file mode 100644
index 0000000000..6bc838bd6a
--- /dev/null
+++ b/modules/text_server_fb/bitmap_font_fb.cpp
@@ -0,0 +1,356 @@
+/*************************************************************************/
+/* bitmap_font_fb.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "bitmap_font_fb.h"
+
+Error BitmapFontDataFallback::load_from_file(const String &p_filename, int p_base_size) {
+ _THREAD_SAFE_METHOD_
+ //fnt format used by angelcode bmfont
+ //http://www.angelcode.com/products/bmfont/
+
+ FileAccess *f = FileAccess::open(p_filename, FileAccess::READ);
+ ERR_FAIL_COND_V_MSG(!f, ERR_FILE_NOT_FOUND, "Can't open font: " + p_filename + ".");
+
+ while (true) {
+ String line = f->get_line();
+
+ int delimiter = line.find(" ");
+ String type = line.substr(0, delimiter);
+ int pos = delimiter + 1;
+ Map<String, String> keys;
+
+ while (pos < line.size() && line[pos] == ' ') {
+ pos++;
+ }
+
+ while (pos < line.size()) {
+ int eq = line.find("=", pos);
+ if (eq == -1) {
+ break;
+ }
+ String key = line.substr(pos, eq - pos);
+ int end = -1;
+ String value;
+ if (line[eq + 1] == '"') {
+ end = line.find("\"", eq + 2);
+ if (end == -1) {
+ break;
+ }
+ value = line.substr(eq + 2, end - 1 - eq - 1);
+ pos = end + 1;
+ } else {
+ end = line.find(" ", eq + 1);
+ if (end == -1) {
+ end = line.size();
+ }
+ value = line.substr(eq + 1, end - eq);
+ pos = end;
+ }
+
+ while (pos < line.size() && line[pos] == ' ') {
+ pos++;
+ }
+
+ keys[key] = value;
+ }
+
+ if (type == "info") {
+ if (keys.has("size")) {
+ base_size = keys["size"].to_int();
+ }
+ } else if (type == "common") {
+ if (keys.has("lineHeight")) {
+ height = keys["lineHeight"].to_int();
+ }
+ if (keys.has("base")) {
+ ascent = keys["base"].to_int();
+ }
+ } else if (type == "page") {
+ if (keys.has("file")) {
+ String base_dir = p_filename.get_base_dir();
+ String file = base_dir.plus_file(keys["file"]);
+ if (RenderingServer::get_singleton() != nullptr) {
+ Ref<Texture2D> tex = ResourceLoader::load(file);
+ if (tex.is_null()) {
+ ERR_PRINT("Can't load font texture!");
+ } else {
+ ERR_FAIL_COND_V_MSG(tex.is_null(), ERR_FILE_CANT_READ, "It's not a reference to a valid Texture object.");
+ textures.push_back(tex);
+ }
+ }
+ }
+ } else if (type == "char") {
+ Character c;
+ char32_t idx = 0;
+ if (keys.has("id")) {
+ idx = keys["id"].to_int();
+ }
+ if (keys.has("x")) {
+ c.rect.position.x = keys["x"].to_int();
+ }
+ if (keys.has("y")) {
+ c.rect.position.y = keys["y"].to_int();
+ }
+ if (keys.has("width")) {
+ c.rect.size.width = keys["width"].to_int();
+ }
+ if (keys.has("height")) {
+ c.rect.size.height = keys["height"].to_int();
+ }
+ if (keys.has("xoffset")) {
+ c.align.x = keys["xoffset"].to_int();
+ }
+ if (keys.has("yoffset")) {
+ c.align.y = keys["yoffset"].to_int();
+ }
+ if (keys.has("page")) {
+ c.texture_idx = keys["page"].to_int();
+ }
+ if (keys.has("xadvance")) {
+ c.advance.x = keys["xadvance"].to_int();
+ }
+ if (keys.has("yadvance")) {
+ c.advance.y = keys["yadvance"].to_int();
+ }
+ if (c.advance.x < 0) {
+ c.advance.x = c.rect.size.width + 1;
+ }
+ if (c.advance.y < 0) {
+ c.advance.y = c.rect.size.height + 1;
+ }
+ char_map[idx] = c;
+ } else if (type == "kerning") {
+ KerningPairKey kpk;
+ float k = 0;
+ if (keys.has("first")) {
+ kpk.A = keys["first"].to_int();
+ }
+ if (keys.has("second")) {
+ kpk.B = keys["second"].to_int();
+ }
+ if (keys.has("amount")) {
+ k = keys["amount"].to_int();
+ }
+ kerning_map[kpk] = k;
+ }
+
+ if (f->eof_reached()) {
+ break;
+ }
+ }
+ if (base_size == 0) {
+ base_size = height;
+ }
+
+ valid = true;
+
+ memdelete(f);
+ return OK;
+}
+
+Error BitmapFontDataFallback::load_from_memory(const uint8_t *p_data, size_t p_size, int p_base_size) {
+ _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND_V(p_data == nullptr, ERR_CANT_CREATE);
+ ERR_FAIL_COND_V(p_size != sizeof(TextServer::BitmapFontData), ERR_CANT_CREATE);
+
+ const TextServer::BitmapFontData *data = (const TextServer::BitmapFontData *)p_data;
+
+ if (RenderingServer::get_singleton() != nullptr) {
+ Ref<Image> image = memnew(Image(data->img));
+ Ref<ImageTexture> tex = memnew(ImageTexture);
+ tex->create_from_image(image);
+
+ textures.push_back(tex);
+ }
+
+ for (int i = 0; i < data->charcount; i++) {
+ const int *c = &data->char_rects[i * 8];
+
+ Character chr;
+ chr.rect.position.x = c[1];
+ chr.rect.position.y = c[2];
+ chr.rect.size.x = c[3];
+ chr.rect.size.y = c[4];
+ if (c[7] < 0) {
+ chr.advance.x = c[3];
+ } else {
+ chr.advance.x = c[7];
+ }
+ chr.align = Vector2(c[6], c[5]);
+ char_map[c[0]] = chr;
+ }
+
+ for (int i = 0; i < data->kerning_count; i++) {
+ KerningPairKey kpk;
+ kpk.A = data->kernings[i * 3 + 0];
+ kpk.B = data->kernings[i * 3 + 1];
+
+ if (data->kernings[i * 3 + 2] == 0 && kerning_map.has(kpk)) {
+ kerning_map.erase(kpk);
+ } else {
+ kerning_map[kpk] = data->kernings[i * 3 + 2];
+ }
+ }
+
+ height = data->height;
+ ascent = data->ascent;
+
+ base_size = p_base_size;
+ if (base_size == 0) {
+ base_size = height;
+ }
+
+ valid = true;
+
+ return OK;
+}
+
+float BitmapFontDataFallback::get_height(int p_size) const {
+ ERR_FAIL_COND_V(!valid, 0.f);
+ return height * (float(p_size) / float(base_size));
+}
+
+float BitmapFontDataFallback::get_ascent(int p_size) const {
+ ERR_FAIL_COND_V(!valid, 0.f);
+ return ascent * (float(p_size) / float(base_size));
+}
+
+float BitmapFontDataFallback::get_descent(int p_size) const {
+ ERR_FAIL_COND_V(!valid, 0.f);
+ return (height - ascent) * (float(p_size) / float(base_size));
+}
+
+float BitmapFontDataFallback::get_underline_position(int p_size) const {
+ ERR_FAIL_COND_V(!valid, 0.f);
+ return 2 * (float(p_size) / float(base_size));
+}
+
+float BitmapFontDataFallback::get_underline_thickness(int p_size) const {
+ ERR_FAIL_COND_V(!valid, 0.f);
+ return 1 * (float(p_size) / float(base_size));
+}
+
+void BitmapFontDataFallback::set_distance_field_hint(bool p_distance_field) {
+ distance_field_hint = p_distance_field;
+}
+
+bool BitmapFontDataFallback::get_distance_field_hint() const {
+ return distance_field_hint;
+}
+
+float BitmapFontDataFallback::get_base_size() const {
+ return base_size;
+}
+
+bool BitmapFontDataFallback::has_char(char32_t p_char) const {
+ _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND_V(!valid, false);
+ return char_map.has(p_char);
+}
+
+String BitmapFontDataFallback::get_supported_chars() const {
+ _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND_V(!valid, String());
+ String chars;
+ const char32_t *k = nullptr;
+ while ((k = char_map.next(k))) {
+ chars += char32_t(*k);
+ }
+ return chars;
+}
+
+Vector2 BitmapFontDataFallback::get_advance(char32_t p_char, int p_size) const {
+ _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND_V(!valid, Vector2());
+ const Character *c = char_map.getptr(p_char);
+ ERR_FAIL_COND_V(c == nullptr, Vector2());
+
+ return c->advance * (float(p_size) / float(base_size));
+}
+
+Vector2 BitmapFontDataFallback::get_kerning(char32_t p_char, char32_t p_next, int p_size) const {
+ _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND_V(!valid, Vector2());
+ KerningPairKey kpk;
+ kpk.A = p_char;
+ kpk.B = p_next;
+
+ const Map<KerningPairKey, int>::Element *E = kerning_map.find(kpk);
+ if (E) {
+ return Vector2(-E->get() * (float(p_size) / float(base_size)), 0);
+ } else {
+ return Vector2();
+ }
+}
+
+Vector2 BitmapFontDataFallback::draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const {
+ _THREAD_SAFE_METHOD_
+ if (p_index == 0) {
+ return Vector2();
+ }
+ ERR_FAIL_COND_V(!valid, Vector2());
+ const Character *c = char_map.getptr(p_index);
+
+ ERR_FAIL_COND_V(c == nullptr, Vector2());
+ ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), Vector2());
+ if (c->texture_idx != -1) {
+ Point2i cpos = p_pos;
+ cpos += c->align * (float(p_size) / float(base_size));
+ cpos.y -= ascent * (float(p_size) / float(base_size));
+
+ if (RenderingServer::get_singleton() != nullptr) {
+ //if (distance_field_hint) { // Not implemented.
+ // RenderingServer::get_singleton()->canvas_item_set_distance_field_mode(p_canvas, true);
+ //}
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, c->rect.size * (float(p_size) / float(base_size))), textures[c->texture_idx]->get_rid(), c->rect, p_color, false, false);
+ //if (distance_field_hint) {
+ // RenderingServer::get_singleton()->canvas_item_set_distance_field_mode(p_canvas, false);
+ //}
+ }
+ }
+
+ return c->advance * (float(p_size) / float(base_size));
+}
+
+Vector2 BitmapFontDataFallback::draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const {
+ _THREAD_SAFE_METHOD_
+ if (p_index == 0) {
+ return Vector2();
+ }
+ ERR_FAIL_COND_V(!valid, Vector2());
+ const Character *c = char_map.getptr(p_index);
+
+ ERR_FAIL_COND_V(c == nullptr, Vector2());
+ ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), Vector2());
+
+ // Not supported, return advance for compatibility.
+
+ return c->advance * (float(p_size) / float(base_size));
+}
diff --git a/modules/text_server_fb/bitmap_font_fb.h b/modules/text_server_fb/bitmap_font_fb.h
new file mode 100644
index 0000000000..33401b85fa
--- /dev/null
+++ b/modules/text_server_fb/bitmap_font_fb.h
@@ -0,0 +1,107 @@
+/*************************************************************************/
+/* bitmap_font_fb.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef BITMAP_FONT_FALLBACK_H
+#define BITMAP_FONT_FALLBACK_H
+
+#include "font_fb.h"
+
+struct BitmapFontDataFallback : public FontDataFallback {
+ _THREAD_SAFE_CLASS_
+
+private:
+ Vector<Ref<Texture2D>> textures;
+
+ struct Character {
+ int texture_idx = 0;
+ Rect2 rect;
+ Vector2 align;
+ Vector2 advance = Vector2(-1, -1);
+ };
+
+ struct KerningPairKey {
+ union {
+ struct {
+ uint32_t A, B;
+ };
+
+ uint64_t pair = 0;
+ };
+
+ _FORCE_INLINE_ bool operator<(const KerningPairKey &p_r) const { return pair < p_r.pair; }
+ };
+
+ HashMap<char32_t, Character> char_map;
+ Map<KerningPairKey, int> kerning_map;
+
+ float height = 0.f;
+ float ascent = 0.f;
+ int base_size = 0;
+ bool distance_field_hint = false;
+
+public:
+ virtual void clear_cache() override{};
+
+ virtual Error load_from_file(const String &p_filename, int p_base_size) override;
+ virtual Error load_from_memory(const uint8_t *p_data, size_t p_size, int p_base_size) override;
+
+ virtual float get_height(int p_size) const override;
+ virtual float get_ascent(int p_size) const override;
+ virtual float get_descent(int p_size) const override;
+
+ virtual float get_underline_position(int p_size) const override;
+ virtual float get_underline_thickness(int p_size) const override;
+
+ virtual void set_antialiased(bool p_antialiased) override{};
+ virtual bool get_antialiased() const override { return false; };
+
+ virtual void set_hinting(TextServer::Hinting p_hinting) override{};
+ virtual TextServer::Hinting get_hinting() const override { return TextServer::HINTING_NONE; };
+
+ virtual void set_distance_field_hint(bool p_distance_field) override;
+ virtual bool get_distance_field_hint() const override;
+
+ virtual void set_force_autohinter(bool p_enabeld) override{};
+ virtual bool get_force_autohinter() const override { return false; };
+
+ virtual bool has_outline() const override { return false; };
+ virtual float get_base_size() const override;
+
+ virtual bool has_char(char32_t p_char) const override;
+ virtual String get_supported_chars() const override;
+
+ virtual Vector2 get_advance(char32_t p_char, int p_size) const override;
+ virtual Vector2 get_kerning(char32_t p_char, char32_t p_next, int p_size) const override;
+
+ virtual Vector2 draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const override;
+ virtual Vector2 draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const override;
+};
+
+#endif // BITMAP_FONT_FALLBACK_H
diff --git a/modules/text_server_fb/config.py b/modules/text_server_fb/config.py
new file mode 100644
index 0000000000..491377a369
--- /dev/null
+++ b/modules/text_server_fb/config.py
@@ -0,0 +1,11 @@
+def can_build(env, platform):
+ return env.module_check_dependencies("text_server_fb", ["freetype"])
+
+
+def configure(env):
+ pass
+
+
+def is_enabled():
+ # The module is disabled by default. Use module_text_server_fb_enabled=yes to enable it.
+ return False
diff --git a/modules/text_server_fb/dynamic_font_fb.cpp b/modules/text_server_fb/dynamic_font_fb.cpp
new file mode 100644
index 0000000000..df7756cbd0
--- /dev/null
+++ b/modules/text_server_fb/dynamic_font_fb.cpp
@@ -0,0 +1,685 @@
+/*************************************************************************/
+/* dynamic_font_fb.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "dynamic_font_fb.h"
+
+#include FT_STROKER_H
+#include FT_ADVANCES_H
+
+DynamicFontDataFallback::DataAtSize *DynamicFontDataFallback::get_data_for_size(int p_size, int p_outline_size) {
+ ERR_FAIL_COND_V(!valid, nullptr);
+ ERR_FAIL_COND_V(p_size < 0 || p_size > UINT16_MAX, nullptr);
+ ERR_FAIL_COND_V(p_outline_size < 0 || p_outline_size > UINT16_MAX, nullptr);
+
+ CacheID id;
+ id.size = p_size;
+ id.outline_size = p_outline_size;
+
+ DataAtSize *fds = nullptr;
+ Map<CacheID, DataAtSize *>::Element *E = nullptr;
+ if (p_outline_size != 0) {
+ E = size_cache_outline.find(id);
+ } else {
+ E = size_cache.find(id);
+ }
+
+ if (E != nullptr) {
+ fds = E->get();
+ } else {
+ if (font_mem == nullptr && font_path != String()) {
+ if (!font_mem_cache.is_empty()) {
+ font_mem = font_mem_cache.ptr();
+ font_mem_size = font_mem_cache.size();
+ } else {
+ FileAccess *f = FileAccess::open(font_path, FileAccess::READ);
+ if (!f) {
+ ERR_FAIL_V_MSG(nullptr, "Cannot open font file '" + font_path + "'.");
+ }
+
+ size_t len = f->get_len();
+ font_mem_cache.resize(len);
+ f->get_buffer(font_mem_cache.ptrw(), len);
+ font_mem = font_mem_cache.ptr();
+ font_mem_size = len;
+ f->close();
+ }
+ }
+
+ int error = 0;
+ fds = memnew(DataAtSize);
+ if (font_mem) {
+ memset(&fds->stream, 0, sizeof(FT_StreamRec));
+ fds->stream.base = (unsigned char *)font_mem;
+ fds->stream.size = font_mem_size;
+ fds->stream.pos = 0;
+
+ FT_Open_Args fargs;
+ memset(&fargs, 0, sizeof(FT_Open_Args));
+ fargs.memory_base = (unsigned char *)font_mem;
+ fargs.memory_size = font_mem_size;
+ fargs.flags = FT_OPEN_MEMORY;
+ fargs.stream = &fds->stream;
+ error = FT_Open_Face(library, &fargs, 0, &fds->face);
+
+ } else {
+ memdelete(fds);
+ ERR_FAIL_V_MSG(nullptr, "DynamicFont uninitialized.");
+ }
+
+ if (error == FT_Err_Unknown_File_Format) {
+ memdelete(fds);
+ ERR_FAIL_V_MSG(nullptr, "Unknown font format.");
+
+ } else if (error) {
+ memdelete(fds);
+ ERR_FAIL_V_MSG(nullptr, "Error loading font.");
+ }
+
+ oversampling = TS->font_get_oversampling();
+
+ if (FT_HAS_COLOR(fds->face) && fds->face->num_fixed_sizes > 0) {
+ int best_match = 0;
+ int diff = ABS(p_size - ((int64_t)fds->face->available_sizes[0].width));
+ fds->scale_color_font = float(p_size * oversampling) / fds->face->available_sizes[0].width;
+ for (int i = 1; i < fds->face->num_fixed_sizes; i++) {
+ int ndiff = ABS(p_size - ((int64_t)fds->face->available_sizes[i].width));
+ if (ndiff < diff) {
+ best_match = i;
+ diff = ndiff;
+ fds->scale_color_font = float(p_size * oversampling) / fds->face->available_sizes[i].width;
+ }
+ }
+ FT_Select_Size(fds->face, best_match);
+ } else {
+ FT_Set_Pixel_Sizes(fds->face, 0, p_size * oversampling);
+ }
+
+ fds->size = p_size;
+ fds->ascent = (fds->face->size->metrics.ascender / 64.0) / oversampling * fds->scale_color_font;
+ fds->descent = (-fds->face->size->metrics.descender / 64.0) / oversampling * fds->scale_color_font;
+ fds->underline_position = -fds->face->underline_position / 64.0 / oversampling * fds->scale_color_font;
+ fds->underline_thickness = fds->face->underline_thickness / 64.0 / oversampling * fds->scale_color_font;
+ if (p_outline_size != 0) {
+ size_cache_outline[id] = fds;
+ } else {
+ size_cache[id] = fds;
+ }
+ }
+
+ return fds;
+}
+
+DynamicFontDataFallback::TexturePosition DynamicFontDataFallback::find_texture_pos_for_glyph(DynamicFontDataFallback::DataAtSize *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height) {
+ TexturePosition ret;
+ ret.index = -1;
+
+ int mw = p_width;
+ int mh = p_height;
+
+ for (int i = 0; i < p_data->textures.size(); i++) {
+ const CharTexture &ct = p_data->textures[i];
+
+ if (RenderingServer::get_singleton() != nullptr) {
+ if (ct.texture->get_format() != p_image_format) {
+ continue;
+ }
+ }
+
+ if (mw > ct.texture_size || mh > ct.texture_size) { //too big for this texture
+ continue;
+ }
+
+ ret.y = 0x7FFFFFFF;
+ ret.x = 0;
+
+ for (int j = 0; j < ct.texture_size - mw; j++) {
+ int max_y = 0;
+
+ for (int k = j; k < j + mw; k++) {
+ int y = ct.offsets[k];
+ if (y > max_y) {
+ max_y = y;
+ }
+ }
+
+ if (max_y < ret.y) {
+ ret.y = max_y;
+ ret.x = j;
+ }
+ }
+
+ if (ret.y == 0x7FFFFFFF || ret.y + mh > ct.texture_size) {
+ continue; //fail, could not fit it here
+ }
+
+ ret.index = i;
+ break;
+ }
+
+ if (ret.index == -1) {
+ //could not find texture to fit, create one
+ ret.x = 0;
+ ret.y = 0;
+
+ int texsize = MAX(p_data->size * oversampling * 8, 256);
+ if (mw > texsize) {
+ texsize = mw; //special case, adapt to it?
+ }
+ if (mh > texsize) {
+ texsize = mh; //special case, adapt to it?
+ }
+
+ texsize = next_power_of_2(texsize);
+
+ texsize = MIN(texsize, 4096);
+
+ CharTexture tex;
+ tex.texture_size = texsize;
+ tex.imgdata.resize(texsize * texsize * p_color_size); //grayscale alpha
+
+ {
+ //zero texture
+ uint8_t *w = tex.imgdata.ptrw();
+ ERR_FAIL_COND_V(texsize * texsize * p_color_size > tex.imgdata.size(), ret);
+ // Initialize the texture to all-white pixels to prevent artifacts when the
+ // font is displayed at a non-default scale with filtering enabled.
+ if (p_color_size == 2) {
+ for (int i = 0; i < texsize * texsize * p_color_size; i += 2) { // FORMAT_LA8
+ w[i + 0] = 255;
+ w[i + 1] = 0;
+ }
+ } else if (p_color_size == 4) {
+ for (int i = 0; i < texsize * texsize * p_color_size; i += 4) { // FORMAT_RGBA8
+ w[i + 0] = 255;
+ w[i + 1] = 255;
+ w[i + 2] = 255;
+ w[i + 3] = 0;
+ }
+ } else {
+ ERR_FAIL_V(ret);
+ }
+ }
+ tex.offsets.resize(texsize);
+ for (int i = 0; i < texsize; i++) { //zero offsets
+ tex.offsets.write[i] = 0;
+ }
+
+ p_data->textures.push_back(tex);
+ ret.index = p_data->textures.size() - 1;
+ }
+
+ return ret;
+}
+
+DynamicFontDataFallback::Character DynamicFontDataFallback::Character::not_found() {
+ Character ch;
+ return ch;
+}
+
+DynamicFontDataFallback::Character DynamicFontDataFallback::bitmap_to_character(DynamicFontDataFallback::DataAtSize *p_data, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance) {
+ int w = bitmap.width;
+ int h = bitmap.rows;
+
+ int mw = w + rect_margin * 2;
+ int mh = h + rect_margin * 2;
+
+ ERR_FAIL_COND_V(mw > 4096, Character::not_found());
+ ERR_FAIL_COND_V(mh > 4096, Character::not_found());
+
+ 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;
+
+ TexturePosition tex_pos = find_texture_pos_for_glyph(p_data, color_size, require_format, mw, mh);
+ ERR_FAIL_COND_V(tex_pos.index < 0, Character::not_found());
+
+ //fit character in char texture
+
+ CharTexture &tex = p_data->textures.write[tex_pos.index];
+
+ {
+ uint8_t *wr = tex.imgdata.ptrw();
+
+ for (int i = 0; i < h; i++) {
+ for (int j = 0; j < w; j++) {
+ int ofs = ((i + tex_pos.y + rect_margin) * tex.texture_size + j + tex_pos.x + rect_margin) * color_size;
+ ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), Character::not_found());
+ switch (bitmap.pixel_mode) {
+ case FT_PIXEL_MODE_MONO: {
+ int byte = i * bitmap.pitch + (j >> 3);
+ int bit = 1 << (7 - (j % 8));
+ wr[ofs + 0] = 255; //grayscale as 1
+ wr[ofs + 1] = (bitmap.buffer[byte] & bit) ? 255 : 0;
+ } break;
+ case FT_PIXEL_MODE_GRAY:
+ wr[ofs + 0] = 255; //grayscale as 1
+ wr[ofs + 1] = bitmap.buffer[i * bitmap.pitch + j];
+ break;
+ case FT_PIXEL_MODE_BGRA: {
+ int ofs_color = i * bitmap.pitch + (j << 2);
+ wr[ofs + 2] = bitmap.buffer[ofs_color + 0];
+ wr[ofs + 1] = bitmap.buffer[ofs_color + 1];
+ wr[ofs + 0] = bitmap.buffer[ofs_color + 2];
+ wr[ofs + 3] = bitmap.buffer[ofs_color + 3];
+ } break;
+ // TODO: FT_PIXEL_MODE_LCD
+ default:
+ ERR_FAIL_V_MSG(Character::not_found(), "Font uses unsupported pixel format: " + itos(bitmap.pixel_mode) + ".");
+ break;
+ }
+ }
+ }
+ }
+
+ //blit to image and texture
+ {
+ if (RenderingServer::get_singleton() != nullptr) {
+ Ref<Image> img = memnew(Image(tex.texture_size, tex.texture_size, 0, require_format, tex.imgdata));
+
+ if (tex.texture.is_null()) {
+ tex.texture.instance();
+ tex.texture->create_from_image(img);
+ } else {
+ tex.texture->update(img); //update
+ }
+ }
+ }
+
+ // update height array
+ for (int k = tex_pos.x; k < tex_pos.x + mw; k++) {
+ tex.offsets.write[k] = tex_pos.y + mh;
+ }
+
+ Character chr;
+ chr.align = (Vector2(xofs, -yofs) * p_data->scale_color_font / oversampling).round();
+ chr.advance = (advance * p_data->scale_color_font / oversampling).round();
+ chr.texture_idx = tex_pos.index;
+ chr.found = true;
+
+ chr.rect_uv = Rect2(tex_pos.x + rect_margin, tex_pos.y + rect_margin, w, h);
+ chr.rect = chr.rect_uv;
+ chr.rect.position /= oversampling;
+ chr.rect.size *= (p_data->scale_color_font / oversampling);
+ return chr;
+}
+
+void DynamicFontDataFallback::update_char(int p_size, char32_t p_char) {
+ DataAtSize *fds = get_data_for_size(p_size, false);
+ ERR_FAIL_COND(fds == nullptr);
+
+ if (fds->char_map.has(p_char)) {
+ return;
+ }
+
+ Character character = Character::not_found();
+
+ FT_GlyphSlot slot = fds->face->glyph;
+ FT_UInt gl_index = FT_Get_Char_Index(fds->face, p_char);
+
+ if (gl_index == 0) {
+ fds->char_map[p_char] = character;
+ return;
+ }
+
+ int ft_hinting;
+ switch (hinting) {
+ case TextServer::HINTING_NONE:
+ ft_hinting = FT_LOAD_NO_HINTING;
+ break;
+ case TextServer::HINTING_LIGHT:
+ ft_hinting = FT_LOAD_TARGET_LIGHT;
+ break;
+ default:
+ ft_hinting = FT_LOAD_TARGET_NORMAL;
+ break;
+ }
+
+ FT_Fixed v, h;
+ FT_Get_Advance(fds->face, gl_index, FT_HAS_COLOR(fds->face) ? FT_LOAD_COLOR : FT_LOAD_DEFAULT | (force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0) | ft_hinting, &h);
+ FT_Get_Advance(fds->face, gl_index, FT_HAS_COLOR(fds->face) ? FT_LOAD_COLOR : FT_LOAD_DEFAULT | (force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0) | ft_hinting | FT_LOAD_VERTICAL_LAYOUT, &v);
+
+ int error = FT_Load_Glyph(fds->face, gl_index, FT_HAS_COLOR(fds->face) ? FT_LOAD_COLOR : FT_LOAD_DEFAULT | (force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0) | ft_hinting);
+ if (error) {
+ fds->char_map[p_char] = character;
+ return;
+ }
+
+ error = FT_Render_Glyph(fds->face->glyph, antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
+ if (!error) {
+ character = bitmap_to_character(fds, slot->bitmap, slot->bitmap_top, slot->bitmap_left, Vector2((h + (1 << 9)) >> 10, (v + (1 << 9)) >> 10) / 64.0);
+ }
+
+ fds->char_map[p_char] = character;
+}
+
+void DynamicFontDataFallback::update_char_outline(int p_size, int p_outline_size, char32_t p_char) {
+ DataAtSize *fds = get_data_for_size(p_size, p_outline_size);
+ ERR_FAIL_COND(fds == nullptr);
+
+ if (fds->char_map.has(p_char)) {
+ return;
+ }
+
+ Character character = Character::not_found();
+ FT_UInt gl_index = FT_Get_Char_Index(fds->face, p_char);
+
+ if (gl_index == 0) {
+ fds->char_map[p_char] = character;
+ return;
+ }
+
+ int error = FT_Load_Glyph(fds->face, gl_index, FT_LOAD_NO_BITMAP | (force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
+ if (error) {
+ fds->char_map[p_char] = character;
+ return;
+ }
+
+ FT_Stroker stroker;
+ if (FT_Stroker_New(library, &stroker) != 0) {
+ fds->char_map[p_char] = character;
+ return;
+ }
+
+ FT_Stroker_Set(stroker, (int)(p_outline_size * oversampling * 64.0), FT_STROKER_LINECAP_BUTT, FT_STROKER_LINEJOIN_ROUND, 0);
+ FT_Glyph glyph;
+ FT_BitmapGlyph glyph_bitmap;
+
+ if (FT_Get_Glyph(fds->face->glyph, &glyph) != 0) {
+ goto cleanup_stroker;
+ }
+ if (FT_Glyph_Stroke(&glyph, stroker, 1) != 0) {
+ goto cleanup_glyph;
+ }
+ if (FT_Glyph_To_Bitmap(&glyph, antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO, nullptr, 1) != 0) {
+ goto cleanup_glyph;
+ }
+
+ glyph_bitmap = (FT_BitmapGlyph)glyph;
+ character = bitmap_to_character(fds, glyph_bitmap->bitmap, glyph_bitmap->top, glyph_bitmap->left, Vector2());
+
+cleanup_glyph:
+ FT_Done_Glyph(glyph);
+cleanup_stroker:
+ FT_Stroker_Done(stroker);
+
+ fds->char_map[p_char] = character;
+}
+
+void DynamicFontDataFallback::clear_cache() {
+ _THREAD_SAFE_METHOD_
+ for (Map<CacheID, DataAtSize *>::Element *E = size_cache.front(); E; E = E->next()) {
+ memdelete(E->get());
+ }
+ size_cache.clear();
+ for (Map<CacheID, DataAtSize *>::Element *E = size_cache_outline.front(); E; E = E->next()) {
+ memdelete(E->get());
+ }
+ size_cache_outline.clear();
+}
+
+Error DynamicFontDataFallback::load_from_file(const String &p_filename, int p_base_size) {
+ _THREAD_SAFE_METHOD_
+ if (library == nullptr) {
+ int error = FT_Init_FreeType(&library);
+ ERR_FAIL_COND_V_MSG(error != 0, ERR_CANT_CREATE, "Error initializing FreeType.");
+ }
+ clear_cache();
+
+ font_path = p_filename;
+ base_size = p_base_size;
+
+ valid = true;
+ DataAtSize *fds = get_data_for_size(base_size); // load base size.
+ if (fds == nullptr) {
+ valid = false;
+ ERR_FAIL_V(ERR_CANT_CREATE);
+ }
+
+ return OK;
+}
+
+Error DynamicFontDataFallback::load_from_memory(const uint8_t *p_data, size_t p_size, int p_base_size) {
+ _THREAD_SAFE_METHOD_
+ if (library == nullptr) {
+ int error = FT_Init_FreeType(&library);
+ ERR_FAIL_COND_V_MSG(error != 0, ERR_CANT_CREATE, "Error initializing FreeType.");
+ }
+ clear_cache();
+
+ font_mem = p_data;
+ font_mem_size = p_size;
+ base_size = p_base_size;
+
+ valid = true;
+ DataAtSize *fds = get_data_for_size(base_size); // load base size.
+ if (fds == nullptr) {
+ valid = false;
+ ERR_FAIL_V(ERR_CANT_CREATE);
+ }
+
+ return OK;
+}
+
+float DynamicFontDataFallback::get_height(int p_size) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataFallback *>(this)->get_data_for_size(p_size);
+ ERR_FAIL_COND_V(fds == nullptr, 0.f);
+ return fds->ascent + fds->descent;
+}
+
+float DynamicFontDataFallback::get_ascent(int p_size) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataFallback *>(this)->get_data_for_size(p_size);
+ ERR_FAIL_COND_V(fds == nullptr, 0.f);
+ return fds->ascent;
+}
+
+float DynamicFontDataFallback::get_descent(int p_size) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataFallback *>(this)->get_data_for_size(p_size);
+ ERR_FAIL_COND_V(fds == nullptr, 0.f);
+ return fds->descent;
+}
+
+float DynamicFontDataFallback::get_underline_position(int p_size) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataFallback *>(this)->get_data_for_size(p_size);
+ ERR_FAIL_COND_V(fds == nullptr, 0.f);
+ return fds->underline_position;
+}
+
+float DynamicFontDataFallback::get_underline_thickness(int p_size) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataFallback *>(this)->get_data_for_size(p_size);
+ ERR_FAIL_COND_V(fds == nullptr, 0.f);
+ return fds->underline_thickness;
+}
+
+void DynamicFontDataFallback::set_antialiased(bool p_antialiased) {
+ if (antialiased != p_antialiased) {
+ clear_cache();
+ antialiased = p_antialiased;
+ }
+}
+
+bool DynamicFontDataFallback::get_antialiased() const {
+ return antialiased;
+}
+
+void DynamicFontDataFallback::set_force_autohinter(bool p_enabled) {
+ if (force_autohinter != p_enabled) {
+ clear_cache();
+ force_autohinter = p_enabled;
+ }
+}
+
+bool DynamicFontDataFallback::get_force_autohinter() const {
+ return force_autohinter;
+}
+
+void DynamicFontDataFallback::set_hinting(TextServer::Hinting p_hinting) {
+ if (hinting != p_hinting) {
+ clear_cache();
+ hinting = p_hinting;
+ }
+}
+
+TextServer::Hinting DynamicFontDataFallback::get_hinting() const {
+ return hinting;
+}
+
+bool DynamicFontDataFallback::has_outline() const {
+ return true;
+}
+
+float DynamicFontDataFallback::get_base_size() const {
+ return base_size;
+}
+
+bool DynamicFontDataFallback::has_char(char32_t p_char) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataFallback *>(this)->get_data_for_size(base_size);
+ ERR_FAIL_COND_V(fds == nullptr, false);
+
+ const_cast<DynamicFontDataFallback *>(this)->update_char(base_size, p_char);
+ Character ch = fds->char_map[p_char];
+
+ return (ch.found);
+}
+
+String DynamicFontDataFallback::get_supported_chars() const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataFallback *>(this)->get_data_for_size(base_size);
+ ERR_FAIL_COND_V(fds == nullptr, String());
+
+ String chars;
+
+ FT_UInt gindex;
+ FT_ULong charcode = FT_Get_First_Char(fds->face, &gindex);
+ while (gindex != 0) {
+ if (charcode != 0) {
+ chars += char32_t(charcode);
+ }
+ charcode = FT_Get_Next_Char(fds->face, charcode, &gindex);
+ }
+
+ return chars;
+}
+
+Vector2 DynamicFontDataFallback::get_advance(char32_t p_char, int p_size) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataFallback *>(this)->get_data_for_size(p_size);
+ ERR_FAIL_COND_V(fds == nullptr, Vector2());
+
+ const_cast<DynamicFontDataFallback *>(this)->update_char(p_size, p_char);
+ Character ch = fds->char_map[p_char];
+
+ return ch.advance;
+}
+
+Vector2 DynamicFontDataFallback::get_kerning(char32_t p_char, char32_t p_next, int p_size) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataFallback *>(this)->get_data_for_size(p_size);
+ ERR_FAIL_COND_V(fds == nullptr, Vector2());
+
+ FT_Vector delta;
+ FT_Get_Kerning(fds->face, FT_Get_Char_Index(fds->face, p_char), FT_Get_Char_Index(fds->face, p_next), FT_KERNING_DEFAULT, &delta);
+ return Vector2(delta.x, delta.y);
+}
+
+Vector2 DynamicFontDataFallback::draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataFallback *>(this)->get_data_for_size(p_size);
+ ERR_FAIL_COND_V(fds == nullptr, Vector2());
+
+ const_cast<DynamicFontDataFallback *>(this)->update_char(p_size, p_index);
+ Character ch = fds->char_map[p_index];
+
+ Vector2 advance;
+ if (ch.found) {
+ ERR_FAIL_COND_V(ch.texture_idx < -1 || ch.texture_idx >= fds->textures.size(), Vector2());
+
+ if (ch.texture_idx != -1) {
+ Point2i cpos = p_pos;
+ cpos += ch.align;
+
+ Color modulate = p_color;
+ if (FT_HAS_COLOR(fds->face)) {
+ modulate.r = modulate.g = modulate.b = 1.0;
+ }
+ if (RenderingServer::get_singleton() != nullptr) {
+ RID texture = fds->textures[ch.texture_idx].texture->get_rid();
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, ch.rect.size), texture, ch.rect_uv, modulate, false, false);
+ }
+ }
+
+ advance = ch.advance;
+ }
+
+ return advance;
+}
+
+Vector2 DynamicFontDataFallback::draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataFallback *>(this)->get_data_for_size(p_size, p_outline_size);
+ ERR_FAIL_COND_V(fds == nullptr, Vector2());
+
+ const_cast<DynamicFontDataFallback *>(this)->update_char_outline(p_size, p_outline_size, p_index);
+ Character ch = fds->char_map[p_index];
+
+ Vector2 advance;
+ if (ch.found) {
+ ERR_FAIL_COND_V(ch.texture_idx < -1 || ch.texture_idx >= fds->textures.size(), Vector2());
+
+ if (ch.texture_idx != -1) {
+ Point2i cpos = p_pos;
+ cpos += ch.align;
+
+ Color modulate = p_color;
+ if (FT_HAS_COLOR(fds->face)) {
+ modulate.r = modulate.g = modulate.b = 1.0;
+ }
+ if (RenderingServer::get_singleton() != nullptr) {
+ RID texture = fds->textures[ch.texture_idx].texture->get_rid();
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, ch.rect.size), texture, ch.rect_uv, modulate, false, false);
+ }
+ }
+
+ advance = ch.advance;
+ }
+
+ return advance;
+}
+
+DynamicFontDataFallback::~DynamicFontDataFallback() {
+ clear_cache();
+ if (library != nullptr) {
+ FT_Done_FreeType(library);
+ }
+}
diff --git a/modules/text_server_fb/dynamic_font_fb.h b/modules/text_server_fb/dynamic_font_fb.h
new file mode 100644
index 0000000000..f1cd758f2c
--- /dev/null
+++ b/modules/text_server_fb/dynamic_font_fb.h
@@ -0,0 +1,169 @@
+/*************************************************************************/
+/* dynamic_font_fb.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef DYNAMIC_FONT_FALLBACK_H
+#define DYNAMIC_FONT_FALLBACK_H
+
+#include "font_fb.h"
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+struct DynamicFontDataFallback : public FontDataFallback {
+ _THREAD_SAFE_CLASS_
+
+private:
+ struct CharTexture {
+ Vector<uint8_t> imgdata;
+ int texture_size = 0;
+ Vector<int> offsets;
+ Ref<ImageTexture> texture;
+ };
+
+ struct Character {
+ bool found = false;
+ int texture_idx = 0;
+ Rect2 rect;
+ Rect2 rect_uv;
+ Vector2 align;
+ Vector2 advance = Vector2(-1, -1);
+
+ static Character not_found();
+ };
+
+ struct TexturePosition {
+ int index = 0;
+ int x = 0;
+ int y = 0;
+ };
+
+ struct CacheID {
+ union {
+ struct {
+ uint32_t size : 16;
+ uint32_t outline_size : 16;
+ };
+ uint32_t key;
+ };
+ bool operator<(CacheID right) const {
+ return key < right.key;
+ }
+ CacheID() {
+ key = 0;
+ }
+ };
+
+ struct DataAtSize {
+ FT_Face face = nullptr;
+ FT_StreamRec stream;
+
+ int size = 0;
+ float scale_color_font = 1.f;
+ float ascent = 0;
+ float descent = 0;
+ float underline_position = 0;
+ float underline_thickness = 0;
+
+ Vector<CharTexture> textures;
+ HashMap<char32_t, Character> char_map;
+
+ ~DataAtSize() {
+ if (face != nullptr) {
+ FT_Done_Face(face);
+ }
+ }
+ };
+
+ FT_Library library = nullptr;
+
+ // Source data.
+ const uint8_t *font_mem = nullptr;
+ int font_mem_size = 0;
+ String font_path;
+ Vector<uint8_t> font_mem_cache;
+
+ float rect_margin = 1.f;
+ int base_size = 16;
+ float oversampling = 1.f;
+ bool antialiased = true;
+ bool force_autohinter = false;
+ TextServer::Hinting hinting = TextServer::HINTING_LIGHT;
+
+ Map<CacheID, DataAtSize *> size_cache;
+ Map<CacheID, DataAtSize *> size_cache_outline;
+
+ DataAtSize *get_data_for_size(int p_size, int p_outline_size = 0);
+
+ TexturePosition find_texture_pos_for_glyph(DataAtSize *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height);
+ Character bitmap_to_character(DataAtSize *p_data, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance);
+ _FORCE_INLINE_ void update_char(int p_size, char32_t p_char);
+ _FORCE_INLINE_ void update_char_outline(int p_size, int p_outline_size, char32_t p_char);
+
+public:
+ virtual void clear_cache() override;
+
+ virtual Error load_from_file(const String &p_filename, int p_base_size) override;
+ virtual Error load_from_memory(const uint8_t *p_data, size_t p_size, int p_base_size) override;
+
+ virtual float get_height(int p_size) const override;
+ virtual float get_ascent(int p_size) const override;
+ virtual float get_descent(int p_size) const override;
+
+ virtual float get_underline_position(int p_size) const override;
+ virtual float get_underline_thickness(int p_size) const override;
+
+ virtual void set_antialiased(bool p_antialiased) override;
+ virtual bool get_antialiased() const override;
+
+ virtual void set_hinting(TextServer::Hinting p_hinting) override;
+ virtual TextServer::Hinting get_hinting() const override;
+
+ virtual void set_force_autohinter(bool p_enabeld) override;
+ virtual bool get_force_autohinter() const override;
+
+ virtual void set_distance_field_hint(bool p_distance_field) override{};
+ virtual bool get_distance_field_hint() const override { return false; };
+
+ virtual bool has_outline() const override;
+ virtual float get_base_size() const override;
+
+ virtual bool has_char(char32_t p_char) const override;
+ virtual String get_supported_chars() const override;
+
+ virtual Vector2 get_advance(char32_t p_char, int p_size) const override;
+ virtual Vector2 get_kerning(char32_t p_char, char32_t p_next, int p_size) const override;
+
+ virtual Vector2 draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const override;
+ virtual Vector2 draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const override;
+
+ virtual ~DynamicFontDataFallback() override;
+};
+
+#endif // DYNAMIC_FONT_FALLBACK_H
diff --git a/modules/gdscript/gdscript_functions.h b/modules/text_server_fb/font_fb.h
index 2c6dc02913..cc72919542 100644
--- a/modules/gdscript/gdscript_functions.h
+++ b/modules/text_server_fb/font_fb.h
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* gdscript_functions.h */
+/* font_fb.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -28,110 +28,53 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef GDSCRIPT_FUNCTIONS_H
-#define GDSCRIPT_FUNCTIONS_H
-
-#include "core/variant.h"
-
-class GDScriptFunctions {
-public:
- enum Function {
- MATH_SIN,
- MATH_COS,
- MATH_TAN,
- MATH_SINH,
- MATH_COSH,
- MATH_TANH,
- MATH_ASIN,
- MATH_ACOS,
- MATH_ATAN,
- MATH_ATAN2,
- MATH_SQRT,
- MATH_FMOD,
- MATH_FPOSMOD,
- MATH_POSMOD,
- MATH_FLOOR,
- MATH_CEIL,
- MATH_ROUND,
- MATH_ABS,
- MATH_SIGN,
- MATH_POW,
- MATH_LOG,
- MATH_EXP,
- MATH_ISNAN,
- MATH_ISINF,
- MATH_ISEQUALAPPROX,
- MATH_ISZEROAPPROX,
- MATH_EASE,
- MATH_STEP_DECIMALS,
- MATH_STEPIFY,
- MATH_LERP,
- MATH_LERP_ANGLE,
- MATH_INVERSE_LERP,
- MATH_RANGE_LERP,
- MATH_SMOOTHSTEP,
- MATH_MOVE_TOWARD,
- MATH_DECTIME,
- MATH_RANDOMIZE,
- MATH_RAND,
- MATH_RANDF,
- MATH_RANDOM,
- MATH_SEED,
- MATH_RANDSEED,
- MATH_DEG2RAD,
- MATH_RAD2DEG,
- MATH_LINEAR2DB,
- MATH_DB2LINEAR,
- MATH_POLAR2CARTESIAN,
- MATH_CARTESIAN2POLAR,
- MATH_WRAP,
- MATH_WRAPF,
- LOGIC_MAX,
- LOGIC_MIN,
- LOGIC_CLAMP,
- LOGIC_NEAREST_PO2,
- OBJ_WEAKREF,
- FUNC_FUNCREF,
- TYPE_CONVERT,
- TYPE_OF,
- TYPE_EXISTS,
- TEXT_CHAR,
- TEXT_ORD,
- TEXT_STR,
- TEXT_PRINT,
- TEXT_PRINT_TABBED,
- TEXT_PRINT_SPACED,
- TEXT_PRINTERR,
- TEXT_PRINTRAW,
- TEXT_PRINT_DEBUG,
- PUSH_ERROR,
- PUSH_WARNING,
- VAR_TO_STR,
- STR_TO_VAR,
- VAR_TO_BYTES,
- BYTES_TO_VAR,
- GEN_RANGE,
- RESOURCE_LOAD,
- INST2DICT,
- DICT2INST,
- VALIDATE_JSON,
- PARSE_JSON,
- TO_JSON,
- HASH,
- COLOR8,
- COLORN,
- PRINT_STACK,
- GET_STACK,
- INSTANCE_FROM_ID,
- LEN,
- IS_INSTANCE_VALID,
- FUNC_MAX
- };
-
- static const char *get_func_name(Function p_func);
- static void call(Function p_func, const Variant **p_args, int p_arg_count, Variant &r_ret, Callable::CallError &r_error);
- static bool is_deterministic(Function p_func);
- static MethodInfo get_info(Function p_func);
+#ifndef FONT_FALLBACK_H
+#define FONT_FALLBACK_H
+
+#include "servers/text_server.h"
+
+struct FontDataFallback {
+ Map<String, bool> lang_support_overrides;
+ Map<String, bool> script_support_overrides;
+ bool valid = false;
+
+ virtual void clear_cache() = 0;
+
+ virtual Error load_from_file(const String &p_filename, int p_base_size) = 0;
+ virtual Error load_from_memory(const uint8_t *p_data, size_t p_size, int p_base_size) = 0;
+
+ virtual float get_height(int p_size) const = 0;
+ virtual float get_ascent(int p_size) const = 0;
+ virtual float get_descent(int p_size) const = 0;
+
+ virtual float get_underline_position(int p_size) const = 0;
+ virtual float get_underline_thickness(int p_size) const = 0;
+
+ virtual void set_antialiased(bool p_antialiased) = 0;
+ virtual bool get_antialiased() const = 0;
+
+ virtual void set_hinting(TextServer::Hinting p_hinting) = 0;
+ virtual TextServer::Hinting get_hinting() const = 0;
+
+ virtual void set_distance_field_hint(bool p_distance_field) = 0;
+ virtual bool get_distance_field_hint() const = 0;
+
+ virtual void set_force_autohinter(bool p_enabeld) = 0;
+ virtual bool get_force_autohinter() const = 0;
+
+ virtual bool has_outline() const = 0;
+ virtual float get_base_size() const = 0;
+
+ virtual bool has_char(char32_t p_char) const = 0;
+ virtual String get_supported_chars() const = 0;
+
+ virtual Vector2 get_advance(char32_t p_char, int p_size) const = 0;
+ virtual Vector2 get_kerning(char32_t p_char, char32_t p_next, int p_size) const = 0;
+
+ virtual Vector2 draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const = 0;
+ virtual Vector2 draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const = 0;
+
+ virtual ~FontDataFallback(){};
};
-#endif // GDSCRIPT_FUNCTIONS_H
+#endif // FONT_FALLBACK_H
diff --git a/modules/text_server_fb/register_types.cpp b/modules/text_server_fb/register_types.cpp
new file mode 100644
index 0000000000..87cbd2ac2c
--- /dev/null
+++ b/modules/text_server_fb/register_types.cpp
@@ -0,0 +1,43 @@
+/*************************************************************************/
+/* register_types.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "register_types.h"
+
+#include "text_server_fb.h"
+
+void preregister_text_server_fb_types() {
+ TextServerFallback::register_server();
+}
+
+void register_text_server_fb_types() {
+}
+
+void unregister_text_server_fb_types() {
+}
diff --git a/modules/text_server_fb/register_types.h b/modules/text_server_fb/register_types.h
new file mode 100644
index 0000000000..c854db92e5
--- /dev/null
+++ b/modules/text_server_fb/register_types.h
@@ -0,0 +1,40 @@
+/*************************************************************************/
+/* register_types.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEXT_SERVER_FB_REGISTER_TYPES_H
+#define TEXT_SERVER_FB_REGISTER_TYPES_H
+
+#define MODULE_TEXT_SERVER_FB_HAS_PREREGISTER
+
+void preregister_text_server_fb_types();
+void register_text_server_fb_types();
+void unregister_text_server_fb_types();
+
+#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
new file mode 100644
index 0000000000..e60d269408
--- /dev/null
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -0,0 +1,1383 @@
+/*************************************************************************/
+/* text_server_fb.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "text_server_fb.h"
+
+#include "bitmap_font_fb.h"
+#include "dynamic_font_fb.h"
+
+_FORCE_INLINE_ bool is_control(char32_t p_char) {
+ return (p_char <= 0x001f) || (p_char >= 0x007f && p_char <= 0x009F);
+}
+
+_FORCE_INLINE_ bool is_whitespace(char32_t p_char) {
+ return (p_char == 0x0020) || (p_char == 0x00A0) || (p_char == 0x1680) || (p_char >= 0x2000 && p_char <= 0x200a) || (p_char == 0x202f) || (p_char == 0x205f) || (p_char == 0x3000) || (p_char == 0x2028) || (p_char == 0x2029) || (p_char >= 0x0009 && p_char <= 0x000d) || (p_char == 0x0085);
+}
+
+_FORCE_INLINE_ bool is_linebreak(char32_t p_char) {
+ return (p_char >= 0x000a && p_char <= 0x000d) || (p_char == 0x0085) || (p_char == 0x2028) || (p_char == 0x2029);
+}
+
+_FORCE_INLINE_ bool is_punct(char32_t p_char) {
+ return (p_char >= 0x0020 && p_char <= 0x002F) || (p_char >= 0x003A && p_char <= 0x0040) || (p_char >= 0x005B && p_char <= 0x0060) || (p_char >= 0x007B && p_char <= 0x007E) || (p_char >= 0x2000 && p_char <= 0x206F) || (p_char >= 0x3000 && p_char <= 0x303F);
+}
+
+/*************************************************************************/
+
+String TextServerFallback::interface_name = "Fallback";
+uint32_t TextServerFallback::interface_features = 0; // Nothing is supported.
+
+bool TextServerFallback::has_feature(Feature p_feature) {
+ return (interface_features & p_feature) == p_feature;
+}
+
+String TextServerFallback::get_name() const {
+ return interface_name;
+}
+
+void TextServerFallback::free(RID p_rid) {
+ _THREAD_SAFE_METHOD_
+ if (font_owner.owns(p_rid)) {
+ FontDataFallback *fd = font_owner.getornull(p_rid);
+ font_owner.free(p_rid);
+ memdelete(fd);
+ } else if (shaped_owner.owns(p_rid)) {
+ ShapedTextData *sd = shaped_owner.getornull(p_rid);
+ shaped_owner.free(p_rid);
+ memdelete(sd);
+ }
+}
+
+bool TextServerFallback::has(RID p_rid) {
+ _THREAD_SAFE_METHOD_
+ return font_owner.owns(p_rid) || shaped_owner.owns(p_rid);
+}
+
+bool TextServerFallback::load_support_data(const String &p_filename) {
+ return false; // No extra data used.
+}
+
+#ifdef TOOLS_ENABLED
+
+bool TextServerFallback::save_support_data(const String &p_filename) {
+ return false; // No extra data used.
+}
+
+#endif
+
+bool TextServerFallback::is_locale_right_to_left(const String &p_locale) {
+ return false; // No RTL support.
+}
+
+/*************************************************************************/
+/* Font interface */
+/*************************************************************************/
+
+RID TextServerFallback::create_font_system(const String &p_name, int p_base_size) {
+ ERR_FAIL_V_MSG(RID(), "System fonts are not supported by this text server.");
+}
+
+RID TextServerFallback::create_font_resource(const String &p_filename, int p_base_size) {
+ _THREAD_SAFE_METHOD_
+ FontDataFallback *fd = nullptr;
+ if (p_filename.get_extension() == "ttf" || p_filename.get_extension() == "otf" || p_filename.get_extension() == "woff") {
+ fd = memnew(DynamicFontDataFallback);
+ } else if (p_filename.get_extension() == "fnt" || p_filename.get_extension() == "font") {
+ fd = memnew(BitmapFontDataFallback);
+ } else {
+ return RID();
+ }
+
+ Error err = fd->load_from_file(p_filename, p_base_size);
+ if (err != OK) {
+ memdelete(fd);
+ return RID();
+ }
+
+ return font_owner.make_rid(fd);
+}
+
+RID TextServerFallback::create_font_memory(const uint8_t *p_data, size_t p_size, const String &p_type, int p_base_size) {
+ _THREAD_SAFE_METHOD_
+ FontDataFallback *fd = nullptr;
+ if (p_type == "ttf" || p_type == "otf" || p_type == "woff") {
+ fd = memnew(DynamicFontDataFallback);
+ } else if (p_type == "fnt" || p_type == "font") {
+ fd = memnew(BitmapFontDataFallback);
+ } else {
+ return RID();
+ }
+
+ Error err = fd->load_from_memory(p_data, p_size, p_base_size);
+ if (err != OK) {
+ memdelete(fd);
+ return RID();
+ }
+
+ return font_owner.make_rid(fd);
+}
+
+float TextServerFallback::font_get_height(RID p_font, int p_size) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, 0.f);
+ return fd->get_height(p_size);
+}
+
+float TextServerFallback::font_get_ascent(RID p_font, int p_size) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, 0.f);
+ return fd->get_ascent(p_size);
+}
+
+float TextServerFallback::font_get_descent(RID p_font, int p_size) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, 0.f);
+ return fd->get_descent(p_size);
+}
+
+float TextServerFallback::font_get_underline_position(RID p_font, int p_size) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, 0.f);
+ return fd->get_underline_position(p_size);
+}
+
+float TextServerFallback::font_get_underline_thickness(RID p_font, int p_size) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, 0.f);
+ return fd->get_underline_thickness(p_size);
+}
+
+void TextServerFallback::font_set_antialiased(RID p_font, bool p_antialiased) {
+ _THREAD_SAFE_METHOD_
+ FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->set_antialiased(p_antialiased);
+}
+
+bool TextServerFallback::font_get_antialiased(RID p_font) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, false);
+ return fd->get_antialiased();
+}
+
+void TextServerFallback::font_set_distance_field_hint(RID p_font, bool p_distance_field) {
+ _THREAD_SAFE_METHOD_
+ FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->set_distance_field_hint(p_distance_field);
+}
+
+bool TextServerFallback::font_get_distance_field_hint(RID p_font) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, false);
+ return fd->get_distance_field_hint();
+}
+
+void TextServerFallback::font_set_hinting(RID p_font, TextServer::Hinting p_hinting) {
+ _THREAD_SAFE_METHOD_
+ FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->set_hinting(p_hinting);
+}
+
+TextServer::Hinting TextServerFallback::font_get_hinting(RID p_font) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, TextServer::HINTING_NONE);
+ return fd->get_hinting();
+}
+
+void TextServerFallback::font_set_force_autohinter(RID p_font, bool p_enabeld) {
+ _THREAD_SAFE_METHOD_
+ FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->set_force_autohinter(p_enabeld);
+}
+
+bool TextServerFallback::font_get_force_autohinter(RID p_font) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, false);
+ return fd->get_force_autohinter();
+}
+
+bool TextServerFallback::font_has_char(RID p_font, char32_t p_char) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, false);
+ return fd->has_char(p_char);
+}
+
+String TextServerFallback::font_get_supported_chars(RID p_font) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, String());
+ return fd->get_supported_chars();
+}
+
+bool TextServerFallback::font_has_outline(RID p_font) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, false);
+ return fd->has_outline();
+}
+
+float TextServerFallback::font_get_base_size(RID p_font) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, 0.f);
+ return fd->get_base_size();
+}
+
+bool TextServerFallback::font_is_language_supported(RID p_font, const String &p_language) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, false);
+ if (fd->lang_support_overrides.has(p_language)) {
+ return fd->lang_support_overrides[p_language];
+ } else {
+ Vector<String> tags = p_language.replace("-", "_").split("_");
+ if (tags.size() > 0) {
+ if (fd->lang_support_overrides.has(tags[0])) {
+ return fd->lang_support_overrides[tags[0]];
+ }
+ }
+ return false;
+ }
+}
+
+void TextServerFallback::font_set_language_support_override(RID p_font, const String &p_language, bool p_supported) {
+ _THREAD_SAFE_METHOD_
+ FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->lang_support_overrides[p_language] = p_supported;
+}
+
+bool TextServerFallback::font_get_language_support_override(RID p_font, const String &p_language) {
+ _THREAD_SAFE_METHOD_
+ FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, false);
+ return fd->lang_support_overrides[p_language];
+}
+
+void TextServerFallback::font_remove_language_support_override(RID p_font, const String &p_language) {
+ _THREAD_SAFE_METHOD_
+ FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->lang_support_overrides.erase(p_language);
+}
+
+Vector<String> TextServerFallback::font_get_language_support_overrides(RID p_font) {
+ _THREAD_SAFE_METHOD_
+ FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, Vector<String>());
+ Vector<String> ret;
+ for (Map<String, bool>::Element *E = fd->lang_support_overrides.front(); E; E = E->next()) {
+ ret.push_back(E->key());
+ }
+ return ret;
+}
+
+bool TextServerFallback::font_is_script_supported(RID p_font, const String &p_script) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, false);
+ if (fd->script_support_overrides.has(p_script)) {
+ return fd->script_support_overrides[p_script];
+ } else {
+ return true;
+ }
+}
+
+void TextServerFallback::font_set_script_support_override(RID p_font, const String &p_script, bool p_supported) {
+ _THREAD_SAFE_METHOD_
+ FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->script_support_overrides[p_script] = p_supported;
+}
+
+bool TextServerFallback::font_get_script_support_override(RID p_font, const String &p_script) {
+ _THREAD_SAFE_METHOD_
+ FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, false);
+ return fd->script_support_overrides[p_script];
+}
+
+void TextServerFallback::font_remove_script_support_override(RID p_font, const String &p_script) {
+ _THREAD_SAFE_METHOD_
+ FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->script_support_overrides.erase(p_script);
+}
+
+Vector<String> TextServerFallback::font_get_script_support_overrides(RID p_font) {
+ _THREAD_SAFE_METHOD_
+ FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, Vector<String>());
+ Vector<String> ret;
+ for (Map<String, bool>::Element *E = fd->script_support_overrides.front(); E; E = E->next()) {
+ ret.push_back(E->key());
+ }
+ return ret;
+}
+
+uint32_t TextServerFallback::font_get_glyph_index(RID p_font, char32_t p_char, char32_t p_variation_selector) const {
+ return (uint32_t)p_char;
+}
+
+Vector2 TextServerFallback::font_get_glyph_advance(RID p_font, uint32_t p_index, int p_size) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, Vector2());
+ return fd->get_advance(p_index, p_size);
+}
+
+Vector2 TextServerFallback::font_get_glyph_kerning(RID p_font, uint32_t p_index_a, uint32_t p_index_b, int p_size) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, Vector2());
+ return fd->get_kerning(p_index_a, p_index_b, p_size);
+}
+
+Vector2 TextServerFallback::font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, Vector2());
+ return fd->draw_glyph(p_canvas, p_size, p_pos, p_index, p_color);
+}
+
+Vector2 TextServerFallback::font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, Vector2());
+ return fd->draw_glyph_outline(p_canvas, p_size, p_outline_size, p_pos, p_index, p_color);
+}
+
+float TextServerFallback::font_get_oversampling() const {
+ return oversampling;
+}
+
+void TextServerFallback::font_set_oversampling(float p_oversampling) {
+ _THREAD_SAFE_METHOD_
+ if (oversampling != p_oversampling) {
+ oversampling = p_oversampling;
+ List<RID> fonts;
+ font_owner.get_owned_list(&fonts);
+ for (List<RID>::Element *E = fonts.front(); E; E = E->next()) {
+ font_owner.getornull(E->get())->clear_cache();
+ }
+ }
+}
+
+Vector<String> TextServerFallback::get_system_fonts() const {
+ return Vector<String>();
+}
+
+/*************************************************************************/
+/* Shaped text buffer interface */
+/*************************************************************************/
+
+void TextServerFallback::invalidate(ShapedTextData *p_shaped) {
+ p_shaped->valid = false;
+ 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->glyphs.clear();
+ p_shaped->glyphs_logical.clear();
+}
+
+void TextServerFallback::full_copy(ShapedTextData *p_shaped) {
+ ShapedTextData *parent = shaped_owner.getornull(p_shaped->parent);
+
+ for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = parent->objects.front(); E; E = E->next()) {
+ if (E->get().pos >= p_shaped->start && E->get().pos < p_shaped->end) {
+ p_shaped->objects[E->key()] = E->get();
+ }
+ }
+
+ for (int k = 0; k < parent->spans.size(); k++) {
+ ShapedTextData::Span span = parent->spans[k];
+ if (span.start >= p_shaped->end || span.end <= p_shaped->start) {
+ continue;
+ }
+ span.start = MAX(p_shaped->start, span.start);
+ span.end = MIN(p_shaped->end, span.end);
+ p_shaped->spans.push_back(span);
+ }
+
+ p_shaped->parent = RID();
+}
+
+RID TextServerFallback::create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextData *sd = memnew(ShapedTextData);
+ sd->direction = p_direction;
+ sd->orientation = p_orientation;
+
+ return shaped_owner.make_rid(sd);
+}
+
+void TextServerFallback::shaped_text_clear(RID p_shaped) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND(!sd);
+
+ sd->parent = RID();
+ sd->start = 0;
+ sd->end = 0;
+ sd->text = String();
+ sd->spans.clear();
+ sd->objects.clear();
+ invalidate(sd);
+}
+
+void TextServerFallback::shaped_text_set_direction(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 {
+ return TextServer::DIRECTION_LTR;
+}
+
+void TextServerFallback::shaped_text_set_orientation(RID p_shaped, TextServer::Orientation p_orientation) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND(!sd);
+ if (sd->orientation != p_orientation) {
+ if (sd->parent != RID()) {
+ full_copy(sd);
+ }
+ sd->orientation = p_orientation;
+ invalidate(sd);
+ }
+}
+
+void TextServerFallback::shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) {
+ //No BiDi support, ignore.
+}
+
+TextServer::Orientation TextServerFallback::shaped_text_get_orientation(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, TextServer::ORIENTATION_HORIZONTAL);
+ return sd->orientation;
+}
+
+void TextServerFallback::shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND(!sd);
+ if (sd->preserve_invalid != p_enabled) {
+ if (sd->parent != RID()) {
+ full_copy(sd);
+ }
+ sd->preserve_invalid = p_enabled;
+ invalidate(sd);
+ }
+}
+
+bool TextServerFallback::shaped_text_get_preserve_invalid(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, false);
+ return sd->preserve_invalid;
+}
+
+void TextServerFallback::shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND(!sd);
+ if (sd->preserve_control != p_enabled) {
+ if (sd->parent != RID()) {
+ full_copy(sd);
+ }
+ sd->preserve_control = p_enabled;
+ invalidate(sd);
+ }
+}
+
+bool TextServerFallback::shaped_text_get_preserve_control(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, false);
+ return sd->preserve_control;
+}
+
+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) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, false);
+ ERR_FAIL_COND_V(p_size <= 0, false);
+
+ if (p_text.is_empty()) {
+ return true;
+ }
+
+ if (sd->parent != RID()) {
+ full_copy(sd);
+ }
+
+ ShapedTextData::Span span;
+ span.start = sd->text.length();
+ span.end = span.start + p_text.length();
+ // Pre-sort fonts, push fonts with the language support first.
+ for (int i = 0; i < p_fonts.size(); i++) {
+ if (font_is_language_supported(p_fonts[i], p_language)) {
+ span.fonts.push_back(p_fonts[i]);
+ }
+ }
+ // Push the rest valid fonts.
+ for (int i = 0; i < p_fonts.size(); i++) {
+ if (!font_is_language_supported(p_fonts[i], p_language)) {
+ span.fonts.push_back(p_fonts[i]);
+ }
+ }
+ ERR_FAIL_COND_V(span.fonts.is_empty(), false);
+ span.font_size = p_size;
+ span.language = p_language;
+
+ sd->spans.push_back(span);
+ 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, VAlign p_inline_align, int p_length) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, false);
+ ERR_FAIL_COND_V(p_key == Variant(), false);
+ ERR_FAIL_COND_V(sd->objects.has(p_key), false);
+
+ if (sd->parent != RID()) {
+ full_copy(sd);
+ }
+
+ ShapedTextData::Span span;
+ span.start = sd->text.length();
+ span.end = span.start + p_length;
+ span.embedded_key = p_key;
+
+ ShapedTextData::EmbeddedObject obj;
+ obj.inline_align = p_inline_align;
+ obj.rect.size = p_size;
+ obj.pos = span.start;
+
+ sd->spans.push_back(span);
+ sd->text += String::chr(0xfffc).repeat(p_length);
+ sd->end += p_length;
+ sd->objects[p_key] = obj;
+ invalidate(sd);
+
+ return true;
+}
+
+bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, false);
+ ERR_FAIL_COND_V(!sd->objects.has(p_key), false);
+ sd->objects[p_key].rect.size = p_size;
+ sd->objects[p_key].inline_align = p_inline_align;
+ if (sd->valid) {
+ // Recalc string metrics.
+ sd->ascent = 0;
+ sd->descent = 0;
+ sd->width = 0;
+ sd->upos = 0;
+ sd->uthk = 0;
+ int sd_size = sd->glyphs.size();
+ const FontDataFallback *fd = nullptr;
+ RID prev_rid = RID();
+
+ for (int i = 0; i < sd_size; i++) {
+ Glyph gl = sd->glyphs[i];
+ Variant key;
+ if (gl.count == 1) {
+ for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
+ if (E->get().pos == gl.start) {
+ key = E->key();
+ break;
+ }
+ }
+ }
+ if (key != Variant()) {
+ if (sd->orientation == ORIENTATION_HORIZONTAL) {
+ sd->objects[key].rect.position.x = sd->width;
+ sd->width += sd->objects[key].rect.size.x;
+ switch (sd->objects[key].inline_align) {
+ case VALIGN_TOP: {
+ sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y);
+ } break;
+ case VALIGN_CENTER: {
+ sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.y / 2));
+ sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.y / 2));
+ } break;
+ case VALIGN_BOTTOM: {
+ sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y);
+ } break;
+ }
+ sd->glyphs.write[i].advance = sd->objects[key].rect.size.x;
+ } else {
+ sd->objects[key].rect.position.y = sd->width;
+ sd->width += sd->objects[key].rect.size.y;
+ switch (sd->objects[key].inline_align) {
+ case VALIGN_TOP: {
+ sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x);
+ } break;
+ case VALIGN_CENTER: {
+ sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.x / 2));
+ sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.x / 2));
+ } break;
+ case VALIGN_BOTTOM: {
+ sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x);
+ } break;
+ }
+ sd->glyphs.write[i].advance = sd->objects[key].rect.size.y;
+ }
+ } else {
+ if (prev_rid != gl.font_rid) {
+ fd = font_owner.getornull(gl.font_rid);
+ prev_rid = gl.font_rid;
+ }
+ if (fd != nullptr) {
+ if (sd->orientation == ORIENTATION_HORIZONTAL) {
+ sd->ascent = MAX(sd->ascent, fd->get_ascent(gl.font_size));
+ sd->descent = MAX(sd->descent, fd->get_descent(gl.font_size));
+ } else {
+ sd->ascent = MAX(sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
+ sd->descent = MAX(sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
+ }
+ sd->upos = MAX(sd->upos, font_get_underline_position(gl.font_rid, gl.font_size));
+ sd->uthk = MAX(sd->uthk, font_get_underline_thickness(gl.font_rid, gl.font_size));
+ } else if (sd->preserve_invalid || (sd->preserve_control && is_control(gl.index))) {
+ // Glyph not found, replace with hex code box.
+ if (sd->orientation == ORIENTATION_HORIZONTAL) {
+ sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
+ sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
+ } 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->width += gl.advance * gl.repeat;
+ }
+ }
+
+ // Align embedded objects to baseline.
+ for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
+ if ((E->get().pos >= sd->start) && (E->get().pos < sd->end)) {
+ if (sd->orientation == ORIENTATION_HORIZONTAL) {
+ switch (E->get().inline_align) {
+ case VALIGN_TOP: {
+ E->get().rect.position.y = -sd->ascent;
+ } break;
+ case VALIGN_CENTER: {
+ E->get().rect.position.y = -(E->get().rect.size.y / 2);
+ } break;
+ case VALIGN_BOTTOM: {
+ E->get().rect.position.y = sd->descent - E->get().rect.size.y;
+ } break;
+ }
+ } else {
+ switch (E->get().inline_align) {
+ case VALIGN_TOP: {
+ E->get().rect.position.x = -sd->ascent;
+ } break;
+ case VALIGN_CENTER: {
+ E->get().rect.position.x = -(E->get().rect.size.x / 2);
+ } break;
+ case VALIGN_BOTTOM: {
+ E->get().rect.position.x = sd->descent - E->get().rect.size.x;
+ } break;
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_length) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, RID());
+ if (sd->parent != RID()) {
+ return shaped_text_substr(sd->parent, p_start, p_length);
+ }
+ if (!sd->valid) {
+ const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ }
+ ERR_FAIL_COND_V(p_start < 0 || p_length < 0, RID());
+ ERR_FAIL_COND_V(sd->start > p_start || sd->end < p_start, RID());
+ ERR_FAIL_COND_V(sd->end < p_start + p_length, RID());
+
+ ShapedTextData *new_sd = memnew(ShapedTextData);
+ new_sd->parent = p_shaped;
+ new_sd->start = p_start;
+ new_sd->end = p_start + p_length;
+
+ new_sd->orientation = sd->orientation;
+ new_sd->direction = sd->direction;
+ new_sd->para_direction = sd->para_direction;
+ new_sd->line_breaks_valid = sd->line_breaks_valid;
+ new_sd->justification_ops_valid = sd->justification_ops_valid;
+ new_sd->sort_valid = false;
+ new_sd->upos = sd->upos;
+ new_sd->uthk = sd->uthk;
+
+ if (p_length > 0) {
+ new_sd->text = sd->text.substr(p_start, p_length);
+ int sd_size = sd->glyphs.size();
+ const Glyph *sd_glyphs = sd->glyphs.ptr();
+
+ for (int i = 0; i < sd_size; i++) {
+ if ((sd_glyphs[i].start >= new_sd->start) && (sd_glyphs[i].end <= new_sd->end)) {
+ Glyph gl = sd_glyphs[i];
+ Variant key;
+ bool find_embedded = false;
+ if (gl.count == 1) {
+ for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
+ if (E->get().pos == gl.start) {
+ find_embedded = true;
+ key = E->key();
+ new_sd->objects[key] = E->get();
+ break;
+ }
+ }
+ }
+ if (find_embedded) {
+ if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
+ new_sd->objects[key].rect.position.x = new_sd->width;
+ new_sd->width += new_sd->objects[key].rect.size.x;
+ switch (new_sd->objects[key].inline_align) {
+ case VALIGN_TOP: {
+ new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y);
+ } break;
+ case VALIGN_CENTER: {
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.y / 2));
+ new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.y / 2));
+ } break;
+ case VALIGN_BOTTOM: {
+ new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y);
+ } break;
+ }
+ } else {
+ new_sd->objects[key].rect.position.y = new_sd->width;
+ new_sd->width += new_sd->objects[key].rect.size.y;
+ switch (new_sd->objects[key].inline_align) {
+ case VALIGN_TOP: {
+ new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x);
+ } break;
+ case VALIGN_CENTER: {
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.x / 2));
+ new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.x / 2));
+ } break;
+ case VALIGN_BOTTOM: {
+ new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x);
+ } break;
+ }
+ }
+ } else {
+ const FontDataFallback *fd = font_owner.getornull(gl.font_rid);
+ if (fd != nullptr) {
+ if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
+ new_sd->ascent = MAX(new_sd->ascent, fd->get_ascent(gl.font_size));
+ new_sd->descent = MAX(new_sd->descent, fd->get_descent(gl.font_size));
+ } else {
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
+ new_sd->descent = MAX(new_sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
+ }
+ } else if (new_sd->preserve_invalid || (new_sd->preserve_control && is_control(gl.index))) {
+ // Glyph not found, replace with hex code box.
+ if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
+ new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
+ } 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->width += gl.advance * gl.repeat;
+ }
+ new_sd->glyphs.push_back(gl);
+ }
+ }
+
+ for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = new_sd->objects.front(); E; E = E->next()) {
+ if ((E->get().pos >= new_sd->start) && (E->get().pos < new_sd->end)) {
+ if (sd->orientation == ORIENTATION_HORIZONTAL) {
+ switch (E->get().inline_align) {
+ case VALIGN_TOP: {
+ E->get().rect.position.y = -new_sd->ascent;
+ } break;
+ case VALIGN_CENTER: {
+ E->get().rect.position.y = -(E->get().rect.size.y / 2);
+ } break;
+ case VALIGN_BOTTOM: {
+ E->get().rect.position.y = new_sd->descent - E->get().rect.size.y;
+ } break;
+ }
+ } else {
+ switch (E->get().inline_align) {
+ case VALIGN_TOP: {
+ E->get().rect.position.x = -new_sd->ascent;
+ } break;
+ case VALIGN_CENTER: {
+ E->get().rect.position.x = -(E->get().rect.size.x / 2);
+ } break;
+ case VALIGN_BOTTOM: {
+ E->get().rect.position.x = new_sd->descent - E->get().rect.size.x;
+ } break;
+ }
+ }
+ }
+ }
+ }
+ new_sd->valid = true;
+
+ return shaped_owner.make_rid(new_sd);
+}
+
+RID TextServerFallback::shaped_text_get_parent(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, RID());
+ return sd->parent;
+}
+
+float TextServerFallback::shaped_text_fit_to_width(RID p_shaped, float p_width, uint8_t /*JustificationFlag*/ p_jst_flags) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, 0.f);
+ if (!sd->valid) {
+ const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ }
+ if (!sd->justification_ops_valid) {
+ const_cast<TextServerFallback *>(this)->shaped_text_update_justification_ops(p_shaped);
+ }
+
+ int start_pos = 0;
+ int end_pos = sd->glyphs.size() - 1;
+
+ if ((p_jst_flags & JUSTIFICATION_AFTER_LAST_TAB) == JUSTIFICATION_AFTER_LAST_TAB) {
+ int start, end, delta;
+ if (sd->para_direction == DIRECTION_LTR) {
+ start = sd->glyphs.size() - 1;
+ end = -1;
+ delta = -1;
+ } else {
+ start = 0;
+ end = sd->glyphs.size();
+ delta = +1;
+ }
+
+ for (int i = start; i != end; i += delta) {
+ if ((sd->glyphs[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
+ if (sd->para_direction == DIRECTION_LTR) {
+ start_pos = i;
+ break;
+ } else {
+ end_pos = i;
+ break;
+ }
+ }
+ }
+ }
+
+ if ((p_jst_flags & JUSTIFICATION_TRIM_EDGE_SPACES) == JUSTIFICATION_TRIM_EDGE_SPACES) {
+ while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
+ sd->width -= sd->glyphs[start_pos].advance * sd->glyphs[start_pos].repeat;
+ sd->glyphs.write[start_pos].advance = 0;
+ start_pos += sd->glyphs[start_pos].count;
+ }
+ while ((start_pos < end_pos) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
+ sd->width -= sd->glyphs[end_pos].advance * sd->glyphs[end_pos].repeat;
+ sd->glyphs.write[end_pos].advance = 0;
+ end_pos -= sd->glyphs[end_pos].count;
+ }
+ }
+
+ int space_count = 0;
+ for (int i = start_pos; i <= end_pos; i++) {
+ const Glyph &gl = sd->glyphs[i];
+ if (gl.count > 0) {
+ if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) {
+ space_count++;
+ }
+ }
+ }
+
+ if ((space_count > 0) && ((p_jst_flags & JUSTIFICATION_WORD_BOUND) == JUSTIFICATION_WORD_BOUND)) {
+ float delta_width_per_space = (p_width - sd->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;
+ gl.advance = Math::round(MAX(gl.advance + delta_width_per_space, 0.05 * gl.font_size));
+ sd->width += (gl.advance - old_adv);
+ }
+ }
+ }
+ }
+
+ return sd->width;
+}
+
+float TextServerFallback::shaped_text_tab_align(RID p_shaped, const Vector<float> &p_tab_stops) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, 0.f);
+ if (!sd->valid) {
+ const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ }
+ if (!sd->line_breaks_valid) {
+ const_cast<TextServerFallback *>(this)->shaped_text_update_breaks(p_shaped);
+ }
+
+ int tab_index = 0;
+ float off = 0.f;
+
+ int start, end, delta;
+ if (sd->para_direction == DIRECTION_LTR) {
+ start = 0;
+ end = sd->glyphs.size();
+ delta = +1;
+ } else {
+ start = sd->glyphs.size() - 1;
+ end = -1;
+ delta = -1;
+ }
+
+ Glyph *gl = sd->glyphs.ptrw();
+
+ for (int i = start; i != end; i += delta) {
+ if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
+ float tab_off = 0.f;
+ while (tab_off <= off) {
+ tab_off += p_tab_stops[tab_index];
+ tab_index++;
+ if (tab_index >= p_tab_stops.size()) {
+ tab_index = 0;
+ }
+ }
+ float old_adv = gl[i].advance;
+ gl[i].advance = tab_off - off;
+ sd->width += gl[i].advance - old_adv;
+ off = 0;
+ continue;
+ }
+ off += gl[i].advance * gl[i].repeat;
+ }
+
+ return 0.f;
+}
+
+bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, false);
+ if (!sd->valid) {
+ shaped_text_shape(p_shaped);
+ }
+
+ if (sd->line_breaks_valid) {
+ return true; // Noting to do.
+ }
+
+ int sd_size = sd->glyphs.size();
+ for (int i = 0; i < sd_size; i++) {
+ if (sd->glyphs[i].count > 0) {
+ char32_t c = sd->text[sd->glyphs[i].start];
+ if (is_punct(c)) {
+ sd->glyphs.write[i].flags |= GRAPHEME_IS_PUNCTUATION;
+ }
+ if (is_whitespace(c) && !is_linebreak(c)) {
+ sd->glyphs.write[i].flags |= GRAPHEME_IS_SPACE;
+ sd->glyphs.write[i].flags |= GRAPHEME_IS_BREAK_SOFT;
+ }
+ if (is_linebreak(c)) {
+ sd->glyphs.write[i].flags |= GRAPHEME_IS_BREAK_HARD;
+ }
+ if (c == 0x0009 || c == 0x000b) {
+ sd->glyphs.write[i].flags |= GRAPHEME_IS_TAB;
+ }
+
+ i += (sd->glyphs[i].count - 1);
+ }
+ }
+ sd->line_breaks_valid = true;
+ return sd->line_breaks_valid;
+}
+
+bool TextServerFallback::shaped_text_update_justification_ops(RID p_shaped) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, false);
+ if (!sd->valid) {
+ shaped_text_shape(p_shaped);
+ }
+ if (!sd->line_breaks_valid) {
+ shaped_text_update_breaks(p_shaped);
+ }
+
+ sd->justification_ops_valid = true; // Not supported by fallback server.
+ return true;
+}
+
+bool TextServerFallback::shaped_text_shape(RID p_shaped) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, false);
+ if (sd->valid) {
+ return true;
+ }
+
+ if (sd->parent != RID()) {
+ full_copy(sd);
+ }
+
+ // Cleanup.
+ sd->justification_ops_valid = false;
+ sd->line_breaks_valid = false;
+ sd->ascent = 0.f;
+ sd->descent = 0.f;
+ sd->width = 0.f;
+ sd->glyphs.clear();
+
+ if (sd->text.length() == 0) {
+ sd->valid = true;
+ return true;
+ }
+
+ // "Shape" string.
+ for (int i = 0; i < sd->spans.size(); i++) {
+ const ShapedTextData::Span &span = sd->spans[i];
+ if (span.embedded_key != Variant()) {
+ // Embedded object.
+ if (sd->orientation == ORIENTATION_HORIZONTAL) {
+ sd->objects[span.embedded_key].rect.position.x = sd->width;
+ sd->width += sd->objects[span.embedded_key].rect.size.x;
+ switch (sd->objects[span.embedded_key].inline_align) {
+ case VALIGN_TOP: {
+ sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y);
+ } break;
+ case VALIGN_CENTER: {
+ sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2));
+ sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2));
+ } break;
+ case VALIGN_BOTTOM: {
+ sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y);
+ } break;
+ }
+ } else {
+ sd->objects[span.embedded_key].rect.position.y = sd->width;
+ sd->width += sd->objects[span.embedded_key].rect.size.y;
+ switch (sd->objects[span.embedded_key].inline_align) {
+ case VALIGN_TOP: {
+ sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x);
+ } break;
+ case VALIGN_CENTER: {
+ sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2));
+ sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2));
+ } break;
+ case VALIGN_BOTTOM: {
+ sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x);
+ } break;
+ }
+ }
+ Glyph gl;
+ gl.start = span.start;
+ gl.end = span.end;
+ gl.count = 1;
+ gl.index = 0;
+ gl.flags = GRAPHEME_IS_VALID | GRAPHEME_IS_VIRTUAL;
+ if (sd->orientation == ORIENTATION_HORIZONTAL) {
+ gl.advance = sd->objects[span.embedded_key].rect.size.x;
+ } else {
+ gl.advance = sd->objects[span.embedded_key].rect.size.y;
+ }
+ sd->glyphs.push_back(gl);
+ } else {
+ // Text span.
+ for (int j = span.start; j < span.end; j++) {
+ const FontDataFallback *fd = nullptr;
+
+ Glyph gl;
+ gl.start = j;
+ gl.end = j + 1;
+ gl.count = 1;
+ gl.font_size = span.font_size;
+ gl.index = (uint32_t)sd->text[j]; // Use codepoint.
+ if (gl.index == 0x0009 || gl.index == 0x000b) {
+ gl.index = 0x0020;
+ }
+ if (!sd->preserve_control && is_control(gl.index)) {
+ gl.index = 0x0020;
+ }
+ // Select first font which has character (font are already sorted by span language).
+ for (int k = 0; k < span.fonts.size(); k++) {
+ fd = font_owner.getornull(span.fonts[k]);
+ if (fd != nullptr && fd->has_char(gl.index)) {
+ gl.font_rid = span.fonts[k];
+ break;
+ }
+ }
+
+ if (gl.font_rid != RID()) {
+ if (sd->text[j] != 0 && !is_linebreak(sd->text[j])) {
+ if (sd->orientation == ORIENTATION_HORIZONTAL) {
+ gl.advance = fd->get_advance(gl.index, gl.font_size).x;
+ gl.x_off = 0;
+ gl.y_off = 0;
+ sd->ascent = MAX(sd->ascent, fd->get_ascent(gl.font_size));
+ sd->descent = MAX(sd->descent, fd->get_descent(gl.font_size));
+ } else {
+ gl.advance = fd->get_advance(gl.index, gl.font_size).y;
+ gl.x_off = -Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5);
+ gl.y_off = fd->get_ascent(gl.font_size);
+ sd->ascent = MAX(sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
+ sd->descent = MAX(sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
+ }
+ }
+ sd->upos = MAX(sd->upos, fd->get_underline_position(gl.font_size));
+ sd->uthk = MAX(sd->uthk, fd->get_underline_thickness(gl.font_size));
+
+ // Add kerning to previous glyph.
+ if (sd->glyphs.size() > 0) {
+ Glyph &prev_gl = sd->glyphs.write[sd->glyphs.size() - 1];
+ if (prev_gl.font_rid == gl.font_rid && prev_gl.font_size == gl.font_size) {
+ if (sd->orientation == ORIENTATION_HORIZONTAL) {
+ prev_gl.advance += fd->get_kerning(prev_gl.index, gl.index, gl.font_size).x;
+ } else {
+ prev_gl.advance += fd->get_kerning(prev_gl.index, gl.index, gl.font_size).y;
+ }
+ }
+ }
+ } else if (sd->preserve_invalid || (sd->preserve_control && is_control(gl.index))) {
+ // Glyph not found, replace with hex code box.
+ if (sd->orientation == ORIENTATION_HORIZONTAL) {
+ gl.advance = get_hex_code_box_size(gl.font_size, gl.index).x;
+ sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
+ sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
+ } 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->width += gl.advance;
+ sd->glyphs.push_back(gl);
+ }
+ }
+ }
+
+ // Align embedded objects to baseline.
+ for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
+ if (sd->orientation == ORIENTATION_HORIZONTAL) {
+ switch (E->get().inline_align) {
+ case VALIGN_TOP: {
+ E->get().rect.position.y = -sd->ascent;
+ } break;
+ case VALIGN_CENTER: {
+ E->get().rect.position.y = -(E->get().rect.size.y / 2);
+ } break;
+ case VALIGN_BOTTOM: {
+ E->get().rect.position.y = sd->descent - E->get().rect.size.y;
+ } break;
+ }
+ } else {
+ switch (E->get().inline_align) {
+ case VALIGN_TOP: {
+ E->get().rect.position.x = -sd->ascent;
+ } break;
+ case VALIGN_CENTER: {
+ E->get().rect.position.x = -(E->get().rect.size.x / 2);
+ } break;
+ case VALIGN_BOTTOM: {
+ E->get().rect.position.x = sd->descent - E->get().rect.size.x;
+ } break;
+ }
+ }
+ }
+
+ sd->valid = true;
+ return sd->valid;
+}
+
+bool TextServerFallback::shaped_text_is_ready(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, false);
+ return sd->valid;
+}
+
+Vector<TextServer::Glyph> TextServerFallback::shaped_text_get_glyphs(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, Vector<TextServer::Glyph>());
+ if (!sd->valid) {
+ const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ }
+ return sd->glyphs;
+}
+
+Vector2i TextServerFallback::shaped_text_get_range(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, Vector2i());
+ return Vector2(sd->start, sd->end);
+}
+
+Vector<TextServer::Glyph> TextServerFallback::shaped_text_sort_logical(RID p_shaped) {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, Vector<TextServer::Glyph>());
+ if (!sd->valid) {
+ const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ }
+
+ return sd->glyphs; // Already in the logical order, return as is.
+}
+
+Array TextServerFallback::shaped_text_get_objects(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ Array ret;
+ const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, ret);
+ for (const Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
+ ret.push_back(E->key());
+ }
+
+ return ret;
+}
+
+Rect2 TextServerFallback::shaped_text_get_object_rect(RID p_shaped, Variant p_key) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, Rect2());
+ ERR_FAIL_COND_V(!sd->objects.has(p_key), Rect2());
+ if (!sd->valid) {
+ const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ }
+ return sd->objects[p_key].rect;
+}
+
+Size2 TextServerFallback::shaped_text_get_size(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, Size2());
+ if (!sd->valid) {
+ const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ }
+ if (sd->orientation == TextServer::ORIENTATION_HORIZONTAL) {
+ return Size2(sd->width, sd->ascent + sd->descent);
+ } else {
+ return Size2(sd->ascent + sd->descent, sd->width);
+ }
+}
+
+float TextServerFallback::shaped_text_get_ascent(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, 0.f);
+ if (!sd->valid) {
+ const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ }
+ return sd->ascent;
+}
+
+float TextServerFallback::shaped_text_get_descent(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, 0.f);
+ if (!sd->valid) {
+ const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ }
+ return sd->descent;
+}
+
+float TextServerFallback::shaped_text_get_width(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, 0.f);
+ if (!sd->valid) {
+ const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ }
+ return sd->width;
+}
+
+float TextServerFallback::shaped_text_get_underline_position(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, 0.f);
+ if (!sd->valid) {
+ const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ }
+
+ return sd->upos;
+}
+
+float TextServerFallback::shaped_text_get_underline_thickness(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V(!sd, 0.f);
+ if (!sd->valid) {
+ const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ }
+
+ return sd->uthk;
+}
+
+TextServer *TextServerFallback::create_func(Error &r_error, void *p_user_data) {
+ r_error = OK;
+ return memnew(TextServerFallback());
+}
+
+void TextServerFallback::register_server() {
+ TextServerManager::register_create_function(interface_name, interface_features, create_func, nullptr);
+}
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
new file mode 100644
index 0000000000..d142b320e4
--- /dev/null
+++ b/modules/text_server_fb/text_server_fb.h
@@ -0,0 +1,193 @@
+/*************************************************************************/
+/* text_server_fb.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEXT_SERVER_FALLBACK_H
+#define TEXT_SERVER_FALLBACK_H
+
+/*************************************************************************/
+/* Fallback Text Server provides simplified TS functionality, without */
+/* BiDi, shaping and advanced font features support. */
+/*************************************************************************/
+
+#include "servers/text_server.h"
+
+#include "core/templates/rid_owner.h"
+
+#include "scene/resources/texture.h"
+
+#include "font_fb.h"
+
+class TextServerFallback : public TextServer {
+ GDCLASS(TextServerFallback, TextServer);
+ _THREAD_SAFE_CLASS_
+
+ float oversampling = 1.f;
+ mutable RID_PtrOwner<FontDataFallback> font_owner;
+ mutable RID_PtrOwner<ShapedTextData> shaped_owner;
+
+ static String interface_name;
+ static uint32_t interface_features;
+
+protected:
+ static void _bind_methods(){};
+
+ void full_copy(ShapedTextData *p_shaped);
+ void invalidate(ShapedTextData *p_shaped);
+
+public:
+ virtual bool has_feature(Feature p_feature) override;
+ virtual String get_name() const override;
+
+ virtual void free(RID p_rid) override;
+ virtual bool has(RID p_rid) override;
+ virtual bool load_support_data(const String &p_filename) override;
+
+#ifdef TOOLS_ENABLED
+ virtual String get_support_data_filename() override { return ""; };
+ virtual String get_support_data_info() override { return "Not supported"; };
+ virtual bool save_support_data(const String &p_filename) override;
+#endif
+
+ virtual bool is_locale_right_to_left(const String &p_locale) override;
+
+ /* Font interface */
+ virtual RID create_font_system(const String &p_name, int p_base_size = 16) override;
+ virtual RID create_font_resource(const String &p_filename, int p_base_size = 16) override;
+ virtual RID create_font_memory(const uint8_t *p_data, size_t p_size, const String &p_type, int p_base_size = 16) override;
+
+ virtual float font_get_height(RID p_font, int p_size) const override;
+ virtual float font_get_ascent(RID p_font, int p_size) const override;
+ virtual float font_get_descent(RID p_font, int p_size) const override;
+
+ virtual float font_get_underline_position(RID p_font, int p_size) const override;
+ virtual float font_get_underline_thickness(RID p_font, int p_size) const override;
+
+ virtual void font_set_antialiased(RID p_font, bool p_antialiased) override;
+ virtual bool font_get_antialiased(RID p_font) const override;
+
+ virtual void font_set_hinting(RID p_font, Hinting p_hinting) override;
+ virtual Hinting font_get_hinting(RID p_font) const override;
+
+ virtual void font_set_force_autohinter(RID p_font, bool p_enabeld) override;
+ virtual bool font_get_force_autohinter(RID p_font) const override;
+
+ virtual bool font_has_char(RID p_font, char32_t p_char) const override;
+ virtual String font_get_supported_chars(RID p_font) const override;
+
+ virtual void font_set_distance_field_hint(RID p_font, bool p_distance_field) override;
+ virtual bool font_get_distance_field_hint(RID p_font) const override;
+
+ virtual bool font_has_outline(RID p_font) const override;
+ virtual float font_get_base_size(RID p_font) const override;
+
+ virtual bool font_is_language_supported(RID p_font, const String &p_language) const override;
+ virtual void font_set_language_support_override(RID p_font, const String &p_language, bool p_supported) override;
+ virtual bool font_get_language_support_override(RID p_font, const String &p_language) override;
+ virtual void font_remove_language_support_override(RID p_font, const String &p_language) override;
+ Vector<String> font_get_language_support_overrides(RID p_font) override;
+
+ virtual bool font_is_script_supported(RID p_font, const String &p_script) const override;
+ virtual void font_set_script_support_override(RID p_font, const String &p_script, bool p_supported) override;
+ virtual bool font_get_script_support_override(RID p_font, const String &p_script) override;
+ virtual void font_remove_script_support_override(RID p_font, const String &p_script) override;
+ Vector<String> font_get_script_support_overrides(RID p_font) override;
+
+ virtual uint32_t font_get_glyph_index(RID p_font, char32_t p_char, char32_t p_variation_selector = 0x0000) const override;
+ virtual Vector2 font_get_glyph_advance(RID p_font, uint32_t p_index, int p_size) const override;
+ virtual Vector2 font_get_glyph_kerning(RID p_font, uint32_t p_index_a, uint32_t p_index_b, int p_size) const override;
+
+ virtual Vector2 font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
+ virtual Vector2 font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
+
+ virtual float font_get_oversampling() const override;
+ virtual void font_set_oversampling(float p_oversampling) override;
+
+ virtual Vector<String> get_system_fonts() const 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_set_direction(RID p_shaped, Direction p_direction = DIRECTION_AUTO) override;
+ virtual Direction shaped_text_get_direction(RID p_shaped) const override;
+
+ virtual void shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) 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(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(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(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 = "") override;
+ virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1) override;
+ virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER) 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 float shaped_text_fit_to_width(RID p_shaped, float p_width, uint8_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override;
+ virtual float shaped_text_tab_align(RID p_shaped, const Vector<float> &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_is_ready(RID p_shaped) const override;
+
+ virtual Vector<Glyph> shaped_text_get_glyphs(RID p_shaped) const override;
+
+ virtual Vector2i shaped_text_get_range(RID p_shaped) const override;
+
+ virtual Vector<Glyph> shaped_text_sort_logical(RID p_shaped) 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(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;
+
+ static TextServer *create_func(Error &r_error, void *p_user_data);
+ static void register_server();
+
+ TextServerFallback(){};
+ ~TextServerFallback(){};
+};
+
+#endif // TEXT_SERVER_FALLBACK_H
diff --git a/modules/tga/image_loader_tga.cpp b/modules/tga/image_loader_tga.cpp
index 1475d24792..2da9159228 100644
--- a/modules/tga/image_loader_tga.cpp
+++ b/modules/tga/image_loader_tga.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,10 +30,10 @@
#include "image_loader_tga.h"
-#include "core/error_macros.h"
+#include "core/error/error_macros.h"
#include "core/io/file_access_memory.h"
#include "core/os/os.h"
-#include "core/print_string.h"
+#include "core/string/print_string.h"
Error ImageLoaderTGA::decode_tga_rle(const uint8_t *p_compressed_buffer, size_t p_pixel_size, uint8_t *p_uncompressed_buffer, size_t p_output_size) {
Error error;
@@ -313,9 +313,9 @@ void ImageLoaderTGA::get_recognized_extensions(List<String> *p_extensions) const
p_extensions->push_back("tga");
}
-static Ref<Image> _tga_mem_loader_func(const uint8_t *p_png, int p_size) {
+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_png, p_size);
+ 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.instance();
diff --git a/modules/tga/image_loader_tga.h b/modules/tga/image_loader_tga.h
index 6b3d33e7ef..249e33411e 100644
--- a/modules/tga/image_loader_tga.h
+++ b/modules/tga/image_loader_tga.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/tga/register_types.cpp b/modules/tga/register_types.cpp
index 320f748083..9e5fe124ef 100644
--- a/modules/tga/register_types.cpp
+++ b/modules/tga/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/tga/register_types.h b/modules/tga/register_types.h
index 94a77d295e..0dcd750250 100644
--- a/modules/tga/register_types.h
+++ b/modules/tga/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/theora/SCsub b/modules/theora/SCsub
index a01e65b4b0..6038ea086a 100644
--- a/modules/theora/SCsub
+++ b/modules/theora/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_theora = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_libtheora"]:
thirdparty_dir = "#thirdparty/libtheora/"
thirdparty_sources = [
@@ -80,7 +83,16 @@ if env["builtin_libtheora"]:
env_thirdparty = env_theora.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
# Godot source files
-env_theora.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_theora.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/theora/register_types.cpp b/modules/theora/register_types.cpp
index 0676cab5c5..0218b8c7a4 100644
--- a/modules/theora/register_types.cpp
+++ b/modules/theora/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/theora/register_types.h b/modules/theora/register_types.h
index 4f0670b2c7..654d70e417 100644
--- a/modules/theora/register_types.h
+++ b/modules/theora/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp
index 498391e44a..1026d58b85 100644
--- a/modules/theora/video_stream_theora.cpp
+++ b/modules/theora/video_stream_theora.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,8 +30,8 @@
#include "video_stream_theora.h"
+#include "core/config/project_settings.h"
#include "core/os/os.h"
-#include "core/project_settings.h"
#include "thirdparty/misc/yuv2rgb.h"
@@ -140,9 +140,7 @@ void VideoStreamPlaybackTheora::clear() {
#ifdef THEORA_USE_THREAD_STREAMING
thread_exit = true;
thread_sem->post(); //just in case
- Thread::wait_to_finish(thread);
- memdelete(thread);
- thread = nullptr;
+ thread.wait_to_finish();
ring_buffer.clear();
#endif
@@ -181,7 +179,7 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) {
int read = file->get_buffer(read_buffer.ptr(), to_read);
ring_buffer.write(read_buffer.ptr(), read);
- thread = Thread::create(_streaming_thread, this);
+ thread.start(_streaming_thread, this);
#endif
@@ -669,7 +667,6 @@ VideoStreamPlaybackTheora::VideoStreamPlaybackTheora() {
ring_buffer.resize(rb_power);
read_buffer.resize(RB_SIZE_KB * 1024);
thread_sem = Semaphore::create();
- thread = nullptr;
thread_exit = false;
thread_eof = false;
diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h
index 84f816acf8..c315d682da 100644
--- a/modules/theora/video_stream_theora.h
+++ b/modules/theora/video_stream_theora.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,7 +35,7 @@
#include "core/os/file_access.h"
#include "core/os/semaphore.h"
#include "core/os/thread.h"
-#include "core/ring_buffer.h"
+#include "core/templates/ring_buffer.h"
#include "scene/resources/video_stream.h"
#include "servers/audio_server.h"
@@ -112,7 +112,7 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback {
Vector<uint8_t> read_buffer;
bool thread_eof;
Semaphore *thread_sem;
- Thread *thread;
+ Thread thread;
volatile bool thread_exit;
static void _streaming_thread(void *ud);
diff --git a/modules/tinyexr/SCsub b/modules/tinyexr/SCsub
index 84b3b4015b..30bde96fb4 100644
--- a/modules/tinyexr/SCsub
+++ b/modules/tinyexr/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_tinyexr = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
# Not unbundled for now as they are not commonly available as shared library
thirdparty_dir = "#thirdparty/tinyexr/"
thirdparty_sources = [
@@ -20,7 +23,15 @@ env_tinyexr.Append(CPPDEFINES=["TINYEXR_USE_THREAD"])
env_thirdparty = env_tinyexr.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_tinyexr.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-# Godot's own source files
-env_tinyexr.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/tinyexr/image_loader_tinyexr.cpp b/modules/tinyexr/image_loader_tinyexr.cpp
index 5bdcb84244..47214e6974 100644
--- a/modules/tinyexr/image_loader_tinyexr.cpp
+++ b/modules/tinyexr/image_loader_tinyexr.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,7 +31,7 @@
#include "image_loader_tinyexr.h"
#include "core/os/os.h"
-#include "core/print_string.h"
+#include "core/string/print_string.h"
#include "thirdparty/tinyexr/tinyexr.h"
diff --git a/modules/tinyexr/image_loader_tinyexr.h b/modules/tinyexr/image_loader_tinyexr.h
index ff040b0915..34390fccb0 100644
--- a/modules/tinyexr/image_loader_tinyexr.h
+++ b/modules/tinyexr/image_loader_tinyexr.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/tinyexr/image_saver_tinyexr.cpp b/modules/tinyexr/image_saver_tinyexr.cpp
index 420619bd5f..f747763248 100644
--- a/modules/tinyexr/image_saver_tinyexr.cpp
+++ b/modules/tinyexr/image_saver_tinyexr.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/tinyexr/image_saver_tinyexr.h b/modules/tinyexr/image_saver_tinyexr.h
index c7154bcfc7..e5060ef11c 100644
--- a/modules/tinyexr/image_saver_tinyexr.h
+++ b/modules/tinyexr/image_saver_tinyexr.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/tinyexr/register_types.cpp b/modules/tinyexr/register_types.cpp
index 9d0fb8729e..ecbabc4951 100644
--- a/modules/tinyexr/register_types.cpp
+++ b/modules/tinyexr/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/tinyexr/register_types.h b/modules/tinyexr/register_types.h
index 9739488312..e401f37066 100644
--- a/modules/tinyexr/register_types.h
+++ b/modules/tinyexr/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/upnp/SCsub b/modules/upnp/SCsub
index 2e129e15ca..bc0b215be3 100644
--- a/modules/upnp/SCsub
+++ b/modules/upnp/SCsub
@@ -7,6 +7,8 @@ env_upnp = env_modules.Clone()
# Thirdparty source files
+thirdparty_obj = []
+
if env["builtin_miniupnpc"]:
thirdparty_dir = "#thirdparty/miniupnpc/"
thirdparty_sources = [
@@ -31,7 +33,16 @@ if env["builtin_miniupnpc"]:
env_thirdparty = env_upnp.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
# Godot source files
-env_upnp.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_upnp.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/upnp/register_types.cpp b/modules/upnp/register_types.cpp
index 34900206de..a5ee39517f 100644
--- a/modules/upnp/register_types.cpp
+++ b/modules/upnp/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,7 +30,7 @@
#include "register_types.h"
-#include "core/error_macros.h"
+#include "core/error/error_macros.h"
#include "upnp.h"
#include "upnp_device.h"
diff --git a/modules/upnp/register_types.h b/modules/upnp/register_types.h
index 0c71db9ffa..768031c4d9 100644
--- a/modules/upnp/register_types.h
+++ b/modules/upnp/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/upnp/upnp.cpp b/modules/upnp/upnp.cpp
index 988bf3017d..8c3be884bd 100644
--- a/modules/upnp/upnp.cpp
+++ b/modules/upnp/upnp.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -36,7 +36,7 @@
#include <stdlib.h>
bool UPNP::is_common_device(const String &dev) const {
- return dev.empty() ||
+ return dev.is_empty() ||
dev.find("InternetGatewayDevice") >= 0 ||
dev.find("WANIPConnection") >= 0 ||
dev.find("WANPPPConnection") >= 0 ||
@@ -76,7 +76,7 @@ int UPNP::discover(int timeout, int ttl, const String &device_filter) {
struct UPNPDev *dev = devlist;
while (dev) {
- if (device_filter.empty() || strstr(dev->st, device_filter.utf8().get_data())) {
+ if (device_filter.is_empty() || strstr(dev->st, device_filter.utf8().get_data())) {
add_device_to_list(dev, devlist);
}
diff --git a/modules/upnp/upnp.h b/modules/upnp/upnp.h
index 1c4b5549f4..9dfa907476 100644
--- a/modules/upnp/upnp.h
+++ b/modules/upnp/upnp.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,7 +31,7 @@
#ifndef GODOT_UPNP_H
#define GODOT_UPNP_H
-#include "core/reference.h"
+#include "core/object/reference.h"
#include "upnp_device.h"
@@ -57,7 +57,6 @@ protected:
public:
enum UPNPResult {
-
UPNP_RESULT_SUCCESS,
UPNP_RESULT_NOT_AUTHORIZED,
UPNP_RESULT_PORT_MAPPING_NOT_FOUND,
diff --git a/modules/upnp/upnp_device.cpp b/modules/upnp/upnp_device.cpp
index 40eb6106a0..ddc66d593c 100644
--- a/modules/upnp/upnp_device.cpp
+++ b/modules/upnp/upnp_device.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -65,7 +65,7 @@ int UPNPDevice::add_port_mapping(int port, int port_internal, String desc, Strin
itos(port).utf8().get_data(),
itos(port_internal).utf8().get_data(),
igd_our_addr.utf8().get_data(),
- desc.empty() ? nullptr : desc.utf8().get_data(),
+ desc.is_empty() ? nullptr : desc.utf8().get_data(),
proto.utf8().get_data(),
nullptr, // Remote host, always nullptr as IGDs don't support it
duration > 0 ? itos(duration).utf8().get_data() : nullptr);
diff --git a/modules/upnp/upnp_device.h b/modules/upnp/upnp_device.h
index 4b519fce32..126e761a56 100644
--- a/modules/upnp/upnp_device.h
+++ b/modules/upnp/upnp_device.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,14 +31,13 @@
#ifndef GODOT_UPNP_DEVICE_H
#define GODOT_UPNP_DEVICE_H
-#include "core/reference.h"
+#include "core/object/reference.h"
class UPNPDevice : public Reference {
GDCLASS(UPNPDevice, Reference);
public:
enum IGDStatus {
-
IGD_STATUS_OK,
IGD_STATUS_HTTP_ERROR,
IGD_STATUS_HTTP_EMPTY,
diff --git a/modules/vhacd/SCsub b/modules/vhacd/SCsub
index ecd432b275..1ff4122114 100644
--- a/modules/vhacd/SCsub
+++ b/modules/vhacd/SCsub
@@ -7,6 +7,8 @@ env_vhacd = env_modules.Clone()
# Thirdparty source files
+thirdparty_obj = []
+
thirdparty_dir = "#thirdparty/vhacd/"
thirdparty_sources = [
@@ -24,10 +26,19 @@ thirdparty_sources = [
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
-env_vhacd.Prepend(CPPPATH=[thirdparty_dir + "/inc"])
+env_vhacd.Prepend(CPPPATH=[thirdparty_dir + "inc"])
env_thirdparty = env_vhacd.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_vhacd.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-env_vhacd.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/vhacd/register_types.cpp b/modules/vhacd/register_types.cpp
index 40c5e47440..daad39bdfb 100644
--- a/modules/vhacd/register_types.cpp
+++ b/modules/vhacd/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/vhacd/register_types.h b/modules/vhacd/register_types.h
index d02a990901..24ad9378f4 100644
--- a/modules/vhacd/register_types.h
+++ b/modules/vhacd/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/visual_script/doc_classes/VisualScript.xml b/modules/visual_script/doc_classes/VisualScript.xml
index 088d84d2ec..5112ea43a7 100644
--- a/modules/visual_script/doc_classes/VisualScript.xml
+++ b/modules/visual_script/doc_classes/VisualScript.xml
@@ -26,23 +26,23 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
+ <argument index="1" name="func_node_id" type="int">
+ </argument>
<description>
- Add a function with the specified name to the VisualScript.
+ Add a function with the specified name to the VisualScript, and assign the root [VisualScriptFunction] node's id as [code]func_node_id[/code].
</description>
</method>
<method name="add_node">
<return type="void">
</return>
- <argument index="0" name="func" type="StringName">
- </argument>
- <argument index="1" name="id" type="int">
+ <argument index="0" name="id" type="int">
</argument>
- <argument index="2" name="node" type="VisualScriptNode">
+ <argument index="1" name="node" type="VisualScriptNode">
</argument>
- <argument index="3" name="position" type="Vector2" default="Vector2( 0, 0 )">
+ <argument index="2" name="position" type="Vector2" default="Vector2( 0, 0 )">
</argument>
<description>
- Add a node to a function of the VisualScript.
+ Add a node to the VisualScript.
</description>
</method>
<method name="add_variable">
@@ -157,15 +157,13 @@
<method name="data_connect">
<return type="void">
</return>
- <argument index="0" name="func" type="StringName">
- </argument>
- <argument index="1" name="from_node" type="int">
+ <argument index="0" name="from_node" type="int">
</argument>
- <argument index="2" name="from_port" type="int">
+ <argument index="1" name="from_port" type="int">
</argument>
- <argument index="3" name="to_node" type="int">
+ <argument index="2" name="to_node" type="int">
</argument>
- <argument index="4" name="to_port" type="int">
+ <argument index="3" name="to_port" type="int">
</argument>
<description>
Connect two data ports. The value of [code]from_node[/code]'s [code]from_port[/code] would be fed into [code]to_node[/code]'s [code]to_port[/code].
@@ -174,15 +172,13 @@
<method name="data_disconnect">
<return type="void">
</return>
- <argument index="0" name="func" type="StringName">
+ <argument index="0" name="from_node" type="int">
</argument>
- <argument index="1" name="from_node" type="int">
+ <argument index="1" name="from_port" type="int">
</argument>
- <argument index="2" name="from_port" type="int">
+ <argument index="2" name="to_node" type="int">
</argument>
- <argument index="3" name="to_node" type="int">
- </argument>
- <argument index="4" name="to_port" type="int">
+ <argument index="3" name="to_port" type="int">
</argument>
<description>
Disconnect two data ports previously connected with [method data_connect].
@@ -197,37 +193,31 @@
Returns the id of a function's entry point node.
</description>
</method>
- <method name="get_function_scroll" qualifiers="const">
- <return type="Vector2">
- </return>
- <argument index="0" name="name" type="StringName">
- </argument>
- <description>
- Returns the position of the center of the screen for a given function.
- </description>
- </method>
<method name="get_node" qualifiers="const">
<return type="VisualScriptNode">
</return>
- <argument index="0" name="func" type="StringName">
- </argument>
- <argument index="1" name="id" type="int">
+ <argument index="0" name="id" type="int">
</argument>
<description>
- Returns a node given its id and its function.
+ Returns a node given its id.
</description>
</method>
<method name="get_node_position" qualifiers="const">
<return type="Vector2">
</return>
- <argument index="0" name="func" type="StringName">
- </argument>
- <argument index="1" name="id" type="int">
+ <argument index="0" name="id" type="int">
</argument>
<description>
Returns a node's position in pixels.
</description>
</method>
+ <method name="get_scroll" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <description>
+ Returns the current position of the center of the screen.
+ </description>
+ </method>
<method name="get_variable_default_value" qualifiers="const">
<return type="Variant">
</return>
@@ -267,15 +257,13 @@
<method name="has_data_connection" qualifiers="const">
<return type="bool">
</return>
- <argument index="0" name="func" type="StringName">
- </argument>
- <argument index="1" name="from_node" type="int">
+ <argument index="0" name="from_node" type="int">
</argument>
- <argument index="2" name="from_port" type="int">
+ <argument index="1" name="from_port" type="int">
</argument>
- <argument index="3" name="to_node" type="int">
+ <argument index="2" name="to_node" type="int">
</argument>
- <argument index="4" name="to_port" type="int">
+ <argument index="3" name="to_port" type="int">
</argument>
<description>
Returns whether the specified data ports are connected.
@@ -293,9 +281,7 @@
<method name="has_node" qualifiers="const">
<return type="bool">
</return>
- <argument index="0" name="func" type="StringName">
- </argument>
- <argument index="1" name="id" type="int">
+ <argument index="0" name="id" type="int">
</argument>
<description>
Returns whether a node exists with the given id.
@@ -304,13 +290,11 @@
<method name="has_sequence_connection" qualifiers="const">
<return type="bool">
</return>
- <argument index="0" name="func" type="StringName">
- </argument>
- <argument index="1" name="from_node" type="int">
+ <argument index="0" name="from_node" type="int">
</argument>
- <argument index="2" name="from_output" type="int">
+ <argument index="1" name="from_output" type="int">
</argument>
- <argument index="3" name="to_node" type="int">
+ <argument index="2" name="to_node" type="int">
</argument>
<description>
Returns whether the specified sequence ports are connected.
@@ -346,12 +330,10 @@
<method name="remove_node">
<return type="void">
</return>
- <argument index="0" name="func" type="StringName">
- </argument>
- <argument index="1" name="id" type="int">
+ <argument index="0" name="id" type="int">
</argument>
<description>
- Remove a specific node.
+ Remove the node with the specified id.
</description>
</method>
<method name="remove_variable">
@@ -399,13 +381,11 @@
<method name="sequence_connect">
<return type="void">
</return>
- <argument index="0" name="func" type="StringName">
+ <argument index="0" name="from_node" type="int">
</argument>
- <argument index="1" name="from_node" type="int">
+ <argument index="1" name="from_output" type="int">
</argument>
- <argument index="2" name="from_output" type="int">
- </argument>
- <argument index="3" name="to_node" type="int">
+ <argument index="2" name="to_node" type="int">
</argument>
<description>
Connect two sequence ports. The execution will flow from of [code]from_node[/code]'s [code]from_output[/code] into [code]to_node[/code].
@@ -415,29 +395,16 @@
<method name="sequence_disconnect">
<return type="void">
</return>
- <argument index="0" name="func" type="StringName">
- </argument>
- <argument index="1" name="from_node" type="int">
+ <argument index="0" name="from_node" type="int">
</argument>
- <argument index="2" name="from_output" type="int">
+ <argument index="1" name="from_output" type="int">
</argument>
- <argument index="3" name="to_node" type="int">
+ <argument index="2" name="to_node" type="int">
</argument>
<description>
Disconnect two sequence ports previously connected with [method sequence_connect].
</description>
</method>
- <method name="set_function_scroll">
- <return type="void">
- </return>
- <argument index="0" name="name" type="StringName">
- </argument>
- <argument index="1" name="ofs" type="Vector2">
- </argument>
- <description>
- Position the center of the screen for a function.
- </description>
- </method>
<method name="set_instance_base_type">
<return type="void">
</return>
@@ -450,14 +417,21 @@
<method name="set_node_position">
<return type="void">
</return>
- <argument index="0" name="func" type="StringName">
+ <argument index="0" name="id" type="int">
</argument>
- <argument index="1" name="id" type="int">
+ <argument index="1" name="position" type="Vector2">
</argument>
- <argument index="2" name="position" type="Vector2">
+ <description>
+ Set the node position in the VisualScript graph.
+ </description>
+ </method>
+ <method name="set_scroll">
+ <return type="void">
+ </return>
+ <argument index="0" name="ofs" type="Vector2">
</argument>
<description>
- Position a node on the screen.
+ Set the screen center to the given position.
</description>
</method>
<method name="set_variable_default_value">
@@ -496,9 +470,7 @@
</methods>
<signals>
<signal name="node_ports_changed">
- <argument index="0" name="function" type="String">
- </argument>
- <argument index="1" name="id" type="int">
+ <argument index="0" name="id" type="int">
</argument>
<description>
Emitted when the ports of a node are changed.
diff --git a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
index ef4183e6f6..219ffd01d3 100644
--- a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
+++ b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
@@ -92,7 +92,7 @@
<constant name="MATH_STEP_DECIMALS" value="24" enum="BuiltinFunc">
Return the number of digit places after the decimal that the first non-zero digit occurs.
</constant>
- <constant name="MATH_STEPIFY" value="25" enum="BuiltinFunc">
+ <constant name="MATH_SNAPPED" value="25" enum="BuiltinFunc">
Return the input snapped to a given step.
</constant>
<constant name="MATH_LERP" value="26" enum="BuiltinFunc">
@@ -111,61 +111,61 @@
<constant name="MATH_RANDOMIZE" value="31" enum="BuiltinFunc">
Randomize the seed (or the internal state) of the random number generator. Current implementation reseeds using a number based on time.
</constant>
- <constant name="MATH_RAND" value="32" enum="BuiltinFunc">
+ <constant name="MATH_RANDI" value="32" enum="BuiltinFunc">
Return a random 32 bits integer value. To obtain a random value between 0 to N (where N is smaller than 2^32 - 1), you can use it with the remainder function.
</constant>
<constant name="MATH_RANDF" value="33" enum="BuiltinFunc">
Return a random floating-point value between 0 and 1. To obtain a random value between 0 to N, you can use it with multiplication.
</constant>
- <constant name="MATH_RANDOM" value="34" enum="BuiltinFunc">
+ <constant name="MATH_RANDF_RANGE" value="34" enum="BuiltinFunc">
Return a random floating-point value between the two inputs.
</constant>
- <constant name="MATH_SEED" value="35" enum="BuiltinFunc">
+ <constant name="MATH_RANDI_RANGE" value="35" enum="BuiltinFunc">
+ Return a random 32-bit integer value between the two inputs.
+ </constant>
+ <constant name="MATH_SEED" value="36" enum="BuiltinFunc">
Set the seed for the random number generator.
</constant>
- <constant name="MATH_RANDSEED" value="36" enum="BuiltinFunc">
+ <constant name="MATH_RANDSEED" value="37" enum="BuiltinFunc">
Return a random value from the given seed, along with the new seed.
</constant>
- <constant name="MATH_DEG2RAD" value="37" enum="BuiltinFunc">
+ <constant name="MATH_DEG2RAD" value="38" enum="BuiltinFunc">
Convert the input from degrees to radians.
</constant>
- <constant name="MATH_RAD2DEG" value="38" enum="BuiltinFunc">
+ <constant name="MATH_RAD2DEG" value="39" enum="BuiltinFunc">
Convert the input from radians to degrees.
</constant>
- <constant name="MATH_LINEAR2DB" value="39" enum="BuiltinFunc">
+ <constant name="MATH_LINEAR2DB" value="40" enum="BuiltinFunc">
Convert the input from linear volume to decibel volume.
</constant>
- <constant name="MATH_DB2LINEAR" value="40" enum="BuiltinFunc">
+ <constant name="MATH_DB2LINEAR" value="41" enum="BuiltinFunc">
Convert the input from decibel volume to linear volume.
</constant>
- <constant name="MATH_POLAR2CARTESIAN" value="41" enum="BuiltinFunc">
+ <constant name="MATH_POLAR2CARTESIAN" value="42" enum="BuiltinFunc">
Converts a 2D point expressed in the polar coordinate system (a distance from the origin [code]r[/code] and an angle [code]th[/code]) to the cartesian coordinate system (X and Y axis).
</constant>
- <constant name="MATH_CARTESIAN2POLAR" value="42" enum="BuiltinFunc">
+ <constant name="MATH_CARTESIAN2POLAR" value="43" enum="BuiltinFunc">
Converts a 2D point expressed in the cartesian coordinate system (X and Y axis) to the polar coordinate system (a distance from the origin and an angle).
</constant>
- <constant name="MATH_WRAP" value="43" enum="BuiltinFunc">
+ <constant name="MATH_WRAP" value="44" enum="BuiltinFunc">
</constant>
- <constant name="MATH_WRAPF" value="44" enum="BuiltinFunc">
+ <constant name="MATH_WRAPF" value="45" enum="BuiltinFunc">
</constant>
- <constant name="LOGIC_MAX" value="45" enum="BuiltinFunc">
+ <constant name="LOGIC_MAX" value="46" enum="BuiltinFunc">
Return the greater of the two numbers, also known as their maximum.
</constant>
- <constant name="LOGIC_MIN" value="46" enum="BuiltinFunc">
+ <constant name="LOGIC_MIN" value="47" enum="BuiltinFunc">
Return the lesser of the two numbers, also known as their minimum.
</constant>
- <constant name="LOGIC_CLAMP" value="47" enum="BuiltinFunc">
+ <constant name="LOGIC_CLAMP" value="48" enum="BuiltinFunc">
Return the input clamped inside the given range, ensuring the result is never outside it. Equivalent to [code]min(max(input, range_low), range_high)[/code].
</constant>
- <constant name="LOGIC_NEAREST_PO2" value="48" enum="BuiltinFunc">
+ <constant name="LOGIC_NEAREST_PO2" value="49" enum="BuiltinFunc">
Return the nearest power of 2 to the input.
</constant>
- <constant name="OBJ_WEAKREF" value="49" enum="BuiltinFunc">
+ <constant name="OBJ_WEAKREF" value="50" enum="BuiltinFunc">
Create a [WeakRef] from the input.
</constant>
- <constant name="FUNC_FUNCREF" value="50" enum="BuiltinFunc">
- Create a [FuncRef] from the input.
- </constant>
<constant name="TYPE_CONVERT" value="51" enum="BuiltinFunc">
Convert between types.
</constant>
@@ -202,24 +202,20 @@
<constant name="BYTES_TO_VAR" value="62" enum="BuiltinFunc">
Deserialize a [Variant] from a [PackedByteArray] serialized using [constant VAR_TO_BYTES].
</constant>
- <constant name="COLORN" value="63" enum="BuiltinFunc">
- Return the [Color] with the given name and alpha ranging from 0 to 1.
- [b]Note:[/b] Names are defined in [code]color_names.inc[/code].
- </constant>
- <constant name="MATH_SMOOTHSTEP" value="64" enum="BuiltinFunc">
+ <constant name="MATH_SMOOTHSTEP" value="63" enum="BuiltinFunc">
Return a number smoothly interpolated between the first two inputs, based on the third input. Similar to [constant MATH_LERP], but interpolates faster at the beginning and slower at the end. Using Hermite interpolation formula:
[codeblock]
var t = clamp((weight - from) / (to - from), 0.0, 1.0)
return t * t * (3.0 - 2.0 * t)
[/codeblock]
</constant>
- <constant name="MATH_POSMOD" value="65" enum="BuiltinFunc">
+ <constant name="MATH_POSMOD" value="64" enum="BuiltinFunc">
</constant>
- <constant name="MATH_LERP_ANGLE" value="66" enum="BuiltinFunc">
+ <constant name="MATH_LERP_ANGLE" value="65" enum="BuiltinFunc">
</constant>
- <constant name="TEXT_ORD" value="67" enum="BuiltinFunc">
+ <constant name="TEXT_ORD" value="66" enum="BuiltinFunc">
</constant>
- <constant name="FUNC_MAX" value="68" enum="BuiltinFunc">
+ <constant name="FUNC_MAX" value="67" enum="BuiltinFunc">
Represents the size of the [enum BuiltinFunc] enum.
</constant>
</constants>
diff --git a/modules/visual_script/doc_classes/VisualScriptLists.xml b/modules/visual_script/doc_classes/VisualScriptLists.xml
index 5b64d8438b..8a7254b46a 100644
--- a/modules/visual_script/doc_classes/VisualScriptLists.xml
+++ b/modules/visual_script/doc_classes/VisualScriptLists.xml
@@ -4,7 +4,7 @@
A Visual Script virtual class for in-graph editable nodes.
</brief_description>
<description>
- A Visual Script virtual class that defines the shape and the default behaviour of the nodes that have to be in-graph editable nodes.
+ A Visual Script virtual class that defines the shape and the default behavior of the nodes that have to be in-graph editable nodes.
</description>
<tutorials>
</tutorials>
diff --git a/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml b/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
index f13d449064..1c22070ab1 100644
--- a/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
@@ -31,5 +31,7 @@
</constant>
<constant name="CALL_MODE_INSTANCE" value="2" enum="CallMode">
</constant>
+ <constant name="CALL_MODE_BASIC_TYPE" value="3" enum="CallMode">
+ </constant>
</constants>
</class>
diff --git a/modules/visual_script/icons/VisualScript.svg b/modules/visual_script/icons/VisualScript.svg
index f6475d590e..2352ba5d87 100644
--- a/modules/visual_script/icons/VisualScript.svg
+++ b/modules/visual_script/icons/VisualScript.svg
@@ -1,6 +1 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1036.4)">
-<ellipse cx="3" cy="1039.4" r="2" fill="#6e6e6e"/>
-<path transform="translate(0 1036.4)" d="m7 1l-0.56445 2.2578a5 5 0 0 0 -0.68945 0.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941a5 5 0 0 0 -0.28516 0.68555l-2.2539 0.5625v2h5.2715a2 2 0 0 1 -0.27148 -1 2 2 0 0 1 2 -2 2 2 0 0 1 2 2 2 2 0 0 1 -0.26953 1h5.2695v-2l-2.2578-0.56445a5 5 0 0 0 -0.2793 -0.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953a5 5 0 0 0 -0.68555 -0.28516l-0.5625-2.2539h-2zm-4 9v6h2a3 3 0 0 0 3 -3v-3h-2v3a1 1 0 0 1 -1 1v-4h-2zm8 0a2 2 0 0 0 -1.7324 1 2 2 0 0 0 0 2 2 2 0 0 0 1.7324 1h-2v2h2a2 2 0 0 0 1.7324 -1 2 2 0 0 0 0 -2 2 2 0 0 0 -1.7324 -1h2v-2h-2z" fill="#e0e0e0"/>
-</g>
-</svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><ellipse cx="3" cy="1039.4" fill="#6e6e6e"/><path d="m7 1-.56445 2.2578a5 5 0 0 0 -.68945.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941a5 5 0 0 0 -.28516.68555l-2.2539.5625v2h5.2715a2 2 0 0 1 -.27148-1 2 2 0 0 1 2-2 2 2 0 0 1 2 2 2 2 0 0 1 -.26953 1h5.2695v-2l-2.2578-.56445a5 5 0 0 0 -.2793-.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953a5 5 0 0 0 -.68555-.28516l-.5625-2.2539h-2zm-4 9v6h2a3 3 0 0 0 3-3v-3h-2v3a1 1 0 0 1 -1 1v-4zm8 0a2 2 0 0 0 -1.7324 1 2 2 0 0 0 0 2 2 2 0 0 0 1.7324 1h-2v2h2a2 2 0 0 0 1.7324-1 2 2 0 0 0 0-2 2 2 0 0 0 -1.7324-1h2v-2z" fill="#e0e0e0" transform="translate(0 1036.4)"/></g></svg>
diff --git a/modules/visual_script/register_types.cpp b/modules/visual_script/register_types.cpp
index 8afed1229f..4c7b66e368 100644
--- a/modules/visual_script/register_types.cpp
+++ b/modules/visual_script/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,7 +30,7 @@
#include "register_types.h"
-#include "core/engine.h"
+#include "core/config/engine.h"
#include "core/io/resource_loader.h"
#include "visual_script.h"
#include "visual_script_builtin_funcs.h"
diff --git a/modules/visual_script/register_types.h b/modules/visual_script/register_types.h
index c18c2930b1..b02a93ebc1 100644
--- a/modules/visual_script/register_types.h
+++ b/modules/visual_script/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index 1af4b46e22..fe92f59179 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,13 +30,13 @@
#include "visual_script.h"
+#include "core/config/project_settings.h"
#include "core/core_string_names.h"
#include "core/os/os.h"
-#include "core/project_settings.h"
#include "scene/main/node.h"
#include "visual_script_nodes.h"
-//used by editor, this is not really saved
+// Used by editor, this is not really saved.
void VisualScriptNode::set_breakpoint(bool p_breakpoint) {
breakpoint = p_breakpoint;
}
@@ -55,8 +55,8 @@ void VisualScriptNode::set_default_input_value(int p_port, const Variant &p_valu
default_input_values[p_port] = p_value;
#ifdef TOOLS_ENABLED
- for (Set<VisualScript *>::Element *E = scripts_used.front(); E; E = E->next()) {
- E->get()->set_edited(true);
+ if (script_used.is_valid()) {
+ script_used->set_edited(true);
}
#endif
}
@@ -73,28 +73,28 @@ void VisualScriptNode::_set_default_input_values(Array p_values) {
void VisualScriptNode::validate_input_default_values() {
default_input_values.resize(MAX(default_input_values.size(), get_input_value_port_count())); //let it grow as big as possible, we don't want to lose values on resize
- //actually validate on save
+ // Actually validate on save.
for (int i = 0; i < get_input_value_port_count(); i++) {
Variant::Type expected = get_input_value_port_info(i).type;
if (expected == Variant::NIL || expected == default_input_values[i].get_type()) {
continue;
} else {
- //not the same, reconvert
+ // Not the same, reconvert.
Callable::CallError ce;
Variant existing = default_input_values[i];
const Variant *existingp = &existing;
- default_input_values[i] = Variant::construct(expected, &existingp, 1, ce, false);
+ Variant::construct(expected, default_input_values[i], &existingp, 1, ce);
if (ce.error != Callable::CallError::CALL_OK) {
//could not convert? force..
- default_input_values[i] = Variant::construct(expected, nullptr, 0, ce, false);
+ Variant::construct(expected, default_input_values[i], nullptr, 0, ce);
}
}
}
}
Array VisualScriptNode::_get_default_input_values() const {
- //validate on save, since on load there is little info about this
+ // Validate on save, since on load there is little info about this.
Array values = default_input_values;
values.resize(get_input_value_port_count());
@@ -118,6 +118,8 @@ void VisualScriptNode::_bind_methods() {
}
VisualScriptNode::TypeGuess VisualScriptNode::guess_output_type(TypeGuess *p_inputs, int p_output) const {
+ ERR_FAIL_COND_V(get_output_value_port_count() <= p_output, TypeGuess());
+
PropertyInfo pinfo = get_output_value_port_info(p_output);
TypeGuess tg;
@@ -131,11 +133,7 @@ VisualScriptNode::TypeGuess VisualScriptNode::guess_output_type(TypeGuess *p_inp
}
Ref<VisualScript> VisualScriptNode::get_visual_script() const {
- if (scripts_used.size()) {
- return Ref<VisualScript>(scripts_used.front()->get());
- }
-
- return Ref<VisualScript>();
+ return script_used;
}
VisualScriptNode::VisualScriptNode() {
@@ -165,13 +163,15 @@ VisualScriptNodeInstance::~VisualScriptNodeInstance() {
}
}
-void VisualScript::add_function(const StringName &p_name) {
+void VisualScript::add_function(const StringName &p_name, int p_func_node_id) {
ERR_FAIL_COND(instances.size());
ERR_FAIL_COND(!String(p_name).is_valid_identifier());
ERR_FAIL_COND(functions.has(p_name));
+ ERR_FAIL_COND(variables.has(p_name));
+ ERR_FAIL_COND(custom_signals.has(p_name));
functions[p_name] = Function();
- functions[p_name].scroll = Vector2(-50, -100);
+ functions[p_name].func_id = p_func_node_id;
}
bool VisualScript::has_function(const StringName &p_name) const {
@@ -182,11 +182,7 @@ void VisualScript::remove_function(const StringName &p_name) {
ERR_FAIL_COND(instances.size());
ERR_FAIL_COND(!functions.has(p_name));
- for (Map<int, Function::NodeData>::Element *E = functions[p_name].nodes.front(); E; E = E->next()) {
- E->get().node->disconnect("ports_changed", callable_mp(this, &VisualScript::_node_ports_changed));
- E->get().node->scripts_used.erase(this);
- }
-
+ // Let the editor handle the node removal.
functions.erase(p_name);
}
@@ -207,53 +203,36 @@ void VisualScript::rename_function(const StringName &p_name, const StringName &p
functions.erase(p_name);
}
-void VisualScript::set_function_scroll(const StringName &p_name, const Vector2 &p_scroll) {
- ERR_FAIL_COND(!functions.has(p_name));
- functions[p_name].scroll = p_scroll;
+void VisualScript::set_scroll(const Vector2 &p_scroll) {
+ scroll = p_scroll;
}
-Vector2 VisualScript::get_function_scroll(const StringName &p_name) const {
- ERR_FAIL_COND_V(!functions.has(p_name), Vector2());
- return functions[p_name].scroll;
+Vector2 VisualScript::get_scroll() const {
+ return scroll;
}
void VisualScript::get_function_list(List<StringName> *r_functions) const {
- for (const Map<StringName, Function>::Element *E = functions.front(); E; E = E->next()) {
- r_functions->push_back(E->key());
- }
-
- r_functions->sort_custom<StringName::AlphCompare>();
+ functions.get_key_list(r_functions);
+ // r_functions->sort_custom<StringName::AlphCompare>(); // Don't force sorting.
}
int VisualScript::get_function_node_id(const StringName &p_name) const {
ERR_FAIL_COND_V(!functions.has(p_name), -1);
- return functions[p_name].function_id;
+ return functions[p_name].func_id;
}
void VisualScript::_node_ports_changed(int p_id) {
- StringName function;
-
- for (Map<StringName, Function>::Element *E = functions.front(); E; E = E->next()) {
- if (E->get().nodes.has(p_id)) {
- function = E->key();
- break;
- }
- }
-
- ERR_FAIL_COND(function == StringName());
-
- Function &func = functions[function];
- Ref<VisualScriptNode> vsn = func.nodes[p_id].node;
+ Ref<VisualScriptNode> vsn = nodes[p_id].node;
vsn->validate_input_default_values();
- //must revalidate all the functions
+ // Must revalidate all the functions.
{
List<SequenceConnection> to_remove;
- for (Set<SequenceConnection>::Element *E = func.sequence_connections.front(); E; E = E->next()) {
+ for (Set<SequenceConnection>::Element *E = sequence_connections.front(); E; E = E->next()) {
if (E->get().from_node == p_id && E->get().from_output >= vsn->get_output_sequence_port_count()) {
to_remove.push_back(E->get());
}
@@ -263,7 +242,7 @@ void VisualScript::_node_ports_changed(int p_id) {
}
while (to_remove.size()) {
- func.sequence_connections.erase(to_remove.front()->get());
+ sequence_connections.erase(to_remove.front()->get());
to_remove.pop_front();
}
}
@@ -271,7 +250,7 @@ void VisualScript::_node_ports_changed(int p_id) {
{
List<DataConnection> to_remove;
- for (Set<DataConnection>::Element *E = func.data_connections.front(); E; E = E->next()) {
+ for (Set<DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
if (E->get().from_node == p_id && E->get().from_port >= vsn->get_output_value_port_count()) {
to_remove.push_back(E->get());
}
@@ -281,63 +260,47 @@ void VisualScript::_node_ports_changed(int p_id) {
}
while (to_remove.size()) {
- func.data_connections.erase(to_remove.front()->get());
+ data_connections.erase(to_remove.front()->get());
to_remove.pop_front();
}
}
#ifdef TOOLS_ENABLED
- set_edited(true); //something changed, let's set as edited
- emit_signal("node_ports_changed", function, p_id);
+ set_edited(true); // Something changed, let's set as edited.
+ emit_signal("node_ports_changed", p_id);
#endif
}
-void VisualScript::add_node(const StringName &p_func, int p_id, const Ref<VisualScriptNode> &p_node, const Point2 &p_pos) {
+void VisualScript::add_node(int p_id, const Ref<VisualScriptNode> &p_node, const Point2 &p_pos) {
ERR_FAIL_COND(instances.size());
- ERR_FAIL_COND(!functions.has(p_func));
-
- for (Map<StringName, Function>::Element *E = functions.front(); E; E = E->next()) {
- ERR_FAIL_COND(E->get().nodes.has(p_id)); //id can exist only one in script, even for different functions
- }
+ ERR_FAIL_COND(nodes.has(p_id)); // ID can exist only one in script.
- Function &func = functions[p_func];
-
- if (Object::cast_to<VisualScriptFunction>(*p_node)) {
- //the function indeed
- ERR_FAIL_COND_MSG(func.function_id >= 0, "A function node has already been set here.");
-
- func.function_id = p_id;
- }
-
- Function::NodeData nd;
+ NodeData nd;
nd.node = p_node;
nd.pos = p_pos;
Ref<VisualScriptNode> vsn = p_node;
vsn->connect("ports_changed", callable_mp(this, &VisualScript::_node_ports_changed), varray(p_id));
- vsn->scripts_used.insert(this);
- vsn->validate_input_default_values(); // Validate when fully loaded
+ vsn->script_used = Ref<VisualScript>(this);
+ vsn->validate_input_default_values(); // Validate when fully loaded.
- func.nodes[p_id] = nd;
+ nodes[p_id] = nd;
}
-void VisualScript::remove_node(const StringName &p_func, int p_id) {
+void VisualScript::remove_node(int p_id) {
ERR_FAIL_COND(instances.size());
- ERR_FAIL_COND(!functions.has(p_func));
- Function &func = functions[p_func];
-
- ERR_FAIL_COND(!func.nodes.has(p_id));
+ ERR_FAIL_COND(!nodes.has(p_id));
{
List<SequenceConnection> to_remove;
- for (Set<SequenceConnection>::Element *E = func.sequence_connections.front(); E; E = E->next()) {
+ for (Set<SequenceConnection>::Element *E = sequence_connections.front(); E; E = E->next()) {
if (E->get().from_node == p_id || E->get().to_node == p_id) {
to_remove.push_back(E->get());
}
}
while (to_remove.size()) {
- func.sequence_connections.erase(to_remove.front()->get());
+ sequence_connections.erase(to_remove.front()->get());
to_remove.pop_front();
}
}
@@ -345,122 +308,88 @@ void VisualScript::remove_node(const StringName &p_func, int p_id) {
{
List<DataConnection> to_remove;
- for (Set<DataConnection>::Element *E = func.data_connections.front(); E; E = E->next()) {
+ for (Set<DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
if (E->get().from_node == p_id || E->get().to_node == p_id) {
to_remove.push_back(E->get());
}
}
while (to_remove.size()) {
- func.data_connections.erase(to_remove.front()->get());
+ data_connections.erase(to_remove.front()->get());
to_remove.pop_front();
}
}
- if (Object::cast_to<VisualScriptFunction>(func.nodes[p_id].node.ptr())) {
- func.function_id = -1; //revert to invalid
- }
+ nodes[p_id].node->disconnect("ports_changed", callable_mp(this, &VisualScript::_node_ports_changed));
+ nodes[p_id].node->script_used.unref();
- func.nodes[p_id].node->disconnect("ports_changed", callable_mp(this, &VisualScript::_node_ports_changed));
- func.nodes[p_id].node->scripts_used.erase(this);
-
- func.nodes.erase(p_id);
+ nodes.erase(p_id);
}
-bool VisualScript::has_node(const StringName &p_func, int p_id) const {
- ERR_FAIL_COND_V(!functions.has(p_func), false);
- const Function &func = functions[p_func];
-
- return func.nodes.has(p_id);
+bool VisualScript::has_node(int p_id) const {
+ return nodes.has(p_id);
}
-Ref<VisualScriptNode> VisualScript::get_node(const StringName &p_func, int p_id) const {
- ERR_FAIL_COND_V(!functions.has(p_func), Ref<VisualScriptNode>());
- const Function &func = functions[p_func];
-
- ERR_FAIL_COND_V(!func.nodes.has(p_id), Ref<VisualScriptNode>());
+Ref<VisualScriptNode> VisualScript::get_node(int p_id) const {
+ ERR_FAIL_COND_V(!nodes.has(p_id), Ref<VisualScriptNode>());
- return func.nodes[p_id].node;
+ return nodes[p_id].node;
}
-void VisualScript::set_node_position(const StringName &p_func, int p_id, const Point2 &p_pos) {
+void VisualScript::set_node_position(int p_id, const Point2 &p_pos) {
ERR_FAIL_COND(instances.size());
- ERR_FAIL_COND(!functions.has(p_func));
- Function &func = functions[p_func];
-
- ERR_FAIL_COND(!func.nodes.has(p_id));
- func.nodes[p_id].pos = p_pos;
+ ERR_FAIL_COND(!nodes.has(p_id));
+ nodes[p_id].pos = p_pos;
}
-Point2 VisualScript::get_node_position(const StringName &p_func, int p_id) const {
- ERR_FAIL_COND_V(!functions.has(p_func), Point2());
- const Function &func = functions[p_func];
-
- ERR_FAIL_COND_V(!func.nodes.has(p_id), Point2());
- return func.nodes[p_id].pos;
+Point2 VisualScript::get_node_position(int p_id) const {
+ ERR_FAIL_COND_V(!nodes.has(p_id), Point2());
+ return nodes[p_id].pos;
}
-void VisualScript::get_node_list(const StringName &p_func, List<int> *r_nodes) const {
- ERR_FAIL_COND(!functions.has(p_func));
- const Function &func = functions[p_func];
-
- for (const Map<int, Function::NodeData>::Element *E = func.nodes.front(); E; E = E->next()) {
- r_nodes->push_back(E->key());
- }
+void VisualScript::get_node_list(List<int> *r_nodes) const {
+ nodes.get_key_list(r_nodes);
}
-void VisualScript::sequence_connect(const StringName &p_func, int p_from_node, int p_from_output, int p_to_node) {
+void VisualScript::sequence_connect(int p_from_node, int p_from_output, int p_to_node) {
ERR_FAIL_COND(instances.size());
- ERR_FAIL_COND(!functions.has(p_func));
- Function &func = functions[p_func];
SequenceConnection sc;
sc.from_node = p_from_node;
sc.from_output = p_from_output;
sc.to_node = p_to_node;
- ERR_FAIL_COND(func.sequence_connections.has(sc));
+ ERR_FAIL_COND(sequence_connections.has(sc));
- func.sequence_connections.insert(sc);
+ sequence_connections.insert(sc);
}
-void VisualScript::sequence_disconnect(const StringName &p_func, int p_from_node, int p_from_output, int p_to_node) {
- ERR_FAIL_COND(!functions.has(p_func));
- Function &func = functions[p_func];
-
+void VisualScript::sequence_disconnect(int p_from_node, int p_from_output, int p_to_node) {
SequenceConnection sc;
sc.from_node = p_from_node;
sc.from_output = p_from_output;
sc.to_node = p_to_node;
- ERR_FAIL_COND(!func.sequence_connections.has(sc));
+ ERR_FAIL_COND(!sequence_connections.has(sc));
- func.sequence_connections.erase(sc);
+ sequence_connections.erase(sc);
}
-bool VisualScript::has_sequence_connection(const StringName &p_func, int p_from_node, int p_from_output, int p_to_node) const {
- ERR_FAIL_COND_V(!functions.has(p_func), false);
- const Function &func = functions[p_func];
-
+bool VisualScript::has_sequence_connection(int p_from_node, int p_from_output, int p_to_node) const {
SequenceConnection sc;
sc.from_node = p_from_node;
sc.from_output = p_from_output;
sc.to_node = p_to_node;
- return func.sequence_connections.has(sc);
+ return sequence_connections.has(sc);
}
-void VisualScript::get_sequence_connection_list(const StringName &p_func, List<SequenceConnection> *r_connection) const {
- ERR_FAIL_COND(!functions.has(p_func));
- const Function &func = functions[p_func];
-
- for (const Set<SequenceConnection>::Element *E = func.sequence_connections.front(); E; E = E->next()) {
+void VisualScript::get_sequence_connection_list(List<SequenceConnection> *r_connection) const {
+ for (const Set<SequenceConnection>::Element *E = sequence_connections.front(); E; E = E->next()) {
r_connection->push_back(E->get());
}
}
-void VisualScript::data_connect(const StringName &p_func, int p_from_node, int p_from_port, int p_to_node, int p_to_port) {
+void VisualScript::data_connect(int p_from_node, int p_from_port, int p_to_node, int p_to_port) {
ERR_FAIL_COND(instances.size());
- ERR_FAIL_COND(!functions.has(p_func));
- Function &func = functions[p_func];
DataConnection dc;
dc.from_node = p_from_node;
@@ -468,72 +397,55 @@ void VisualScript::data_connect(const StringName &p_func, int p_from_node, int p
dc.to_node = p_to_node;
dc.to_port = p_to_port;
- ERR_FAIL_COND(func.data_connections.has(dc));
+ ERR_FAIL_COND(data_connections.has(dc));
- func.data_connections.insert(dc);
+ data_connections.insert(dc);
}
-void VisualScript::data_disconnect(const StringName &p_func, int p_from_node, int p_from_port, int p_to_node, int p_to_port) {
- ERR_FAIL_COND(!functions.has(p_func));
- Function &func = functions[p_func];
-
+void VisualScript::data_disconnect(int p_from_node, int p_from_port, int p_to_node, int p_to_port) {
DataConnection dc;
dc.from_node = p_from_node;
dc.from_port = p_from_port;
dc.to_node = p_to_node;
dc.to_port = p_to_port;
- ERR_FAIL_COND(!func.data_connections.has(dc));
+ ERR_FAIL_COND(!data_connections.has(dc));
- func.data_connections.erase(dc);
+ data_connections.erase(dc);
}
-bool VisualScript::has_data_connection(const StringName &p_func, int p_from_node, int p_from_port, int p_to_node, int p_to_port) const {
- ERR_FAIL_COND_V(!functions.has(p_func), false);
- const Function &func = functions[p_func];
-
+bool VisualScript::has_data_connection(int p_from_node, int p_from_port, int p_to_node, int p_to_port) const {
DataConnection dc;
dc.from_node = p_from_node;
dc.from_port = p_from_port;
dc.to_node = p_to_node;
dc.to_port = p_to_port;
- return func.data_connections.has(dc);
+ return data_connections.has(dc);
}
-bool VisualScript::is_input_value_port_connected(const StringName &p_func, int p_node, int p_port) const {
- ERR_FAIL_COND_V(!functions.has(p_func), false);
- const Function &func = functions[p_func];
-
- for (const Set<DataConnection>::Element *E = func.data_connections.front(); E; E = E->next()) {
+bool VisualScript::is_input_value_port_connected(int p_node, int p_port) const {
+ for (const Set<DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
if (E->get().to_node == p_node && E->get().to_port == p_port) {
return true;
}
}
-
return false;
}
-bool VisualScript::get_input_value_port_connection_source(const StringName &p_func, int p_node, int p_port, int *r_node, int *r_port) const {
- ERR_FAIL_COND_V(!functions.has(p_func), false);
- const Function &func = functions[p_func];
-
- for (const Set<DataConnection>::Element *E = func.data_connections.front(); E; E = E->next()) {
+bool VisualScript::get_input_value_port_connection_source(int p_node, int p_port, int *r_node, int *r_port) const {
+ for (const Set<DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
if (E->get().to_node == p_node && E->get().to_port == p_port) {
*r_node = E->get().from_node;
*r_port = E->get().from_port;
return true;
}
}
-
return false;
}
-void VisualScript::get_data_connection_list(const StringName &p_func, List<DataConnection> *r_connection) const {
- ERR_FAIL_COND(!functions.has(p_func));
- const Function &func = functions[p_func];
-
- for (const Set<DataConnection>::Element *E = func.data_connections.front(); E; E = E->next()) {
+void VisualScript::get_data_connection_list(List<DataConnection> *r_connection) const {
+ for (const Set<DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
r_connection->push_back(E->get());
}
}
@@ -653,11 +565,8 @@ Dictionary VisualScript::_get_variable_info(const StringName &p_name) const {
}
void VisualScript::get_variable_list(List<StringName> *r_variables) const {
- for (Map<StringName, Variable>::Element *E = variables.front(); E; E = E->next()) {
- r_variables->push_back(E->key());
- }
-
- r_variables->sort_custom<StringName::AlphCompare>();
+ variables.get_key_list(r_variables);
+ // r_variables->sort_custom<StringName::AlphCompare>(); // Don't force it.
}
void VisualScript::set_instance_base_type(const StringName &p_type) {
@@ -680,24 +589,19 @@ void VisualScript::rename_variable(const StringName &p_name, const StringName &p
variables[p_new_name] = variables[p_name];
variables.erase(p_name);
-
- List<StringName> funcs;
- get_function_list(&funcs);
- for (List<StringName>::Element *F = funcs.front(); F; F = F->next()) { // loop through all the functions
- List<int> ids;
- get_node_list(F->get(), &ids);
- for (List<int>::Element *E = ids.front(); E; E = E->next()) {
- Ref<VisualScriptVariableGet> nodeget = get_node(F->get(), E->get());
- if (nodeget.is_valid()) {
- if (nodeget->get_variable() == p_name) {
- nodeget->set_variable(p_new_name);
- }
- } else {
- Ref<VisualScriptVariableSet> nodeset = get_node(F->get(), E->get());
- if (nodeset.is_valid()) {
- if (nodeset->get_variable() == p_name) {
- nodeset->set_variable(p_new_name);
- }
+ List<int> ids;
+ get_node_list(&ids);
+ for (List<int>::Element *E = ids.front(); E; E = E->next()) {
+ Ref<VisualScriptVariableGet> nodeget = get_node(E->get());
+ if (nodeget.is_valid()) {
+ if (nodeget->get_variable() == p_name) {
+ nodeget->set_variable(p_new_name);
+ }
+ } else {
+ Ref<VisualScriptVariableSet> nodeset = get_node(E->get());
+ if (nodeset.is_valid()) {
+ if (nodeset->get_variable() == p_name) {
+ nodeset->set_variable(p_new_name);
}
}
}
@@ -808,23 +712,24 @@ void VisualScript::get_custom_signal_list(List<StringName> *r_custom_signals) co
}
int VisualScript::get_available_id() const {
- int max_id = 0;
- for (Map<StringName, Function>::Element *E = functions.front(); E; E = E->next()) {
- if (E->get().nodes.empty()) {
- continue;
+ // This is infinitely increasing,
+ // so one might want to implement a better solution,
+ // if the there is a case for huge number of nodes to be added to visual script.
+ List<int> nds;
+ nodes.get_key_list(&nds);
+ int max = -1;
+ for (const List<int>::Element *E = nds.front(); E; E = E->next()) {
+ if (E->get() > max) {
+ max = E->get();
}
-
- int last_id = E->get().nodes.back()->key();
- max_id = MAX(max_id, last_id + 1);
}
-
- return max_id;
+ return (max + 1);
}
/////////////////////////////////
bool VisualScript::can_instance() const {
- return true; //ScriptServer::is_scripting_enabled();
+ return true; // ScriptServer::is_scripting_enabled();
}
StringName VisualScript::get_instance_base_type() const {
@@ -832,7 +737,7 @@ StringName VisualScript::get_instance_base_type() const {
}
Ref<Script> VisualScript::get_base_script() const {
- return Ref<Script>(); // no inheritance in visual script
+ return Ref<Script>(); // No inheritance in visual script.
}
#ifdef TOOLS_ENABLED
@@ -842,20 +747,23 @@ void VisualScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder)
void VisualScript::_update_placeholders() {
if (placeholders.size() == 0) {
- return; //no bother if no placeholders
+ return; // No bother if no placeholders.
}
List<PropertyInfo> pinfo;
Map<StringName, Variant> values;
- for (Map<StringName, Variable>::Element *E = variables.front(); E; E = E->next()) {
- if (!E->get()._export) {
+ List<StringName> keys;
+ variables.get_key_list(&keys);
+
+ for (List<StringName>::Element *E = keys.front(); E; E = E->next()) {
+ if (!variables[E->get()]._export) {
continue;
}
- PropertyInfo p = E->get().info;
- p.name = String(E->key());
+ PropertyInfo p = variables[E->get()].info;
+ p.name = String(E->get());
pinfo.push_back(p);
- values[p.name] = E->get().default_value;
+ values[p.name] = variables[E->get()].default_value;
}
for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
@@ -875,17 +783,18 @@ ScriptInstance *VisualScript::instance_create(Object *p_this) {
List<PropertyInfo> pinfo;
Map<StringName, Variant> values;
- for (Map<StringName, Variable>::Element *E = variables.front(); E; E = E->next()) {
- if (!E->get()._export) {
+ List<StringName> keys;
+ variables.get_key_list(&keys);
+
+ for (const List<StringName>::Element *E = keys.front(); E; E = E->next()) {
+ if (!variables[E->get()]._export)
continue;
- }
- PropertyInfo p = E->get().info;
- p.name = String(E->key());
+ PropertyInfo p = variables[E->get()].info;
+ p.name = String(E->get());
pinfo.push_back(p);
- values[p.name] = E->get().default_value;
+ values[p.name] = variables[E->get()].default_value;
}
-
sins->update(pinfo, values);
return sins;
@@ -928,7 +837,7 @@ bool VisualScript::is_tool() const {
}
bool VisualScript::is_valid() const {
- return true; //always valid
+ return true; // Always valid.
}
ScriptLanguage *VisualScript::get_language() const {
@@ -964,11 +873,14 @@ bool VisualScript::get_property_default_value(const StringName &p_property, Vari
}
void VisualScript::get_script_method_list(List<MethodInfo> *p_list) const {
- for (Map<StringName, Function>::Element *E = functions.front(); E; E = E->next()) {
+ List<StringName> funcs;
+ functions.get_key_list(&funcs);
+
+ for (List<StringName>::Element *E = funcs.front(); E; E = E->next()) {
MethodInfo mi;
- mi.name = E->key();
- if (E->get().function_id >= 0) {
- Ref<VisualScriptFunction> func = E->get().nodes[E->get().function_id].node;
+ mi.name = E->get();
+ if (functions[E->get()].func_id >= 0) {
+ Ref<VisualScriptFunction> func = nodes[functions[E->get()].func_id].node;
if (func.is_valid()) {
for (int i = 0; i < func->get_argument_count(); i++) {
PropertyInfo arg;
@@ -988,15 +900,15 @@ bool VisualScript::has_method(const StringName &p_method) const {
}
MethodInfo VisualScript::get_method_info(const StringName &p_method) const {
- const Map<StringName, Function>::Element *E = functions.find(p_method);
- if (!E) {
+ const Function funct = functions[p_method];
+ if (funct.func_id == -1) {
return MethodInfo();
}
MethodInfo mi;
- mi.name = E->key();
- if (E->get().function_id >= 0) {
- Ref<VisualScriptFunction> func = E->get().nodes[E->get().function_id].node;
+ mi.name = p_method;
+ if (funct.func_id >= 0) {
+ Ref<VisualScriptFunction> func = nodes[funct.func_id].node;
if (func.is_valid()) {
for (int i = 0; i < func->get_argument_count(); i++) {
PropertyInfo arg;
@@ -1028,28 +940,18 @@ void VisualScript::get_script_property_list(List<PropertyInfo> *p_list) const {
}
int VisualScript::get_member_line(const StringName &p_member) const {
-#ifdef TOOLS_ENABLED
- if (has_function(p_member)) {
- for (Map<int, Function::NodeData>::Element *E = functions[p_member].nodes.front(); E; E = E->next()) {
- if (Object::cast_to<VisualScriptFunction>(E->get().node.ptr())) {
- return E->key();
- }
- }
- }
-#endif
- return -1;
+ return functions[p_member].func_id; // will be -1 if not found
}
#ifdef TOOLS_ENABLED
bool VisualScript::are_subnodes_edited() const {
- for (const Map<StringName, Function>::Element *E = functions.front(); E; E = E->next()) {
- for (const Map<int, Function::NodeData>::Element *F = E->get().nodes.front(); F; F = F->next()) {
- if (F->get().node->is_edited()) {
- return true;
- }
+ List<int> keys;
+ nodes.get_key_list(&keys);
+ for (const List<int>::Element *F = keys.front(); F; F = F->next()) {
+ if (nodes[F->get()].node->is_edited()) {
+ return true;
}
}
-
return false;
}
#endif
@@ -1140,85 +1042,41 @@ void VisualScript::_set_data(const Dictionary &p_data) {
Array funcs = d["functions"];
functions.clear();
- Vector2 last_pos = Vector2(-100 * funcs.size(), -100 * funcs.size()); // this is the center of the last fn box
- Vector2 last_size = Vector2(0.0, 0.0);
-
for (int i = 0; i < funcs.size(); i++) {
Dictionary func = funcs[i];
-
- StringName name = func["name"];
- //int id=func["function_id"];
- add_function(name);
-
- set_function_scroll(name, func["scroll"]);
-
- Array nodes = func["nodes"];
-
- if (!d.has("vs_unify") && nodes.size() > 0) {
- Vector2 top_left = nodes[1];
- Vector2 bottom_right = nodes[1];
-
- for (int j = 0; j < nodes.size(); j += 3) {
- Point2 pos = nodes[j + 1];
- if (pos.y > top_left.y) {
- top_left.y = pos.y;
- }
- if (pos.y < bottom_right.y) {
- bottom_right.y = pos.y;
- }
- if (pos.x > bottom_right.x) {
- bottom_right.x = pos.x;
- }
- if (pos.x < top_left.x) {
- top_left.x = pos.x;
- }
- }
-
- Vector2 size = Vector2(bottom_right.x - top_left.x, top_left.y - bottom_right.y);
-
- Vector2 offset = last_pos + (last_size / 2.0) + (size / 2.0); // dunno I might just keep it in one axis but diagonal feels better....
-
- last_pos = offset;
- last_size = size;
-
- for (int j = 0; j < nodes.size(); j += 3) {
- add_node(name, nodes[j], nodes[j + 2], offset + nodes[j + 1]); // also add an additional buffer if you want to
- }
-
- } else {
- for (int j = 0; j < nodes.size(); j += 3) {
- add_node(name, nodes[j], nodes[j + 2], nodes[j + 1]);
- }
+ add_function(func["name"], func["function_id"]);
+ }
+ {
+ Array nodes = d["nodes"];
+ for (int i = 0; i < nodes.size(); i += 3) {
+ add_node(nodes[i], nodes[i + 2], nodes[i + 1]);
}
- Array sequence_connections = func["sequence_connections"];
+ Array sequence_connections = d["sequence_connections"];
for (int j = 0; j < sequence_connections.size(); j += 3) {
- sequence_connect(name, sequence_connections[j + 0], sequence_connections[j + 1], sequence_connections[j + 2]);
+ sequence_connect(sequence_connections[j + 0], sequence_connections[j + 1], sequence_connections[j + 2]);
}
- Array data_connections = func["data_connections"];
-
+ Array data_connections = d["data_connections"];
for (int j = 0; j < data_connections.size(); j += 4) {
- data_connect(name, data_connections[j + 0], data_connections[j + 1], data_connections[j + 2], data_connections[j + 3]);
+ data_connect(data_connections[j + 0], data_connections[j + 1], data_connections[j + 2], data_connections[j + 3]);
}
}
+ is_tool_script = d["is_tool_script"];
+ scroll = d["scroll"];
- if (d.has("is_tool_script")) {
- is_tool_script = d["is_tool_script"];
- } else {
- is_tool_script = false;
- }
-
- // Takes all the rpc methods
+ // Takes all the rpc methods.
rpc_functions.clear();
rpc_variables.clear();
- for (Map<StringName, Function>::Element *E = functions.front(); E; E = E->next()) {
- if (E->get().function_id >= 0 && E->get().nodes.find(E->get().function_id)) {
- Ref<VisualScriptFunction> vsf = E->get().nodes[E->get().function_id].node;
+ List<StringName> fns;
+ functions.get_key_list(&fns);
+ for (const List<StringName>::Element *E = fns.front(); E; E = E->next()) {
+ if (functions[E->get()].func_id >= 0 && nodes.has(functions[E->get()].func_id)) {
+ Ref<VisualScriptFunction> vsf = nodes[functions[E->get()].func_id].node;
if (vsf.is_valid()) {
if (vsf->get_rpc_mode() != MultiplayerAPI::RPC_MODE_DISABLED) {
ScriptNetData nd;
- nd.name = E->key();
+ nd.name = E->get();
nd.mode = vsf->get_rpc_mode();
if (rpc_functions.find(nd) == -1) {
rpc_functions.push_back(nd);
@@ -1228,8 +1086,6 @@ void VisualScript::_set_data(const Dictionary &p_data) {
}
}
- // Visual script doesn't have rset :(
-
// Sort so we are 100% that they are always the same.
rpc_functions.sort_custom<SortNetData>();
}
@@ -1237,12 +1093,15 @@ void VisualScript::_set_data(const Dictionary &p_data) {
Dictionary VisualScript::_get_data() const {
Dictionary d;
d["base_type"] = base_type;
+
Array vars;
- for (const Map<StringName, Variable>::Element *E = variables.front(); E; E = E->next()) {
- Dictionary var = _get_variable_info(E->key());
- var["name"] = E->key(); //make sure it's the right one
- var["default_value"] = E->get().default_value;
- var["export"] = E->get()._export;
+ List<StringName> var_names;
+ variables.get_key_list(&var_names);
+ for (const List<StringName>::Element *E = var_names.front(); E; E = E->next()) {
+ Dictionary var = _get_variable_info(E->get());
+ var["name"] = E->get(); // Make sure it's the right one.
+ var["default_value"] = variables[E->get()].default_value;
+ var["export"] = variables[E->get()]._export;
vars.push_back(var);
}
d["variables"] = vars;
@@ -1264,78 +1123,73 @@ Dictionary VisualScript::_get_data() const {
d["signals"] = sigs;
Array funcs;
-
- for (const Map<StringName, Function>::Element *E = functions.front(); E; E = E->next()) {
+ List<StringName> func_names;
+ functions.get_key_list(&func_names);
+ for (const List<StringName>::Element *E = func_names.front(); E; E = E->next()) {
Dictionary func;
- func["name"] = E->key();
- func["function_id"] = E->get().function_id;
- func["scroll"] = E->get().scroll;
-
- Array nodes;
-
- for (const Map<int, Function::NodeData>::Element *F = E->get().nodes.front(); F; F = F->next()) {
- nodes.push_back(F->key());
- nodes.push_back(F->get().pos);
- nodes.push_back(F->get().node);
- }
-
- func["nodes"] = nodes;
-
- Array sequence_connections;
-
- for (const Set<SequenceConnection>::Element *F = E->get().sequence_connections.front(); F; F = F->next()) {
- sequence_connections.push_back(F->get().from_node);
- sequence_connections.push_back(F->get().from_output);
- sequence_connections.push_back(F->get().to_node);
- }
-
- func["sequence_connections"] = sequence_connections;
-
- Array data_connections;
+ func["name"] = E->get();
+ func["function_id"] = functions[E->get()].func_id;
+ funcs.push_back(func);
+ }
+ d["functions"] = funcs;
- for (const Set<DataConnection>::Element *F = E->get().data_connections.front(); F; F = F->next()) {
- data_connections.push_back(F->get().from_node);
- data_connections.push_back(F->get().from_port);
- data_connections.push_back(F->get().to_node);
- data_connections.push_back(F->get().to_port);
- }
+ Array nds;
+ List<int> node_ids;
+ nodes.get_key_list(&node_ids);
+ for (const List<int>::Element *F = node_ids.front(); F; F = F->next()) {
+ nds.push_back(F->get());
+ nds.push_back(nodes[F->get()].pos);
+ nds.push_back(nodes[F->get()].node);
+ }
+ d["nodes"] = nds;
- func["data_connections"] = data_connections;
+ Array seqconns;
+ for (const Set<SequenceConnection>::Element *F = sequence_connections.front(); F; F = F->next()) {
+ seqconns.push_back(F->get().from_node);
+ seqconns.push_back(F->get().from_output);
+ seqconns.push_back(F->get().to_node);
+ }
+ d["sequence_connections"] = seqconns;
- funcs.push_back(func);
+ Array dataconns;
+ for (const Set<DataConnection>::Element *F = data_connections.front(); F; F = F->next()) {
+ dataconns.push_back(F->get().from_node);
+ dataconns.push_back(F->get().from_port);
+ dataconns.push_back(F->get().to_node);
+ dataconns.push_back(F->get().to_port);
}
+ d["data_connections"] = dataconns;
- d["functions"] = funcs;
d["is_tool_script"] = is_tool_script;
- d["vs_unify"] = true;
+ d["scroll"] = scroll;
return d;
}
void VisualScript::_bind_methods() {
- ClassDB::bind_method(D_METHOD("add_function", "name"), &VisualScript::add_function);
+ ClassDB::bind_method(D_METHOD("add_function", "name", "func_node_id"), &VisualScript::add_function);
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_function_scroll", "name", "ofs"), &VisualScript::set_function_scroll);
- ClassDB::bind_method(D_METHOD("get_function_scroll", "name"), &VisualScript::get_function_scroll);
+ ClassDB::bind_method(D_METHOD("set_scroll", "ofs"), &VisualScript::set_scroll);
+ ClassDB::bind_method(D_METHOD("get_scroll"), &VisualScript::get_scroll);
- ClassDB::bind_method(D_METHOD("add_node", "func", "id", "node", "position"), &VisualScript::add_node, DEFVAL(Point2()));
- ClassDB::bind_method(D_METHOD("remove_node", "func", "id"), &VisualScript::remove_node);
+ ClassDB::bind_method(D_METHOD("add_node", "id", "node", "position"), &VisualScript::add_node, DEFVAL(Point2()));
+ ClassDB::bind_method(D_METHOD("remove_node", "id"), &VisualScript::remove_node);
ClassDB::bind_method(D_METHOD("get_function_node_id", "name"), &VisualScript::get_function_node_id);
- ClassDB::bind_method(D_METHOD("get_node", "func", "id"), &VisualScript::get_node);
- ClassDB::bind_method(D_METHOD("has_node", "func", "id"), &VisualScript::has_node);
- ClassDB::bind_method(D_METHOD("set_node_position", "func", "id", "position"), &VisualScript::set_node_position);
- ClassDB::bind_method(D_METHOD("get_node_position", "func", "id"), &VisualScript::get_node_position);
+ ClassDB::bind_method(D_METHOD("get_node", "id"), &VisualScript::get_node);
+ ClassDB::bind_method(D_METHOD("has_node", "id"), &VisualScript::has_node);
+ ClassDB::bind_method(D_METHOD("set_node_position", "id", "position"), &VisualScript::set_node_position);
+ ClassDB::bind_method(D_METHOD("get_node_position", "id"), &VisualScript::get_node_position);
- ClassDB::bind_method(D_METHOD("sequence_connect", "func", "from_node", "from_output", "to_node"), &VisualScript::sequence_connect);
- ClassDB::bind_method(D_METHOD("sequence_disconnect", "func", "from_node", "from_output", "to_node"), &VisualScript::sequence_disconnect);
- ClassDB::bind_method(D_METHOD("has_sequence_connection", "func", "from_node", "from_output", "to_node"), &VisualScript::has_sequence_connection);
+ ClassDB::bind_method(D_METHOD("sequence_connect", "from_node", "from_output", "to_node"), &VisualScript::sequence_connect);
+ ClassDB::bind_method(D_METHOD("sequence_disconnect", "from_node", "from_output", "to_node"), &VisualScript::sequence_disconnect);
+ ClassDB::bind_method(D_METHOD("has_sequence_connection", "from_node", "from_output", "to_node"), &VisualScript::has_sequence_connection);
- ClassDB::bind_method(D_METHOD("data_connect", "func", "from_node", "from_port", "to_node", "to_port"), &VisualScript::data_connect);
- ClassDB::bind_method(D_METHOD("data_disconnect", "func", "from_node", "from_port", "to_node", "to_port"), &VisualScript::data_disconnect);
- ClassDB::bind_method(D_METHOD("has_data_connection", "func", "from_node", "from_port", "to_node", "to_port"), &VisualScript::has_data_connection);
+ ClassDB::bind_method(D_METHOD("data_connect", "from_node", "from_port", "to_node", "to_port"), &VisualScript::data_connect);
+ ClassDB::bind_method(D_METHOD("data_disconnect", "from_node", "from_port", "to_node", "to_port"), &VisualScript::data_disconnect);
+ ClassDB::bind_method(D_METHOD("has_data_connection", "from_node", "from_port", "to_node", "to_port"), &VisualScript::has_data_connection);
ClassDB::bind_method(D_METHOD("add_variable", "name", "default_value", "export"), &VisualScript::add_variable, DEFVAL(Variant()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("has_variable", "name"), &VisualScript::has_variable);
@@ -1371,7 +1225,7 @@ void VisualScript::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
- ADD_SIGNAL(MethodInfo("node_ports_changed", PropertyInfo(Variant::STRING, "function"), PropertyInfo(Variant::INT, "id")));
+ ADD_SIGNAL(MethodInfo("node_ports_changed", PropertyInfo(Variant::INT, "id")));
}
VisualScript::VisualScript() {
@@ -1380,16 +1234,12 @@ VisualScript::VisualScript() {
}
bool VisualScript::inherits_script(const Ref<Script> &p_script) const {
- return this == p_script.ptr(); //there is no inheritance in visual scripts, so this is enough
-}
-
-StringName VisualScript::get_default_func() const {
- return StringName("f_312843592");
+ return this == p_script.ptr(); // There is no inheritance in visual scripts, so this is enough.
}
-Set<int> VisualScript::get_output_sequence_ports_connected(const String &edited_func, int from_node) {
+Set<int> VisualScript::get_output_sequence_ports_connected(int from_node) {
List<VisualScript::SequenceConnection> *sc = memnew(List<VisualScript::SequenceConnection>);
- get_sequence_connection_list(edited_func, sc);
+ get_sequence_connection_list(sc);
Set<int> connected;
for (List<VisualScript::SequenceConnection>::Element *E = sc->front(); E; E = E->next()) {
if (E->get().from_node == from_node) {
@@ -1401,8 +1251,11 @@ Set<int> VisualScript::get_output_sequence_ports_connected(const String &edited_
}
VisualScript::~VisualScript() {
- while (!functions.empty()) {
- remove_function(functions.front()->key());
+ // Remove all nodes and stuff that hold data refs.
+ List<int> nds;
+ nodes.get_key_list(&nds);
+ for (const List<int>::Element *E = nds.front(); E; E = E->next()) {
+ remove_node(E->get());
}
}
@@ -1430,20 +1283,21 @@ bool VisualScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
}
void VisualScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const {
- for (const Map<StringName, VisualScript::Variable>::Element *E = script->variables.front(); E; E = E->next()) {
- if (!E->get()._export) {
+ List<StringName> vars;
+ script->variables.get_key_list(&vars);
+ for (const List<StringName>::Element *E = vars.front(); E; E = E->next()) {
+ if (!script->variables[E->get()]._export) {
continue;
}
- PropertyInfo p = E->get().info;
- p.name = String(E->key());
+ PropertyInfo p = script->variables[E->get()].info;
+ p.name = String(E->get());
p.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE;
p_properties->push_back(p);
}
}
Variant::Type VisualScriptInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const {
- const Map<StringName, VisualScript::Variable>::Element *E = script->variables.find(p_name);
- if (!E) {
+ if (!script->variables.has(p_name)) {
if (r_is_valid) {
*r_is_valid = false;
}
@@ -1454,19 +1308,17 @@ Variant::Type VisualScriptInstance::get_property_type(const StringName &p_name,
*r_is_valid = true;
}
- return E->get().info.type;
+ return script->variables[p_name].info.type;
}
void VisualScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
- for (const Map<StringName, VisualScript::Function>::Element *E = script->functions.front(); E; E = E->next()) {
- if (E->key() == script->get_default_func()) {
- continue;
- }
-
+ List<StringName> fns;
+ script->functions.get_key_list(&fns);
+ for (const List<StringName>::Element *E = fns.front(); E; E = E->next()) {
MethodInfo mi;
- mi.name = E->key();
- if (E->get().function_id >= 0 && E->get().nodes.has(E->get().function_id)) {
- Ref<VisualScriptFunction> vsf = E->get().nodes[E->get().function_id].node;
+ mi.name = E->get();
+ if (script->functions[E->get()].func_id >= 0 && script->nodes.has(script->functions[E->get()].func_id)) {
+ Ref<VisualScriptFunction> vsf = script->nodes[script->functions[E->get()].func_id].node;
if (vsf.is_valid()) {
for (int i = 0; i < vsf->get_argument_count(); i++) {
PropertyInfo arg;
@@ -1476,21 +1328,16 @@ void VisualScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
mi.arguments.push_back(arg);
}
- if (!vsf->is_sequenced()) { //assumed constant if not sequenced
+ if (!vsf->is_sequenced()) { // Assumed constant if not sequenced.
mi.flags |= METHOD_FLAG_CONST;
}
}
}
-
p_list->push_back(mi);
}
}
bool VisualScriptInstance::has_method(const StringName &p_method) const {
- if (p_method == script->get_default_func()) {
- return false;
- }
-
return script->functions.has(p_method);
}
@@ -1506,7 +1353,7 @@ void VisualScriptInstance::_dependency_step(VisualScriptNodeInstance *node, int
pass_stack[node->pass_idx] = p_pass;
- if (!node->dependencies.empty()) {
+ if (!node->dependencies.is_empty()) {
int dc = node->dependencies.size();
VisualScriptNodeInstance **deps = node->dependencies.ptrw();
@@ -1522,10 +1369,10 @@ void VisualScriptInstance::_dependency_step(VisualScriptNodeInstance *node, int
int index = node->input_ports[i] & VisualScriptNodeInstance::INPUT_MASK;
if (node->input_ports[i] & VisualScriptNodeInstance::INPUT_DEFAULT_VALUE_BIT) {
- //is a default value (unassigned input port)
+ // Is a default value (unassigned input port).
input_args[i] = &default_values[index];
} else {
- //regular temporary in stack
+ // Rregular temporary in stack.
input_args[i] = &variant_stack[index];
}
}
@@ -1536,7 +1383,7 @@ void VisualScriptInstance::_dependency_step(VisualScriptNodeInstance *node, int
Variant *working_mem = node->working_mem_idx >= 0 ? &variant_stack[node->working_mem_idx] : (Variant *)nullptr;
node->step(input_args, output_args, VisualScriptNodeInstance::START_MODE_BEGIN_SEQUENCE, working_mem, r_error, error_str);
- //ignore return
+ // Ignore return.
if (r_error.error != Callable::CallError::CALL_OK) {
*r_error_node = node;
}
@@ -1547,7 +1394,7 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
ERR_FAIL_COND_V(!F, Variant());
Function *f = &F->get();
- //this call goes separate, so it can e yielded and suspended
+ // This call goes separate, so it can e yielded and suspended.
Variant *variant_stack = (Variant *)p_stack;
bool *sequence_bits = (bool *)(variant_stack + f->max_stack);
const Variant **input_args = (const Variant **)(sequence_bits + f->node_count);
@@ -1573,27 +1420,27 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
#endif
while (true) {
- p_pass++; //increment pass
+ p_pass++; // Increment pass.
current_node_id = node->get_id();
VSDEBUG("==========AT NODE: " + itos(current_node_id) + " base: " + node->get_base_node()->get_class_name());
VSDEBUG("AT STACK POS: " + itos(flow_stack_pos));
- //setup working mem
+ // Setup working mem.
working_mem = node->working_mem_idx >= 0 ? &variant_stack[node->working_mem_idx] : (Variant *)nullptr;
VSDEBUG("WORKING MEM: " + itos(node->working_mem_idx));
if (current_node_id == f->node) {
- //if function node, set up function arguments from beginning of stack
+ // If function node, set up function arguments from beginning of stack.
for (int i = 0; i < f->argument_count; i++) {
input_args[i] = &variant_stack[i];
}
} else {
- //run dependencies first
+ // Run dependencies first.
- if (!node->dependencies.empty()) {
+ if (!node->dependencies.is_empty()) {
int dc = node->dependencies.size();
VisualScriptNodeInstance **deps = node->dependencies.ptrw();
@@ -1608,18 +1455,18 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
}
if (!error) {
- //setup input pointers normally
+ // Setup input pointers normally.
VSDEBUG("INPUT PORTS: " + itos(node->input_port_count));
for (int i = 0; i < node->input_port_count; i++) {
int index = node->input_ports[i] & VisualScriptNodeInstance::INPUT_MASK;
if (node->input_ports[i] & VisualScriptNodeInstance::INPUT_DEFAULT_VALUE_BIT) {
- //is a default value (unassigned input port)
+ // Is a default value (unassigned input port).
input_args[i] = &default_values[index];
VSDEBUG("\tPORT " + itos(i) + " DEFAULT VAL");
} else {
- //regular temporary in stack
+ // Regular temporary in stack.
input_args[i] = &variant_stack[index];
VSDEBUG("PORT " + itos(i) + " AT STACK " + itos(index));
}
@@ -1631,7 +1478,7 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
break;
}
- //setup output pointers
+ // Setup output pointers.
VSDEBUG("OUTPUT PORTS: " + itos(node->output_port_count));
for (int i = 0; i < node->output_port_count; i++) {
@@ -1639,15 +1486,15 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
VSDEBUG("PORT " + itos(i) + " AT STACK " + itos(node->output_ports[i]));
}
- //do step
+ // Do step.
VisualScriptNodeInstance::StartMode start_mode;
{
if (p_resuming_yield) {
start_mode = VisualScriptNodeInstance::START_MODE_RESUME_YIELD;
- p_resuming_yield = false; // should resume only the first time
+ p_resuming_yield = false; // Should resume only the first time.
} else if (flow_stack && (flow_stack[flow_stack_pos] & VisualScriptNodeInstance::FLOW_STACK_PUSHED_BIT)) {
- //if there is a push bit, it means we are continuing a sequence
+ // If there is a push bit, it means we are continuing a sequence.
start_mode = VisualScriptNodeInstance::START_MODE_CONTINUE_SEQUENCE;
} else {
start_mode = VisualScriptNodeInstance::START_MODE_BEGIN_SEQUENCE;
@@ -1659,13 +1506,13 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
int ret = node->step(input_args, output_args, start_mode, working_mem, r_error, error_str);
if (r_error.error != Callable::CallError::CALL_OK) {
- //use error from step
+ // Use error from step.
error = true;
break;
}
if (ret & VisualScriptNodeInstance::STEP_YIELD_BIT) {
- //yielded!
+ // Yielded!
if (node->get_working_memory_size() == 0) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
error_str = RTR("A node yielded without working memory, please read the docs on how to yield properly!");
@@ -1681,7 +1528,7 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
break;
}
- //step 1, capture all state
+ // Step 1, capture all state.
state->instance_id = get_owner_ptr()->get_instance_id();
state->script_id = get_script()->get_instance_id();
state->instance = this;
@@ -1693,11 +1540,11 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
state->stack.resize(p_stack_size);
state->pass = p_pass;
copymem(state->stack.ptrw(), p_stack, p_stack_size);
- //step 2, run away, return directly
+ // Step 2, run away, return directly.
r_error.error = Callable::CallError::CALL_OK;
#ifdef DEBUG_ENABLED
- //will re-enter later, so exiting
+ // Will re-enter later, so exiting.
if (EngineDebugger::is_active()) {
VisualScriptLanguage::singleton->exit_function();
}
@@ -1742,18 +1589,18 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
error_str = RTR("Return value must be assigned to first element of node working memory! Fix your node please.");
error = true;
} else {
- //assign from working memory, first element
+ // Assign from working memory, first element.
return_value = *working_mem;
}
VSDEBUG("EXITING FUNCTION - VALUE " + String(return_value));
- break; //exit function requested, bye
+ break; // Exit function requested, bye
}
- VisualScriptNodeInstance *next = nullptr; //next node
+ VisualScriptNodeInstance *next = nullptr; // Next node.
if ((ret == output || ret & VisualScriptNodeInstance::STEP_FLAG_PUSH_STACK_BIT) && node->sequence_output_count) {
- //if no exit bit was set, and has sequence outputs, guess next node
+ // If no exit bit was set, and has sequence outputs, guess next node.
if (output >= node->sequence_output_count) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
error_str = RTR("Node returned an invalid sequence output: ") + itos(output);
@@ -1766,21 +1613,21 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
}
if (flow_stack) {
- //update flow stack pos (may have changed)
+ // Update flow stack pos (may have changed).
flow_stack[flow_stack_pos] = current_node_id;
- //add stack push bit if requested
+ // Add stack push bit if requested.
if (ret & VisualScriptNodeInstance::STEP_FLAG_PUSH_STACK_BIT) {
flow_stack[flow_stack_pos] |= VisualScriptNodeInstance::FLOW_STACK_PUSHED_BIT;
- sequence_bits[node->sequence_index] = true; //remember sequence bit
+ sequence_bits[node->sequence_index] = true; // Remember sequence bit.
VSDEBUG("NEXT SEQ - FLAG BIT");
} else {
- sequence_bits[node->sequence_index] = false; //forget sequence bit
+ sequence_bits[node->sequence_index] = false; // Forget sequence bit.
VSDEBUG("NEXT SEQ - NORMAL");
}
if (ret & VisualScriptNodeInstance::STEP_FLAG_GO_BACK_BIT) {
- //go back request
+ // Go back request.
if (flow_stack_pos > 0) {
flow_stack_pos--;
@@ -1788,20 +1635,20 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
VSDEBUG("NEXT IS GO BACK");
} else {
VSDEBUG("NEXT IS GO BACK, BUT NO NEXT SO EXIT");
- break; //simply exit without value or error
+ break; // Simply exit without value or error.
}
} else if (next) {
if (sequence_bits[next->sequence_index]) {
- // what happened here is that we are entering a node that is in the middle of doing a sequence (pushed stack) from the front
+ // What happened here is that we are entering a node that is in the middle of doing a sequence (pushed stack) from the front
// because each node has a working memory, we can't really do a sub-sequence
// as a result, the sequence will be restarted and the stack will roll back to find where this node
- // started the sequence
+ // started the sequence.
bool found = false;
for (int i = flow_stack_pos; i >= 0; i--) {
if ((flow_stack[i] & VisualScriptNodeInstance::FLOW_STACK_MASK) == next->get_id()) {
- flow_stack_pos = i; //roll back and remove bit
+ flow_stack_pos = i; // Roll back and remove bit.
flow_stack[i] = next->get_id();
sequence_bits[next->sequence_index] = false;
found = true;
@@ -1819,7 +1666,7 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
VSDEBUG("RE-ENTERED A LOOP, RETURNED STACK POS TO - " + itos(flow_stack_pos));
} else {
- // check for stack overflow
+ // Check for stack overflow.
if (flow_stack_pos + 1 >= flow_max) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
error_str = RTR("Stack overflow with stack depth: ") + itos(output);
@@ -1836,7 +1683,7 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
}
} else {
- //no next node, try to go back in stack to pushed bit
+ // No next node, try to go back in stack to pushed bit.
bool found = false;
@@ -1852,22 +1699,22 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
if (!found) {
VSDEBUG("NO NEXT NODE, NO GO BACK, EXITING");
- break; //done, couldn't find a push stack bit
+ break; // Done, couldn't find a push stack bit.
}
VSDEBUG("NO NEXT NODE, GO BACK TO: " + itos(flow_stack_pos));
}
} else {
- node = next; //stackless mode, simply assign next node
+ node = next; // Stackless mode, simply assign next node.
}
}
if (error) {
- //error
- // function, file, line, error, explanation
+ // Error
+ // Function, file, line, error, explanation.
String err_file = script->get_path();
String err_func = p_method;
- int err_line = current_node_id; //not a line but it works as one
+ int err_line = current_node_id; // Not a line but it works as one.
if (node && (r_error.error != Callable::CallError::CALL_ERROR_INVALID_METHOD || error_str == String())) {
if (error_str != String()) {
@@ -1906,7 +1753,7 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
}
#endif
- //clean up variant stack
+ // Clean up variant stack.
for (int i = 0; i < f->max_stack; i++) {
variant_stack[i].~Variant();
}
@@ -1954,7 +1801,7 @@ Variant VisualScriptInstance::call(const StringName &p_method, const Variant **p
int *pass_stack = flow_stack ? (int *)(flow_stack + flow_max) : (int *)nullptr;
for (int i = 0; i < f->node_count; i++) {
- sequence_bits[i] = false; //all starts as false
+ sequence_bits[i] = false; // All starts as false.
}
zeromem(pass_stack, f->pass_stack_size * sizeof(int));
@@ -1988,12 +1835,12 @@ Variant VisualScriptInstance::call(const StringName &p_method, const Variant **p
return Variant();
}
- //allocate variant stack
+ // Allocate variant stack.
for (int i = 0; i < f->max_stack; i++) {
memnew_placement(&variant_stack[i], Variant);
}
- //allocate function arguments (must be copied for yield to work properly)
+ // Allocate function arguments (must be copied for yield to work properly).
for (int i = 0; i < p_argcount; i++) {
variant_stack[i] = *p_args[i];
}
@@ -2002,12 +1849,12 @@ Variant VisualScriptInstance::call(const StringName &p_method, const Variant **p
}
void VisualScriptInstance::notification(int p_notification) {
- //do nothing as this is called using virtual
+ // Do nothing as this is called using virtual.
Variant what = p_notification;
const Variant *whatp = &what;
Callable::CallError ce;
- call(VisualScriptLanguage::singleton->notification, &whatp, 1, ce); //do as call
+ call(VisualScriptLanguage::singleton->notification, &whatp, 1, ce); // Do as call.
}
String VisualScriptInstance::to_string(bool *r_valid) {
@@ -2086,7 +1933,7 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
max_output_args = 0;
if (Object::cast_to<Node>(p_owner)) {
- //turn on these if they exist and base is a node
+ // Turn on these if they exist and base is a node.
Node *node = Object::cast_to<Node>(p_owner);
if (p_script->functions.has("_process")) {
node->set_process(true);
@@ -2105,190 +1952,236 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
}
}
- for (const Map<StringName, VisualScript::Variable>::Element *E = script->variables.front(); E; E = E->next()) {
- variables[E->key()] = E->get().default_value;
- }
-
- for (const Map<StringName, VisualScript::Function>::Element *E = script->functions.front(); E; E = E->next()) {
- if (E->key() == script->get_default_func()) {
- continue;
- }
-
- Function function;
- function.node = E->get().function_id;
- function.max_stack = 0;
- function.flow_stack_size = 0;
- function.pass_stack_size = 0;
- function.node_count = 0;
-
- Map<StringName, int> local_var_indices;
-
- if (function.node < 0) {
- VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(), 0, "No start node in function: " + String(E->key()));
-
- ERR_CONTINUE(function.node < 0);
+ // Setup variables.
+ {
+ List<StringName> keys;
+ script->variables.get_key_list(&keys);
+ for (const List<StringName>::Element *E = keys.front(); E; E = E->next()) {
+ variables[E->get()] = script->variables[E->get()].default_value;
}
+ }
- {
- Ref<VisualScriptFunction> func_node = script->get_node(E->key(), E->get().function_id);
-
- if (func_node.is_null()) {
- VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(), 0, "No VisualScriptFunction typed start node in function: " + String(E->key()));
+ // Setup functions from sequence trees.
+ {
+ List<StringName> keys;
+ script->functions.get_key_list(&keys);
+ for (const List<StringName>::Element *E = keys.front(); E; E = E->next()) {
+ const VisualScript::Function vsfn = p_script->functions[E->get()];
+ Function function;
+ function.node = vsfn.func_id;
+ function.max_stack = 0;
+ function.flow_stack_size = 0;
+ function.pass_stack_size = 0;
+ function.node_count = 0;
+
+ Map<StringName, int> local_var_indices;
+
+ if (function.node < 0) {
+ VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(), 0, "No start node in function: " + String(E->get()));
+ ERR_CONTINUE(function.node < 0);
}
- ERR_CONTINUE(!func_node.is_valid());
+ {
+ Ref<VisualScriptFunction> func_node = script->get_node(vsfn.func_id);
- function.argument_count = func_node->get_argument_count();
- function.max_stack += function.argument_count;
- function.flow_stack_size = func_node->is_stack_less() ? 0 : func_node->get_stack_size();
- max_input_args = MAX(max_input_args, function.argument_count);
- }
-
- //multiple passes are required to set up this complex thing..
-
- //first create the nodes
- for (const Map<int, VisualScript::Function::NodeData>::Element *F = E->get().nodes.front(); F; F = F->next()) {
- Ref<VisualScriptNode> node = F->get().node;
-
- VisualScriptNodeInstance *instance = node->instance(this); //create instance
- ERR_FAIL_COND(!instance);
-
- instance->base = node.ptr();
+ if (func_node.is_null()) {
+ VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(), 0, "No VisualScriptFunction typed start node in function: " + String(E->get()));
+ }
- instance->id = F->key();
- instance->input_port_count = node->get_input_value_port_count();
- instance->input_ports = nullptr;
- instance->output_port_count = node->get_output_value_port_count();
- instance->output_ports = nullptr;
- instance->sequence_output_count = node->get_output_sequence_port_count();
- instance->sequence_index = function.node_count++;
- instance->sequence_outputs = nullptr;
- instance->pass_idx = -1;
+ ERR_CONTINUE(!func_node.is_valid());
- if (instance->input_port_count) {
- instance->input_ports = memnew_arr(int, instance->input_port_count);
- for (int i = 0; i < instance->input_port_count; i++) {
- instance->input_ports[i] = -1; //if not assigned, will become default value
- }
+ function.argument_count = func_node->get_argument_count();
+ function.max_stack += function.argument_count;
+ function.flow_stack_size = func_node->is_stack_less() ? 0 : func_node->get_stack_size();
+ max_input_args = MAX(max_input_args, function.argument_count);
}
-
- if (instance->output_port_count) {
- instance->output_ports = memnew_arr(int, instance->output_port_count);
- for (int i = 0; i < instance->output_port_count; i++) {
- instance->output_ports[i] = -1; //if not assigned, will output to trash
+ // Function nodes graphs.
+ Set<VisualScript::SequenceConnection> seqconns;
+ Set<VisualScript::DataConnection> dataconns;
+ Set<int> node_ids;
+ node_ids.insert(function.node);
+ {
+ List<int> nd_queue;
+ nd_queue.push_back(function.node);
+ while (!nd_queue.is_empty()) {
+ for (const Set<VisualScript::SequenceConnection>::Element *F = script->sequence_connections.front(); F; F = F->next()) {
+ if (nd_queue.front()->get() == F->get().from_node && !node_ids.has(F->get().to_node)) {
+ nd_queue.push_back(F->get().to_node);
+ node_ids.insert(F->get().to_node);
+ }
+ if (nd_queue.front()->get() == F->get().from_node && !seqconns.has(F->get())) {
+ seqconns.insert(F->get());
+ }
+ }
+ nd_queue.pop_front();
}
- }
-
- if (instance->sequence_output_count) {
- instance->sequence_outputs = memnew_arr(VisualScriptNodeInstance *, instance->sequence_output_count);
- for (int i = 0; i < instance->sequence_output_count; i++) {
- instance->sequence_outputs[i] = nullptr; //if it remains null, flow ends here
+ HashMap<int, HashMap<int, Pair<int, int>>> dc_lut; // :: to -> to_port -> (from, from_port)
+ for (const Set<VisualScript::DataConnection>::Element *F = script->data_connections.front(); F; F = F->next()) {
+ dc_lut[F->get().to_node][F->get().to_port] = Pair<int, int>(F->get().from_node, F->get().from_port);
+ }
+ for (const Set<int>::Element *F = node_ids.front(); F; F = F->next()) {
+ nd_queue.push_back(F->get());
+ }
+ List<int> dc_keys;
+ while (!nd_queue.is_empty()) {
+ int ky = nd_queue.front()->get();
+ dc_lut[ky].get_key_list(&dc_keys);
+ for (const List<int>::Element *F = dc_keys.front(); F; F = F->next()) {
+ VisualScript::DataConnection dc;
+ dc.from_node = dc_lut[ky][F->get()].first;
+ dc.from_port = dc_lut[ky][F->get()].second;
+ dc.to_node = ky;
+ dc.to_port = F->get();
+ dataconns.insert(dc);
+ nd_queue.push_back(dc.from_node);
+ node_ids.insert(dc.from_node);
+ }
+ dc_keys.clear(); // Necessary as get_key_list does a push_back not a set.
+ nd_queue.pop_front();
}
}
- if (Object::cast_to<VisualScriptLocalVar>(node.ptr()) || Object::cast_to<VisualScriptLocalVarSet>(*node)) {
- //working memory is shared only for this node, for the same variables
- Ref<VisualScriptLocalVar> vslv = node;
-
- StringName var_name;
+ //Multiple passes are required to set up this complex thing..
+ //First create the nodes.
+ for (const Set<int>::Element *F = node_ids.front(); F; F = F->next()) {
+ Ref<VisualScriptNode> node = script->nodes[F->get()].node;
+
+ VisualScriptNodeInstance *instance = node->instance(this); // Create instance.
+ ERR_FAIL_COND(!instance);
+
+ instance->base = node.ptr();
+
+ instance->id = F->get();
+ instance->input_port_count = node->get_input_value_port_count();
+ instance->input_ports = NULL;
+ instance->output_port_count = node->get_output_value_port_count();
+ instance->output_ports = NULL;
+ instance->sequence_output_count = node->get_output_sequence_port_count();
+ instance->sequence_index = function.node_count++;
+ instance->sequence_outputs = NULL;
+ instance->pass_idx = -1;
+
+ if (instance->input_port_count) {
+ instance->input_ports = memnew_arr(int, instance->input_port_count);
+ for (int i = 0; i < instance->input_port_count; i++) {
+ instance->input_ports[i] = -1; // If not assigned, will become default value.
+ }
+ }
- if (Object::cast_to<VisualScriptLocalVar>(*node)) {
- var_name = String(Object::cast_to<VisualScriptLocalVar>(*node)->get_var_name()).strip_edges();
- } else {
- var_name = String(Object::cast_to<VisualScriptLocalVarSet>(*node)->get_var_name()).strip_edges();
+ if (instance->output_port_count) {
+ instance->output_ports = memnew_arr(int, instance->output_port_count);
+ for (int i = 0; i < instance->output_port_count; i++) {
+ instance->output_ports[i] = -1; // If not assigned, will output to trash.
+ }
}
- if (!local_var_indices.has(var_name)) {
- local_var_indices[var_name] = function.max_stack;
- function.max_stack++;
+ if (instance->sequence_output_count) {
+ instance->sequence_outputs = memnew_arr(VisualScriptNodeInstance *, instance->sequence_output_count);
+ for (int i = 0; i < instance->sequence_output_count; i++) {
+ instance->sequence_outputs[i] = NULL; // If it remains null, flow ends here.
+ }
}
- instance->working_mem_idx = local_var_indices[var_name];
+ if (Object::cast_to<VisualScriptLocalVar>(node.ptr()) || Object::cast_to<VisualScriptLocalVarSet>(*node)) {
+ // Working memory is shared only for this node, for the same variables.
+ Ref<VisualScriptLocalVar> vslv = node;
- } else if (instance->get_working_memory_size()) {
- instance->working_mem_idx = function.max_stack;
- function.max_stack += instance->get_working_memory_size();
- } else {
- instance->working_mem_idx = -1; //no working mem
- }
+ StringName var_name;
- max_input_args = MAX(max_input_args, instance->input_port_count);
- max_output_args = MAX(max_output_args, instance->output_port_count);
+ if (Object::cast_to<VisualScriptLocalVar>(*node))
+ var_name = String(Object::cast_to<VisualScriptLocalVar>(*node)->get_var_name()).strip_edges();
+ else
+ var_name = String(Object::cast_to<VisualScriptLocalVarSet>(*node)->get_var_name()).strip_edges();
- instances[F->key()] = instance;
- }
+ if (!local_var_indices.has(var_name)) {
+ local_var_indices[var_name] = function.max_stack;
+ function.max_stack++;
+ }
- function.trash_pos = function.max_stack++; //create pos for trash
+ instance->working_mem_idx = local_var_indices[var_name];
- //second pass, do data connections
+ } else if (instance->get_working_memory_size()) {
+ instance->working_mem_idx = function.max_stack;
+ function.max_stack += instance->get_working_memory_size();
+ } else {
+ instance->working_mem_idx = -1; //no working mem
+ }
- for (const Set<VisualScript::DataConnection>::Element *F = E->get().data_connections.front(); F; F = F->next()) {
- VisualScript::DataConnection dc = F->get();
- ERR_CONTINUE(!instances.has(dc.from_node));
- VisualScriptNodeInstance *from = instances[dc.from_node];
- ERR_CONTINUE(!instances.has(dc.to_node));
- VisualScriptNodeInstance *to = instances[dc.to_node];
- ERR_CONTINUE(dc.from_port >= from->output_port_count);
- ERR_CONTINUE(dc.to_port >= to->input_port_count);
+ max_input_args = MAX(max_input_args, instance->input_port_count);
+ max_output_args = MAX(max_output_args, instance->output_port_count);
- if (from->output_ports[dc.from_port] == -1) {
- int stack_pos = function.max_stack++;
- from->output_ports[dc.from_port] = stack_pos;
+ instances[F->get()] = instance;
}
- if (from->get_sequence_output_count() == 0 && to->dependencies.find(from) == -1) {
- //if the node we are reading from has no output sequence, we must call step() before reading from it.
- if (from->pass_idx == -1) {
- from->pass_idx = function.pass_stack_size;
- function.pass_stack_size++;
+ function.trash_pos = function.max_stack++; // create pos for trash
+
+ // Second pass, do data connections.
+ for (const Set<VisualScript::DataConnection>::Element *F = dataconns.front(); F; F = F->next()) {
+ VisualScript::DataConnection dc = F->get();
+ ERR_CONTINUE(!instances.has(dc.from_node));
+ VisualScriptNodeInstance *from = instances[dc.from_node];
+ ERR_CONTINUE(!instances.has(dc.to_node));
+ VisualScriptNodeInstance *to = instances[dc.to_node];
+ ERR_CONTINUE(dc.from_port >= from->output_port_count);
+ ERR_CONTINUE(dc.to_port >= to->input_port_count);
+
+ if (from->output_ports[dc.from_port] == -1) {
+ int stack_pos = function.max_stack++;
+ from->output_ports[dc.from_port] = stack_pos;
}
- to->dependencies.push_back(from);
- }
-
- to->input_ports[dc.to_port] = from->output_ports[dc.from_port]; //read from wherever the stack is
- }
- //third pass, do sequence connections
+ if (from->get_sequence_output_count() == 0 && to->dependencies.find(from) == -1) {
+ // If the node we are reading from has no output sequence, we must call step() before reading from it.
+ if (from->pass_idx == -1) {
+ from->pass_idx = function.pass_stack_size;
+ function.pass_stack_size++;
+ }
+ to->dependencies.push_back(from);
+ }
- for (const Set<VisualScript::SequenceConnection>::Element *F = E->get().sequence_connections.front(); F; F = F->next()) {
- VisualScript::SequenceConnection sc = F->get();
- ERR_CONTINUE(!instances.has(sc.from_node));
- VisualScriptNodeInstance *from = instances[sc.from_node];
- ERR_CONTINUE(!instances.has(sc.to_node));
- VisualScriptNodeInstance *to = instances[sc.to_node];
- ERR_CONTINUE(sc.from_output >= from->sequence_output_count);
+ to->input_ports[dc.to_port] = from->output_ports[dc.from_port]; // Read from wherever the stack is.
+ }
- from->sequence_outputs[sc.from_output] = to;
- }
+ // Third pass, do sequence connections.
+ for (const Set<VisualScript::SequenceConnection>::Element *F = seqconns.front(); F; F = F->next()) {
+ VisualScript::SequenceConnection sc = F->get();
+ ERR_CONTINUE(!instances.has(sc.from_node));
+ VisualScriptNodeInstance *from = instances[sc.from_node];
+ ERR_CONTINUE(!instances.has(sc.to_node));
+ VisualScriptNodeInstance *to = instances[sc.to_node];
+ ERR_CONTINUE(sc.from_output >= from->sequence_output_count);
- //fourth pass:
- // 1) unassigned input ports to default values
- // 2) connect unassigned output ports to trash
+ from->sequence_outputs[sc.from_output] = to;
+ }
- for (const Map<int, VisualScript::Function::NodeData>::Element *F = E->get().nodes.front(); F; F = F->next()) {
- ERR_CONTINUE(!instances.has(F->key()));
+ //fourth pass:
+ // 1) unassigned input ports to default values
+ // 2) connect unassigned output ports to trash
+ for (const Set<int>::Element *F = node_ids.front(); F; F = F->next()) {
+ ERR_CONTINUE(!instances.has(F->get()));
- Ref<VisualScriptNode> node = F->get().node;
- VisualScriptNodeInstance *instance = instances[F->key()];
+ Ref<VisualScriptNode> node = script->nodes[F->get()].node;
+ VisualScriptNodeInstance *instance = instances[F->get()];
- // connect to default values
- for (int i = 0; i < instance->input_port_count; i++) {
- if (instance->input_ports[i] == -1) {
- //unassigned, connect to default val
- instance->input_ports[i] = default_values.size() | VisualScriptNodeInstance::INPUT_DEFAULT_VALUE_BIT;
- default_values.push_back(node->get_default_input_value(i));
+ // Connect to default values.
+ for (int i = 0; i < instance->input_port_count; i++) {
+ if (instance->input_ports[i] == -1) {
+ // Unassigned, connect to default val.
+ instance->input_ports[i] = default_values.size() | VisualScriptNodeInstance::INPUT_DEFAULT_VALUE_BIT;
+ default_values.push_back(node->get_default_input_value(i));
+ }
}
- }
- // connect to trash
- for (int i = 0; i < instance->output_port_count; i++) {
- if (instance->output_ports[i] == -1) {
- instance->output_ports[i] = function.trash_pos; //trash is same for all
+ // Connect to trash.
+ for (int i = 0; i < instance->output_port_count; i++) {
+ if (instance->output_ports[i] == -1) {
+ instance->output_ports[i] = function.trash_pos; //trash is same for all
+ }
}
}
- }
- functions[E->key()] = function;
+ functions[E->get()] = function;
+ }
}
}
@@ -2354,7 +2247,7 @@ Variant VisualScriptFunctionState::_signal_callback(const Variant **p_args, int
Variant *working_mem = ((Variant *)stack.ptr()) + working_mem_index;
- *working_mem = args; //arguments go to working mem.
+ *working_mem = args; // Arguments go to working mem.
Variant ret = instance->_call_internal(function, stack.ptrw(), stack.size(), node, flow_stack_pos, pass, true, r_error);
function = StringName(); //invalidate
@@ -2367,7 +2260,7 @@ void VisualScriptFunctionState::connect_to_signal(Object *p_obj, const String &p
binds.push_back(p_binds[i]);
}
binds.push_back(Ref<VisualScriptFunctionState>(this)); //add myself on the back to avoid dying from unreferencing
- p_obj->connect_compat(p_signal, this, "_signal_callback", binds, CONNECT_ONESHOT);
+ p_obj->connect(p_signal, Callable(this, "_signal_callback"), binds, CONNECT_ONESHOT);
}
bool VisualScriptFunctionState::is_valid() const {
@@ -2388,7 +2281,7 @@ Variant VisualScriptFunctionState::resume(Array p_args) {
Variant *working_mem = ((Variant *)stack.ptr()) + working_mem_index;
- *working_mem = p_args; //arguments go to working mem.
+ *working_mem = p_args; // Arguments go to working mem.
Variant ret = instance->_call_internal(function, stack.ptrw(), stack.size(), node, flow_stack_pos, pass, true, r_error);
function = StringName(); //invalidate
@@ -2498,7 +2391,7 @@ void VisualScriptLanguage::add_global_constant(const StringName &p_variable, con
/* DEBUGGER FUNCTIONS */
bool VisualScriptLanguage::debug_break_parse(const String &p_file, int p_node, const String &p_error) {
- //break because of parse error
+ // Break because of parse error.
if (EngineDebugger::is_active() && Thread::get_caller_id() == Thread::get_main_id()) {
_debug_parse_err_node = p_node;
@@ -2635,7 +2528,6 @@ void VisualScriptLanguage::debug_get_stack_level_locals(int p_level, List<String
f->debug_get_stack_member_state(*_call_stack[l].line,&locals);
for( List<Pair<StringName,int> >::Element *E = locals.front();E;E=E->next() ) {
-
p_locals->push_back(E->get().first);
p_values->push_back(_call_stack[l].stack[E->get().second]);
}
@@ -2667,7 +2559,7 @@ void VisualScriptLanguage::debug_get_stack_level_members(int p_level, List<Strin
}
void VisualScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {
- //no globals are really reachable in gdscript
+ // No globals are really reachable in gdscript.
}
String VisualScriptLanguage::debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) {
@@ -2743,7 +2635,7 @@ VisualScriptLanguage::VisualScriptLanguage() {
ProjectSettings::get_singleton()->set_custom_property_info("debug/settings/visual_script/max_call_stack", PropertyInfo(Variant::INT, "debug/settings/visual_script/max_call_stack", PROPERTY_HINT_RANGE, "1024,4096,1,or_greater")); //minimum is 1024
if (EngineDebugger::is_active()) {
- //debugging enabled!
+ // Debugging enabled!
_debug_max_call_stack = dmcs;
_call_stack = memnew_arr(CallLevel, _debug_max_call_stack + 1);
diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h
index cb5ed37ba1..bdb3c3a16b 100644
--- a/modules/visual_script/visual_script.h
+++ b/modules/visual_script/visual_script.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,8 +33,9 @@
#include "core/debugger/engine_debugger.h"
#include "core/debugger/script_debugger.h"
+#include "core/doc_data.h"
+#include "core/object/script_language.h"
#include "core/os/thread.h"
-#include "core/script_language.h"
class VisualScriptInstance;
class VisualScriptNodeInstance;
@@ -45,7 +46,7 @@ class VisualScriptNode : public Resource {
friend class VisualScript;
- Set<VisualScript *> scripts_used;
+ Ref<VisualScript> script_used;
Array default_input_values;
bool breakpoint;
@@ -82,7 +83,7 @@ public:
virtual String get_text() const;
virtual String get_category() const = 0;
- //used by editor, this is not really saved
+ // Used by editor, this is not really saved.
void set_breakpoint(bool p_breakpoint);
bool is_breakpoint() const;
@@ -105,9 +106,9 @@ public:
class VisualScriptNodeInstance {
friend class VisualScriptInstance;
- friend class VisualScriptLanguage; //for debugger
+ friend class VisualScriptLanguage; // For debugger.
- enum { //input argument addressing
+ enum { // Input argument addressing.
INPUT_SHIFT = 1 << 24,
INPUT_MASK = INPUT_SHIFT - 1,
INPUT_DEFAULT_VALUE_BIT = INPUT_SHIFT, // from unassigned input port, using default value (edited by user)
@@ -137,13 +138,13 @@ public:
enum {
STEP_SHIFT = 1 << 24,
STEP_MASK = STEP_SHIFT - 1,
- STEP_FLAG_PUSH_STACK_BIT = STEP_SHIFT, //push bit to stack
- STEP_FLAG_GO_BACK_BIT = STEP_SHIFT << 1, //go back to previous node
- STEP_NO_ADVANCE_BIT = STEP_SHIFT << 2, //do not advance past this node
- STEP_EXIT_FUNCTION_BIT = STEP_SHIFT << 3, //return from function
- STEP_YIELD_BIT = STEP_SHIFT << 4, //yield (will find VisualScriptFunctionState state in first working memory)
+ STEP_FLAG_PUSH_STACK_BIT = STEP_SHIFT, // push bit to stack
+ STEP_FLAG_GO_BACK_BIT = STEP_SHIFT << 1, // go back to previous node
+ STEP_NO_ADVANCE_BIT = STEP_SHIFT << 2, // do not advance past this node
+ STEP_EXIT_FUNCTION_BIT = STEP_SHIFT << 3, // return from function
+ STEP_YIELD_BIT = STEP_SHIFT << 4, // yield (will find VisualScriptFunctionState state in first working memory)
- FLOW_STACK_PUSHED_BIT = 1 << 30, //in flow stack, means bit was pushed (must go back here if end of sequence)
+ FLOW_STACK_PUSHED_BIT = 1 << 30, // in flow stack, means bit was pushed (must go back here if end of sequence)
FLOW_STACK_MASK = FLOW_STACK_PUSHED_BIT - 1
};
@@ -156,7 +157,7 @@ public:
virtual int get_working_memory_size() const { 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) = 0; //do a step, return which sequence port to go out
+ 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) = 0; // Do a step, return which sequence port to go out.
Ref<VisualScriptNode> get_base_node() { return Ref<VisualScriptNode>(base); }
@@ -210,34 +211,32 @@ private:
Variant::Type type;
};
- struct Function {
- struct NodeData {
- Point2 pos;
- Ref<VisualScriptNode> node;
- };
-
- Map<int, NodeData> nodes;
-
- Set<SequenceConnection> sequence_connections;
+ struct NodeData {
+ Point2 pos;
+ Ref<VisualScriptNode> node;
+ };
- Set<DataConnection> data_connections;
+ HashMap<int, NodeData> nodes; // Can be a sparse map.
- int function_id;
+ Set<SequenceConnection> sequence_connections;
+ Set<DataConnection> data_connections;
- Vector2 scroll;
+ Vector2 scroll;
- Function() { function_id = -1; }
+ struct Function {
+ int func_id;
+ Function() { func_id = -1; }
};
struct Variable {
PropertyInfo info;
Variant default_value;
bool _export;
- // add getter & setter options here
+ // Add getter & setter options here.
};
- Map<StringName, Function> functions;
- Map<StringName, Variable> variables;
+ HashMap<StringName, Function> functions;
+ HashMap<StringName, Variable> variables;
Map<StringName, Vector<Argument>> custom_signals;
Vector<ScriptNetData> rpc_functions;
Vector<ScriptNetData> rpc_variables;
@@ -248,7 +247,7 @@ private:
#ifdef TOOLS_ENABLED
Set<PlaceHolderScriptInstance *> placeholders;
- //void _update_placeholder(PlaceHolderScriptInstance *p_placeholder);
+ // void _update_placeholder(PlaceHolderScriptInstance *p_placeholder);
virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) override;
void _update_placeholders();
#endif
@@ -266,37 +265,38 @@ protected:
public:
bool inherits_script(const Ref<Script> &p_script) const override;
- // TODO: Remove it in future when breaking changes are acceptable
- StringName get_default_func() const;
- void add_function(const StringName &p_name);
+ void set_scroll(const Vector2 &p_scroll);
+ Vector2 get_scroll() const;
+
+ void add_function(const StringName &p_name, int p_func_node_id);
bool has_function(const StringName &p_name) const;
void remove_function(const StringName &p_name);
void rename_function(const StringName &p_name, const StringName &p_new_name);
- void set_function_scroll(const StringName &p_name, const Vector2 &p_scroll);
- Vector2 get_function_scroll(const StringName &p_name) const;
void get_function_list(List<StringName> *r_functions) const;
int get_function_node_id(const StringName &p_name) const;
void set_tool_enabled(bool p_enabled);
- void add_node(const StringName &p_func, int p_id, const Ref<VisualScriptNode> &p_node, const Point2 &p_pos = Point2());
- void remove_node(const StringName &p_func, int p_id);
- bool has_node(const StringName &p_func, int p_id) const;
- Ref<VisualScriptNode> get_node(const StringName &p_func, int p_id) const;
- void set_node_position(const StringName &p_func, int p_id, const Point2 &p_pos);
- Point2 get_node_position(const StringName &p_func, int p_id) const;
- void get_node_list(const StringName &p_func, List<int> *r_nodes) const;
-
- void sequence_connect(const StringName &p_func, int p_from_node, int p_from_output, int p_to_node);
- void sequence_disconnect(const StringName &p_func, int p_from_node, int p_from_output, int p_to_node);
- bool has_sequence_connection(const StringName &p_func, int p_from_node, int p_from_output, int p_to_node) const;
- void get_sequence_connection_list(const StringName &p_func, List<SequenceConnection> *r_connection) const;
-
- void data_connect(const StringName &p_func, int p_from_node, int p_from_port, int p_to_node, int p_to_port);
- void data_disconnect(const StringName &p_func, int p_from_node, int p_from_port, int p_to_node, int p_to_port);
- bool has_data_connection(const StringName &p_func, int p_from_node, int p_from_port, int p_to_node, int p_to_port) const;
- void get_data_connection_list(const StringName &p_func, List<DataConnection> *r_connection) const;
- bool is_input_value_port_connected(const StringName &p_func, int p_node, int p_port) const;
- bool get_input_value_port_connection_source(const StringName &p_func, int p_node, int p_port, int *r_node, int *r_port) const;
+ void add_node(int p_id, const Ref<VisualScriptNode> &p_node, const Point2 &p_pos = Point2());
+ void remove_node(int p_id);
+ bool has_node(int p_id) const;
+ Ref<VisualScriptNode> get_node(int p_id) const;
+ void set_node_position(int p_id, const Point2 &p_pos);
+ Point2 get_node_position(int p_id) const;
+ void get_node_list(List<int> *r_nodes) const;
+
+ void sequence_connect(int p_from_node, int p_from_output, int p_to_node);
+ void sequence_disconnect(int p_from_node, int p_from_output, int p_to_node);
+ bool has_sequence_connection(int p_from_node, int p_from_output, int p_to_node) const;
+ void get_sequence_connection_list(List<SequenceConnection> *r_connection) const;
+ Set<int> get_output_sequence_ports_connected(int from_node);
+
+ void data_connect(int p_from_node, int p_from_port, int p_to_node, int p_to_port);
+ void data_disconnect(int p_from_node, int p_from_port, int p_to_node, int p_to_port);
+ bool has_data_connection(int p_from_node, int p_from_port, int p_to_node, int p_to_port) const;
+ void get_data_connection_list(List<DataConnection> *r_connection) const;
+
+ bool is_input_value_port_connected(int p_node, int p_port) const;
+ bool get_input_value_port_connection_source(int p_node, int p_port, int *r_node, int *r_port) const;
void add_variable(const StringName &p_name, const Variant &p_default_value = Variant(), bool p_export = false);
bool has_variable(const StringName &p_name) const;
@@ -342,6 +342,13 @@ public:
virtual void set_source_code(const String &p_code) override;
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;
+ return docs;
+ }
+#endif // TOOLS_ENABLED
+
virtual bool is_tool() const override;
virtual bool is_valid() const override;
@@ -384,7 +391,7 @@ class VisualScriptInstance : public ScriptInstance {
Object *owner;
Ref<VisualScript> script;
- Map<StringName, Variant> variables; //using variable path, not script
+ Map<StringName, Variant> variables; // Using variable path, not script.
Map<int, VisualScriptNodeInstance *> instances;
struct Function {
@@ -407,9 +414,8 @@ class VisualScriptInstance : public ScriptInstance {
void _dependency_step(VisualScriptNodeInstance *node, int p_pass, int *pass_stack, const Variant **input_args, Variant **output_args, Variant *variant_stack, Callable::CallError &r_error, String &error_str, VisualScriptNodeInstance **r_error_node);
Variant _call_internal(const StringName &p_method, void *p_stack, int p_stack_size, VisualScriptNodeInstance *p_node, int p_flow_stack_pos, int p_pass, bool p_resuming_yield, Callable::CallError &r_error);
- //Map<StringName,Function> functions;
- friend class VisualScriptFunctionState; //for yield
- friend class VisualScriptLanguage; //for debugger
+ friend class VisualScriptFunctionState; // For yield.
+ friend class VisualScriptLanguage; // For debugger.
public:
virtual bool set(const StringName &p_name, const Variant &p_value);
virtual bool get(const StringName &p_name, Variant &r_ret) const;
@@ -530,7 +536,7 @@ public:
_FORCE_INLINE_ void enter_function(VisualScriptInstance *p_instance, const StringName *p_function, Variant *p_stack, Variant **p_work_mem, int *current_id) {
if (Thread::get_main_id() != Thread::get_caller_id()) {
- return; //no support for other threads than main for now
+ return; // No support for other threads than main for now.
}
if (EngineDebugger::get_script_debugger()->get_lines_left() > 0 && EngineDebugger::get_script_debugger()->get_depth() >= 0) {
@@ -538,7 +544,7 @@ public:
}
if (_debug_call_stack_pos >= _debug_max_call_stack) {
- //stack overflow
+ // Stack overflow.
_debug_error = "Stack Overflow (Stack Size: " + itos(_debug_max_call_stack) + ")";
EngineDebugger::get_script_debugger()->debug(this);
return;
@@ -554,7 +560,7 @@ public:
_FORCE_INLINE_ void exit_function() {
if (Thread::get_main_id() != Thread::get_caller_id()) {
- return; //no support for other threads than main for now
+ return; // No support for other threads than main for now.
}
if (EngineDebugger::get_script_debugger()->get_lines_left() > 0 && EngineDebugger::get_script_debugger()->get_depth() >= 0) {
@@ -632,7 +638,7 @@ public:
~VisualScriptLanguage();
};
-//aid for registering
+// Aid for registering.
template <class T>
static Ref<VisualScriptNode> create_node_generic(const String &p_name) {
Ref<T> node;
diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp
index 177f9192b8..b96311ba6c 100644
--- a/modules/visual_script/visual_script_builtin_funcs.cpp
+++ b/modules/visual_script/visual_script_builtin_funcs.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,13 +30,12 @@
#include "visual_script_builtin_funcs.h"
-#include "core/class_db.h"
-#include "core/func_ref.h"
#include "core/io/marshalls.h"
#include "core/math/math_funcs.h"
+#include "core/object/class_db.h"
+#include "core/object/reference.h"
#include "core/os/os.h"
-#include "core/reference.h"
-#include "core/variant_parser.h"
+#include "core/variant/variant_parser.h"
const char *VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX] = {
"sin",
@@ -64,7 +63,7 @@ const char *VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX
"is_inf",
"ease",
"step_decimals",
- "stepify",
+ "snapped",
"lerp",
"inverse_lerp",
"range_lerp",
@@ -73,7 +72,8 @@ const char *VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX
"randomize",
"randi",
"randf",
- "rand_range",
+ "randf_range",
+ "randi_range",
"seed",
"rand_seed",
"deg2rad",
@@ -89,7 +89,6 @@ const char *VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX
"clamp",
"nearest_po2",
"weakref",
- "funcref",
"convert",
"typeof",
"type_exists",
@@ -102,7 +101,6 @@ const char *VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX
"str2var",
"var2bytes",
"bytes2var",
- "color_named",
"smoothstep",
"posmod",
"lerp_angle",
@@ -143,7 +141,7 @@ bool VisualScriptBuiltinFunc::has_input_sequence_port() const {
int VisualScriptBuiltinFunc::get_func_argument_count(BuiltinFunc p_func) {
switch (p_func) {
case MATH_RANDOMIZE:
- case MATH_RAND:
+ case MATH_RANDI:
case MATH_RANDF:
return 0;
case MATH_SIN:
@@ -193,15 +191,14 @@ int VisualScriptBuiltinFunc::get_func_argument_count(BuiltinFunc p_func) {
case MATH_POSMOD:
case MATH_POW:
case MATH_EASE:
- case MATH_STEPIFY:
- case MATH_RANDOM:
+ case MATH_SNAPPED:
+ case MATH_RANDF_RANGE:
+ case MATH_RANDI_RANGE:
case MATH_POLAR2CARTESIAN:
case MATH_CARTESIAN2POLAR:
case LOGIC_MAX:
case LOGIC_MIN:
- case FUNC_FUNCREF:
case TYPE_CONVERT:
- case COLORN:
return 2;
case MATH_LERP:
case MATH_LERP_ANGLE:
@@ -310,7 +307,7 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const
case MATH_STEP_DECIMALS: {
return PropertyInfo(Variant::FLOAT, "step");
} break;
- case MATH_STEPIFY: {
+ case MATH_SNAPPED: {
if (p_idx == 0) {
return PropertyInfo(Variant::FLOAT, "s");
} else {
@@ -361,16 +358,23 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const
}
} break;
case MATH_RANDOMIZE:
- case MATH_RAND:
+ case MATH_RANDI:
case MATH_RANDF: {
} break;
- case MATH_RANDOM: {
+ case MATH_RANDF_RANGE: {
if (p_idx == 0) {
return PropertyInfo(Variant::FLOAT, "from");
} else {
return PropertyInfo(Variant::FLOAT, "to");
}
} break;
+ case MATH_RANDI_RANGE: {
+ if (p_idx == 0) {
+ return PropertyInfo(Variant::INT, "from");
+ } else {
+ return PropertyInfo(Variant::INT, "to");
+ }
+ } break;
case MATH_SEED:
case MATH_RANDSEED: {
return PropertyInfo(Variant::INT, "seed");
@@ -426,13 +430,6 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const
case OBJ_WEAKREF: {
return PropertyInfo(Variant::OBJECT, "source");
} break;
- case FUNC_FUNCREF: {
- if (p_idx == 0) {
- return PropertyInfo(Variant::OBJECT, "instance");
- } else {
- return PropertyInfo(Variant::STRING, "funcname");
- }
- } break;
case TYPE_CONVERT: {
if (p_idx == 0) {
return PropertyInfo(Variant::NIL, "what");
@@ -477,13 +474,6 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const
return PropertyInfo(Variant::BOOL, "allow_objects");
}
} break;
- case COLORN: {
- if (p_idx == 0) {
- return PropertyInfo(Variant::STRING, "name");
- } else {
- return PropertyInfo(Variant::FLOAT, "alpha");
- }
- } break;
case FUNC_MAX: {
}
}
@@ -538,7 +528,7 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons
case MATH_STEP_DECIMALS: {
t = Variant::INT;
} break;
- case MATH_STEPIFY:
+ case MATH_SNAPPED:
case MATH_LERP:
case MATH_LERP_ANGLE:
case MATH_INVERSE_LERP:
@@ -551,13 +541,16 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons
} break;
case MATH_RANDOMIZE: {
} break;
- case MATH_RAND: {
+ case MATH_RANDI: {
t = Variant::INT;
} break;
case MATH_RANDF:
- case MATH_RANDOM: {
+ case MATH_RANDF_RANGE: {
t = Variant::FLOAT;
} break;
+ case MATH_RANDI_RANGE: {
+ t = Variant::INT;
+ } break;
case MATH_SEED: {
} break;
case MATH_RANDSEED: {
@@ -593,10 +586,6 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons
t = Variant::OBJECT;
} break;
- case FUNC_FUNCREF: {
- t = Variant::OBJECT;
-
- } break;
case TYPE_CONVERT: {
} break;
case TEXT_ORD:
@@ -637,9 +626,6 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons
t = Variant::BOOL;
}
} break;
- case COLORN: {
- t = Variant::COLOR;
- } break;
case FUNC_MAX: {
}
}
@@ -649,7 +635,6 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons
/*
String VisualScriptBuiltinFunc::get_caption() const {
-
return "BuiltinFunc";
}
@@ -808,10 +793,10 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
VALIDATE_ARG_NUM(0);
*r_return = Math::step_decimals((double)*p_inputs[0]);
} break;
- case VisualScriptBuiltinFunc::MATH_STEPIFY: {
+ case VisualScriptBuiltinFunc::MATH_SNAPPED: {
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
- *r_return = Math::stepify((double)*p_inputs[0], (double)*p_inputs[1]);
+ *r_return = Math::snapped((double)*p_inputs[0], (double)*p_inputs[1]);
} break;
case VisualScriptBuiltinFunc::MATH_LERP: {
VALIDATE_ARG_NUM(0);
@@ -861,17 +846,22 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
Math::randomize();
} break;
- case VisualScriptBuiltinFunc::MATH_RAND: {
+ case VisualScriptBuiltinFunc::MATH_RANDI: {
*r_return = Math::rand();
} break;
case VisualScriptBuiltinFunc::MATH_RANDF: {
*r_return = Math::randf();
} break;
- case VisualScriptBuiltinFunc::MATH_RANDOM: {
+ case VisualScriptBuiltinFunc::MATH_RANDF_RANGE: {
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
*r_return = Math::random((double)*p_inputs[0], (double)*p_inputs[1]);
} break;
+ case VisualScriptBuiltinFunc::MATH_RANDI_RANGE: {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ *r_return = Math::random((int)*p_inputs[0], (int)*p_inputs[1]);
+ } break;
case VisualScriptBuiltinFunc::MATH_SEED: {
VALIDATE_ARG_NUM(0);
uint64_t seed = *p_inputs[0];
@@ -1013,30 +1003,6 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
}
} break;
- case VisualScriptBuiltinFunc::FUNC_FUNCREF: {
- if (p_inputs[0]->get_type() != Variant::OBJECT) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
-
- return;
- }
- if (p_inputs[1]->get_type() != Variant::STRING && p_inputs[1]->get_type() != Variant::NODE_PATH) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 1;
- r_error.expected = Variant::STRING;
-
- return;
- }
-
- Ref<FuncRef> fr = memnew(FuncRef);
-
- fr->set_instance(*p_inputs[0]);
- fr->set_function(*p_inputs[1]);
-
- *r_return = fr;
-
- } break;
case VisualScriptBuiltinFunc::TYPE_CONVERT: {
VALIDATE_ARG_NUM(1);
int type = *p_inputs[1];
@@ -1048,7 +1014,7 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
return;
} else {
- *r_return = Variant::construct(Variant::Type(type), p_inputs, 1, r_error);
+ Variant::construct(Variant::Type(type), *r_return, p_inputs, 1, r_error);
}
} break;
case VisualScriptBuiltinFunc::TYPE_OF: {
@@ -1198,15 +1164,6 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
*r_return = ret;
} break;
- case VisualScriptBuiltinFunc::COLORN: {
- VALIDATE_ARG_NUM(1);
-
- Color color = Color::named(*p_inputs[0]);
- color.a = *p_inputs[1];
-
- *r_return = String(color);
-
- } break;
default: {
}
}
@@ -1276,16 +1233,17 @@ void VisualScriptBuiltinFunc::_bind_methods() {
BIND_ENUM_CONSTANT(MATH_ISINF);
BIND_ENUM_CONSTANT(MATH_EASE);
BIND_ENUM_CONSTANT(MATH_STEP_DECIMALS);
- BIND_ENUM_CONSTANT(MATH_STEPIFY);
+ BIND_ENUM_CONSTANT(MATH_SNAPPED);
BIND_ENUM_CONSTANT(MATH_LERP);
BIND_ENUM_CONSTANT(MATH_INVERSE_LERP);
BIND_ENUM_CONSTANT(MATH_RANGE_LERP);
BIND_ENUM_CONSTANT(MATH_MOVE_TOWARD);
BIND_ENUM_CONSTANT(MATH_DECTIME);
BIND_ENUM_CONSTANT(MATH_RANDOMIZE);
- BIND_ENUM_CONSTANT(MATH_RAND);
+ BIND_ENUM_CONSTANT(MATH_RANDI);
BIND_ENUM_CONSTANT(MATH_RANDF);
- BIND_ENUM_CONSTANT(MATH_RANDOM);
+ BIND_ENUM_CONSTANT(MATH_RANDF_RANGE);
+ BIND_ENUM_CONSTANT(MATH_RANDI_RANGE);
BIND_ENUM_CONSTANT(MATH_SEED);
BIND_ENUM_CONSTANT(MATH_RANDSEED);
BIND_ENUM_CONSTANT(MATH_DEG2RAD);
@@ -1301,7 +1259,6 @@ void VisualScriptBuiltinFunc::_bind_methods() {
BIND_ENUM_CONSTANT(LOGIC_CLAMP);
BIND_ENUM_CONSTANT(LOGIC_NEAREST_PO2);
BIND_ENUM_CONSTANT(OBJ_WEAKREF);
- BIND_ENUM_CONSTANT(FUNC_FUNCREF);
BIND_ENUM_CONSTANT(TYPE_CONVERT);
BIND_ENUM_CONSTANT(TYPE_OF);
BIND_ENUM_CONSTANT(TYPE_EXISTS);
@@ -1314,7 +1271,6 @@ void VisualScriptBuiltinFunc::_bind_methods() {
BIND_ENUM_CONSTANT(STR_TO_VAR);
BIND_ENUM_CONSTANT(VAR_TO_BYTES);
BIND_ENUM_CONSTANT(BYTES_TO_VAR);
- BIND_ENUM_CONSTANT(COLORN);
BIND_ENUM_CONSTANT(MATH_SMOOTHSTEP);
BIND_ENUM_CONSTANT(MATH_POSMOD);
BIND_ENUM_CONSTANT(MATH_LERP_ANGLE);
@@ -1366,7 +1322,7 @@ void register_visual_script_builtin_func_node() {
VisualScriptLanguage::singleton->add_register_func("functions/built_in/ease", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_EASE>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/step_decimals", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_STEP_DECIMALS>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/stepify", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_STEPIFY>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/snapped", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SNAPPED>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LERP>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/lerp_angle", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LERP_ANGLE>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/inverse_lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_INVERSE_LERP>);
@@ -1375,9 +1331,10 @@ void register_visual_script_builtin_func_node() {
VisualScriptLanguage::singleton->add_register_func("functions/built_in/move_toward", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_MOVE_TOWARD>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/dectime", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DECTIME>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/randomize", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDOMIZE>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/rand", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RAND>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/randi", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDI>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/randf", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDF>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/random", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDOM>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/randf_range", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDF_RANGE>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/randi_range", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDI_RANGE>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/seed", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SEED>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/randseed", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDSEED>);
@@ -1396,7 +1353,6 @@ void register_visual_script_builtin_func_node() {
VisualScriptLanguage::singleton->add_register_func("functions/built_in/nearest_po2", create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_NEAREST_PO2>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/weakref", create_builtin_func_node<VisualScriptBuiltinFunc::OBJ_WEAKREF>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/funcref", create_builtin_func_node<VisualScriptBuiltinFunc::FUNC_FUNCREF>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/convert", create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_CONVERT>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/typeof", create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_OF>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/type_exists", create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_EXISTS>);
@@ -1410,5 +1366,4 @@ void register_visual_script_builtin_func_node() {
VisualScriptLanguage::singleton->add_register_func("functions/built_in/str2var", create_builtin_func_node<VisualScriptBuiltinFunc::STR_TO_VAR>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/var2bytes", create_builtin_func_node<VisualScriptBuiltinFunc::VAR_TO_BYTES>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/bytes2var", create_builtin_func_node<VisualScriptBuiltinFunc::BYTES_TO_VAR>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/color_named", create_builtin_func_node<VisualScriptBuiltinFunc::COLORN>);
}
diff --git a/modules/visual_script/visual_script_builtin_funcs.h b/modules/visual_script/visual_script_builtin_funcs.h
index aee2ed79ce..1fafaf1d98 100644
--- a/modules/visual_script/visual_script_builtin_funcs.h
+++ b/modules/visual_script/visual_script_builtin_funcs.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -63,16 +63,17 @@ public:
MATH_ISINF,
MATH_EASE,
MATH_STEP_DECIMALS,
- MATH_STEPIFY,
+ MATH_SNAPPED,
MATH_LERP,
MATH_INVERSE_LERP,
MATH_RANGE_LERP,
MATH_MOVE_TOWARD,
MATH_DECTIME,
MATH_RANDOMIZE,
- MATH_RAND,
+ MATH_RANDI,
MATH_RANDF,
- MATH_RANDOM,
+ MATH_RANDF_RANGE,
+ MATH_RANDI_RANGE,
MATH_SEED,
MATH_RANDSEED,
MATH_DEG2RAD,
@@ -88,7 +89,6 @@ public:
LOGIC_CLAMP,
LOGIC_NEAREST_PO2,
OBJ_WEAKREF,
- FUNC_FUNCREF,
TYPE_CONVERT,
TYPE_OF,
TYPE_EXISTS,
@@ -101,7 +101,6 @@ public:
STR_TO_VAR,
VAR_TO_BYTES,
BYTES_TO_VAR,
- COLORN,
MATH_SMOOTHSTEP,
MATH_POSMOD,
MATH_LERP_ANGLE,
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index b1d8c05d87..78e4a7f113 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,10 +31,10 @@
#include "visual_script_editor.h"
#include "core/input/input.h"
-#include "core/object.h"
+#include "core/object/class_db.h"
+#include "core/object/script_language.h"
#include "core/os/keyboard.h"
-#include "core/script_language.h"
-#include "core/variant.h"
+#include "core/variant/variant.h"
#include "editor/editor_node.h"
#include "editor/editor_resource_preview.h"
#include "editor/editor_scale.h"
@@ -199,7 +199,7 @@ protected:
emit_signal("changed");
}
void _var_value_changed() {
- _change_notify("value"); //so the whole tree is not redrawn, makes editing smoother in general
+ _change_notify("value"); // So the whole tree is not redrawn, makes editing smoother in general.
emit_signal("changed");
}
@@ -227,6 +227,19 @@ protected:
undo_redo->create_action(TTR("Set Variable Type"));
undo_redo->add_do_method(script.ptr(), "set_variable_info", var, dc);
undo_redo->add_undo_method(script.ptr(), "set_variable_info", var, d);
+
+ // Setting the default value.
+ Variant::Type type = (Variant::Type)(int)p_value;
+ if (type != Variant::NIL) {
+ Variant default_value;
+ Callable::CallError ce;
+ Variant::construct(type, default_value, nullptr, 0, ce);
+ if (ce.error == Callable::CallError::CALL_OK) {
+ undo_redo->add_do_method(script.ptr(), "set_variable_default_value", var, default_value);
+ undo_redo->add_undo_method(script.ptr(), "set_variable_default_value", var, dc["value"]);
+ }
+ }
+
undo_redo->add_do_method(this, "_var_changed");
undo_redo->add_undo_method(this, "_var_changed");
undo_redo->commit_action();
@@ -309,7 +322,7 @@ protected:
}
p_list->push_back(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt));
p_list->push_back(PropertyInfo(script->get_variable_info(var).type, "value", script->get_variable_info(var).hint, script->get_variable_info(var).hint_string, PROPERTY_USAGE_DEFAULT));
- // Update this when PropertyHint changes
+ // Update this when PropertyHint changes.
p_list->push_back(PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_ENUM, "None,Range,ExpRange,Enum,ExpEasing,Length,SpriteFrame,KeyAccel,Flags,Layers2dRender,Layers2dPhysics,Layer3dRender,Layer3dPhysics,File,Dir,GlobalFile,GlobalDir,ResourceType,MultilineText,PlaceholderText,ColorNoAlpha,ImageCompressLossy,ImageCompressLossLess,ObjectId,String,NodePathToEditedNode,MethodOfVariantType,MethodOfBaseType,MethodOfInstance,MethodOfScript,PropertyOfVariantType,PropertyOfBaseType,PropertyOfInstance,PropertyOfScript,ObjectTooBig,NodePathValidTypes"));
p_list->push_back(PropertyInfo(Variant::STRING, "hint_string"));
p_list->push_back(PropertyInfo(Variant::BOOL, "export"));
@@ -388,7 +401,7 @@ static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) {
case Variant::NODE_PATH:
color = Color(0.41, 0.58, 0.93);
break;
- case Variant::_RID:
+ case Variant::RID:
color = Color(0.41, 0.93, 0.6);
break;
case Variant::OBJECT:
@@ -494,7 +507,7 @@ static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) {
case Variant::NODE_PATH:
color = Color(0.41, 0.58, 0.93);
break;
- case Variant::_RID:
+ case Variant::RID:
color = Color(0.17, 0.9, 0.45);
break;
case Variant::OBJECT:
@@ -546,39 +559,29 @@ static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) {
void VisualScriptEditor::_update_graph_connections() {
graph->clear_connections();
- List<StringName> funcs;
- script->get_function_list(&funcs);
+ List<VisualScript::SequenceConnection> sequence_conns;
+ script->get_sequence_connection_list(&sequence_conns);
- if (funcs.size() <= 0) {
- updating_graph = false;
- return;
+ for (List<VisualScript::SequenceConnection>::Element *E = sequence_conns.front(); E; E = E->next()) {
+ graph->connect_node(itos(E->get().from_node), E->get().from_output, itos(E->get().to_node), 0);
}
- for (List<StringName>::Element *F = funcs.front(); F; F = F->next()) {
- List<VisualScript::SequenceConnection> sequence_conns;
- script->get_sequence_connection_list(F->get(), &sequence_conns);
-
- for (List<VisualScript::SequenceConnection>::Element *E = sequence_conns.front(); E; E = E->next()) {
- graph->connect_node(itos(E->get().from_node), E->get().from_output, itos(E->get().to_node), 0);
- }
-
- List<VisualScript::DataConnection> data_conns;
- script->get_data_connection_list(F->get(), &data_conns);
+ List<VisualScript::DataConnection> data_conns;
+ script->get_data_connection_list(&data_conns);
- for (List<VisualScript::DataConnection>::Element *E = data_conns.front(); E; E = E->next()) {
- VisualScript::DataConnection dc = E->get();
+ for (List<VisualScript::DataConnection>::Element *E = data_conns.front(); E; E = E->next()) {
+ VisualScript::DataConnection dc = E->get();
- Ref<VisualScriptNode> from_node = script->get_node(F->get(), E->get().from_node);
- Ref<VisualScriptNode> to_node = script->get_node(F->get(), E->get().to_node);
+ Ref<VisualScriptNode> from_node = script->get_node(E->get().from_node);
+ Ref<VisualScriptNode> to_node = script->get_node(E->get().to_node);
- if (to_node->has_input_sequence_port()) {
- dc.to_port++;
- }
+ if (to_node->has_input_sequence_port()) {
+ dc.to_port++;
+ }
- dc.from_port += from_node->get_output_sequence_port_count();
+ dc.from_port += from_node->get_output_sequence_port_count();
- graph->connect_node(itos(E->get().from_node), dc.from_port, itos(E->get().to_node), dc.to_port);
- }
+ graph->connect_node(itos(E->get().from_node), dc.from_port, itos(E->get().to_node), dc.to_port);
}
}
@@ -605,17 +608,6 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
}
}
}
-
- List<StringName> funcs;
- script->get_function_list(&funcs);
-
- if (funcs.size() <= 0) {
- graph->hide();
- select_func_text->show();
- updating_graph = false;
- return;
- }
-
graph->show();
select_func_text->hide();
@@ -655,347 +647,351 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
};
Ref<Texture2D> seq_port = Control::get_theme_icon("VisualShaderPort", "EditorIcons");
+ List<int> node_ids;
+ script->get_node_list(&node_ids);
- for (List<StringName>::Element *F = funcs.front(); F; F = F->next()) { // loop through all the functions
-
- List<int> ids;
- script->get_node_list(F->get(), &ids);
- StringName editor_icons = "EditorIcons";
+ List<int> ids;
+ script->get_node_list(&ids);
+ StringName editor_icons = "EditorIcons";
- for (List<int>::Element *E = ids.front(); E; E = E->next()) {
- if (p_only_id >= 0 && p_only_id != E->get()) {
- continue;
- }
+ for (List<int>::Element *E = ids.front(); E; E = E->next()) {
+ if (p_only_id >= 0 && p_only_id != E->get()) {
+ continue;
+ }
- Ref<VisualScriptNode> node = script->get_node(F->get(), E->get());
- Vector2 pos = script->get_node_position(F->get(), E->get());
+ Ref<VisualScriptNode> node = script->get_node(E->get());
+ Vector2 pos = script->get_node_position(E->get());
- GraphNode *gnode = memnew(GraphNode);
- gnode->set_title(node->get_caption());
- gnode->set_offset(pos * EDSCALE);
- if (error_line == E->get()) {
- gnode->set_overlay(GraphNode::OVERLAY_POSITION);
- } else if (node->is_breakpoint()) {
- gnode->set_overlay(GraphNode::OVERLAY_BREAKPOINT);
- }
+ GraphNode *gnode = memnew(GraphNode);
+ gnode->set_title(node->get_caption());
+ gnode->set_position_offset(pos * EDSCALE);
+ if (error_line == E->get()) {
+ gnode->set_overlay(GraphNode::OVERLAY_POSITION);
+ } else if (node->is_breakpoint()) {
+ gnode->set_overlay(GraphNode::OVERLAY_BREAKPOINT);
+ }
- gnode->set_meta("__vnode", node);
- gnode->set_name(itos(E->get()));
- gnode->connect("dragged", callable_mp(this, &VisualScriptEditor::_node_moved), varray(E->get()));
- gnode->connect("close_request", callable_mp(this, &VisualScriptEditor::_remove_node), varray(E->get()), CONNECT_DEFERRED);
+ gnode->set_meta("__vnode", node);
+ gnode->set_name(itos(E->get()));
+ gnode->connect("dragged", callable_mp(this, &VisualScriptEditor::_node_moved), varray(E->get()));
+ gnode->connect("close_request", callable_mp(this, &VisualScriptEditor::_remove_node), varray(E->get()), CONNECT_DEFERRED);
- if (E->get() != script->get_function_node_id(F->get())) {
- //function can't be erased
+ {
+ Ref<VisualScriptFunction> v = node;
+ if (!v.is_valid()) {
gnode->set_show_close_button(true);
}
+ }
- bool has_gnode_text = false;
+ bool has_gnode_text = false;
- Ref<VisualScriptLists> nd_list = node;
- bool is_vslist = nd_list.is_valid();
- if (is_vslist) {
- HBoxContainer *hbnc = memnew(HBoxContainer);
+ Ref<VisualScriptLists> nd_list = node;
+ bool is_vslist = nd_list.is_valid();
+ if (is_vslist) {
+ HBoxContainer *hbnc = memnew(HBoxContainer);
+ if (nd_list->is_input_port_editable()) {
+ has_gnode_text = true;
+ Button *btn = memnew(Button);
+ btn->set_text(TTR("Add Input Port"));
+ hbnc->add_child(btn);
+ btn->connect("pressed", callable_mp(this, &VisualScriptEditor::_add_input_port), varray(E->get()), CONNECT_DEFERRED);
+ }
+ if (nd_list->is_output_port_editable()) {
if (nd_list->is_input_port_editable()) {
- has_gnode_text = true;
- Button *btn = memnew(Button);
- btn->set_text(TTR("Add Input Port"));
- hbnc->add_child(btn);
- btn->connect("pressed", callable_mp(this, &VisualScriptEditor::_add_input_port), varray(E->get()), CONNECT_DEFERRED);
- }
- if (nd_list->is_output_port_editable()) {
- if (nd_list->is_input_port_editable()) {
- hbnc->add_spacer();
- }
- has_gnode_text = true;
- Button *btn = memnew(Button);
- btn->set_text(TTR("Add Output Port"));
- hbnc->add_child(btn);
- btn->connect("pressed", callable_mp(this, &VisualScriptEditor::_add_output_port), varray(E->get()), CONNECT_DEFERRED);
+ hbnc->add_spacer();
}
- gnode->add_child(hbnc);
- } else if (Object::cast_to<VisualScriptExpression>(node.ptr())) {
has_gnode_text = true;
- LineEdit *line_edit = memnew(LineEdit);
- line_edit->set_text(node->get_text());
- line_edit->set_expand_to_text_length(true);
- line_edit->add_theme_font_override("font", get_theme_font("source", "EditorFonts"));
- gnode->add_child(line_edit);
- line_edit->connect("text_changed", callable_mp(this, &VisualScriptEditor::_expression_text_changed), varray(E->get()));
- } else {
- String text = node->get_text();
- if (!text.empty()) {
- has_gnode_text = true;
- Label *label = memnew(Label);
- label->set_text(text);
- gnode->add_child(label);
- }
+ Button *btn = memnew(Button);
+ btn->set_text(TTR("Add Output Port"));
+ hbnc->add_child(btn);
+ btn->connect("pressed", callable_mp(this, &VisualScriptEditor::_add_output_port), varray(E->get()), CONNECT_DEFERRED);
}
-
- if (Object::cast_to<VisualScriptComment>(node.ptr())) {
- Ref<VisualScriptComment> vsc = node;
- gnode->set_comment(true);
- gnode->set_resizable(true);
- gnode->set_custom_minimum_size(vsc->get_size() * EDSCALE);
- gnode->connect("resize_request", callable_mp(this, &VisualScriptEditor::_comment_node_resized), varray(E->get()));
+ gnode->add_child(hbnc);
+ } else if (Object::cast_to<VisualScriptExpression>(node.ptr())) {
+ has_gnode_text = true;
+ LineEdit *line_edit = memnew(LineEdit);
+ line_edit->set_text(node->get_text());
+ line_edit->set_expand_to_text_length(true);
+ line_edit->add_theme_font_override("font", get_theme_font("source", "EditorFonts"));
+ gnode->add_child(line_edit);
+ line_edit->connect("text_changed", callable_mp(this, &VisualScriptEditor::_expression_text_changed), varray(E->get()));
+ } else {
+ String text = node->get_text();
+ if (!text.is_empty()) {
+ has_gnode_text = true;
+ Label *label = memnew(Label);
+ label->set_text(text);
+ gnode->add_child(label);
}
+ }
- if (node_styles.has(node->get_category())) {
- Ref<StyleBoxFlat> sbf = node_styles[node->get_category()];
- if (gnode->is_comment()) {
- sbf = EditorNode::get_singleton()->get_theme_base()->get_theme()->get_stylebox("comment", "GraphNode");
- }
+ if (Object::cast_to<VisualScriptComment>(node.ptr())) {
+ Ref<VisualScriptComment> vsc = node;
+ gnode->set_comment(true);
+ gnode->set_resizable(true);
+ gnode->set_custom_minimum_size(vsc->get_size() * EDSCALE);
+ gnode->connect("resize_request", callable_mp(this, &VisualScriptEditor::_comment_node_resized), varray(E->get()));
+ }
- Color c = sbf->get_border_color();
- Color ic = c;
- c.a = 1;
- if (EditorSettings::get_singleton()->get("interface/theme/use_graph_node_headers")) {
- Color mono_color;
- if (((c.r + c.g + c.b) / 3) < 0.7) {
- mono_color = Color(1.0, 1.0, 1.0);
- ic = Color(0.0, 0.0, 0.0, 0.7);
- } else {
- mono_color = Color(0.0, 0.0, 0.0);
- ic = Color(1.0, 1.0, 1.0, 0.7);
- }
- mono_color.a = 0.85;
- c = mono_color;
+ if (node_styles.has(node->get_category())) {
+ Ref<StyleBoxFlat> sbf = node_styles[node->get_category()];
+ if (gnode->is_comment()) {
+ sbf = EditorNode::get_singleton()->get_theme_base()->get_theme()->get_stylebox("comment", "GraphNode");
+ }
+
+ Color c = sbf->get_border_color();
+ Color ic = c;
+ c.a = 1;
+ if (EditorSettings::get_singleton()->get("interface/theme/use_graph_node_headers")) {
+ Color mono_color;
+ if (((c.r + c.g + c.b) / 3) < 0.7) {
+ mono_color = Color(1.0, 1.0, 1.0);
+ ic = Color(0.0, 0.0, 0.0, 0.7);
+ } else {
+ mono_color = Color(0.0, 0.0, 0.0);
+ ic = Color(1.0, 1.0, 1.0, 0.7);
}
- gnode->add_theme_color_override("title_color", c);
- c.a = 0.7;
- gnode->add_theme_color_override("close_color", c);
- gnode->add_theme_color_override("resizer_color", ic);
- gnode->add_theme_style_override("frame", sbf);
+ mono_color.a = 0.85;
+ c = mono_color;
}
+ gnode->add_theme_color_override("title_color", c);
+ c.a = 0.7;
+ gnode->add_theme_color_override("close_color", c);
+ gnode->add_theme_color_override("resizer_color", ic);
+ gnode->add_theme_style_override("frame", sbf);
+ }
- const Color mono_color = get_theme_color("mono_color", "Editor");
+ const Color mono_color = get_theme_color("mono_color", "Editor");
- int slot_idx = 0;
+ int slot_idx = 0;
- bool single_seq_output = node->get_output_sequence_port_count() == 1 && node->get_output_sequence_port_text(0) == String();
- if ((node->has_input_sequence_port() || single_seq_output) || has_gnode_text) {
- // IF has_gnode_text is true BUT we have no sequence ports to draw (in here),
- // we still draw the disabled default ones to shift up the slots by one,
- // so the slots DON'T start with the content text.
+ bool single_seq_output = node->get_output_sequence_port_count() == 1 && node->get_output_sequence_port_text(0) == String();
+ if ((node->has_input_sequence_port() || single_seq_output) || has_gnode_text) {
+ // IF has_gnode_text is true BUT we have no sequence ports to draw (in here),
+ // we still draw the disabled default ones to shift up the slots by one,
+ // so the slots DON'T start with the content text.
- // IF has_gnode_text is false, but we DO want to draw default sequence ports,
- // we draw a dummy text to take up the position of the sequence nodes, so all the other ports are still aligned correctly.
- if (!has_gnode_text) {
- Label *dummy = memnew(Label);
- dummy->set_text(" ");
- gnode->add_child(dummy);
- }
- gnode->set_slot(0, node->has_input_sequence_port(), TYPE_SEQUENCE, mono_color, single_seq_output, TYPE_SEQUENCE, mono_color, seq_port, seq_port);
- slot_idx++;
+ // IF has_gnode_text is false, but we DO want to draw default sequence ports,
+ // we draw a dummy text to take up the position of the sequence nodes, so all the other ports are still aligned correctly.
+ if (!has_gnode_text) {
+ Label *dummy = memnew(Label);
+ dummy->set_text(" ");
+ gnode->add_child(dummy);
}
+ gnode->set_slot(0, node->has_input_sequence_port(), TYPE_SEQUENCE, mono_color, single_seq_output, TYPE_SEQUENCE, mono_color, seq_port, seq_port);
+ slot_idx++;
+ }
- int mixed_seq_ports = 0;
+ int mixed_seq_ports = 0;
- if (!single_seq_output) {
- if (node->has_mixed_input_and_sequence_ports()) {
- mixed_seq_ports = node->get_output_sequence_port_count();
- } else {
- for (int i = 0; i < node->get_output_sequence_port_count(); i++) {
- Label *text2 = memnew(Label);
- text2->set_text(node->get_output_sequence_port_text(i));
- text2->set_align(Label::ALIGN_RIGHT);
- gnode->add_child(text2);
- gnode->set_slot(slot_idx, false, 0, Color(), true, TYPE_SEQUENCE, mono_color, seq_port, seq_port);
- slot_idx++;
- }
+ if (!single_seq_output) {
+ if (node->has_mixed_input_and_sequence_ports()) {
+ mixed_seq_ports = node->get_output_sequence_port_count();
+ } else {
+ for (int i = 0; i < node->get_output_sequence_port_count(); i++) {
+ Label *text2 = memnew(Label);
+ text2->set_text(node->get_output_sequence_port_text(i));
+ text2->set_align(Label::ALIGN_RIGHT);
+ gnode->add_child(text2);
+ gnode->set_slot(slot_idx, false, 0, Color(), true, TYPE_SEQUENCE, mono_color, seq_port, seq_port);
+ slot_idx++;
}
}
+ }
- for (int i = 0; i < MAX(node->get_output_value_port_count(), MAX(mixed_seq_ports, node->get_input_value_port_count())); i++) {
- bool left_ok = false;
- Variant::Type left_type = Variant::NIL;
- String left_name;
+ for (int i = 0; i < MAX(node->get_output_value_port_count(), MAX(mixed_seq_ports, node->get_input_value_port_count())); i++) {
+ bool left_ok = false;
+ Variant::Type left_type = Variant::NIL;
+ String left_name;
- if (i < node->get_input_value_port_count()) {
- PropertyInfo pi = node->get_input_value_port_info(i);
- left_ok = true;
- left_type = pi.type;
- left_name = pi.name;
- }
+ if (i < node->get_input_value_port_count()) {
+ PropertyInfo pi = node->get_input_value_port_info(i);
+ left_ok = true;
+ left_type = pi.type;
+ left_name = pi.name;
+ }
- bool right_ok = false;
- Variant::Type right_type = Variant::NIL;
- String right_name;
+ bool right_ok = false;
+ Variant::Type right_type = Variant::NIL;
+ String right_name;
- if (i >= mixed_seq_ports && i < node->get_output_value_port_count() + mixed_seq_ports) {
- PropertyInfo pi = node->get_output_value_port_info(i - mixed_seq_ports);
- right_ok = true;
- right_type = pi.type;
- right_name = pi.name;
+ if (i >= mixed_seq_ports && i < node->get_output_value_port_count() + mixed_seq_ports) {
+ PropertyInfo pi = node->get_output_value_port_info(i - mixed_seq_ports);
+ right_ok = true;
+ right_type = pi.type;
+ right_name = pi.name;
+ }
+ VBoxContainer *vbc = memnew(VBoxContainer);
+ HBoxContainer *hbc = memnew(HBoxContainer);
+ HBoxContainer *hbc2 = memnew(HBoxContainer);
+ vbc->add_child(hbc);
+ vbc->add_child(hbc2);
+ if (left_ok) {
+ Ref<Texture2D> t;
+ if (left_type >= 0 && left_type < Variant::VARIANT_MAX) {
+ t = type_icons[left_type];
+ }
+ if (t.is_valid()) {
+ TextureRect *tf = memnew(TextureRect);
+ tf->set_texture(t);
+ tf->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
+ hbc->add_child(tf);
}
- VBoxContainer *vbc = memnew(VBoxContainer);
- HBoxContainer *hbc = memnew(HBoxContainer);
- HBoxContainer *hbc2 = memnew(HBoxContainer);
- vbc->add_child(hbc);
- vbc->add_child(hbc2);
- if (left_ok) {
- Ref<Texture2D> t;
- if (left_type >= 0 && left_type < Variant::VARIANT_MAX) {
- t = type_icons[left_type];
- }
- if (t.is_valid()) {
- TextureRect *tf = memnew(TextureRect);
- tf->set_texture(t);
- tf->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
- hbc->add_child(tf);
- }
-
- if (is_vslist) {
- if (nd_list->is_input_port_name_editable()) {
- LineEdit *name_box = memnew(LineEdit);
- hbc->add_child(name_box);
- name_box->set_custom_minimum_size(Size2(60 * EDSCALE, 0));
- name_box->set_text(left_name);
- name_box->set_expand_to_text_length(true);
- name_box->connect("resized", callable_mp(this, &VisualScriptEditor::_update_node_size), varray(E->get()));
- name_box->connect("focus_exited", callable_mp(this, &VisualScriptEditor::_port_name_focus_out), varray(name_box, E->get(), i, true));
- } else {
- hbc->add_child(memnew(Label(left_name)));
- }
-
- if (nd_list->is_input_port_type_editable()) {
- OptionButton *opbtn = memnew(OptionButton);
- for (int j = Variant::NIL; j < Variant::VARIANT_MAX; j++) {
- opbtn->add_item(Variant::get_type_name(Variant::Type(j)));
- }
- opbtn->select(left_type);
- opbtn->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
- hbc->add_child(opbtn);
- opbtn->connect("item_selected", callable_mp(this, &VisualScriptEditor::_change_port_type), varray(E->get(), i, true), CONNECT_DEFERRED);
- }
- Button *rmbtn = memnew(Button);
- rmbtn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Remove", "EditorIcons"));
- hbc->add_child(rmbtn);
- rmbtn->connect("pressed", callable_mp(this, &VisualScriptEditor::_remove_input_port), varray(E->get(), i), CONNECT_DEFERRED);
+ if (is_vslist) {
+ if (nd_list->is_input_port_name_editable()) {
+ LineEdit *name_box = memnew(LineEdit);
+ hbc->add_child(name_box);
+ name_box->set_custom_minimum_size(Size2(60 * EDSCALE, 0));
+ name_box->set_text(left_name);
+ name_box->set_expand_to_text_length(true);
+ name_box->connect("resized", callable_mp(this, &VisualScriptEditor::_update_node_size), varray(E->get()));
+ name_box->connect("focus_exited", callable_mp(this, &VisualScriptEditor::_port_name_focus_out), varray(name_box, E->get(), i, true));
} else {
hbc->add_child(memnew(Label(left_name)));
}
- if (left_type != Variant::NIL && !script->is_input_value_port_connected(F->get(), E->get(), i)) {
- PropertyInfo pi = node->get_input_value_port_info(i);
- Button *button = memnew(Button);
- Variant value = node->get_default_input_value(i);
- if (value.get_type() != left_type) {
- //different type? for now convert
- //not the same, reconvert
- Callable::CallError ce;
- const Variant *existingp = &value;
- value = Variant::construct(left_type, &existingp, 1, ce, false);
- }
-
- if (left_type == Variant::COLOR) {
- button->set_custom_minimum_size(Size2(30, 0) * EDSCALE);
- button->connect("draw", callable_mp(this, &VisualScriptEditor::_draw_color_over_button), varray(button, value));
- } else if (left_type == Variant::OBJECT && Ref<Resource>(value).is_valid()) {
- Ref<Resource> res = value;
- Array arr;
- arr.push_back(button->get_instance_id());
- arr.push_back(String(value));
- EditorResourcePreview::get_singleton()->queue_edited_resource_preview(res, this, "_button_resource_previewed", arr);
-
- } else if (pi.type == Variant::INT && pi.hint == PROPERTY_HINT_ENUM) {
- button->set_text(pi.hint_string.get_slice(",", value));
- } else {
- button->set_text(value);
+ if (nd_list->is_input_port_type_editable()) {
+ OptionButton *opbtn = memnew(OptionButton);
+ for (int j = Variant::NIL; j < Variant::VARIANT_MAX; j++) {
+ opbtn->add_item(Variant::get_type_name(Variant::Type(j)));
}
- button->connect("pressed", callable_mp(this, &VisualScriptEditor::_default_value_edited), varray(button, E->get(), i));
- hbc2->add_child(button);
+ opbtn->select(left_type);
+ opbtn->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
+ hbc->add_child(opbtn);
+ opbtn->connect("item_selected", callable_mp(this, &VisualScriptEditor::_change_port_type), varray(E->get(), i, true), CONNECT_DEFERRED);
}
+
+ Button *rmbtn = memnew(Button);
+ rmbtn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Remove", "EditorIcons"));
+ hbc->add_child(rmbtn);
+ rmbtn->connect("pressed", callable_mp(this, &VisualScriptEditor::_remove_input_port), varray(E->get(), i), CONNECT_DEFERRED);
} else {
- Control *c = memnew(Control);
- c->set_custom_minimum_size(Size2(10, 0) * EDSCALE);
- hbc->add_child(c);
+ hbc->add_child(memnew(Label(left_name)));
}
- hbc->add_spacer();
- hbc2->add_spacer();
+ if (left_type != Variant::NIL && !script->is_input_value_port_connected(E->get(), i)) {
+ PropertyInfo pi = node->get_input_value_port_info(i);
+ Button *button = memnew(Button);
+ Variant value = node->get_default_input_value(i);
+ if (value.get_type() != left_type) {
+ //different type? for now convert
+ //not the same, reconvert
+ Callable::CallError ce;
+ const Variant *existingp = &value;
+ Variant::construct(left_type, value, &existingp, 1, ce);
+ }
- if (i < mixed_seq_ports) {
- Label *text2 = memnew(Label);
- text2->set_text(node->get_output_sequence_port_text(i));
- text2->set_align(Label::ALIGN_RIGHT);
- hbc->add_child(text2);
+ if (left_type == Variant::COLOR) {
+ button->set_custom_minimum_size(Size2(30, 0) * EDSCALE);
+ button->connect("draw", callable_mp(this, &VisualScriptEditor::_draw_color_over_button), varray(button, value));
+ } else if (left_type == Variant::OBJECT && Ref<Resource>(value).is_valid()) {
+ Ref<Resource> res = value;
+ Array arr;
+ arr.push_back(button->get_instance_id());
+ arr.push_back(String(value));
+ EditorResourcePreview::get_singleton()->queue_edited_resource_preview(res, this, "_button_resource_previewed", arr);
+
+ } else if (pi.type == Variant::INT && pi.hint == PROPERTY_HINT_ENUM) {
+ button->set_text(pi.hint_string.get_slice(",", value));
+ } else {
+ button->set_text(value);
+ }
+ button->connect("pressed", callable_mp(this, &VisualScriptEditor::_default_value_edited), varray(button, E->get(), i));
+ hbc2->add_child(button);
}
+ } else {
+ Control *c = memnew(Control);
+ c->set_custom_minimum_size(Size2(10, 0) * EDSCALE);
+ hbc->add_child(c);
+ }
- if (right_ok) {
- if (is_vslist) {
- Button *rmbtn = memnew(Button);
- rmbtn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Remove", "EditorIcons"));
- hbc->add_child(rmbtn);
- rmbtn->connect("pressed", callable_mp(this, &VisualScriptEditor::_remove_output_port), varray(E->get(), i), CONNECT_DEFERRED);
-
- if (nd_list->is_output_port_type_editable()) {
- OptionButton *opbtn = memnew(OptionButton);
- for (int j = Variant::NIL; j < Variant::VARIANT_MAX; j++) {
- opbtn->add_item(Variant::get_type_name(Variant::Type(j)));
- }
- opbtn->select(right_type);
- opbtn->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
- hbc->add_child(opbtn);
- opbtn->connect("item_selected", callable_mp(this, &VisualScriptEditor::_change_port_type), varray(E->get(), i, false), CONNECT_DEFERRED);
- }
+ hbc->add_spacer();
+ hbc2->add_spacer();
- if (nd_list->is_output_port_name_editable()) {
- LineEdit *name_box = memnew(LineEdit);
- hbc->add_child(name_box);
- name_box->set_custom_minimum_size(Size2(60 * EDSCALE, 0));
- name_box->set_text(right_name);
- name_box->set_expand_to_text_length(true);
- name_box->connect("resized", callable_mp(this, &VisualScriptEditor::_update_node_size), varray(E->get()));
- name_box->connect("focus_exited", callable_mp(this, &VisualScriptEditor::_port_name_focus_out), varray(name_box, E->get(), i, false));
- } else {
- hbc->add_child(memnew(Label(right_name)));
+ if (i < mixed_seq_ports) {
+ Label *text2 = memnew(Label);
+ text2->set_text(node->get_output_sequence_port_text(i));
+ text2->set_align(Label::ALIGN_RIGHT);
+ hbc->add_child(text2);
+ }
+
+ if (right_ok) {
+ if (is_vslist) {
+ Button *rmbtn = memnew(Button);
+ rmbtn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Remove", "EditorIcons"));
+ hbc->add_child(rmbtn);
+ rmbtn->connect("pressed", callable_mp(this, &VisualScriptEditor::_remove_output_port), varray(E->get(), i), CONNECT_DEFERRED);
+
+ if (nd_list->is_output_port_type_editable()) {
+ OptionButton *opbtn = memnew(OptionButton);
+ for (int j = Variant::NIL; j < Variant::VARIANT_MAX; j++) {
+ opbtn->add_item(Variant::get_type_name(Variant::Type(j)));
}
- } else {
- hbc->add_child(memnew(Label(right_name)));
+ opbtn->select(right_type);
+ opbtn->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
+ hbc->add_child(opbtn);
+ opbtn->connect("item_selected", callable_mp(this, &VisualScriptEditor::_change_port_type), varray(E->get(), i, false), CONNECT_DEFERRED);
}
- Ref<Texture2D> t;
- if (right_type >= 0 && right_type < Variant::VARIANT_MAX) {
- t = type_icons[right_type];
- }
- if (t.is_valid()) {
- TextureRect *tf = memnew(TextureRect);
- tf->set_texture(t);
- tf->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
- hbc->add_child(tf);
+ if (nd_list->is_output_port_name_editable()) {
+ LineEdit *name_box = memnew(LineEdit);
+ hbc->add_child(name_box);
+ name_box->set_custom_minimum_size(Size2(60 * EDSCALE, 0));
+ name_box->set_text(right_name);
+ name_box->set_expand_to_text_length(true);
+ name_box->connect("resized", callable_mp(this, &VisualScriptEditor::_update_node_size), varray(E->get()));
+ name_box->connect("focus_exited", callable_mp(this, &VisualScriptEditor::_port_name_focus_out), varray(name_box, E->get(), i, false));
+ } else {
+ hbc->add_child(memnew(Label(right_name)));
}
- }
-
- gnode->add_child(vbc);
-
- bool dark_theme = get_theme_constant("dark_theme", "Editor");
- if (i < mixed_seq_ports) {
- gnode->set_slot(slot_idx, left_ok, left_type, _color_from_type(left_type, dark_theme), true, TYPE_SEQUENCE, mono_color, Ref<Texture2D>(), seq_port);
} else {
- gnode->set_slot(slot_idx, left_ok, left_type, _color_from_type(left_type, dark_theme), right_ok, right_type, _color_from_type(right_type, dark_theme));
+ hbc->add_child(memnew(Label(right_name)));
}
- slot_idx++;
+ Ref<Texture2D> t;
+ if (right_type >= 0 && right_type < Variant::VARIANT_MAX) {
+ t = type_icons[right_type];
+ }
+ if (t.is_valid()) {
+ TextureRect *tf = memnew(TextureRect);
+ tf->set_texture(t);
+ tf->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
+ hbc->add_child(tf);
+ }
}
- graph->add_child(gnode);
+ gnode->add_child(vbc);
- if (gnode->is_comment()) {
- graph->move_child(gnode, 0);
+ bool dark_theme = get_theme_constant("dark_theme", "Editor");
+ if (i < mixed_seq_ports) {
+ gnode->set_slot(slot_idx, left_ok, left_type, _color_from_type(left_type, dark_theme), true, TYPE_SEQUENCE, mono_color, Ref<Texture2D>(), seq_port);
+ } else {
+ gnode->set_slot(slot_idx, left_ok, left_type, _color_from_type(left_type, dark_theme), right_ok, right_type, _color_from_type(right_type, dark_theme));
}
+
+ slot_idx++;
+ }
+
+ graph->add_child(gnode);
+
+ if (gnode->is_comment()) {
+ graph->move_child(gnode, 0);
}
}
+
_update_graph_connections();
- // use default_func instead of default_func for now I think that should be good stop gap solution to ensure not breaking anything
- graph->call_deferred("set_scroll_ofs", script->get_function_scroll(default_func) * EDSCALE);
+
+ float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity");
+ graph->set_minimap_opacity(graph_minimap_opacity);
+
+ // Use default_func instead of default_func for now I think that should be good stop gap solution to ensure not breaking anything.
+ graph->call_deferred("set_scroll_ofs", script->get_scroll() * EDSCALE);
updating_graph = false;
}
void VisualScriptEditor::_change_port_type(int p_select, int p_id, int p_port, bool is_input) {
- StringName func = _get_function_of_node(p_id);
-
- Ref<VisualScriptLists> vsn = script->get_node(func, p_id);
+ Ref<VisualScriptLists> vsn = script->get_node(p_id);
if (!vsn.is_valid()) {
return;
}
@@ -1014,14 +1010,12 @@ void VisualScriptEditor::_change_port_type(int p_select, int p_id, int p_port, b
void VisualScriptEditor::_update_node_size(int p_id) {
Node *node = graph->get_node(itos(p_id));
if (Object::cast_to<Control>(node)) {
- Object::cast_to<Control>(node)->set_size(Vector2(1, 1)); //shrink if text is smaller
+ Object::cast_to<Control>(node)->set_size(Vector2(1, 1)); // Shrink if text is smaller.
}
}
void VisualScriptEditor::_port_name_focus_out(const Node *p_name_box, int p_id, int p_port, bool is_input) {
- StringName func = _get_function_of_node(p_id);
-
- Ref<VisualScriptLists> vsn = script->get_node(func, p_id);
+ Ref<VisualScriptLists> vsn = script->get_node(p_id);
if (!vsn.is_valid()) {
return;
}
@@ -1062,11 +1056,8 @@ void VisualScriptEditor::_update_members() {
List<StringName> func_names;
script->get_function_list(&func_names);
+ func_names.sort_custom<StringName::AlphCompare>();
for (List<StringName>::Element *E = func_names.front(); E; E = E->next()) {
- if (E->get() == default_func) {
- continue;
- }
-
TreeItem *ti = members->create_item(functions);
ti->set_text(0, E->get());
ti->set_selectable(0, true);
@@ -1173,7 +1164,9 @@ String VisualScriptEditor::_sanitized_variant_text(const StringName &property_na
if (script->get_variable_info(property_name).type != Variant::NIL) {
Callable::CallError ce;
const Variant *converted = &var;
- var = Variant::construct(script->get_variable_info(property_name).type, &converted, 1, ce, false);
+ Variant n;
+ Variant::construct(script->get_variable_info(property_name).type, n, &converted, 1, ce);
+ var = n;
}
return String(var);
@@ -1197,7 +1190,7 @@ void VisualScriptEditor::_member_selected() {
#endif
if (held_ctrl) {
ERR_FAIL_COND(!script->has_function(selected));
- _center_on_node(selected, script->get_function_node_id(selected));
+ _center_on_node(script->get_function_node_id(selected));
}
}
}
@@ -1240,8 +1233,8 @@ void VisualScriptEditor::_member_edited() {
int node_id = script->get_function_node_id(name);
Ref<VisualScriptFunction> func;
- if (script->has_node(name, node_id)) {
- func = script->get_node(name, node_id);
+ if (script->has_node(node_id)) {
+ func = script->get_node(node_id);
}
undo_redo->create_action(TTR("Rename Function"));
undo_redo->add_do_method(script.ptr(), "rename_function", name, new_name);
@@ -1251,21 +1244,17 @@ void VisualScriptEditor::_member_edited() {
undo_redo->add_undo_method(func.ptr(), "set_name", name);
}
- // also fix all function calls
- List<StringName> flst;
- script->get_function_list(&flst);
- for (List<StringName>::Element *E = flst.front(); E; E = E->next()) {
- List<int> lst;
- script->get_node_list(E->get(), &lst);
- for (List<int>::Element *F = lst.front(); F; F = F->next()) {
- Ref<VisualScriptFunctionCall> fncall = script->get_node(E->get(), F->get());
- if (!fncall.is_valid()) {
- continue;
- }
- if (fncall->get_function() == name) {
- undo_redo->add_do_method(fncall.ptr(), "set_function", new_name);
- undo_redo->add_undo_method(fncall.ptr(), "set_function", name);
- }
+ // Also fix all function calls.
+ List<int> lst;
+ script->get_node_list(&lst);
+ for (List<int>::Element *F = lst.front(); F; F = F->next()) {
+ Ref<VisualScriptFunctionCall> fncall = script->get_node(F->get());
+ if (!fncall.is_valid()) {
+ continue;
+ }
+ if (fncall->get_function() == name) {
+ undo_redo->add_do_method(fncall.ptr(), "set_function", new_name);
+ undo_redo->add_undo_method(fncall.ptr(), "set_function", name);
}
}
@@ -1277,7 +1266,7 @@ void VisualScriptEditor::_member_edited() {
undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
undo_redo->commit_action();
- return; //or crash because it will become invalid
+ return; // Or crash because it will become invalid.
}
if (ti->get_parent() == root->get_children()->get_next()) {
@@ -1293,7 +1282,7 @@ void VisualScriptEditor::_member_edited() {
undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
undo_redo->commit_action();
- return; //or crash because it will become invalid
+ return; // Or crash because it will become invalid.
}
if (ti->get_parent() == root->get_children()->get_next()->get_next()) {
@@ -1307,7 +1296,7 @@ void VisualScriptEditor::_member_edited() {
undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
undo_redo->commit_action();
- return; //or crash because it will become invalid
+ return; // Or crash because it will become invalid.
}
}
@@ -1341,10 +1330,13 @@ void VisualScriptEditor::_create_function() {
func_node->add_argument(arg_type, arg_name);
}
+ int func_node_id = script->get_available_id();
+
undo_redo->create_action(TTR("Add Function"));
- undo_redo->add_do_method(script.ptr(), "add_function", name);
- undo_redo->add_do_method(script.ptr(), "add_node", name, script->get_available_id(), func_node, ofs);
+ undo_redo->add_do_method(script.ptr(), "add_function", name, func_node_id);
undo_redo->add_undo_method(script.ptr(), "remove_function", name);
+ undo_redo->add_do_method(script.ptr(), "add_node", func_node_id, func_node, ofs);
+ undo_redo->add_undo_method(script.ptr(), "remove_node", func_node_id);
undo_redo->add_do_method(this, "_update_members");
undo_redo->add_undo_method(this, "_update_members");
undo_redo->add_do_method(this, "_update_graph");
@@ -1428,11 +1420,12 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt
if (ti->get_parent() == root) {
//main buttons
if (ti == root->get_children()) {
- //add function, this one uses menu
+ // Add function, this one uses menu.
if (p_button == 1) {
+ // Ensure script base exists otherwise use custom base type.
+ ERR_FAIL_COND(script.is_null());
new_virtual_method_select->select_method_from_base_type(script->get_instance_base_type(), String(), true);
-
return;
} else if (p_button == 0) {
String name = _validate_name("new_function");
@@ -1442,11 +1435,13 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt
Ref<VisualScriptFunction> func_node;
func_node.instance();
func_node->set_name(name);
+ int fn_id = script->get_available_id();
undo_redo->create_action(TTR("Add Function"));
- undo_redo->add_do_method(script.ptr(), "add_function", name);
- undo_redo->add_do_method(script.ptr(), "add_node", name, script->get_available_id(), func_node, ofs);
+ undo_redo->add_do_method(script.ptr(), "add_function", name, fn_id);
+ undo_redo->add_do_method(script.ptr(), "add_node", fn_id, func_node, ofs);
undo_redo->add_undo_method(script.ptr(), "remove_function", name);
+ undo_redo->add_do_method(script.ptr(), "remove_node", fn_id);
undo_redo->add_do_method(this, "_update_members");
undo_redo->add_undo_method(this, "_update_members");
undo_redo->add_do_method(this, "_update_graph");
@@ -1458,11 +1453,11 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt
_update_graph();
}
- return; //or crash because it will become invalid
+ return; // Or crash because it will become invalid.
}
if (ti == root->get_children()->get_next()) {
- //add variable
+ // Add variable.
String name = _validate_name("new_variable");
selected = name;
@@ -1474,11 +1469,11 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt
undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");
undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
undo_redo->commit_action();
- return; //or crash because it will become invalid
+ return; // Or crash because it will become invalid.
}
if (ti == root->get_children()->get_next()->get_next()) {
- //add variable
+ // Add variable.
String name = _validate_name("new_signal");
selected = name;
@@ -1490,7 +1485,7 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt
undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");
undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
undo_redo->commit_action();
- return; //or crash because it will become invalid
+ return; // Or crash because it will become invalid.
}
} else if (ti->get_parent() == root->get_children()) {
selected = ti->get_text(0);
@@ -1502,9 +1497,7 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt
}
void VisualScriptEditor::_add_input_port(int p_id) {
- StringName func = _get_function_of_node(p_id);
-
- Ref<VisualScriptLists> vsn = script->get_node(func, p_id);
+ Ref<VisualScriptLists> vsn = script->get_node(p_id);
if (!vsn.is_valid()) {
return;
}
@@ -1524,9 +1517,7 @@ void VisualScriptEditor::_add_input_port(int p_id) {
}
void VisualScriptEditor::_add_output_port(int p_id) {
- StringName func = _get_function_of_node(p_id);
-
- Ref<VisualScriptLists> vsn = script->get_node(func, p_id);
+ Ref<VisualScriptLists> vsn = script->get_node(p_id);
if (!vsn.is_valid()) {
return;
}
@@ -1546,9 +1537,7 @@ void VisualScriptEditor::_add_output_port(int p_id) {
}
void VisualScriptEditor::_remove_input_port(int p_id, int p_port) {
- StringName func = _get_function_of_node(p_id);
-
- Ref<VisualScriptLists> vsn = script->get_node(func, p_id);
+ Ref<VisualScriptLists> vsn = script->get_node(p_id);
if (!vsn.is_valid()) {
return;
}
@@ -1558,17 +1547,17 @@ void VisualScriptEditor::_remove_input_port(int p_id, int p_port) {
undo_redo->create_action(TTR("Remove Input Port"), UndoRedo::MERGE_ENDS);
int conn_from = -1, conn_port = -1;
- script->get_input_value_port_connection_source(func, p_id, p_port, &conn_from, &conn_port);
+ script->get_input_value_port_connection_source(p_id, p_port, &conn_from, &conn_port);
if (conn_from != -1) {
- undo_redo->add_do_method(script.ptr(), "data_disconnect", func, conn_from, conn_port, p_id, p_port);
+ undo_redo->add_do_method(script.ptr(), "data_disconnect", conn_from, conn_port, p_id, p_port);
}
undo_redo->add_do_method(vsn.ptr(), "remove_input_data_port", p_port);
undo_redo->add_do_method(this, "_update_graph", p_id);
if (conn_from != -1) {
- undo_redo->add_undo_method(script.ptr(), "data_connect", func, conn_from, conn_port, p_id, p_port);
+ undo_redo->add_undo_method(script.ptr(), "data_connect", conn_from, conn_port, p_id, p_port);
}
undo_redo->add_undo_method(vsn.ptr(), "add_input_data_port", vsn->get_input_value_port_info(p_port).type, vsn->get_input_value_port_info(p_port).name, p_port);
@@ -1580,9 +1569,7 @@ void VisualScriptEditor::_remove_input_port(int p_id, int p_port) {
}
void VisualScriptEditor::_remove_output_port(int p_id, int p_port) {
- StringName func = _get_function_of_node(p_id);
-
- Ref<VisualScriptLists> vsn = script->get_node(func, p_id);
+ Ref<VisualScriptLists> vsn = script->get_node(p_id);
if (!vsn.is_valid()) {
return;
}
@@ -1592,12 +1579,12 @@ void VisualScriptEditor::_remove_output_port(int p_id, int p_port) {
undo_redo->create_action(TTR("Remove Output Port"), UndoRedo::MERGE_ENDS);
List<VisualScript::DataConnection> data_connections;
- script->get_data_connection_list(func, &data_connections);
+ script->get_data_connection_list(&data_connections);
HashMap<int, Set<int>> conn_map;
for (const List<VisualScript::DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
if (E->get().from_node == p_id && E->get().from_port == p_port) {
- // push into the connections map
+ // Push into the connections map.
if (!conn_map.has(E->get().to_node)) {
conn_map.set(E->get().to_node, Set<int>());
}
@@ -1612,7 +1599,7 @@ void VisualScriptEditor::_remove_output_port(int p_id, int p_port) {
conn_map.get_key_list(&keys);
for (const List<int>::Element *E = keys.front(); E; E = E->next()) {
for (const Set<int>::Element *F = conn_map[E->get()].front(); F; F = F->next()) {
- undo_redo->add_undo_method(script.ptr(), "data_connect", func, p_id, p_port, E->get(), F->get());
+ undo_redo->add_undo_method(script.ptr(), "data_connect", p_id, p_port, E->get(), F->get());
}
}
@@ -1625,9 +1612,7 @@ void VisualScriptEditor::_remove_output_port(int p_id, int p_port) {
}
void VisualScriptEditor::_expression_text_changed(const String &p_text, int p_id) {
- StringName func = _get_function_of_node(p_id);
-
- Ref<VisualScriptExpression> vse = script->get_node(func, p_id);
+ Ref<VisualScriptExpression> vse = script->get_node(p_id);
if (!vse.is_valid()) {
return;
}
@@ -1643,7 +1628,7 @@ void VisualScriptEditor::_expression_text_changed(const String &p_text, int p_id
Node *node = graph->get_node(itos(p_id));
if (Object::cast_to<Control>(node)) {
- Object::cast_to<Control>(node)->set_size(Vector2(1, 1)); //shrink if text is smaller
+ Object::cast_to<Control>(node)->set_size(Vector2(1, 1)); // Shrink if text is smaller.
}
updating_graph = false;
@@ -1663,19 +1648,14 @@ Vector2 VisualScriptEditor::_get_available_pos(bool centered, Vector2 ofs) const
while (true) {
bool exists = false;
- List<StringName> all_fn;
- script->get_function_list(&all_fn);
- for (List<StringName>::Element *F = all_fn.front(); F; F = F->next()) {
- StringName curr_fn = F->get();
- List<int> existing;
- script->get_node_list(curr_fn, &existing);
- for (List<int>::Element *E = existing.front(); E; E = E->next()) {
- Point2 pos = script->get_node_position(curr_fn, E->get());
- if (pos.distance_to(ofs) < 50) {
- ofs += Vector2(graph->get_snap(), graph->get_snap());
- exists = true;
- break;
- }
+ List<int> existing;
+ script->get_node_list(&existing);
+ for (List<int>::Element *E = existing.front(); E; E = E->next()) {
+ Point2 pos = script->get_node_position(E->get());
+ if (pos.distance_to(ofs) < 50) {
+ ofs += Vector2(graph->get_snap(), graph->get_snap());
+ exists = true;
+ break;
}
}
if (exists) {
@@ -1707,7 +1687,7 @@ String VisualScriptEditor::_validate_name(const String &p_name) const {
}
void VisualScriptEditor::_on_nodes_delete() {
- // delete all the selected nodes
+ // Delete all the selected nodes.
List<int> to_erase;
@@ -1720,7 +1700,7 @@ void VisualScriptEditor::_on_nodes_delete() {
}
}
- if (to_erase.empty()) {
+ if (to_erase.is_empty()) {
return;
}
@@ -1729,26 +1709,24 @@ void VisualScriptEditor::_on_nodes_delete() {
for (List<int>::Element *F = to_erase.front(); F; F = F->next()) {
int cr_node = F->get();
- StringName func = _get_function_of_node(cr_node);
-
- undo_redo->add_do_method(script.ptr(), "remove_node", func, cr_node);
- undo_redo->add_undo_method(script.ptr(), "add_node", func, cr_node, script->get_node(func, cr_node), script->get_node_position(func, cr_node));
+ undo_redo->add_do_method(script.ptr(), "remove_node", cr_node);
+ undo_redo->add_undo_method(script.ptr(), "add_node", cr_node, script->get_node(cr_node), script->get_node_position(cr_node));
List<VisualScript::SequenceConnection> sequence_conns;
- script->get_sequence_connection_list(func, &sequence_conns);
+ script->get_sequence_connection_list(&sequence_conns);
for (List<VisualScript::SequenceConnection>::Element *E = sequence_conns.front(); E; E = E->next()) {
if (E->get().from_node == cr_node || E->get().to_node == cr_node) {
- undo_redo->add_undo_method(script.ptr(), "sequence_connect", func, E->get().from_node, E->get().from_output, E->get().to_node);
+ undo_redo->add_undo_method(script.ptr(), "sequence_connect", E->get().from_node, E->get().from_output, E->get().to_node);
}
}
List<VisualScript::DataConnection> data_conns;
- script->get_data_connection_list(func, &data_conns);
+ script->get_data_connection_list(&data_conns);
for (List<VisualScript::DataConnection>::Element *E = data_conns.front(); E; E = E->next()) {
if (E->get().from_node == F->get() || E->get().to_node == F->get()) {
- undo_redo->add_undo_method(script.ptr(), "data_connect", func, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
+ undo_redo->add_undo_method(script.ptr(), "data_connect", E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
}
}
}
@@ -1760,7 +1738,6 @@ void VisualScriptEditor::_on_nodes_delete() {
void VisualScriptEditor::_on_nodes_duplicate() {
Set<int> to_duplicate;
- List<StringName> funcs;
for (int i = 0; i < graph->get_child_count(); i++) {
GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
@@ -1768,12 +1745,11 @@ void VisualScriptEditor::_on_nodes_duplicate() {
if (gn->is_selected() && gn->is_close_button_visible()) {
int id = gn->get_name().operator String().to_int();
to_duplicate.insert(id);
- funcs.push_back(_get_function_of_node(id));
}
}
}
- if (to_duplicate.empty()) {
+ if (to_duplicate.is_empty()) {
return;
}
@@ -1784,9 +1760,8 @@ void VisualScriptEditor::_on_nodes_duplicate() {
HashMap<int, int> remap;
for (Set<int>::Element *F = to_duplicate.front(); F; F = F->next()) {
- // duplicate from the specific function but place it into the default func as it would lack the connections
- StringName func = _get_function_of_node(F->get());
- Ref<VisualScriptNode> node = script->get_node(func, F->get());
+ // Duplicate from the specific function but place it into the default func as it would lack the connections.
+ Ref<VisualScriptNode> node = script->get_node(F->get());
Ref<VisualScriptNode> dupe = node->duplicate(true);
@@ -1794,25 +1769,23 @@ void VisualScriptEditor::_on_nodes_duplicate() {
remap.set(F->get(), new_id);
to_select.insert(new_id);
- undo_redo->add_do_method(script.ptr(), "add_node", default_func, new_id, dupe, script->get_node_position(func, F->get()) + Vector2(20, 20));
- undo_redo->add_undo_method(script.ptr(), "remove_node", default_func, new_id);
+ undo_redo->add_do_method(script.ptr(), "add_node", new_id, dupe, script->get_node_position(F->get()) + Vector2(20, 20));
+ undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
}
- for (List<StringName>::Element *F = funcs.front(); F; F = F->next()) {
- List<VisualScript::SequenceConnection> seqs;
- script->get_sequence_connection_list(F->get(), &seqs);
- for (List<VisualScript::SequenceConnection>::Element *E = seqs.front(); E; E = E->next()) {
- if (to_duplicate.has(E->get().from_node) && to_duplicate.has(E->get().to_node)) {
- undo_redo->add_do_method(script.ptr(), "sequence_connect", default_func, remap[E->get().from_node], E->get().from_output, remap[E->get().to_node]);
- }
+ List<VisualScript::SequenceConnection> seqs;
+ script->get_sequence_connection_list(&seqs);
+ for (List<VisualScript::SequenceConnection>::Element *E = seqs.front(); E; E = E->next()) {
+ if (to_duplicate.has(E->get().from_node) && to_duplicate.has(E->get().to_node)) {
+ undo_redo->add_do_method(script.ptr(), "sequence_connect", remap[E->get().from_node], E->get().from_output, remap[E->get().to_node]);
}
+ }
- List<VisualScript::DataConnection> data;
- script->get_data_connection_list(F->get(), &data);
- for (List<VisualScript::DataConnection>::Element *E = data.front(); E; E = E->next()) {
- if (to_duplicate.has(E->get().from_node) && to_duplicate.has(E->get().to_node)) {
- undo_redo->add_do_method(script.ptr(), "data_connect", default_func, remap[E->get().from_node], E->get().from_port, remap[E->get().to_node], E->get().to_port);
- }
+ List<VisualScript::DataConnection> data;
+ script->get_data_connection_list(&data);
+ for (List<VisualScript::DataConnection>::Element *E = data.front(); E; E = E->next()) {
+ if (to_duplicate.has(E->get().from_node) && to_duplicate.has(E->get().to_node)) {
+ undo_redo->add_do_method(script.ptr(), "data_connect", remap[E->get().from_node], E->get().from_port, remap[E->get().to_node], E->get().to_port);
}
}
@@ -1830,7 +1803,7 @@ void VisualScriptEditor::_on_nodes_duplicate() {
}
if (to_select.size()) {
- EditorNode::get_singleton()->push_item(script->get_node(default_func, to_select.front()->get()).ptr());
+ EditorNode::get_singleton()->push_item(script->get_node(to_select.front()->get()).ptr());
}
}
@@ -1843,7 +1816,7 @@ void VisualScriptEditor::_generic_search(String p_base_type, Vector2 pos, bool n
new_connect_node_select->select_from_visual_script(p_base_type, false, false); // neither connecting nor reset text
- // ensure that the dialog fits inside the graph
+ // Ensure that the dialog fits inside the graph.
Size2 bounds = graph->get_global_position() + graph->get_size() - new_connect_node_select->get_size();
pos.x = pos.x > bounds.x ? bounds.x : pos.x;
pos.y = pos.y > bounds.y ? bounds.y : pos.y;
@@ -1904,7 +1877,7 @@ void VisualScriptEditor::_members_gui_input(const Ref<InputEvent> &p_event) {
if (btn.is_valid() && btn->is_doubleclick()) {
TreeItem *ti = members->get_selected();
if (ti && ti->get_parent() == members->get_root()->get_children()) { // to check if it's a function
- _center_on_node(ti->get_metadata(0), script->get_function_node_id(ti->get_metadata(0)));
+ _center_on_node(script->get_function_node_id(ti->get_metadata(0)));
}
}
}
@@ -1922,8 +1895,8 @@ void VisualScriptEditor::_rename_function(const String &name, const String &new_
int node_id = script->get_function_node_id(name);
Ref<VisualScriptFunction> func;
- if (script->has_node(name, node_id)) {
- func = script->get_node(name, node_id);
+ if (script->has_node(node_id)) {
+ func = script->get_node(node_id);
}
undo_redo->create_action(TTR("Rename Function"));
undo_redo->add_do_method(script.ptr(), "rename_function", name, new_name);
@@ -1933,21 +1906,17 @@ void VisualScriptEditor::_rename_function(const String &name, const String &new_
undo_redo->add_undo_method(func.ptr(), "set_name", name);
}
- // also fix all function calls
- List<StringName> flst;
- script->get_function_list(&flst);
- for (List<StringName>::Element *E = flst.front(); E; E = E->next()) {
- List<int> lst;
- script->get_node_list(E->get(), &lst);
- for (List<int>::Element *F = lst.front(); F; F = F->next()) {
- Ref<VisualScriptFunctionCall> fncall = script->get_node(E->get(), F->get());
- if (!fncall.is_valid()) {
- continue;
- }
- if (fncall->get_function() == name) {
- undo_redo->add_do_method(fncall.ptr(), "set_function", new_name);
- undo_redo->add_undo_method(fncall.ptr(), "set_function", name);
- }
+ // Also fix all function calls.
+ List<int> lst;
+ script->get_node_list(&lst);
+ for (List<int>::Element *F = lst.front(); F; F = F->next()) {
+ Ref<VisualScriptFunctionCall> fncall = script->get_node(F->get());
+ if (!fncall.is_valid()) {
+ continue;
+ }
+ if (fncall->get_function() == name) {
+ undo_redo->add_do_method(fncall.ptr(), "set_function", new_name);
+ undo_redo->add_undo_method(fncall.ptr(), "set_function", name);
}
}
@@ -2100,7 +2069,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
ofs /= EDSCALE;
- int new_id = _create_new_node_from_name(d["node_type"], ofs, default_func);
+ int new_id = _create_new_node_from_name(d["node_type"], ofs);
Node *node = graph->get_node(itos(new_id));
if (node) {
@@ -2139,8 +2108,8 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
int new_id = script->get_available_id();
undo_redo->create_action(TTR("Add Node"));
- undo_redo->add_do_method(script.ptr(), "add_node", default_func, new_id, vnode, ofs);
- undo_redo->add_undo_method(script.ptr(), "remove_node", default_func, new_id);
+ undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, ofs);
+ undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
undo_redo->commit_action();
@@ -2168,11 +2137,11 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
int new_id = script->get_available_id();
undo_redo->create_action(TTR("Add Node"));
- undo_redo->add_do_method(script.ptr(), "add_node", default_func, new_id, vnode, ofs);
+ undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, ofs);
undo_redo->add_do_method(vnode.ptr(), "set_base_type", script->get_instance_base_type());
undo_redo->add_do_method(vnode.ptr(), "set_function", d["function"]);
- undo_redo->add_undo_method(script.ptr(), "remove_node", default_func, new_id);
+ undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
undo_redo->commit_action();
@@ -2200,8 +2169,8 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
int new_id = script->get_available_id();
undo_redo->create_action(TTR("Add Node"));
- undo_redo->add_do_method(script.ptr(), "add_node", default_func, new_id, vnode, ofs);
- undo_redo->add_undo_method(script.ptr(), "remove_node", default_func, new_id);
+ undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, ofs);
+ undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
undo_redo->commit_action();
@@ -2229,8 +2198,8 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
int new_id = script->get_available_id();
undo_redo->create_action(TTR("Add Preload Node"));
- undo_redo->add_do_method(script.ptr(), "add_node", default_func, new_id, prnode, ofs);
- undo_redo->add_undo_method(script.ptr(), "remove_node", default_func, new_id);
+ undo_redo->add_do_method(script.ptr(), "add_node", new_id, prnode, ofs);
+ undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
undo_redo->commit_action();
@@ -2269,8 +2238,8 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
prnode.instance();
prnode->set_preload(res);
- undo_redo->add_do_method(script.ptr(), "add_node", default_func, new_id, prnode, ofs);
- undo_redo->add_undo_method(script.ptr(), "remove_node", default_func, new_id);
+ undo_redo->add_do_method(script.ptr(), "add_node", new_id, prnode, ofs);
+ undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
new_ids.push_back(new_id);
new_id++;
ofs += Vector2(20, 20) * EDSCALE;
@@ -2336,7 +2305,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
scene_node->set_node_path(sn->get_path_to(node));
n = scene_node;
} else {
- // ! Doesn't work properly
+ // ! Doesn't work properly.
Ref<VisualScriptFunctionCall> call;
call.instance();
call->set_call_mode(VisualScriptFunctionCall::CALL_MODE_NODE_PATH);
@@ -2347,8 +2316,8 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
selecting_method_id = base_id;
}
- undo_redo->add_do_method(script.ptr(), "add_node", default_func, base_id, n, ofs);
- undo_redo->add_undo_method(script.ptr(), "remove_node", default_func, base_id);
+ undo_redo->add_do_method(script.ptr(), "add_node", base_id, n, ofs);
+ undo_redo->add_undo_method(script.ptr(), "remove_node", base_id);
base_id++;
ofs += Vector2(25, 25);
@@ -2417,13 +2386,13 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
vnode = pget;
}
- undo_redo->add_do_method(script.ptr(), "add_node", default_func, base_id, vnode, ofs);
+ undo_redo->add_do_method(script.ptr(), "add_node", base_id, vnode, ofs);
undo_redo->add_do_method(vnode.ptr(), "set_property", d["property"]);
if (!use_get) {
undo_redo->add_do_method(vnode.ptr(), "set_default_input_value", 0, d["value"]);
}
- undo_redo->add_undo_method(script.ptr(), "remove_node", default_func, base_id);
+ undo_redo->add_undo_method(script.ptr(), "remove_node", base_id);
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
@@ -2462,12 +2431,12 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
}
vnode = pget;
}
- undo_redo->add_do_method(script.ptr(), "add_node", default_func, base_id, vnode, ofs);
+ undo_redo->add_do_method(script.ptr(), "add_node", base_id, vnode, ofs);
undo_redo->add_do_method(vnode.ptr(), "set_property", d["property"]);
if (!use_get) {
undo_redo->add_do_method(vnode.ptr(), "set_default_input_value", 0, d["value"]);
}
- undo_redo->add_undo_method(script.ptr(), "remove_node", default_func, base_id);
+ undo_redo->add_undo_method(script.ptr(), "remove_node", base_id);
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
@@ -2477,7 +2446,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
}
void VisualScriptEditor::_selected_method(const String &p_method, const String &p_type, const bool p_connecting) {
- Ref<VisualScriptFunctionCall> vsfc = script->get_node(default_func, selecting_method_id);
+ Ref<VisualScriptFunctionCall> vsfc = script->get_node(selecting_method_id);
if (!vsfc.is_valid()) {
return;
}
@@ -2535,16 +2504,8 @@ void VisualScriptEditor::set_edited_resource(const RES &p_res) {
script->connect("node_ports_changed", callable_mp(this, &VisualScriptEditor::_node_ports_changed));
- default_func = script->get_default_func();
-
- if (!script->has_function(default_func)) // this is the supposed default function
- {
- script->add_function(default_func);
- script->set_edited(true); //so that if a function was added it's saved
- }
-
_update_graph();
- _update_members();
+ call_deferred("_update_members");
}
void VisualScriptEditor::enable_editor() {
@@ -2563,7 +2524,7 @@ String VisualScriptEditor::get_name() {
if (script->get_path().find("local://") == -1 && script->get_path().find("::") == -1) {
name = script->get_path().get_file();
if (is_unsaved()) {
- if (script->get_path().empty()) {
+ if (script->get_path().is_empty()) {
name = TTR("[unsaved]");
}
name += "(*)";
@@ -2585,13 +2546,12 @@ bool VisualScriptEditor::is_unsaved() {
bool unsaved =
script->is_edited() ||
script->are_subnodes_edited() ||
- script->get_path().empty(); // In memory.
+ script->get_path().is_empty(); // In memory.
return unsaved;
}
Variant VisualScriptEditor::get_edit_state() {
Dictionary d;
- d["function"] = default_func;
d["scroll"] = graph->get_scroll_ofs();
d["zoom"] = graph->get_zoom();
d["using_snap"] = graph->is_using_snap();
@@ -2601,9 +2561,6 @@ Variant VisualScriptEditor::get_edit_state() {
void VisualScriptEditor::set_edit_state(const Variant &p_state) {
Dictionary d = p_state;
- if (d.has("function")) {
- selected = default_func;
- }
_update_graph();
_update_members();
@@ -2622,11 +2579,11 @@ void VisualScriptEditor::set_edit_state(const Variant &p_state) {
}
}
-void VisualScriptEditor::_center_on_node(const StringName &p_func, int p_id) {
+void VisualScriptEditor::_center_on_node(int p_id) {
Node *n = graph->get_node(itos(p_id));
GraphNode *gn = Object::cast_to<GraphNode>(n);
- // clear selection
+ // Clear selection.
for (int i = 0; i < graph->get_child_count(); i++) {
GraphNode *gnd = Object::cast_to<GraphNode>(graph->get_child(i));
if (gnd) {
@@ -2636,15 +2593,15 @@ void VisualScriptEditor::_center_on_node(const StringName &p_func, int p_id) {
if (gn) {
gn->set_selected(true);
- Vector2 new_scroll = gn->get_offset() - graph->get_size() * 0.5 + gn->get_size() * 0.5;
+ Vector2 new_scroll = gn->get_position_offset() - graph->get_size() * 0.5 + gn->get_size() * 0.5;
graph->set_scroll_ofs(new_scroll);
- script->set_function_scroll(p_func, new_scroll / EDSCALE);
+ script->set_scroll(new_scroll / EDSCALE);
script->set_edited(true);
}
}
void VisualScriptEditor::goto_line(int p_line, bool p_with_error) {
- p_line += 1; //add one because script lines begin from 0.
+ p_line += 1; // Add one because script lines begin from 0.
if (p_with_error) {
error_line = p_line;
@@ -2653,7 +2610,7 @@ void VisualScriptEditor::goto_line(int p_line, bool p_with_error) {
List<StringName> functions;
script->get_function_list(&functions);
for (List<StringName>::Element *E = functions.front(); E; E = E->next()) {
- if (script->has_node(E->get(), p_line)) {
+ if (script->has_node(p_line)) {
_update_graph();
_update_members();
@@ -2700,11 +2657,11 @@ Array VisualScriptEditor::get_breakpoints() {
script->get_function_list(&functions);
for (List<StringName>::Element *E = functions.front(); E; E = E->next()) {
List<int> nodes;
- script->get_node_list(E->get(), &nodes);
+ script->get_node_list(&nodes);
for (List<int>::Element *F = nodes.front(); F; F = F->next()) {
- Ref<VisualScriptNode> vsn = script->get_node(E->get(), F->get());
+ Ref<VisualScriptNode> vsn = script->get_node(F->get());
if (vsn->is_breakpoint()) {
- breakpoints.push_back(F->get() - 1); //subtract 1 because breakpoints in text start from zero
+ breakpoints.push_back(F->get() - 1); // Subtract 1 because breakpoints in text start from zero.
}
}
}
@@ -2715,7 +2672,7 @@ void VisualScriptEditor::add_callback(const String &p_function, PackedStringArra
if (script->has_function(p_function)) {
_update_members();
_update_graph();
- _center_on_node(p_function, script->get_function_node_id(p_function));
+ _center_on_node(script->get_function_node_id(p_function));
return;
}
@@ -2739,15 +2696,15 @@ void VisualScriptEditor::add_callback(const String &p_function, PackedStringArra
func->add_argument(type, name);
}
-
+ int fn_id = script->get_available_id();
func->set_name(p_function);
- script->add_function(p_function);
- script->add_node(p_function, script->get_available_id(), func);
+ script->add_function(p_function, fn_id);
+ script->add_node(fn_id, func);
_update_members();
_update_graph();
- _center_on_node(p_function, script->get_function_node_id(p_function));
+ _center_on_node(script->get_function_node_id(p_function));
}
bool VisualScriptEditor::show_members_overview() {
@@ -2841,62 +2798,46 @@ void VisualScriptEditor::_end_node_move() {
undo_redo->commit_action();
}
-void VisualScriptEditor::_move_node(const StringName &p_func, int p_id, const Vector2 &p_to) {
- if (!script->has_function(p_func)) {
+void VisualScriptEditor::_move_node(int p_id, const Vector2 &p_to) {
+ if (!script->has_node(p_id)) {
return;
}
Node *node = graph->get_node(itos(p_id));
if (Object::cast_to<GraphNode>(node)) {
- Object::cast_to<GraphNode>(node)->set_offset(p_to);
+ Object::cast_to<GraphNode>(node)->set_position_offset(p_to);
}
- script->set_node_position(p_func, p_id, p_to / EDSCALE);
-}
-
-StringName VisualScriptEditor::_get_function_of_node(int p_id) const {
- List<StringName> funcs;
- script->get_function_list(&funcs);
- for (List<StringName>::Element *E = funcs.front(); E; E = E->next()) {
- if (script->has_node(E->get(), p_id)) {
- return E->get();
- }
- }
-
- return ""; // this is passed to avoid crash and is tested against later
+ script->set_node_position(p_id, p_to / EDSCALE);
}
void VisualScriptEditor::_node_moved(Vector2 p_from, Vector2 p_to, int p_id) {
- StringName func = _get_function_of_node(p_id);
-
- undo_redo->add_do_method(this, "_move_node", func, p_id, p_to);
- undo_redo->add_undo_method(this, "_move_node", func, p_id, p_from);
+ undo_redo->add_do_method(this, "_move_node", p_id, p_to);
+ undo_redo->add_undo_method(this, "_move_node", p_id, p_from);
}
void VisualScriptEditor::_remove_node(int p_id) {
undo_redo->create_action(TTR("Remove VisualScript Node"));
- StringName func = _get_function_of_node(p_id);
-
- undo_redo->add_do_method(script.ptr(), "remove_node", func, p_id);
- undo_redo->add_undo_method(script.ptr(), "add_node", func, p_id, script->get_node(func, p_id), script->get_node_position(func, p_id));
+ undo_redo->add_do_method(script.ptr(), "remove_node", p_id);
+ undo_redo->add_undo_method(script.ptr(), "add_node", p_id, script->get_node(p_id), script->get_node_position(p_id));
List<VisualScript::SequenceConnection> sequence_conns;
- script->get_sequence_connection_list(func, &sequence_conns);
+ script->get_sequence_connection_list(&sequence_conns);
for (List<VisualScript::SequenceConnection>::Element *E = sequence_conns.front(); E; E = E->next()) {
if (E->get().from_node == p_id || E->get().to_node == p_id) {
- undo_redo->add_undo_method(script.ptr(), "sequence_connect", func, E->get().from_node, E->get().from_output, E->get().to_node);
+ undo_redo->add_undo_method(script.ptr(), "sequence_connect", E->get().from_node, E->get().from_output, E->get().to_node);
}
}
List<VisualScript::DataConnection> data_conns;
- script->get_data_connection_list(func, &data_conns);
+ script->get_data_connection_list(&data_conns);
for (List<VisualScript::DataConnection>::Element *E = data_conns.front(); E; E = E->next()) {
if (E->get().from_node == p_id || E->get().to_node == p_id) {
- undo_redo->add_undo_method(script.ptr(), "data_connect", func, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
+ undo_redo->add_undo_method(script.ptr(), "data_connect", E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
}
}
@@ -2906,13 +2847,13 @@ void VisualScriptEditor::_remove_node(int p_id) {
undo_redo->commit_action();
}
-void VisualScriptEditor::_node_ports_changed(const String &p_func, int p_id) {
+void VisualScriptEditor::_node_ports_changed(int p_id) {
_update_graph(p_id);
}
-bool VisualScriptEditor::node_has_sequence_connections(const StringName &p_func, int p_id) {
+bool VisualScriptEditor::node_has_sequence_connections(int p_id) {
List<VisualScript::SequenceConnection> sequence_conns;
- script->get_sequence_connection_list(p_func, &sequence_conns);
+ script->get_sequence_connection_list(&sequence_conns);
for (List<VisualScript::SequenceConnection>::Element *E = sequence_conns.front(); E; E = E->next()) {
int from = E->get().from_node;
@@ -2927,9 +2868,7 @@ bool VisualScriptEditor::node_has_sequence_connections(const StringName &p_func,
}
void VisualScriptEditor::_graph_connected(const String &p_from, int p_from_slot, const String &p_to, int p_to_slot) {
- StringName from_func = _get_function_of_node(p_from.to_int());
-
- Ref<VisualScriptNode> from_node = script->get_node(from_func, p_from.to_int());
+ Ref<VisualScriptNode> from_node = script->get_node(p_from.to_int());
ERR_FAIL_COND(!from_node.is_valid());
bool from_seq;
@@ -2939,9 +2878,7 @@ void VisualScriptEditor::_graph_connected(const String &p_from, int p_from_slot,
return; //can't connect this, it's invalid
}
- StringName to_func = _get_function_of_node(p_to.to_int());
-
- Ref<VisualScriptNode> to_node = script->get_node(to_func, p_to.to_int());
+ Ref<VisualScriptNode> to_node = script->get_node(p_to.to_int());
ERR_FAIL_COND(!to_node.is_valid());
bool to_seq;
@@ -2953,56 +2890,23 @@ void VisualScriptEditor::_graph_connected(const String &p_from, int p_from_slot,
ERR_FAIL_COND(from_seq != to_seq);
- // Do all the checks here
- StringName func; // this the func where we store the one the nodes at the end of the resolution on having multiple nodes
+ // Do all the checks here.
+ StringName func; // This the func where we store the one the nodes at the end of the resolution on having multiple nodes.
undo_redo->create_action(TTR("Connect Nodes"));
- if (from_func == to_func) {
- func = to_func;
- } else if (from_seq) {
- // this is a sequence connection
- _move_nodes_with_rescan(to_func, from_func, p_to.to_int()); // this function moves the nodes from func1 to func2
- func = from_func;
- } else {
- if (node_has_sequence_connections(to_func, p_to.to_int())) {
- if (node_has_sequence_connections(from_func, p_from.to_int())) {
- ERR_PRINT("Trying to connect between different sequence node trees");
- return;
- } else {
- _move_nodes_with_rescan(from_func, to_func, p_from.to_int());
- func = to_func;
- }
- } else if (node_has_sequence_connections(from_func, p_from.to_int())) {
- if (from_func == default_func) {
- _move_nodes_with_rescan(from_func, to_func, p_from.to_int());
- func = to_func;
- } else {
- _move_nodes_with_rescan(to_func, from_func, p_to.to_int());
- func = from_func;
- }
- } else {
- if (to_func == default_func) {
- _move_nodes_with_rescan(to_func, from_func, p_to.to_int());
- func = from_func;
- } else {
- _move_nodes_with_rescan(from_func, to_func, p_from.to_int());
- func = to_func;
- }
- }
- }
-
if (from_seq) {
- undo_redo->add_do_method(script.ptr(), "sequence_connect", func, p_from.to_int(), from_port, p_to.to_int());
- // this undo error on undo after move can't be removed without painful gymnastics
- undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", func, p_from.to_int(), from_port, p_to.to_int());
+ undo_redo->add_do_method(script.ptr(), "sequence_connect", p_from.to_int(), from_port, p_to.to_int());
+ // This undo error on undo after move can't be removed without painful gymnastics
+ undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", p_from.to_int(), from_port, p_to.to_int());
+ undo_redo->add_do_method(this, "_update_graph");
+ undo_redo->add_undo_method(this, "_update_graph");
} else {
bool converted = false;
- int conv_node = -1;
Ref<VisualScriptOperator> oper = to_node;
if (oper.is_valid() && oper->get_typed() == Variant::NIL) {
- // it's an operator Node and if the type is already nil
+ // It's an operator Node and if the type is already nil
if (from_node->get_output_value_port_info(from_port).type != Variant::NIL) {
oper->set_typed(from_node->get_output_value_port_info(from_port).type);
}
@@ -3010,106 +2914,36 @@ void VisualScriptEditor::_graph_connected(const String &p_from, int p_from_slot,
Ref<VisualScriptOperator> operf = from_node;
if (operf.is_valid() && operf->get_typed() == Variant::NIL) {
- // it's an operator Node and if the type is already nil
+ // It's an operator Node and if the type is already nil
if (to_node->get_input_value_port_info(to_port).type != Variant::NIL) {
operf->set_typed(to_node->get_input_value_port_info(to_port).type);
}
}
- Variant::Type to_type = to_node->get_input_value_port_info(to_port).type;
- Variant::Type from_type = from_node->get_output_value_port_info(from_port).type;
-
- if (to_type != Variant::NIL && from_type != Variant::NIL && to_type != from_type) {
- // add a constructor node between the ports
- bool exceptions = false; // true if there are any exceptions
- exceptions = exceptions || (to_type == Variant::INT && from_type == Variant::FLOAT);
- exceptions = exceptions || (to_type == Variant::FLOAT && from_type == Variant::INT);
- if (Variant::can_convert(from_type, to_type) && !exceptions) {
- MethodInfo mi;
- mi.name = Variant::get_type_name(to_type);
- PropertyInfo pi;
- pi.name = "from";
- pi.type = from_type;
- mi.arguments.push_back(pi);
- mi.return_val.type = to_type;
- // we know that this is allowed so create a new constructor node
- Ref<VisualScriptConstructor> constructor;
- constructor.instance();
- constructor->set_constructor_type(to_type);
- constructor->set_constructor(mi);
- // add the new constructor node
-
- GraphNode *gn = Object::cast_to<GraphNode>(graph->get_node(p_from));
- GraphNode *gn2 = Object::cast_to<GraphNode>(graph->get_node(p_to));
- if (gn && gn2) {
- Vector2 from_node_size = gn->get_rect().get_size();
- Vector2 to_node_size = gn2->get_rect().get_size();
- Vector2 to_node_pos = script->get_node_position(func, p_to.to_int());
- Vector2 from_node_pos = script->get_node_position(func, p_from.to_int());
- Vector2 new_to_node_pos = from_node_pos;
- Vector2 constructor_pos;
- if ((to_node_pos.x - from_node_pos.x) < 0) {
- // to is behind from node
- if (to_node_pos.x > (from_node_pos.x - to_node_size.x - 240)) {
- new_to_node_pos.x = from_node_pos.x - to_node_size.x - 240; // approx size of constructor node + padding
- } else {
- new_to_node_pos.x = to_node_pos.x;
- }
- new_to_node_pos.y = to_node_pos.y;
- constructor_pos.x = from_node_pos.x - 210;
- constructor_pos.y = to_node_pos.y;
- } else {
- // to is ahead of from node
- if (to_node_pos.x < (from_node_size.x + from_node_pos.x + 240)) {
- new_to_node_pos.x = from_node_size.x + from_node_pos.x + 240; // approx size of constructor node + padding
- } else {
- new_to_node_pos.x = to_node_pos.x;
- }
- new_to_node_pos.y = to_node_pos.y;
- constructor_pos.x = from_node_size.x + from_node_pos.x + 10;
- constructor_pos.y = to_node_pos.y;
- }
- undo_redo->add_do_method(this, "_move_node", func, p_to.to_int(), new_to_node_pos);
- undo_redo->add_undo_method(this, "_move_node", func, p_to.to_int(), to_node_pos);
- conv_node = script->get_available_id();
- undo_redo->add_do_method(script.ptr(), "add_node", func, conv_node, constructor, _get_available_pos(false, constructor_pos));
- undo_redo->add_undo_method(script.ptr(), "remove_node", func, conv_node);
- converted = true;
- }
- }
- }
-
- // disconnect current, and connect the new one
- if (script->is_input_value_port_connected(func, p_to.to_int(), to_port)) {
+ // Disconnect current, and connect the new one
+ if (script->is_input_value_port_connected(p_to.to_int(), to_port)) {
if (can_swap && data_disconnect_node == p_to.to_int()) {
int conn_from;
int conn_port;
- script->get_input_value_port_connection_source(func, p_to.to_int(), to_port, &conn_from, &conn_port);
- undo_redo->add_do_method(script.ptr(), "data_disconnect", func, conn_from, conn_port, p_to.to_int(), to_port);
- undo_redo->add_do_method(script.ptr(), "data_connect", func, conn_from, conn_port, data_disconnect_node, data_disconnect_port);
- undo_redo->add_undo_method(script.ptr(), "data_disconnect", func, conn_from, conn_port, data_disconnect_node, data_disconnect_port);
- undo_redo->add_undo_method(script.ptr(), "data_connect", func, conn_from, conn_port, p_to.to_int(), to_port);
+ script->get_input_value_port_connection_source(p_to.to_int(), to_port, &conn_from, &conn_port);
+ undo_redo->add_do_method(script.ptr(), "data_disconnect", conn_from, conn_port, p_to.to_int(), to_port);
+ undo_redo->add_do_method(script.ptr(), "data_connect", conn_from, conn_port, data_disconnect_node, data_disconnect_port);
+ undo_redo->add_undo_method(script.ptr(), "data_disconnect", conn_from, conn_port, data_disconnect_node, data_disconnect_port);
+ undo_redo->add_undo_method(script.ptr(), "data_connect", conn_from, conn_port, p_to.to_int(), to_port);
can_swap = false; // swapped
} else {
int conn_from;
int conn_port;
- script->get_input_value_port_connection_source(func, p_to.to_int(), to_port, &conn_from, &conn_port);
- undo_redo->add_do_method(script.ptr(), "data_disconnect", func, conn_from, conn_port, p_to.to_int(), to_port);
- undo_redo->add_undo_method(script.ptr(), "data_connect", func, conn_from, conn_port, p_to.to_int(), to_port);
+ script->get_input_value_port_connection_source(p_to.to_int(), to_port, &conn_from, &conn_port);
+ undo_redo->add_do_method(script.ptr(), "data_disconnect", conn_from, conn_port, p_to.to_int(), to_port);
+ undo_redo->add_undo_method(script.ptr(), "data_connect", conn_from, conn_port, p_to.to_int(), to_port);
}
}
if (!converted) {
- undo_redo->add_do_method(script.ptr(), "data_connect", func, p_from.to_int(), from_port, p_to.to_int(), to_port);
- undo_redo->add_undo_method(script.ptr(), "data_disconnect", func, p_from.to_int(), from_port, p_to.to_int(), to_port);
- } else {
- // this is noice
- undo_redo->add_do_method(script.ptr(), "data_connect", func, p_from.to_int(), from_port, conv_node, 0);
- undo_redo->add_do_method(script.ptr(), "data_connect", func, conv_node, 0, p_to.to_int(), to_port);
- // I don't think this is needed but gonna leave it here for now... until I need to finalise it all
- undo_redo->add_undo_method(script.ptr(), "data_disconnect", func, p_from.to_int(), from_port, conv_node, 0);
- undo_redo->add_undo_method(script.ptr(), "data_disconnect", func, conv_node, 0, p_to.to_int(), to_port);
+ undo_redo->add_do_method(script.ptr(), "data_connect", p_from.to_int(), from_port, p_to.to_int(), to_port);
+ undo_redo->add_undo_method(script.ptr(), "data_disconnect", p_from.to_int(), from_port, p_to.to_int(), to_port);
}
- //update nodes in graph
+ // Update nodes in graph
if (!converted) {
undo_redo->add_do_method(this, "_update_graph", p_from.to_int());
undo_redo->add_do_method(this, "_update_graph", p_to.to_int());
@@ -3121,34 +2955,28 @@ void VisualScriptEditor::_graph_connected(const String &p_from, int p_from_slot,
}
}
- undo_redo->add_do_method(this, "_update_graph_connections");
- undo_redo->add_undo_method(this, "_update_graph_connections");
-
undo_redo->commit_action();
}
void VisualScriptEditor::_graph_disconnected(const String &p_from, int p_from_slot, const String &p_to, int p_to_slot) {
- StringName func = _get_function_of_node(p_from.to_int());
- ERR_FAIL_COND(func != _get_function_of_node(p_to.to_int()));
-
- Ref<VisualScriptNode> from_node = script->get_node(func, p_from.to_int());
+ Ref<VisualScriptNode> from_node = script->get_node(p_from.to_int());
ERR_FAIL_COND(!from_node.is_valid());
bool from_seq;
int from_port;
if (!_get_out_slot(from_node, p_from_slot, from_port, from_seq)) {
- return; //can't connect this, it's invalid
+ return; // Can't connect this, it's invalid.
}
- Ref<VisualScriptNode> to_node = script->get_node(func, p_to.to_int());
+ Ref<VisualScriptNode> to_node = script->get_node(p_to.to_int());
ERR_FAIL_COND(!to_node.is_valid());
bool to_seq;
int to_port;
if (!_get_in_slot(to_node, p_to_slot, to_port, to_seq)) {
- return; //can't connect this, it's invalid
+ return; // Can't connect this, it's invalid.
}
ERR_FAIL_COND(from_seq != to_seq);
@@ -3156,248 +2984,27 @@ void VisualScriptEditor::_graph_disconnected(const String &p_from, int p_from_sl
undo_redo->create_action(TTR("Disconnect Nodes"));
if (from_seq) {
- undo_redo->add_do_method(script.ptr(), "sequence_disconnect", func, p_from.to_int(), from_port, p_to.to_int());
- undo_redo->add_undo_method(script.ptr(), "sequence_connect", func, p_from.to_int(), from_port, p_to.to_int());
+ undo_redo->add_do_method(script.ptr(), "sequence_disconnect", p_from.to_int(), from_port, p_to.to_int());
+ undo_redo->add_undo_method(script.ptr(), "sequence_connect", p_from.to_int(), from_port, p_to.to_int());
+ undo_redo->add_do_method(this, "_update_graph");
+ undo_redo->add_undo_method(this, "_update_graph");
} else {
can_swap = true;
data_disconnect_node = p_to.to_int();
data_disconnect_port = to_port;
- undo_redo->add_do_method(script.ptr(), "data_disconnect", func, p_from.to_int(), from_port, p_to.to_int(), to_port);
- undo_redo->add_undo_method(script.ptr(), "data_connect", func, p_from.to_int(), from_port, p_to.to_int(), to_port);
- //update relevant nodes in the graph
+ undo_redo->add_do_method(script.ptr(), "data_disconnect", p_from.to_int(), from_port, p_to.to_int(), to_port);
+ undo_redo->add_undo_method(script.ptr(), "data_connect", p_from.to_int(), from_port, p_to.to_int(), to_port);
+ // Update relevant nodes in the graph.
undo_redo->add_do_method(this, "_update_graph", p_from.to_int());
undo_redo->add_do_method(this, "_update_graph", p_to.to_int());
undo_redo->add_undo_method(this, "_update_graph", p_from.to_int());
undo_redo->add_undo_method(this, "_update_graph", p_to.to_int());
}
- undo_redo->add_do_method(this, "_update_graph_connections");
- undo_redo->add_undo_method(this, "_update_graph_connections");
undo_redo->commit_action();
}
-void VisualScriptEditor::_move_nodes_with_rescan(const StringName &p_func_from, const StringName &p_func_to, int p_id) {
- Set<int> nodes_to_move;
- HashMap<int, Map<int, int>> seqconns_to_move; // from => List(outp, to)
- HashMap<int, Map<int, Pair<int, int>>> dataconns_to_move; // to => List(inp_p => from, outp)
-
- nodes_to_move.insert(p_id);
- Set<int> sequence_connections;
- {
- List<VisualScript::SequenceConnection> sequence_conns;
- script->get_sequence_connection_list(p_func_from, &sequence_conns);
-
- HashMap<int, Map<int, int>> seqcons; // from => List(out_p => to)
-
- for (List<VisualScript::SequenceConnection>::Element *E = sequence_conns.front(); E; E = E->next()) {
- int from = E->get().from_node;
- int to = E->get().to_node;
- int out_p = E->get().from_output;
- if (!seqcons.has(from)) {
- seqcons.set(from, Map<int, int>());
- }
- seqcons[from].insert(out_p, to);
- sequence_connections.insert(to);
- sequence_connections.insert(from);
- }
-
- int conn = p_id;
- List<int> stack;
- HashMap<int, Set<int>> seen; // from, outp
- while (seqcons.has(conn)) {
- for (auto E = seqcons[conn].front(); E; E = E->next()) {
- if (seen.has(conn) && seen[conn].has(E->key())) {
- if (!E->next()) {
- if (stack.size() > 0) {
- conn = stack.back()->get();
- stack.pop_back();
- break;
- }
- conn = -101;
- break;
- }
- continue;
- }
- if (!seen.has(conn)) {
- seen.set(conn, Set<int>());
- }
- seen[conn].insert(E->key());
- stack.push_back(conn);
- if (!seqconns_to_move.has(conn)) {
- seqconns_to_move.set(conn, Map<int, int>());
- }
- seqconns_to_move[conn].insert(E->key(), E->get());
- conn = E->get();
- nodes_to_move.insert(conn);
- break;
- }
- if (!seqcons.has(conn) && stack.size() > 0) {
- conn = stack.back()->get();
- stack.pop_back();
- }
- }
- }
-
- {
- List<VisualScript::DataConnection> data_connections;
- script->get_data_connection_list(p_func_from, &data_connections);
- int func_from_node_id = script->get_function_node_id(p_func_from);
-
- HashMap<int, Map<int, Pair<int, int>>> connections;
-
- for (List<VisualScript::DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
- int from = E->get().from_node;
- int to = E->get().to_node;
- int out_p = E->get().from_port;
- int in_p = E->get().to_port;
-
- // skip if the from_node is a function node
- if (from == func_from_node_id) {
- continue;
- }
-
- if (!connections.has(to)) {
- connections.set(to, Map<int, Pair<int, int>>());
- }
- connections[to].insert(in_p, Pair<int, int>(from, out_p));
- }
-
- // go through the HashMap and do all sorts of crazy ass stuff now...
- Set<int> nodes_to_be_added;
- for (Set<int>::Element *F = nodes_to_move.front(); F; F = F->next()) {
- HashMap<int, Set<int>> seen;
- List<int> stack;
- int id = F->get();
- while (connections.has(id)) {
- for (auto E = connections[id].front(); E; E = E->next()) {
- if (seen.has(id) && seen[id].has(E->key())) {
- if (!E->next()) {
- if (stack.size() > 0) {
- id = stack.back()->get();
- stack.pop_back();
- break;
- }
- id = -11; // I assume ids can't be negative should confirm it...
- break;
- }
- continue;
- }
-
- if (sequence_connections.has(E->get().first)) {
- if (!nodes_to_move.has(E->get().first)) {
- if (stack.size() > 0) {
- id = stack.back()->get();
- stack.pop_back();
- break;
- }
- id = -11; // I assume ids can't be negative should confirm it...
- break;
- }
- }
-
- if (!seen.has(id)) {
- seen.set(id, Set<int>());
- }
- seen[id].insert(E->key());
- stack.push_back(id);
- if (!dataconns_to_move.has(id)) {
- dataconns_to_move.set(id, Map<int, Pair<int, int>>());
- }
- dataconns_to_move[id].insert(E->key(), Pair<int, int>(E->get().first, E->get().second));
- id = E->get().first;
- nodes_to_be_added.insert(id);
- break;
- }
- if (!connections.has(id) && stack.size() > 0) {
- id = stack.back()->get();
- stack.pop_back();
- }
- }
- }
- for (Set<int>::Element *E = nodes_to_be_added.front(); E; E = E->next()) {
- nodes_to_move.insert(E->get());
- }
- }
-
- // * this is primarily for the sake of the having proper undo
- List<VisualScript::SequenceConnection> seqext;
- List<VisualScript::DataConnection> dataext;
-
- List<VisualScript::SequenceConnection> seq_connections;
- script->get_sequence_connection_list(p_func_from, &seq_connections);
-
- for (List<VisualScript::SequenceConnection>::Element *E = seq_connections.front(); E; E = E->next()) {
- if (!nodes_to_move.has(E->get().from_node) && nodes_to_move.has(E->get().to_node)) {
- seqext.push_back(E->get());
- } else if (nodes_to_move.has(E->get().from_node) && !nodes_to_move.has(E->get().to_node)) {
- seqext.push_back(E->get());
- }
- }
-
- List<VisualScript::DataConnection> data_connections;
- script->get_data_connection_list(p_func_from, &data_connections);
-
- for (List<VisualScript::DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
- if (!nodes_to_move.has(E->get().from_node) && nodes_to_move.has(E->get().to_node)) {
- dataext.push_back(E->get());
- } else if (nodes_to_move.has(E->get().from_node) && !nodes_to_move.has(E->get().to_node)) {
- dataext.push_back(E->get());
- }
- }
-
- // undo_redo->create_action("Rescan Functions");
-
- for (Set<int>::Element *E = nodes_to_move.front(); E; E = E->next()) {
- int id = E->get();
-
- undo_redo->add_do_method(script.ptr(), "remove_node", p_func_from, id);
- undo_redo->add_do_method(script.ptr(), "add_node", p_func_to, id, script->get_node(p_func_from, id), script->get_node_position(p_func_from, id));
-
- undo_redo->add_undo_method(script.ptr(), "remove_node", p_func_to, id);
- undo_redo->add_undo_method(script.ptr(), "add_node", p_func_from, id, script->get_node(p_func_from, id), script->get_node_position(p_func_from, id));
- }
-
- List<int> skeys;
- seqconns_to_move.get_key_list(&skeys);
- for (List<int>::Element *E = skeys.front(); E; E = E->next()) {
- int from_node = E->get();
- for (Map<int, int>::Element *F = seqconns_to_move[from_node].front(); F; F = F->next()) {
- int from_port = F->key();
- int to_node = F->get();
- undo_redo->add_do_method(script.ptr(), "sequence_connect", p_func_to, from_node, from_port, to_node);
- undo_redo->add_undo_method(script.ptr(), "sequence_connect", p_func_from, from_node, from_port, to_node);
- }
- }
-
- List<int> keys;
- dataconns_to_move.get_key_list(&keys);
- for (List<int>::Element *E = keys.front(); E; E = E->next()) {
- int to_node = E->get(); // to_node
- for (Map<int, Pair<int, int>>::Element *F = dataconns_to_move[E->get()].front(); F; F = F->next()) {
- int inp_p = F->key();
- Pair<int, int> fro = F->get();
-
- undo_redo->add_do_method(script.ptr(), "data_connect", p_func_to, fro.first, fro.second, to_node, inp_p);
- undo_redo->add_undo_method(script.ptr(), "data_connect", p_func_from, fro.first, fro.second, to_node, inp_p);
- }
- }
-
- // this to have proper undo operations
- for (List<VisualScript::SequenceConnection>::Element *E = seqext.front(); E; E = E->next()) {
- undo_redo->add_undo_method(script.ptr(), "sequence_connect", p_func_from, E->get().from_node, E->get().from_output, E->get().to_node);
- }
- for (List<VisualScript::DataConnection>::Element *E = dataext.front(); E; E = E->next()) {
- undo_redo->add_undo_method(script.ptr(), "data_connect", p_func_from, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
- }
- // this doesn't need do methods as they are handled by the subsequent do calls implicitly
-
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
-
- // undo_redo->commit_action();
-}
-
void VisualScriptEditor::_graph_connect_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_pos) {
Node *node = graph->get_node(p_from);
GraphNode *gn = Object::cast_to<GraphNode>(node);
@@ -3405,23 +3012,22 @@ void VisualScriptEditor::_graph_connect_to_empty(const String &p_from, int p_fro
return;
}
- StringName func = _get_function_of_node(p_from.to_int());
-
- Ref<VisualScriptNode> vsn = script->get_node(func, p_from.to_int());
+ Ref<VisualScriptNode> vsn = script->get_node(p_from.to_int());
if (!vsn.is_valid()) {
return;
}
+ if (vsn->get_output_value_port_count())
- port_action_pos = p_release_pos;
+ port_action_pos = p_release_pos;
if (p_from_slot < vsn->get_output_sequence_port_count()) {
port_action_node = p_from.to_int();
port_action_output = p_from_slot;
- _port_action_menu(CREATE_ACTION, func);
+ _port_action_menu(CREATE_ACTION);
} else {
port_action_output = p_from_slot - vsn->get_output_sequence_port_count();
port_action_node = p_from.to_int();
- _port_action_menu(CREATE_CALL_SET_GET, func);
+ _port_action_menu(CREATE_CALL_SET_GET);
}
}
@@ -3435,9 +3041,7 @@ VisualScriptNode::TypeGuess VisualScriptEditor::_guess_output_type(int p_port_ac
visited_nodes.insert(p_port_action_node);
- StringName func = _get_function_of_node(p_port_action_node);
-
- Ref<VisualScriptNode> node = script->get_node(func, p_port_action_node);
+ Ref<VisualScriptNode> node = script->get_node(p_port_action_node);
if (!node.is_valid()) {
return tg;
@@ -3451,11 +3055,11 @@ VisualScriptNode::TypeGuess VisualScriptEditor::_guess_output_type(int p_port_ac
g.type = pi.type;
if (g.type == Variant::NIL || g.type == Variant::OBJECT) {
- //any or object input, must further guess what this is
+ // Any or object input, must further guess what this is.
int from_node;
int from_port;
- if (script->get_input_value_port_connection_source(func, p_port_action_node, i, &from_node, &from_port)) {
+ if (script->get_input_value_port_connection_source(p_port_action_node, i, &from_node, &from_port)) {
g = _guess_output_type(from_node, from_port, visited_nodes);
} else {
Variant defval = node->get_default_input_value(i);
@@ -3477,7 +3081,7 @@ VisualScriptNode::TypeGuess VisualScriptEditor::_guess_output_type(int p_port_ac
return node->guess_output_type(in_guesses.ptrw(), p_port_action_output);
}
-void VisualScriptEditor::_port_action_menu(int p_option, const StringName &func) {
+void VisualScriptEditor::_port_action_menu(int p_option) {
Vector2 ofs = graph->get_scroll_ofs() + port_action_pos;
if (graph->is_using_snap()) {
int snap = graph->get_snap();
@@ -3500,8 +3104,8 @@ void VisualScriptEditor::_port_action_menu(int p_option, const StringName &func)
n->set_base_type("Object");
}
String type_string;
- if (script->get_node(func, port_action_node)->get_output_value_port_count() > 0) {
- type_string = script->get_node(func, port_action_node)->get_output_value_port_info(port_action_output).hint_string;
+ if (script->get_node(port_action_node)->get_output_value_port_count() > 0) {
+ type_string = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint_string;
}
if (tg.type == Variant::OBJECT) {
if (tg.script.is_valid()) {
@@ -3516,7 +3120,7 @@ void VisualScriptEditor::_port_action_menu(int p_option, const StringName &func)
} else {
new_connect_node_select->select_from_basic_type(tg.type);
}
- // ensure that the dialog fits inside the graph
+ // Ensure that the dialog fits inside the graph.
Vector2 pos = mouse_up_position;
Size2 bounds = graph->get_global_position() + graph->get_size() - new_connect_node_select->get_size();
pos.x = pos.x > bounds.x ? bounds.x : pos.x;
@@ -3526,8 +3130,8 @@ void VisualScriptEditor::_port_action_menu(int p_option, const StringName &func)
case CREATE_ACTION: {
VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn);
PropertyInfo property_info;
- if (script->get_node(func, port_action_node)->get_output_value_port_count() > 0) {
- property_info = script->get_node(func, port_action_node)->get_output_value_port_info(port_action_output);
+ if (script->get_node(port_action_node)->get_output_value_port_count() > 0) {
+ property_info = script->get_node(port_action_node)->get_output_value_port_info(port_action_output);
}
if (tg.type == Variant::OBJECT) {
if (property_info.type == Variant::OBJECT && property_info.hint_string != String()) {
@@ -3540,7 +3144,7 @@ void VisualScriptEditor::_port_action_menu(int p_option, const StringName &func)
} else {
new_connect_node_select->select_from_action(Variant::get_type_name(tg.type));
}
- // ensure that the dialog fits inside the graph
+ // Ensure that the dialog fits inside the graph.
Vector2 pos = mouse_up_position;
Size2 bounds = graph->get_global_position() + graph->get_size() - new_connect_node_select->get_size();
pos.x = pos.x > bounds.x ? bounds.x : pos.x;
@@ -3569,9 +3173,8 @@ void VisualScriptEditor::connect_data(Ref<VisualScriptNode> vnode_old, Ref<Visua
if (port >= value_count) {
port = 0;
}
- StringName func = _get_function_of_node(port_action_node);
- undo_redo->add_do_method(script.ptr(), "data_connect", func, port_action_node, port, new_id, 0);
- undo_redo->add_undo_method(script.ptr(), "data_disconnect", func, port_action_node, port, new_id, 0);
+ undo_redo->add_do_method(script.ptr(), "data_connect", port_action_node, port, new_id, 0);
+ undo_redo->add_undo_method(script.ptr(), "data_disconnect", port_action_node, port, new_id, 0);
undo_redo->commit_action();
}
@@ -3588,17 +3191,16 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri
bool port_node_exists = true;
- StringName func = _get_function_of_node(port_action_node);
- if (func == StringName()) {
- func = default_func;
- port_node_exists = false;
- }
+ // if (func == StringName()) {
+ // func = default_func;
+ // port_node_exists = false;
+ // }
if (p_category == "visualscript") {
Ref<VisualScriptNode> vnode_new = VisualScriptLanguage::singleton->create_node_from_name(p_text);
Ref<VisualScriptNode> vnode_old;
- if (port_node_exists) {
- vnode_old = script->get_node(func, port_action_node);
+ if (port_node_exists && p_connecting) {
+ vnode_old = script->get_node(port_action_node);
}
int new_id = script->get_available_id();
@@ -3621,13 +3223,13 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri
}
undo_redo->create_action(TTR("Add Node"));
- undo_redo->add_do_method(script.ptr(), "add_node", func, new_id, vnode_new, ofs);
+ undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode_new, ofs);
if (vnode_old.is_valid() && p_connecting) {
connect_seq(vnode_old, vnode_new, new_id);
connect_data(vnode_old, vnode_new, new_id);
}
- undo_redo->add_undo_method(script.ptr(), "remove_node", func, new_id);
+ undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
undo_redo->commit_action();
@@ -3684,8 +3286,8 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri
int new_id = script->get_available_id();
undo_redo->create_action(TTR("Add Node"));
- undo_redo->add_do_method(script.ptr(), "add_node", func, new_id, vnode, ofs);
- undo_redo->add_undo_method(script.ptr(), "remove_node", func, new_id);
+ undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, ofs);
+ undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
undo_redo->add_do_method(this, "_update_graph", new_id);
undo_redo->add_undo_method(this, "_update_graph", new_id);
undo_redo->commit_action();
@@ -3696,7 +3298,7 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri
port_action_new_node = new_id;
- Ref<VisualScriptNode> vsn = script->get_node(func, port_action_new_node);
+ Ref<VisualScriptNode> vsn = script->get_node(port_action_new_node);
if (Object::cast_to<VisualScriptFunctionCall>(vsn.ptr())) {
Ref<VisualScriptFunctionCall> vsfc = vsn;
@@ -3710,10 +3312,9 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri
vsfc->set_base_type(String(""));
if (tg.gdclass != StringName()) {
vsfc->set_base_type(tg.gdclass);
-
- } else if (script->get_node(func, port_action_node).is_valid()) {
- PropertyHint hint = script->get_node(func, port_action_node)->get_output_value_port_info(port_action_output).hint;
- String base_type = script->get_node(func, port_action_node)->get_output_value_port_info(port_action_output).hint_string;
+ } else if (script->get_node(port_action_node).is_valid()) {
+ PropertyHint hint = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint;
+ String base_type = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint_string;
if (base_type != String() && hint == PROPERTY_HINT_TYPE_STRING) {
vsfc->set_base_type(base_type);
@@ -3746,9 +3347,9 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri
if (tg.gdclass != StringName()) {
vsp->set_base_type(tg.gdclass);
- } else if (script->get_node(func, port_action_node).is_valid()) {
- PropertyHint hint = script->get_node(func, port_action_node)->get_output_value_port_info(port_action_output).hint;
- String base_type = script->get_node(func, port_action_node)->get_output_value_port_info(port_action_output).hint_string;
+ } else if (script->get_node(port_action_node).is_valid()) {
+ PropertyHint hint = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint;
+ String base_type = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint_string;
if (base_type != String() && hint == PROPERTY_HINT_TYPE_STRING) {
vsp->set_base_type(base_type);
@@ -3776,9 +3377,9 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri
if (tg.gdclass != StringName()) {
vsp->set_base_type(tg.gdclass);
- } else if (script->get_node(func, port_action_node).is_valid()) {
- PropertyHint hint = script->get_node(func, port_action_node)->get_output_value_port_info(port_action_output).hint;
- String base_type = script->get_node(func, port_action_node)->get_output_value_port_info(port_action_output).hint_string;
+ } else if (script->get_node(port_action_node).is_valid()) {
+ PropertyHint hint = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint;
+ String base_type = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint_string;
if (base_type != String() && hint == PROPERTY_HINT_TYPE_STRING) {
vsp->set_base_type(base_type);
}
@@ -3796,16 +3397,13 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri
}
}
if (port_node_exists) {
- Ref<VisualScriptNode> vnode_old = script->get_node(func, port_action_node);
+ Ref<VisualScriptNode> vnode_old = script->get_node(port_action_node);
if (vnode_old.is_valid() && p_connecting) {
connect_seq(vnode_old, vnode, port_action_new_node);
connect_data(vnode_old, vnode, port_action_new_node);
}
}
_update_graph(port_action_new_node);
- if (port_node_exists) {
- _update_graph_connections();
- }
}
void VisualScriptEditor::connect_seq(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode_new, int new_id) {
@@ -3824,29 +3422,27 @@ void VisualScriptEditor::connect_seq(Ref<VisualScriptNode> vnode_old, Ref<Visual
return;
}
- StringName func = _get_function_of_node(port_action_node);
-
undo_redo->create_action(TTR("Connect Node Sequence"));
int pass_port = -vnode_old->get_output_sequence_port_count() + 1;
int return_port = port_action_output - 1;
if (vnode_old->get_output_value_port_info(port_action_output).name == String("pass") &&
- !script->get_output_sequence_ports_connected(func, port_action_node).has(pass_port)) {
- undo_redo->add_do_method(script.ptr(), "sequence_connect", func, port_action_node, pass_port, new_id);
- undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", func, port_action_node, pass_port, new_id);
+ !script->get_output_sequence_ports_connected(port_action_node).has(pass_port)) {
+ undo_redo->add_do_method(script.ptr(), "sequence_connect", port_action_node, pass_port, new_id);
+ undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", port_action_node, pass_port, new_id);
} else if (vnode_old->get_output_value_port_info(port_action_output).name == String("return") &&
- !script->get_output_sequence_ports_connected(func, port_action_node).has(return_port)) {
- undo_redo->add_do_method(script.ptr(), "sequence_connect", func, port_action_node, return_port, new_id);
- undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", func, port_action_node, return_port, new_id);
+ !script->get_output_sequence_ports_connected(port_action_node).has(return_port)) {
+ undo_redo->add_do_method(script.ptr(), "sequence_connect", port_action_node, return_port, new_id);
+ undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", port_action_node, return_port, new_id);
} else {
for (int port = 0; port < vnode_old->get_output_sequence_port_count(); port++) {
int count = vnode_old->get_output_sequence_port_count();
- if (port_action_output < count && !script->get_output_sequence_ports_connected(func, port_action_node).has(port_action_output)) {
- undo_redo->add_do_method(script.ptr(), "sequence_connect", func, port_action_node, port_action_output, new_id);
- undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", func, port_action_node, port_action_output, new_id);
+ if (port_action_output < count && !script->get_output_sequence_ports_connected(port_action_node).has(port_action_output)) {
+ undo_redo->add_do_method(script.ptr(), "sequence_connect", port_action_node, port_action_output, new_id);
+ undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", port_action_node, port_action_output, new_id);
break;
- } else if (!script->get_output_sequence_ports_connected(func, port_action_node).has(port)) {
- undo_redo->add_do_method(script.ptr(), "sequence_connect", func, port_action_node, port, new_id);
- undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", func, port_action_node, port, new_id);
+ } else if (!script->get_output_sequence_ports_connected(port_action_node).has(port)) {
+ undo_redo->add_do_method(script.ptr(), "sequence_connect", port_action_node, port, new_id);
+ undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", port_action_node, port, new_id);
break;
}
}
@@ -3881,9 +3477,9 @@ void VisualScriptEditor::_selected_new_virtual_method(const String &p_text, cons
Ref<VisualScriptFunction> func_node;
func_node.instance();
func_node->set_name(name);
-
+ int fn_id = script->get_available_id();
undo_redo->create_action(TTR("Add Function"));
- undo_redo->add_do_method(script.ptr(), "add_function", name);
+ undo_redo->add_do_method(script.ptr(), "add_function", name, fn_id);
for (int i = 0; i < minfo.arguments.size(); i++) {
func_node->add_argument(minfo.arguments[i].type, minfo.arguments[i].name, -1, minfo.arguments[i].hint, minfo.arguments[i].hint_string);
@@ -3891,14 +3487,17 @@ void VisualScriptEditor::_selected_new_virtual_method(const String &p_text, cons
Vector2 ofs = _get_available_pos();
- undo_redo->add_do_method(script.ptr(), "add_node", name, script->get_available_id(), func_node, ofs);
+ undo_redo->add_do_method(script.ptr(), "add_node", fn_id, func_node, ofs);
+ undo_redo->add_undo_method(script.ptr(), "remove_node", fn_id);
if (minfo.return_val.type != Variant::NIL || minfo.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
Ref<VisualScriptReturn> ret_node;
ret_node.instance();
ret_node->set_return_type(minfo.return_val.type);
ret_node->set_enable_return_value(true);
ret_node->set_name(name);
- undo_redo->add_do_method(script.ptr(), "add_node", name, script->get_available_id() + 1, ret_node, _get_available_pos(false, ofs + Vector2(500, 0)));
+ int nid = script->get_available_id() + 1;
+ undo_redo->add_do_method(script.ptr(), "add_node", nid, ret_node, _get_available_pos(false, ofs + Vector2(500, 0)));
+ undo_redo->add_undo_method(script.ptr(), "remove_node", nid);
}
undo_redo->add_undo_method(script.ptr(), "remove_function", name);
@@ -3913,21 +3512,16 @@ void VisualScriptEditor::_selected_new_virtual_method(const String &p_text, cons
}
void VisualScriptEditor::_cancel_connect_node() {
- // ensure the cancel is done
+ // Ensure the cancel is done.
port_action_new_node = -1;
}
-int VisualScriptEditor::_create_new_node_from_name(const String &p_text, const Vector2 &p_point, const StringName &p_func) {
- StringName func = default_func;
- if (p_func != StringName()) {
- func = p_func;
- }
-
+int VisualScriptEditor::_create_new_node_from_name(const String &p_text, const Vector2 &p_point) {
Ref<VisualScriptNode> vnode = VisualScriptLanguage::singleton->create_node_from_name(p_text);
int new_id = script->get_available_id();
undo_redo->create_action(TTR("Add Node"));
- undo_redo->add_do_method(script.ptr(), "add_node", func, new_id, vnode, p_point);
- undo_redo->add_undo_method(script.ptr(), "remove_node", func, new_id);
+ undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, p_point);
+ undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
undo_redo->commit_action();
@@ -3935,7 +3529,7 @@ int VisualScriptEditor::_create_new_node_from_name(const String &p_text, const V
}
void VisualScriptEditor::_default_value_changed() {
- Ref<VisualScriptNode> vsn = script->get_node(_get_function_of_node(editing_id), editing_id);
+ Ref<VisualScriptNode> vsn = script->get_node(editing_id);
if (vsn.is_null()) {
return;
}
@@ -3950,7 +3544,7 @@ void VisualScriptEditor::_default_value_changed() {
}
void VisualScriptEditor::_default_value_edited(Node *p_button, int p_id, int p_input_port) {
- Ref<VisualScriptNode> vsn = script->get_node(_get_function_of_node(p_id), p_id);
+ Ref<VisualScriptNode> vsn = script->get_node(p_id);
if (vsn.is_null()) {
return;
}
@@ -3959,8 +3553,9 @@ void VisualScriptEditor::_default_value_edited(Node *p_button, int p_id, int p_i
Variant existing = vsn->get_default_input_value(p_input_port);
if (pinfo.type != Variant::NIL && existing.get_type() != pinfo.type) {
Callable::CallError ce;
- const Variant *existingp = &existing;
- existing = Variant::construct(pinfo.type, &existingp, 1, ce, false);
+ Variant e = existing;
+ const Variant *existingp = &e;
+ Variant::construct(pinfo.type, existing, &existingp, 1, ce);
}
default_value_edit->set_position(Object::cast_to<Control>(p_button)->get_global_position() + Vector2(0, Object::cast_to<Control>(p_button)->get_size().y));
@@ -3968,15 +3563,15 @@ void VisualScriptEditor::_default_value_edited(Node *p_button, int p_id, int p_i
if (pinfo.type == Variant::NODE_PATH) {
Node *edited_scene = get_tree()->get_edited_scene_root();
- if (edited_scene) { // Fixing an old crash bug ( Visual Script Crashes on editing NodePath with an empty scene open)
+ if (edited_scene) { // Fixing an old crash bug ( Visual Script Crashes on editing NodePath with an empty scene open).
Node *script_node = _find_script_node(edited_scene, edited_scene, script);
if (script_node) {
- //pick a node relative to the script, IF the script exists
+ // Pick a node relative to the script, IF the script exists.
pinfo.hint = PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE;
pinfo.hint_string = script_node->get_path();
} else {
- //pick a path relative to edited scene
+ // Pick a path relative to edited scene.
pinfo.hint = PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE;
pinfo.hint_string = get_tree()->get_edited_scene_root()->get_path();
}
@@ -4074,11 +3669,8 @@ void VisualScriptEditor::_graph_ofs_changed(const Vector2 &p_ofs) {
updating_graph = true;
- // Just use the default func for all the properties that need to be handled for drawing rather than adding to the Visual Script Class
- if (script->has_function(default_func)) {
- script->set_function_scroll(default_func, graph->get_scroll_ofs() / EDSCALE);
- script->set_edited(true);
- }
+ script->set_scroll(graph->get_scroll_ofs() / EDSCALE);
+ script->set_edited(true);
updating_graph = false;
}
@@ -4086,10 +3678,7 @@ void VisualScriptEditor::_comment_node_resized(const Vector2 &p_new_size, int p_
if (updating_graph) {
return;
}
-
- StringName func = _get_function_of_node(p_node);
-
- Ref<VisualScriptComment> vsc = script->get_node(func, p_node);
+ Ref<VisualScriptComment> vsc = script->get_node(p_node);
if (vsc.is_null()) {
return;
}
@@ -4127,8 +3716,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
if (gn) {
if (gn->is_selected()) {
int id = String(gn->get_name()).to_int();
- StringName func = _get_function_of_node(id);
- Ref<VisualScriptNode> vsn = script->get_node(func, id);
+ Ref<VisualScriptNode> vsn = script->get_node(id);
if (vsn.is_valid()) {
vsn->set_breakpoint(!vsn->is_breakpoint());
reselect.push_back(gn->get_name());
@@ -4150,58 +3738,47 @@ void VisualScriptEditor::_menu_option(int p_what) {
} break;
case EDIT_COPY_NODES:
case EDIT_CUT_NODES: {
- if (!script->has_function(default_func)) {
- break;
- }
-
clipboard->nodes.clear();
clipboard->data_connections.clear();
clipboard->sequence_connections.clear();
- Set<String> funcs;
for (int i = 0; i < graph->get_child_count(); i++) {
GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
if (gn) {
if (gn->is_selected()) {
- int id = String(gn->get_name()).to_int();
- StringName func = _get_function_of_node(id);
- Ref<VisualScriptNode> node = script->get_node(func, id);
+ int id = gn->get_name().operator String().to_int();
+ Ref<VisualScriptNode> node = script->get_node(id);
if (Object::cast_to<VisualScriptFunction>(*node)) {
EditorNode::get_singleton()->show_warning(TTR("Can't copy the function node."));
return;
}
if (node.is_valid()) {
clipboard->nodes[id] = node->duplicate(true);
- clipboard->nodes_positions[id] = script->get_node_position(func, id);
- funcs.insert(String(func));
+ clipboard->nodes_positions[id] = script->get_node_position(id);
}
}
}
}
- if (clipboard->nodes.empty()) {
+ if (clipboard->nodes.is_empty()) {
break;
}
- for (Set<String>::Element *F = funcs.front(); F; F = F->next()) {
- List<VisualScript::SequenceConnection> sequence_connections;
-
- script->get_sequence_connection_list(F->get(), &sequence_connections);
+ List<VisualScript::SequenceConnection> sequence_connections;
+ script->get_sequence_connection_list(&sequence_connections);
- for (List<VisualScript::SequenceConnection>::Element *E = sequence_connections.front(); E; E = E->next()) {
- if (clipboard->nodes.has(E->get().from_node) && clipboard->nodes.has(E->get().to_node)) {
- clipboard->sequence_connections.insert(E->get());
- }
+ for (List<VisualScript::SequenceConnection>::Element *E = sequence_connections.front(); E; E = E->next()) {
+ if (clipboard->nodes.has(E->get().from_node) && clipboard->nodes.has(E->get().to_node)) {
+ clipboard->sequence_connections.insert(E->get());
}
+ }
- List<VisualScript::DataConnection> data_connections;
-
- script->get_data_connection_list(F->get(), &data_connections);
+ List<VisualScript::DataConnection> data_connections;
+ script->get_data_connection_list(&data_connections);
- for (List<VisualScript::DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
- if (clipboard->nodes.has(E->get().from_node) && clipboard->nodes.has(E->get().to_node)) {
- clipboard->data_connections.insert(E->get());
- }
+ for (List<VisualScript::DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
+ if (clipboard->nodes.has(E->get().from_node) && clipboard->nodes.has(E->get().to_node)) {
+ clipboard->data_connections.insert(E->get());
}
}
if (p_what == EDIT_CUT_NODES) {
@@ -4210,11 +3787,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
} break;
case EDIT_PASTE_NODES: {
- if (!script->has_function(default_func)) {
- break;
- }
-
- if (clipboard->nodes.empty()) {
+ if (clipboard->nodes.is_empty()) {
EditorNode::get_singleton()->show_warning(TTR("Clipboard is empty!"));
break;
}
@@ -4229,15 +3802,11 @@ void VisualScriptEditor::_menu_option(int p_what) {
Set<Vector2> existing_positions;
{
- List<StringName> functions;
- script->get_function_list(&functions);
- for (List<StringName>::Element *F = functions.front(); F; F = F->next()) {
- List<int> nodes;
- script->get_node_list(F->get(), &nodes);
- for (List<int>::Element *E = nodes.front(); E; E = E->next()) {
- Vector2 pos = script->get_node_position(F->get(), E->get()).snapped(Vector2(2, 2));
- existing_positions.insert(pos);
- }
+ List<int> nodes;
+ script->get_node_list(&nodes);
+ for (List<int>::Element *E = nodes.front(); E; E = E->next()) {
+ Vector2 pos = script->get_node_position(E->get()).snapped(Vector2(2, 2));
+ existing_positions.insert(pos);
}
}
@@ -4255,18 +3824,18 @@ void VisualScriptEditor::_menu_option(int p_what) {
paste_pos += Vector2(20, 20) * EDSCALE;
}
- undo_redo->add_do_method(script.ptr(), "add_node", default_func, new_id, node, paste_pos);
- undo_redo->add_undo_method(script.ptr(), "remove_node", default_func, new_id);
+ undo_redo->add_do_method(script.ptr(), "add_node", new_id, node, paste_pos);
+ undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
}
for (Set<VisualScript::SequenceConnection>::Element *E = clipboard->sequence_connections.front(); E; E = E->next()) {
- undo_redo->add_do_method(script.ptr(), "sequence_connect", default_func, remap[E->get().from_node], E->get().from_output, remap[E->get().to_node]);
- undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", default_func, remap[E->get().from_node], E->get().from_output, remap[E->get().to_node]);
+ undo_redo->add_do_method(script.ptr(), "sequence_connect", remap[E->get().from_node], E->get().from_output, remap[E->get().to_node]);
+ undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", remap[E->get().from_node], E->get().from_output, remap[E->get().to_node]);
}
for (Set<VisualScript::DataConnection>::Element *E = clipboard->data_connections.front(); E; E = E->next()) {
- undo_redo->add_do_method(script.ptr(), "data_connect", default_func, remap[E->get().from_node], E->get().from_port, remap[E->get().to_node], E->get().to_port);
- undo_redo->add_undo_method(script.ptr(), "data_disconnect", default_func, remap[E->get().from_node], E->get().from_port, remap[E->get().to_node], E->get().to_port);
+ undo_redo->add_do_method(script.ptr(), "data_connect", remap[E->get().from_node], E->get().from_port, remap[E->get().to_node], E->get().to_port);
+ undo_redo->add_undo_method(script.ptr(), "data_disconnect", remap[E->get().from_node], E->get().from_port, remap[E->get().to_node], E->get().to_port);
}
undo_redo->add_do_method(this, "_update_graph");
@@ -4283,7 +3852,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
}
} break;
case EDIT_CREATE_FUNCTION: {
- StringName function = "";
+ // Create Function.
Map<int, Ref<VisualScriptNode>> nodes;
Set<int> selections;
for (int i = 0; i < graph->get_child_count(); i++) {
@@ -4291,20 +3860,14 @@ void VisualScriptEditor::_menu_option(int p_what) {
if (gn) {
if (gn->is_selected()) {
int id = String(gn->get_name()).to_int();
- StringName func = _get_function_of_node(id);
- Ref<VisualScriptNode> node = script->get_node(func, id);
+ Ref<VisualScriptNode> node = script->get_node(id);
if (Object::cast_to<VisualScriptFunction>(*node)) {
EditorNode::get_singleton()->show_warning(TTR("Can't create function with a function node."));
return;
}
if (node.is_valid()) {
- if (func != function && function != StringName("")) {
- EditorNode::get_singleton()->show_warning(TTR("Can't create function of nodes from nodes of multiple functions."));
- return;
- }
nodes.insert(id, node);
selections.insert(id);
- function = func;
}
}
}
@@ -4323,7 +3886,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
int start_node = -1;
Set<int> end_nodes;
if (nodes.size() == 1) {
- Ref<VisualScriptNode> nd = script->get_node(function, nodes.front()->key());
+ Ref<VisualScriptNode> nd = script->get_node(nodes.front()->key());
if (nd.is_valid() && nd->has_input_sequence_port()) {
start_node = nodes.front()->key();
} else {
@@ -4332,29 +3895,29 @@ void VisualScriptEditor::_menu_option(int p_what) {
}
} else {
List<VisualScript::SequenceConnection> seqs;
- script->get_sequence_connection_list(function, &seqs);
+ script->get_sequence_connection_list(&seqs);
if (seqs.size() == 0) {
- // in case there are no sequence connections
- // select the top most node cause that's probably how
- // the user wants to connect the nodes
+ // In case there are no sequence connections,
+ // select the top most node cause that's probably how,
+ // the user wants to connect the nodes.
int top_nd = -1;
Vector2 top;
for (Map<int, Ref<VisualScriptNode>>::Element *E = nodes.front(); E; E = E->next()) {
- Ref<VisualScriptNode> nd = script->get_node(function, E->key());
+ Ref<VisualScriptNode> nd = script->get_node(E->key());
if (nd.is_valid() && nd->has_input_sequence_port()) {
if (top_nd < 0) {
top_nd = E->key();
- top = script->get_node_position(function, top_nd);
+ top = script->get_node_position(top_nd);
}
- Vector2 pos = script->get_node_position(function, E->key());
+ Vector2 pos = script->get_node_position(E->key());
if (top.y > pos.y) {
top_nd = E->key();
top = pos;
}
}
}
- Ref<VisualScriptNode> nd = script->get_node(function, top_nd);
+ Ref<VisualScriptNode> nd = script->get_node(top_nd);
if (nd.is_valid() && nd->has_input_sequence_port()) {
start_node = top_nd;
} else {
@@ -4362,7 +3925,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
return;
}
} else {
- // pick the node with input sequence
+ // Pick the node with input sequence.
Set<int> nodes_from;
Set<int> nodes_to;
for (List<VisualScript::SequenceConnection>::Element *E = seqs.front(); E; E = E->next()) {
@@ -4383,13 +3946,13 @@ void VisualScriptEditor::_menu_option(int p_what) {
nodes_to.insert(E->get().to_node);
}
- // to use to add return nodes
+ // To use to add return nodes.
_get_ends(start_node, seqs, selections, end_nodes);
if (start_node == -1) {
- // if we still don't have a start node then
- // run through the nodes and select the first tree node
- // ie node without any input sequence but output sequence
+ // If we still don't have a start node then,
+ // run through the nodes and select the first tree node,
+ // ie node without any input sequence but output sequence.
for (Set<int>::Element *E = nodes_from.front(); E; E = E->next()) {
if (!nodes_to.has(E->get())) {
start_node = E->get();
@@ -4400,20 +3963,20 @@ void VisualScriptEditor::_menu_option(int p_what) {
}
if (start_node == -1) {
- return; // this should not happen, but just in case something goes wrong
+ return; // This should not happen, but just in case something goes wrong.
}
List<Variant::Type> inputs; // input types
List<Pair<int, int>> input_connections;
{
List<VisualScript::DataConnection> dats;
- script->get_data_connection_list(function, &dats);
+ script->get_data_connection_list(&dats);
for (List<VisualScript::DataConnection>::Element *E = dats.front(); E; E = E->next()) {
if (nodes.has(E->get().from_node) && nodes.has(E->get().to_node)) {
datamove.insert(E->get());
} else if (!nodes.has(E->get().from_node) && nodes.has(E->get().to_node)) {
- // add all these as inputs for the Function
- Ref<VisualScriptNode> node = script->get_node(function, E->get().to_node);
+ // Add all these as inputs for the Function.
+ Ref<VisualScriptNode> node = script->get_node(E->get().to_node);
if (node.is_valid()) {
dataext.insert(E->get());
PropertyInfo pi = node->get_input_value_port_info(E->get().to_port);
@@ -4425,59 +3988,55 @@ void VisualScriptEditor::_menu_option(int p_what) {
}
}
}
-
- String new_fn = _validate_name("new_function");
-
- Vector2 ofs = _get_available_pos(false, script->get_node_position(function, start_node) - Vector2(80, 150));
-
- Ref<VisualScriptFunction> func_node;
- func_node.instance();
- func_node->set_name(new_fn);
-
- undo_redo->create_action(TTR("Create Function"));
-
- undo_redo->add_do_method(script.ptr(), "add_function", new_fn);
int fn_id = script->get_available_id();
- undo_redo->add_do_method(script.ptr(), "add_node", new_fn, fn_id, func_node, ofs);
- undo_redo->add_undo_method(script.ptr(), "remove_function", new_fn);
- undo_redo->add_do_method(this, "_update_members");
- undo_redo->add_undo_method(this, "_update_members");
- undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");
- undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
-
- // Move the nodes
+ {
+ String new_fn = _validate_name("new_function");
- for (Map<int, Ref<VisualScriptNode>>::Element *E = nodes.front(); E; E = E->next()) {
- undo_redo->add_do_method(script.ptr(), "remove_node", function, E->key());
- undo_redo->add_do_method(script.ptr(), "add_node", new_fn, E->key(), E->get(), script->get_node_position(function, E->key()));
+ Vector2 ofs = _get_available_pos(false, script->get_node_position(start_node) - Vector2(80, 150));
- // undo_redo->add_undo_method(script.ptr(), "remove_node", new_fn, E->key()); not needed cause we already remove the function :P
- undo_redo->add_undo_method(script.ptr(), "add_node", function, E->key(), E->get(), script->get_node_position(function, E->key()));
- }
+ Ref<VisualScriptFunction> func_node;
+ func_node.instance();
+ func_node->set_name(new_fn);
- for (Set<VisualScript::SequenceConnection>::Element *E = seqmove.front(); E; E = E->next()) {
- undo_redo->add_do_method(script.ptr(), "sequence_connect", new_fn, E->get().from_node, E->get().from_output, E->get().to_node);
- undo_redo->add_undo_method(script.ptr(), "sequence_connect", function, E->get().from_node, E->get().from_output, E->get().to_node);
- }
+ undo_redo->create_action(TTR("Create Function"));
- for (Set<VisualScript::DataConnection>::Element *E = datamove.front(); E; E = E->next()) {
- undo_redo->add_do_method(script.ptr(), "data_connect", new_fn, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
- undo_redo->add_undo_method(script.ptr(), "data_connect", function, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
+ undo_redo->add_do_method(script.ptr(), "add_function", new_fn, fn_id);
+ undo_redo->add_do_method(script.ptr(), "add_node", fn_id, func_node, ofs);
+ undo_redo->add_undo_method(script.ptr(), "remove_function", new_fn);
+ undo_redo->add_undo_method(script.ptr(), "remove_node", fn_id);
+ undo_redo->add_do_method(this, "_update_members");
+ undo_redo->add_undo_method(this, "_update_members");
+ undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");
+ undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
+ // Might make the system more intelligent by checking port from info.
+ int i = 0;
+ List<Pair<int, int>>::Element *F = input_connections.front();
+ for (List<Variant::Type>::Element *E = inputs.front(); E && F; E = E->next(), F = F->next()) {
+ func_node->add_argument(E->get(), "arg_" + String::num_int64(i), i);
+ undo_redo->add_do_method(script.ptr(), "data_connect", fn_id, i, F->get().first, F->get().second);
+ i++; // increment i
+ }
+ // Ensure Preview Selection is of newly created function node.
+ if (selections.size()) {
+ EditorNode::get_singleton()->push_item(func_node.ptr());
+ }
}
+ // Move the nodes.
- // Add undo for external connections as well so that it's easier to revert back and forth
- // these didn't require do methods as it's already handled internally by other do calls
+ // Handles reconnection of sequence connections on undo, start here in case of issues.
for (Set<VisualScript::SequenceConnection>::Element *E = seqext.front(); E; E = E->next()) {
- undo_redo->add_undo_method(script.ptr(), "sequence_connect", function, E->get().from_node, E->get().from_output, E->get().to_node);
+ undo_redo->add_do_method(script.ptr(), "sequence_disconnect", E->get().from_node, E->get().from_output, E->get().to_node);
+ undo_redo->add_undo_method(script.ptr(), "sequence_connect", E->get().from_node, E->get().from_output, E->get().to_node);
}
for (Set<VisualScript::DataConnection>::Element *E = dataext.front(); E; E = E->next()) {
- undo_redo->add_undo_method(script.ptr(), "data_connect", function, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
+ undo_redo->add_do_method(script.ptr(), "data_disconnect", E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
+ undo_redo->add_undo_method(script.ptr(), "data_connect", E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
}
- // I don't really think we need support for non sequenced functions at this moment
- undo_redo->add_do_method(script.ptr(), "sequence_connect", new_fn, fn_id, 0, start_node);
+ // I don't really think we need support for non sequenced functions at this moment.
+ undo_redo->add_do_method(script.ptr(), "sequence_connect", fn_id, 0, start_node);
- // end nodes are mapped to the return nodes with data connections if possible
+ // Could fail with the new changes, start here when searching for bugs in create function shortcut.
int m = 1;
for (Set<int>::Element *G = end_nodes.front(); G; G = G->next()) {
Ref<VisualScriptReturn> ret_node;
@@ -4485,36 +4044,27 @@ void VisualScriptEditor::_menu_option(int p_what) {
int ret_id = fn_id + (m++);
selections.insert(ret_id);
- Vector2 ofsi = _get_available_pos(false, script->get_node_position(function, G->get()) + Vector2(80, -100));
- undo_redo->add_do_method(script.ptr(), "add_node", new_fn, ret_id, ret_node, ofsi);
- undo_redo->add_undo_method(script.ptr(), "remove_node", new_fn, ret_id);
+ Vector2 ofsi = _get_available_pos(false, script->get_node_position(G->get()) + Vector2(80, -100));
+ undo_redo->add_do_method(script.ptr(), "add_node", ret_id, ret_node, ofsi);
+ undo_redo->add_undo_method(script.ptr(), "remove_node", ret_id);
- undo_redo->add_do_method(script.ptr(), "sequence_connect", new_fn, G->get(), 0, ret_id);
- // add data outputs from each of the end_nodes
- Ref<VisualScriptNode> vsn = script->get_node(function, G->get());
+ undo_redo->add_do_method(script.ptr(), "sequence_connect", G->get(), 0, ret_id);
+ // Add data outputs from each of the end_nodes.
+ Ref<VisualScriptNode> vsn = script->get_node(G->get());
if (vsn.is_valid() && vsn->get_output_value_port_count() > 0) {
ret_node->set_enable_return_value(true);
- // use the zeroth data port cause that's the likely one that is planned to be used
+ // Use the zeroth data port cause that's the likely one that is planned to be used.
ret_node->set_return_type(vsn->get_output_value_port_info(0).type);
- undo_redo->add_do_method(script.ptr(), "data_connect", new_fn, G->get(), 0, ret_id, 0);
+ undo_redo->add_do_method(script.ptr(), "data_connect", G->get(), 0, ret_id, 0);
}
}
- // * might make the system more intelligent by checking port from info.
- int i = 0;
- List<Pair<int, int>>::Element *F = input_connections.front();
- for (List<Variant::Type>::Element *E = inputs.front(); E && F; E = E->next(), F = F->next()) {
- func_node->add_argument(E->get(), "arg_" + String::num_int64(i), i);
- undo_redo->add_do_method(script.ptr(), "data_connect", new_fn, fn_id, i, F->get().first, F->get().second);
- i++; // increment i
- }
-
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
undo_redo->commit_action();
- // make sure all Nodes get marked for selection so that they can be moved together
+ // Make sure all Nodes get marked for selection so that they can be moved together.
selections.insert(fn_id);
for (int k = 0; k < graph->get_child_count(); k++) {
GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(k));
@@ -4524,11 +4074,6 @@ void VisualScriptEditor::_menu_option(int p_what) {
}
}
- // Ensure Preview Selection is of newly created function node
- if (selections.size()) {
- EditorNode::get_singleton()->push_item(func_node.ptr());
- }
-
} break;
case REFRESH_GRAPH: {
_update_graph();
@@ -4536,16 +4081,16 @@ void VisualScriptEditor::_menu_option(int p_what) {
}
}
-// this is likely going to be very slow and I am not sure if I should keep it
-// but I hope that it will not be a problem considering that we won't be creating functions so frequently
-// and cyclic connections would be a problem but hopefully we won't let them get to this point
+// This is likely going to be very slow and I am not sure if I should keep it,
+// but I hope that it will not be a problem considering that we won't be creating functions so frequently,
+// and cyclic connections would be a problem but hopefully we won't let them get to this point.
void VisualScriptEditor::_get_ends(int p_node, const List<VisualScript::SequenceConnection> &p_seqs, const Set<int> &p_selected, Set<int> &r_end_nodes) {
for (const List<VisualScript::SequenceConnection>::Element *E = p_seqs.front(); E; E = E->next()) {
int from = E->get().from_node;
int to = E->get().to_node;
if (from == p_node && p_selected.has(to)) {
- // this is an interior connection move forward to the to node
+ // This is an interior connection move forward to the to node.
_get_ends(to, p_seqs, p_selected, r_end_nodes);
} else if (from == p_node && !p_selected.has(to)) {
r_end_nodes.insert(from);
@@ -4605,34 +4150,29 @@ void VisualScriptEditor::_member_option(int p_option) {
switch (member_type) {
case MEMBER_FUNCTION: {
if (p_option == MEMBER_REMOVE) {
- //delete the function
+ // Delete the function.
String name = member_name;
-
+ List<String> lst;
+ int fn_node = script->get_function_node_id(name);
undo_redo->create_action(TTR("Remove Function"));
undo_redo->add_do_method(script.ptr(), "remove_function", name);
- undo_redo->add_undo_method(script.ptr(), "add_function", name);
- List<int> nodes;
- script->get_node_list(name, &nodes);
- for (List<int>::Element *E = nodes.front(); E; E = E->next()) {
- undo_redo->add_undo_method(script.ptr(), "add_node", name, E->get(), script->get_node(name, E->get()), script->get_node_position(name, E->get()));
- }
-
- List<VisualScript::SequenceConnection> seq_connections;
-
- script->get_sequence_connection_list(name, &seq_connections);
-
- for (List<VisualScript::SequenceConnection>::Element *E = seq_connections.front(); E; E = E->next()) {
- undo_redo->add_undo_method(script.ptr(), "sequence_connect", name, E->get().from_node, E->get().from_output, E->get().to_node);
+ undo_redo->add_do_method(script.ptr(), "remove_node", fn_node);
+ undo_redo->add_undo_method(script.ptr(), "add_function", name, fn_node);
+ undo_redo->add_undo_method(script.ptr(), "add_node", fn_node, script->get_node(fn_node), script->get_node_position(fn_node));
+ List<VisualScript::SequenceConnection> seqcons;
+ script->get_sequence_connection_list(&seqcons);
+ for (const List<VisualScript::SequenceConnection>::Element *E = seqcons.front(); E; E = E->next()) {
+ if (E->get().from_node == fn_node) {
+ undo_redo->add_undo_method(script.ptr(), "sequence_connect", fn_node, E->get().from_output, E->get().to_node);
+ }
}
-
- List<VisualScript::DataConnection> data_connections;
-
- script->get_data_connection_list(name, &data_connections);
-
- for (List<VisualScript::DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
- undo_redo->add_undo_method(script.ptr(), "data_connect", name, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
+ List<VisualScript::DataConnection> datcons;
+ script->get_data_connection_list(&datcons);
+ for (const List<VisualScript::DataConnection>::Element *E = datcons.front(); E; E = E->next()) {
+ if (E->get().from_node == fn_node) {
+ undo_redo->add_undo_method(script.ptr(), "data_connect", fn_node, E->get().from_port, E->get().to_node, E->get().to_port);
+ }
}
-
undo_redo->add_do_method(this, "_update_members");
undo_redo->add_undo_method(this, "_update_members");
undo_redo->add_do_method(this, "_update_graph");
@@ -4725,6 +4265,7 @@ VisualScriptEditor::VisualScriptEditor() {
saved_position = Vector2(0, 0);
edit_menu = memnew(MenuButton);
+ edit_menu->set_shortcut_context(this);
edit_menu->set_text(TTR("Edit"));
edit_menu->set_switch_on_hover(true);
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/delete_selected"), EDIT_DELETE_NODES);
@@ -4781,14 +4322,16 @@ VisualScriptEditor::VisualScriptEditor() {
graph = memnew(GraphEdit);
add_child(graph);
graph->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- graph->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+ graph->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
graph->connect("node_selected", callable_mp(this, &VisualScriptEditor::_node_selected));
- graph->connect("_begin_node_move", callable_mp(this, &VisualScriptEditor::_begin_node_move));
- graph->connect("_end_node_move", callable_mp(this, &VisualScriptEditor::_end_node_move));
+ graph->connect("begin_node_move", callable_mp(this, &VisualScriptEditor::_begin_node_move));
+ graph->connect("end_node_move", callable_mp(this, &VisualScriptEditor::_end_node_move));
graph->connect("delete_nodes_request", callable_mp(this, &VisualScriptEditor::_on_nodes_delete));
graph->connect("duplicate_nodes_request", callable_mp(this, &VisualScriptEditor::_on_nodes_duplicate));
graph->connect("gui_input", callable_mp(this, &VisualScriptEditor::_graph_gui_input));
graph->set_drag_forwarding(this);
+ float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity");
+ graph->set_minimap_opacity(graph_minimap_opacity);
graph->hide();
graph->connect("scroll_offset_changed", callable_mp(this, &VisualScriptEditor::_graph_ofs_changed));
@@ -4853,8 +4396,8 @@ VisualScriptEditor::VisualScriptEditor() {
function_create_dialog = memnew(ConfirmationDialog);
function_create_dialog->set_title(TTR("Create Function"));
function_create_dialog->add_child(function_vb);
- function_create_dialog->get_ok()->set_text(TTR("Create"));
- function_create_dialog->get_ok()->connect("pressed", callable_mp(this, &VisualScriptEditor::_create_function));
+ function_create_dialog->get_ok_button()->set_text(TTR("Create"));
+ function_create_dialog->get_ok_button()->connect("pressed", callable_mp(this, &VisualScriptEditor::_create_function));
add_child(function_create_dialog);
select_func_text = memnew(Label);
@@ -4865,9 +4408,9 @@ VisualScriptEditor::VisualScriptEditor() {
add_child(select_func_text);
hint_text = memnew(Label);
- hint_text->set_anchor_and_margin(MARGIN_TOP, ANCHOR_END, -100);
- hint_text->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, 0);
- hint_text->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 0);
+ hint_text->set_anchor_and_offset(SIDE_TOP, ANCHOR_END, -100);
+ hint_text->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0);
+ hint_text->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0);
hint_text->set_align(Label::ALIGN_CENTER);
hint_text->set_valign(Label::VALIGN_CENTER);
graph->add_child(hint_text);
@@ -4897,7 +4440,7 @@ VisualScriptEditor::VisualScriptEditor() {
graph->connect("connection_to_empty", callable_mp(this, &VisualScriptEditor::_graph_connect_to_empty));
edit_signal_dialog = memnew(AcceptDialog);
- edit_signal_dialog->get_ok()->set_text(TTR("Close"));
+ edit_signal_dialog->get_ok_button()->set_text(TTR("Close"));
add_child(edit_signal_dialog);
signal_editor = memnew(VisualScriptEditorSignalEdit);
@@ -4907,7 +4450,7 @@ VisualScriptEditor::VisualScriptEditor() {
edit_signal_edit->edit(signal_editor);
edit_variable_dialog = memnew(AcceptDialog);
- edit_variable_dialog->get_ok()->set_text(TTR("Close"));
+ edit_variable_dialog->get_ok_button()->set_text(TTR("Close"));
add_child(edit_variable_dialog);
variable_editor = memnew(VisualScriptEditorVariableEdit);
@@ -4926,7 +4469,6 @@ VisualScriptEditor::VisualScriptEditor() {
updating_members = false;
set_process_input(true);
- set_process_unhandled_input(true);
default_value_edit = memnew(CustomPropertyEditor);
add_child(default_value_edit);
@@ -4940,7 +4482,7 @@ VisualScriptEditor::VisualScriptEditor() {
new_connect_node_select = memnew(VisualScriptPropertySelector);
add_child(new_connect_node_select);
new_connect_node_select->connect("selected", callable_mp(this, &VisualScriptEditor::_selected_connect_node));
- new_connect_node_select->get_cancel()->connect("pressed", callable_mp(this, &VisualScriptEditor::_cancel_connect_node));
+ new_connect_node_select->get_cancel_button()->connect("pressed", callable_mp(this, &VisualScriptEditor::_cancel_connect_node));
new_virtual_method_select = memnew(VisualScriptPropertySelector);
add_child(new_virtual_method_select);
diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h
index 66e435741f..bb6f194286 100644
--- a/modules/visual_script/visual_script_editor.h
+++ b/modules/visual_script/visual_script_editor.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -64,7 +64,6 @@ class VisualScriptEditor : public ScriptEditorBase {
};
enum PortAction {
-
CREATE_CALL_SET_GET,
CREATE_ACTION,
};
@@ -137,8 +136,6 @@ class VisualScriptEditor : public ScriptEditorBase {
};
HashMap<StringName, Ref<StyleBox>> node_styles;
- StringName edited_func;
- StringName default_func;
void _update_graph_connections();
void _update_graph(int p_only_id = -1);
@@ -177,7 +174,7 @@ class VisualScriptEditor : public ScriptEditorBase {
Vector2 mouse_up_position;
- void _port_action_menu(int p_option, const StringName &p_func);
+ void _port_action_menu(int p_option);
void connect_data(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode, int new_id);
@@ -185,13 +182,13 @@ class VisualScriptEditor : public ScriptEditorBase {
void connect_seq(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode_new, int new_id);
void _cancel_connect_node();
- int _create_new_node_from_name(const String &p_text, const Vector2 &p_point, const StringName &p_func = StringName());
+ int _create_new_node_from_name(const String &p_text, const Vector2 &p_point);
void _selected_new_virtual_method(const String &p_text, const String &p_category, const bool p_connecting);
int error_line;
void _node_selected(Node *p_node);
- void _center_on_node(const StringName &p_func, int p_id);
+ void _center_on_node(int p_id);
void _node_filter_changed(const String &p_text);
void _change_base_type_callback();
@@ -202,7 +199,7 @@ class VisualScriptEditor : public ScriptEditorBase {
void _begin_node_move();
void _end_node_move();
- void _move_node(const StringName &p_func, int p_id, const Vector2 &p_to);
+ void _move_node(int p_id, const Vector2 &p_to);
void _get_ends(int p_node, const List<VisualScript::SequenceConnection> &p_seqs, const Set<int> &p_selected, Set<int> &r_end_nodes);
@@ -212,7 +209,7 @@ class VisualScriptEditor : public ScriptEditorBase {
void _graph_disconnected(const String &p_from, int p_from_slot, const String &p_to, int p_to_slot);
void _graph_connect_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_pos);
- void _node_ports_changed(const String &p_func, int p_id);
+ void _node_ports_changed(int p_id);
void _node_create();
void _update_available_nodes();
@@ -229,10 +226,8 @@ class VisualScriptEditor : public ScriptEditorBase {
void _port_name_focus_out(const Node *p_name_box, int p_id, int p_port, bool is_input);
Vector2 _get_available_pos(bool centered = true, Vector2 ofs = Vector2()) const;
- StringName _get_function_of_node(int p_id) const;
- void _move_nodes_with_rescan(const StringName &p_func_from, const StringName &p_func_to, int p_id);
- bool node_has_sequence_connections(const StringName &p_func, int p_id);
+ bool node_has_sequence_connections(int p_id);
void _generic_search(String p_base_type = "", Vector2 pos = Vector2(), bool node_centered = false);
diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp
index 60a439b291..9596fda95c 100644
--- a/modules/visual_script/visual_script_expression.cpp
+++ b/modules/visual_script/visual_script_expression.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -1341,7 +1341,7 @@ public:
}
bool valid;
- r_ret = base.get_named(index->name, &valid);
+ r_ret = base.get_named(index->name, valid);
if (!valid) {
r_error_str = "Invalid index '" + String(index->name) + "' for base of type " + Variant::get_type_name(base.get_type()) + ".";
return true;
@@ -1405,7 +1405,7 @@ public:
argp.write[i] = &arr[i];
}
- r_ret = Variant::construct(constructor->data_type, (const Variant **)argp.ptr(), argp.size(), ce);
+ Variant::construct(constructor->data_type, r_ret, (const Variant **)argp.ptr(), argp.size(), ce);
if (ce.error != Callable::CallError::CALL_OK) {
r_error_str = "Invalid arguments to construct '" + Variant::get_type_name(constructor->data_type) + "'.";
@@ -1463,7 +1463,7 @@ public:
argp.write[i] = &arr[i];
}
- r_ret = base.call(call->method, (const Variant **)argp.ptr(), argp.size(), ce);
+ base.call(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
r_error_str = "On call to '" + String(call->method) + "':";
diff --git a/modules/visual_script/visual_script_expression.h b/modules/visual_script/visual_script_expression.h
index 2b3b25842d..7fe665769d 100644
--- a/modules/visual_script/visual_script_expression.h
+++ b/modules/visual_script/visual_script_expression.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp
index 3ed20fab35..0049e254c4 100644
--- a/modules/visual_script/visual_script_flow_control.cpp
+++ b/modules/visual_script/visual_script_flow_control.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,9 +30,9 @@
#include "visual_script_flow_control.h"
+#include "core/config/project_settings.h"
#include "core/io/resource_loader.h"
#include "core/os/keyboard.h"
-#include "core/project_settings.h"
//////////////////////////////////////////
////////////////RETURN////////////////////
diff --git a/modules/visual_script/visual_script_flow_control.h b/modules/visual_script/visual_script_flow_control.h
index 1d0d6d103b..46a72bb92d 100644
--- a/modules/visual_script/visual_script_flow_control.h
+++ b/modules/visual_script/visual_script_flow_control.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp
index f13377f3c8..d016b938de 100644
--- a/modules/visual_script/visual_script_func_nodes.cpp
+++ b/modules/visual_script/visual_script_func_nodes.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,7 +30,7 @@
#include "visual_script_func_nodes.h"
-#include "core/engine.h"
+#include "core/config/engine.h"
#include "core/io/resource_loader.h"
#include "core/os/os.h"
#include "scene/main/node.h"
@@ -42,7 +42,7 @@
//////////////////////////////////////////
int VisualScriptFunctionCall::get_output_sequence_port_count() const {
- if ((method_cache.flags & METHOD_FLAG_CONST && call_mode != CALL_MODE_INSTANCE) || (call_mode == CALL_MODE_BASIC_TYPE && Variant::is_method_const(basic_type, function))) {
+ if ((method_cache.flags & METHOD_FLAG_CONST && call_mode != CALL_MODE_INSTANCE) || (call_mode == CALL_MODE_BASIC_TYPE && Variant::is_builtin_method_const(basic_type, function))) {
return 0;
} else {
return 1;
@@ -50,7 +50,7 @@ int VisualScriptFunctionCall::get_output_sequence_port_count() const {
}
bool VisualScriptFunctionCall::has_input_sequence_port() const {
- return !((method_cache.flags & METHOD_FLAG_CONST && call_mode != CALL_MODE_INSTANCE) || (call_mode == CALL_MODE_BASIC_TYPE && Variant::is_method_const(basic_type, function)));
+ return !((method_cache.flags & METHOD_FLAG_CONST && call_mode != CALL_MODE_INSTANCE) || (call_mode == CALL_MODE_BASIC_TYPE && Variant::is_builtin_method_const(basic_type, function)));
}
#ifdef TOOLS_ENABLED
@@ -130,7 +130,11 @@ StringName VisualScriptFunctionCall::_get_base_type() const {
int VisualScriptFunctionCall::get_input_value_port_count() const {
if (call_mode == CALL_MODE_BASIC_TYPE) {
- Vector<Variant::Type> types = Variant::get_method_argument_types(basic_type, function);
+ Vector<Variant::Type> types;
+ int argc = Variant::get_builtin_method_argument_count(basic_type, function);
+ for (int i = 0; i < argc; i++) {
+ types.push_back(Variant::get_builtin_method_argument_type(basic_type, function, i));
+ }
return types.size() + (rpc_call_mode >= RPC_RELIABLE_TO_ID ? 1 : 0) + 1;
} else {
@@ -147,8 +151,7 @@ int VisualScriptFunctionCall::get_input_value_port_count() const {
int VisualScriptFunctionCall::get_output_value_port_count() const {
if (call_mode == CALL_MODE_BASIC_TYPE) {
- bool returns = false;
- Variant::get_method_return_type(basic_type, function, &returns);
+ bool returns = Variant::has_builtin_method_return_value(basic_type, function);
return returns ? 1 : 0;
} else {
@@ -195,10 +198,7 @@ PropertyInfo VisualScriptFunctionCall::get_input_value_port_info(int p_idx) cons
#ifdef DEBUG_METHODS_ENABLED
if (call_mode == CALL_MODE_BASIC_TYPE) {
- Vector<StringName> names = Variant::get_method_argument_names(basic_type, function);
- Vector<Variant::Type> types = Variant::get_method_argument_types(basic_type, function);
- return PropertyInfo(types[p_idx], names[p_idx]);
-
+ return PropertyInfo(Variant::get_builtin_method_argument_type(basic_type, function, p_idx), Variant::get_builtin_method_argument_name(basic_type, function, p_idx));
} else {
MethodBind *mb = ClassDB::get_method(_get_base_type(), function);
if (mb) {
@@ -220,7 +220,7 @@ PropertyInfo VisualScriptFunctionCall::get_output_value_port_info(int p_idx) con
#ifdef DEBUG_METHODS_ENABLED
if (call_mode == CALL_MODE_BASIC_TYPE) {
- return PropertyInfo(Variant::get_method_return_type(basic_type, function), "");
+ return PropertyInfo(Variant::get_builtin_method_return_type(basic_type, function), "");
} else {
if (call_mode == CALL_MODE_INSTANCE) {
if (p_idx == 0) {
@@ -234,7 +234,6 @@ PropertyInfo VisualScriptFunctionCall::get_output_value_port_info(int p_idx) con
/*MethodBind *mb = ClassDB::get_method(_get_base_type(),function);
if (mb) {
-
ret = mb->get_argument_info(-1);
} else {*/
@@ -419,7 +418,7 @@ void VisualScriptFunctionCall::set_function(const StringName &p_type) {
function = p_type;
if (call_mode == CALL_MODE_BASIC_TYPE) {
- use_default_args = Variant::get_method_default_arguments(basic_type, function).size();
+ use_default_args = Variant::get_builtin_method_default_arguments(basic_type, function).size();
} else {
//update all caches
@@ -606,7 +605,7 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const
int mc = 0;
if (call_mode == CALL_MODE_BASIC_TYPE) {
- mc = Variant::get_method_default_arguments(basic_type, function).size();
+ mc = Variant::get_builtin_method_default_arguments(basic_type, function).size();
} else {
MethodBind *mb = ClassDB::get_method(_get_base_type(), function);
if (mb) {
@@ -805,19 +804,21 @@ public:
} else if (returns) {
if (call_mode == VisualScriptFunctionCall::CALL_MODE_INSTANCE) {
if (returns >= 2) {
- *p_outputs[1] = v.call(function, p_inputs + 1, input_args, r_error);
+ v.call(function, p_inputs + 1, input_args, *p_outputs[1], r_error);
} else if (returns == 1) {
- v.call(function, p_inputs + 1, input_args, r_error);
+ Variant ret;
+ v.call(function, p_inputs + 1, input_args, ret, r_error);
} else {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
r_error_str = "Invalid returns count for call_mode == CALL_MODE_INSTANCE";
return 0;
}
} else {
- *p_outputs[0] = v.call(function, p_inputs + 1, input_args, r_error);
+ v.call(function, p_inputs + 1, input_args, *p_outputs[0], r_error);
}
} else {
- v.call(function, p_inputs + 1, input_args, r_error);
+ Variant ret;
+ v.call(function, p_inputs + 1, input_args, ret, r_error);
}
if (call_mode == VisualScriptFunctionCall::CALL_MODE_INSTANCE) {
@@ -976,7 +977,7 @@ void VisualScriptPropertySet::_adjust_input_index(PropertyInfo &pinfo) const {
if (index != StringName()) {
Variant v;
Callable::CallError ce;
- v = Variant::construct(pinfo.type, nullptr, 0, ce);
+ Variant::construct(pinfo.type, v, nullptr, 0, ce);
Variant i = v.get(index);
pinfo.type = i.get_type();
}
@@ -1117,7 +1118,7 @@ void VisualScriptPropertySet::_update_cache() {
Variant v;
Callable::CallError ce;
- v = Variant::construct(basic_type, nullptr, 0, ce);
+ Variant::construct(basic_type, v, nullptr, 0, ce);
List<PropertyInfo> pinfo;
v.get_property_list(&pinfo);
@@ -1336,7 +1337,8 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo &property) const {
if (property.name == "index") {
Callable::CallError ce;
- Variant v = Variant::construct(type_cache.type, nullptr, 0, ce);
+ Variant v;
+ Variant::construct(type_cache.type, v, nullptr, 0, ce);
List<PropertyInfo> plist;
v.get_property_list(&plist);
String options = "";
@@ -1449,11 +1451,11 @@ public:
_FORCE_INLINE_ void _process_get(Variant &source, const Variant &p_argument, bool &valid) {
if (index != StringName() && assign_op == VisualScriptPropertySet::ASSIGN_OP_NONE) {
- source.set_named(index, p_argument, &valid);
+ source.set_named(index, p_argument, valid);
} else {
Variant value;
if (index != StringName()) {
- value = source.get_named(index, &valid);
+ value = source.get_named(index, valid);
} else {
value = source;
}
@@ -1497,7 +1499,7 @@ public:
}
if (index != StringName()) {
- source.set_named(index, value, &valid);
+ source.set_named(index, value, valid);
} else {
source = value;
}
@@ -1562,12 +1564,12 @@ public:
bool valid;
if (needs_get) {
- Variant value = v.get_named(property, &valid);
+ Variant value = v.get_named(property, valid);
_process_get(value, *p_inputs[1], valid);
- v.set_named(property, value, &valid);
+ v.set_named(property, value, valid);
} else {
- v.set_named(property, *p_inputs[1], &valid);
+ v.set_named(property, *p_inputs[1], valid);
}
if (!valid) {
@@ -1786,7 +1788,7 @@ void VisualScriptPropertyGet::_update_cache() {
Variant v;
Callable::CallError ce;
- v = Variant::construct(basic_type, nullptr, 0, ce);
+ Variant::construct(basic_type, v, nullptr, 0, ce);
List<PropertyInfo> pinfo;
v.get_property_list(&pinfo);
@@ -2012,7 +2014,8 @@ void VisualScriptPropertyGet::_validate_property(PropertyInfo &property) const {
if (property.name == "index") {
Callable::CallError ce;
- Variant v = Variant::construct(type_cache, nullptr, 0, ce);
+ Variant v;
+ Variant::construct(type_cache, v, nullptr, 0, ce);
List<PropertyInfo> plist;
v.get_property_list(&plist);
String options = "";
@@ -2088,6 +2091,7 @@ void VisualScriptPropertyGet::_bind_methods() {
BIND_ENUM_CONSTANT(CALL_MODE_SELF);
BIND_ENUM_CONSTANT(CALL_MODE_NODE_PATH);
BIND_ENUM_CONSTANT(CALL_MODE_INSTANCE);
+ BIND_ENUM_CONSTANT(CALL_MODE_BASIC_TYPE);
}
class VisualScriptNodeInstancePropertyGet : public VisualScriptNodeInstance {
@@ -2110,7 +2114,7 @@ public:
*p_outputs[0] = object->get(property, &valid);
if (index != StringName()) {
- *p_outputs[0] = p_outputs[0]->get_named(index);
+ *p_outputs[0] = p_outputs[0]->get_named(index, valid);
}
if (!valid) {
@@ -2139,7 +2143,7 @@ public:
*p_outputs[0] = another->get(property, &valid);
if (index != StringName()) {
- *p_outputs[0] = p_outputs[0]->get_named(index);
+ *p_outputs[0] = p_outputs[0]->get_named(index, valid);
}
if (!valid) {
@@ -2155,7 +2159,7 @@ public:
*p_outputs[0] = v.get(property, &valid);
if (index != StringName()) {
- *p_outputs[0] = p_outputs[0]->get_named(index);
+ *p_outputs[0] = p_outputs[0]->get_named(index, valid);
}
if (!valid) {
@@ -2367,7 +2371,8 @@ void register_visual_script_func_nodes() {
Variant::Type t = Variant::Type(i);
String type_name = Variant::get_type_name(t);
Callable::CallError ce;
- Variant vt = Variant::construct(t, nullptr, 0, ce);
+ Variant vt;
+ Variant::construct(t, vt, nullptr, 0, ce);
List<MethodInfo> ml;
vt.get_method_list(&ml);
diff --git a/modules/visual_script/visual_script_func_nodes.h b/modules/visual_script/visual_script_func_nodes.h
index 8372df561f..2ff9b7a981 100644
--- a/modules/visual_script/visual_script_func_nodes.h
+++ b/modules/visual_script/visual_script_func_nodes.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp
index 28122ade99..ae2b548f21 100644
--- a/modules/visual_script/visual_script_nodes.cpp
+++ b/modules/visual_script/visual_script_nodes.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,11 +30,11 @@
#include "visual_script_nodes.h"
-#include "core/engine.h"
-#include "core/global_constants.h"
+#include "core/config/engine.h"
+#include "core/config/project_settings.h"
+#include "core/core_constants.h"
#include "core/input/input.h"
#include "core/os/os.h"
-#include "core/project_settings.h"
#include "scene/main/node.h"
#include "scene/main/scene_tree.h"
@@ -828,7 +828,6 @@ PropertyInfo VisualScriptOperator::get_input_value_port_info(int p_idx) const {
{ Variant::NIL, Variant::NIL }, //OP_NEGATE,
{ Variant::NIL, Variant::NIL }, //OP_POSITIVE,
{ Variant::INT, Variant::INT }, //OP_MODULE,
- { Variant::STRING, Variant::STRING }, //OP_STRING_CONCAT,
//bitwise
{ Variant::INT, Variant::INT }, //OP_SHIFT_LEFT,
{ Variant::INT, Variant::INT }, //OP_SHIFT_RIGHT,
@@ -873,7 +872,6 @@ PropertyInfo VisualScriptOperator::get_output_value_port_info(int p_idx) const {
Variant::NIL, //OP_NEGATE,
Variant::NIL, //OP_POSITIVE,
Variant::INT, //OP_MODULE,
- Variant::STRING, //OP_STRING_CONCAT,
//bitwise
Variant::INT, //OP_SHIFT_LEFT,
Variant::INT, //OP_SHIFT_RIGHT,
@@ -1433,7 +1431,7 @@ void VisualScriptConstant::set_constant_type(Variant::Type p_type) {
type = p_type;
Callable::CallError ce;
- value = Variant::construct(type, nullptr, 0, ce);
+ Variant::construct(type, value, nullptr, 0, ce);
ports_changed_notify();
_change_notify();
}
@@ -1756,7 +1754,7 @@ PropertyInfo VisualScriptGlobalConstant::get_input_value_port_info(int p_idx) co
}
PropertyInfo VisualScriptGlobalConstant::get_output_value_port_info(int p_idx) const {
- String name = GlobalConstants::get_global_constant_name(index);
+ String name = CoreConstants::get_global_constant_name(index);
return PropertyInfo(Variant::INT, name);
}
@@ -1780,7 +1778,7 @@ public:
//virtual int get_working_memory_size() const { 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) {
- *p_outputs[0] = GlobalConstants::get_global_constant_value(index);
+ *p_outputs[0] = CoreConstants::get_global_constant_value(index);
return 0;
}
};
@@ -1797,11 +1795,11 @@ void VisualScriptGlobalConstant::_bind_methods() {
String cc;
- for (int i = 0; i < GlobalConstants::get_global_constant_count(); i++) {
+ for (int i = 0; i < CoreConstants::get_global_constant_count(); i++) {
if (i > 0) {
cc += ",";
}
- cc += GlobalConstants::get_global_constant_name(i);
+ cc += CoreConstants::get_global_constant_name(i);
}
ADD_PROPERTY(PropertyInfo(Variant::INT, "constant", PROPERTY_HINT_ENUM, cc), "set_global_constant", "get_global_constant");
}
@@ -3257,7 +3255,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) {
Callable::CallError ce;
- *p_outputs[0] = Variant::construct(type, p_inputs, argcount, ce);
+ Variant::construct(type, *p_outputs[0], p_inputs, argcount, ce);
if (ce.error != Callable::CallError::CALL_OK) {
r_error_str = "Invalid arguments for constructor";
}
@@ -3729,7 +3727,7 @@ void VisualScriptDeconstruct::_update_elements() {
elements.clear();
Variant v;
Callable::CallError ce;
- v = Variant::construct(type, nullptr, 0, ce);
+ Variant::construct(type, v, nullptr, 0, ce);
List<PropertyInfo> pinfo;
v.get_property_list(&pinfo);
@@ -3881,7 +3879,6 @@ void register_visual_script_nodes() {
VisualScriptLanguage::singleton->add_register_func("operators/math/negate", create_op_node<Variant::OP_NEGATE>);
VisualScriptLanguage::singleton->add_register_func("operators/math/positive", create_op_node<Variant::OP_POSITIVE>);
VisualScriptLanguage::singleton->add_register_func("operators/math/remainder", create_op_node<Variant::OP_MODULE>);
- VisualScriptLanguage::singleton->add_register_func("operators/math/string_concat", create_op_node<Variant::OP_STRING_CONCAT>);
//bitwise
VisualScriptLanguage::singleton->add_register_func("operators/bitwise/shift_left", create_op_node<Variant::OP_SHIFT_LEFT>);
VisualScriptLanguage::singleton->add_register_func("operators/bitwise/shift_right", create_op_node<Variant::OP_SHIFT_RIGHT>);
diff --git a/modules/visual_script/visual_script_nodes.h b/modules/visual_script/visual_script_nodes.h
index b6061f8838..ae5e04d096 100644
--- a/modules/visual_script/visual_script_nodes.h
+++ b/modules/visual_script/visual_script_nodes.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/visual_script/visual_script_property_selector.cpp b/modules/visual_script/visual_script_property_selector.cpp
index 3c44faab90..862cac5c67 100644
--- a/modules/visual_script/visual_script_property_selector.cpp
+++ b/modules/visual_script/visual_script_property_selector.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,6 +31,7 @@
#include "visual_script_property_selector.h"
#include "core/os/keyboard.h"
+#include "editor/doc_tools.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "modules/visual_script/visual_script.h"
@@ -196,7 +197,7 @@ void VisualScriptPropertySelector::_update_search() {
if (type != Variant::NIL) {
Variant v;
Callable::CallError ce;
- v = Variant::construct(type, nullptr, 0, ce);
+ Variant::construct(type, v, nullptr, 0, ce);
v.get_method_list(&methods);
} else {
Object *obj = ObjectDB::get_instance(script);
@@ -309,7 +310,7 @@ void VisualScriptPropertySelector::_update_search() {
found = true;
}
- get_ok()->set_disabled(root->get_children() == nullptr);
+ get_ok_button()->set_disabled(root->get_children() == nullptr);
}
void VisualScriptPropertySelector::create_visualscript_item(const String &name, TreeItem *const root, const String &search_input, const String &text) {
@@ -357,7 +358,7 @@ void VisualScriptPropertySelector::get_visual_node_names(const String &root_filt
continue;
}
- bool in_modifier = p_modifiers.empty();
+ bool in_modifier = p_modifiers.is_empty();
for (Set<String>::Element *F = p_modifiers.front(); F && in_modifier; F = F->next()) {
if (E->get().findn(F->get()) != -1) {
in_modifier = true;
@@ -437,7 +438,7 @@ void VisualScriptPropertySelector::_item_selected() {
class_type = base_type;
}
- DocData *dd = EditorHelp::get_doc_data();
+ DocTools *dd = EditorHelp::get_doc_data();
String text;
String at_class = class_type;
@@ -704,8 +705,8 @@ VisualScriptPropertySelector::VisualScriptPropertySelector() {
search_box->connect("gui_input", callable_mp(this, &VisualScriptPropertySelector::_sbox_input));
search_options = memnew(Tree);
vbc->add_margin_child(TTR("Matches:"), search_options, true);
- get_ok()->set_text(TTR("Open"));
- get_ok()->set_disabled(true);
+ get_ok_button()->set_text(TTR("Open"));
+ get_ok_button()->set_disabled(true);
register_text_enter(search_box);
set_hide_on_ok(false);
search_options->connect("item_activated", callable_mp(this, &VisualScriptPropertySelector::_confirmed));
diff --git a/modules/visual_script/visual_script_property_selector.h b/modules/visual_script/visual_script_property_selector.h
index cc49b2863d..7a87f3d3ee 100644
--- a/modules/visual_script/visual_script_property_selector.h
+++ b/modules/visual_script/visual_script_property_selector.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp
index dd07cc45a7..6c9af4e600 100644
--- a/modules/visual_script/visual_script_yield_nodes.cpp
+++ b/modules/visual_script/visual_script_yield_nodes.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/visual_script/visual_script_yield_nodes.h b/modules/visual_script/visual_script_yield_nodes.h
index 7a72211027..cc7ce0a1c6 100644
--- a/modules/visual_script/visual_script_yield_nodes.h
+++ b/modules/visual_script/visual_script_yield_nodes.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/vorbis/SCsub b/modules/vorbis/SCsub
index 05d46757d3..bc31fff066 100644
--- a/modules/vorbis/SCsub
+++ b/modules/vorbis/SCsub
@@ -8,9 +8,10 @@ Import("env_modules")
env_vorbis = env_modules.Clone()
-stub = True
-
# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_libvorbis"]:
thirdparty_dir = "#thirdparty/libvorbis/"
thirdparty_sources = [
@@ -51,7 +52,16 @@ if env["builtin_libvorbis"]:
env_thirdparty = env_vorbis.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
+
+# Godot source files
+
+module_obj = []
+
+env_vorbis.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-# Module files
-env_vorbis.add_source_files(env.modules_sources, "register_types.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/vorbis/register_types.cpp b/modules/vorbis/register_types.cpp
index 8874b3887b..d3e77ea629 100644
--- a/modules/vorbis/register_types.cpp
+++ b/modules/vorbis/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/vorbis/register_types.h b/modules/vorbis/register_types.h
index 7fa0dfdeef..1497e6f5e4 100644
--- a/modules/vorbis/register_types.h
+++ b/modules/vorbis/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/webm/SCsub b/modules/webm/SCsub
index 247b4ead37..44e80e2870 100644
--- a/modules/webm/SCsub
+++ b/modules/webm/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_webm = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
thirdparty_dir = "#thirdparty/libsimplewebm/"
thirdparty_sources = [
"libwebm/mkvparser/mkvparser.cc",
@@ -31,7 +34,15 @@ if env["builtin_libvpx"]:
env_thirdparty = env_webm.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
# Godot source files
-env_webm.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_webm.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/webm/doc_classes/VideoStreamWebm.xml b/modules/webm/doc_classes/VideoStreamWebm.xml
index 2edbc08cc8..f3e13ba31a 100644
--- a/modules/webm/doc_classes/VideoStreamWebm.xml
+++ b/modules/webm/doc_classes/VideoStreamWebm.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
[VideoStream] resource handling the [url=https://www.webmproject.org/]WebM[/url] video format with [code].webm[/code] extension. Both the VP8 and VP9 codecs are supported. The VP8 and VP9 codecs are more efficient than [VideoStreamTheora], but they require more CPU resources to decode (especially VP9). Both the VP8 and VP9 codecs are decoded on the CPU.
+ [b]Note:[/b] Alpha channel (also known as transparency) is not supported. The video will always appear to have a black background, even if it originally contains an alpha channel.
[b]Note:[/b] There are known bugs and performance issues with WebM video playback in Godot. If you run into problems, try using the Ogg Theora format instead: [VideoStreamTheora]
</description>
<tutorials>
diff --git a/modules/webm/libvpx/SCsub b/modules/webm/libvpx/SCsub
index d0744fa313..67d3f1bebd 100644
--- a/modules/webm/libvpx/SCsub
+++ b/modules/webm/libvpx/SCsub
@@ -278,7 +278,7 @@ if webm_cpu_x86:
try:
yasm_found = True
subprocess.Popen([yasm_path, "--version"], stdout=devnull, stderr=devnull).communicate()
- except:
+ except Exception:
yasm_found = False
if yasm_found:
break
diff --git a/modules/webm/register_types.cpp b/modules/webm/register_types.cpp
index 6248787879..82157a71c9 100644
--- a/modules/webm/register_types.cpp
+++ b/modules/webm/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/webm/register_types.h b/modules/webm/register_types.h
index 6a02e3a87a..d090fe745b 100644
--- a/modules/webm/register_types.h
+++ b/modules/webm/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/webm/video_stream_webm.cpp b/modules/webm/video_stream_webm.cpp
index 832e14d91a..5d8245c64c 100644
--- a/modules/webm/video_stream_webm.cpp
+++ b/modules/webm/video_stream_webm.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,9 +30,9 @@
#include "video_stream_webm.h"
+#include "core/config/project_settings.h"
#include "core/os/file_access.h"
#include "core/os/os.h"
-#include "core/project_settings.h"
#include "servers/audio_server.h"
#include "thirdparty/misc/yuv2rgb.h"
diff --git a/modules/webm/video_stream_webm.h b/modules/webm/video_stream_webm.h
index 25675cb248..cb3cf58850 100644
--- a/modules/webm/video_stream_webm.h
+++ b/modules/webm/video_stream_webm.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/webp/SCsub b/modules/webp/SCsub
index 58f2bb35e6..4c0c2f7893 100644
--- a/modules/webp/SCsub
+++ b/modules/webp/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_webp = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_libwebp"]:
thirdparty_dir = "#thirdparty/libwebp/"
thirdparty_sources = [
@@ -130,7 +133,16 @@ if env["builtin_libwebp"]:
env_thirdparty = env_webp.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
# Godot source files
-env_webp.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_webp.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/webp/image_loader_webp.cpp b/modules/webp/image_loader_webp.cpp
index d5c80e7909..b304c4824f 100644
--- a/modules/webp/image_loader_webp.cpp
+++ b/modules/webp/image_loader_webp.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,14 +32,14 @@
#include "core/io/marshalls.h"
#include "core/os/os.h"
-#include "core/print_string.h"
+#include "core/string/print_string.h"
#include <stdlib.h>
#include <webp/decode.h>
#include <webp/encode.h>
static Vector<uint8_t> _webp_lossy_pack(const Ref<Image> &p_image, float p_quality) {
- ERR_FAIL_COND_V(p_image.is_null() || p_image->empty(), Vector<uint8_t>());
+ ERR_FAIL_COND_V(p_image.is_null() || p_image->is_empty(), Vector<uint8_t>());
Ref<Image> img = p_image->duplicate();
if (img->detect_alpha()) {
diff --git a/modules/webp/image_loader_webp.h b/modules/webp/image_loader_webp.h
index 49a7407600..9ea3056a19 100644
--- a/modules/webp/image_loader_webp.h
+++ b/modules/webp/image_loader_webp.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/webp/register_types.cpp b/modules/webp/register_types.cpp
index 0788b06309..ea9af72418 100644
--- a/modules/webp/register_types.cpp
+++ b/modules/webp/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/webp/register_types.h b/modules/webp/register_types.h
index d574d7be1d..59d6894bf6 100644
--- a/modules/webp/register_types.h
+++ b/modules/webp/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/webrtc/SCsub b/modules/webrtc/SCsub
index 20b4c8f8d2..31b8a73bf2 100644
--- a/modules/webrtc/SCsub
+++ b/modules/webrtc/SCsub
@@ -3,8 +3,6 @@
Import("env")
Import("env_modules")
-# Thirdparty source files
-
env_webrtc = env_modules.Clone()
use_gdnative = env_webrtc["module_gdnative_enabled"]
@@ -12,4 +10,8 @@ if use_gdnative: # GDNative is retained in Javascript for export compatibility
env_webrtc.Append(CPPDEFINES=["WEBRTC_GDNATIVE_ENABLED"])
env_webrtc.Prepend(CPPPATH=["#modules/gdnative/include/"])
+if env["platform"] == "javascript":
+ # Our JavaScript/C++ interface.
+ env.AddJSLibraries(["library_godot_webrtc.js"])
+
env_webrtc.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/webrtc/library_godot_webrtc.js b/modules/webrtc/library_godot_webrtc.js
new file mode 100644
index 0000000000..404a116716
--- /dev/null
+++ b/modules/webrtc/library_godot_webrtc.js
@@ -0,0 +1,433 @@
+/*************************************************************************/
+/* library_godot_webrtc.js */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+const GodotRTCDataChannel = {
+ // Our socket implementation that forwards events to C++.
+ $GodotRTCDataChannel__deps: ['$IDHandler', '$GodotRuntime'],
+ $GodotRTCDataChannel: {
+ connect: function (p_id, p_on_open, p_on_message, p_on_error, p_on_close) {
+ const ref = IDHandler.get(p_id);
+ if (!ref) {
+ return;
+ }
+
+ ref.binaryType = 'arraybuffer';
+ ref.onopen = function (event) {
+ p_on_open();
+ };
+ ref.onclose = function (event) {
+ p_on_close();
+ };
+ ref.onerror = function (event) {
+ p_on_error();
+ };
+ ref.onmessage = function (event) {
+ let buffer;
+ let is_string = 0;
+ if (event.data instanceof ArrayBuffer) {
+ buffer = new Uint8Array(event.data);
+ } else if (event.data instanceof Blob) {
+ GodotRuntime.error('Blob type not supported');
+ return;
+ } else if (typeof event.data === 'string') {
+ is_string = 1;
+ const enc = new TextEncoder('utf-8');
+ buffer = new Uint8Array(enc.encode(event.data));
+ } else {
+ GodotRuntime.error('Unknown message type');
+ return;
+ }
+ const len = buffer.length * buffer.BYTES_PER_ELEMENT;
+ const out = GodotRuntime.malloc(len);
+ HEAPU8.set(buffer, out);
+ p_on_message(out, len, is_string);
+ GodotRuntime.free(out);
+ };
+ },
+
+ close: function (p_id) {
+ const ref = IDHandler.get(p_id);
+ if (!ref) {
+ return;
+ }
+ ref.onopen = null;
+ ref.onmessage = null;
+ ref.onerror = null;
+ ref.onclose = null;
+ ref.close();
+ },
+
+ get_prop: function (p_id, p_prop, p_def) {
+ const ref = IDHandler.get(p_id);
+ return (ref && ref[p_prop] !== undefined) ? ref[p_prop] : p_def;
+ },
+ },
+
+ godot_js_rtc_datachannel_ready_state_get__sig: 'ii',
+ godot_js_rtc_datachannel_ready_state_get: function (p_id) {
+ const ref = IDHandler.get(p_id);
+ if (!ref) {
+ return 3; // CLOSED
+ }
+
+ switch (ref.readyState) {
+ case 'connecting':
+ return 0;
+ case 'open':
+ return 1;
+ case 'closing':
+ return 2;
+ case 'closed':
+ default:
+ return 3;
+ }
+ },
+
+ godot_js_rtc_datachannel_send__sig: 'iiiii',
+ godot_js_rtc_datachannel_send: function (p_id, p_buffer, p_length, p_raw) {
+ const ref = IDHandler.get(p_id);
+ if (!ref) {
+ return 1;
+ }
+
+ const bytes_array = new Uint8Array(p_length);
+ for (let i = 0; i < p_length; i++) {
+ bytes_array[i] = GodotRuntime.getHeapValue(p_buffer + i, 'i8');
+ }
+
+ if (p_raw) {
+ ref.send(bytes_array.buffer);
+ } else {
+ const string = new TextDecoder('utf-8').decode(bytes_array);
+ ref.send(string);
+ }
+ return 0;
+ },
+
+ godot_js_rtc_datachannel_is_ordered__sig: 'ii',
+ godot_js_rtc_datachannel_is_ordered: function (p_id) {
+ return IDHandler.get_prop(p_id, 'ordered', true);
+ },
+
+ godot_js_rtc_datachannel_id_get__sig: 'ii',
+ godot_js_rtc_datachannel_id_get: function (p_id) {
+ return IDHandler.get_prop(p_id, 'id', 65535);
+ },
+
+ godot_js_rtc_datachannel_max_packet_lifetime_get__sig: 'ii',
+ godot_js_rtc_datachannel_max_packet_lifetime_get: function (p_id) {
+ const ref = IDHandler.get(p_id);
+ if (!ref) {
+ return 65535;
+ }
+ if (ref['maxPacketLifeTime'] !== undefined) {
+ return ref['maxPacketLifeTime'];
+ } else if (ref['maxRetransmitTime'] !== undefined) {
+ // Guess someone didn't appreciate the standardization process.
+ return ref['maxRetransmitTime'];
+ }
+ return 65535;
+ },
+
+ godot_js_rtc_datachannel_max_retransmits_get__sig: 'ii',
+ godot_js_rtc_datachannel_max_retransmits_get: function (p_id) {
+ return IDHandler.get_prop(p_id, 'maxRetransmits', 65535);
+ },
+
+ godot_js_rtc_datachannel_is_negotiated__sig: 'ii',
+ godot_js_rtc_datachannel_is_negotiated: function (p_id) {
+ return IDHandler.get_prop(p_id, 'negotiated', 65535);
+ },
+
+ godot_js_rtc_datachannel_label_get__sig: 'ii',
+ godot_js_rtc_datachannel_label_get: function (p_id) {
+ const ref = IDHandler.get(p_id);
+ if (!ref || !ref.label) {
+ return 0;
+ }
+ return GodotRuntime.allocString(ref.label);
+ },
+
+ godot_js_rtc_datachannel_protocol_get__sig: 'ii',
+ godot_js_rtc_datachannel_protocol_get: function (p_id) {
+ const ref = IDHandler.get(p_id);
+ if (!ref || !ref.protocol) {
+ return 0;
+ }
+ return GodotRuntime.allocString(ref.protocol);
+ },
+
+ godot_js_rtc_datachannel_destroy__sig: 'vi',
+ godot_js_rtc_datachannel_destroy: function (p_id) {
+ GodotRTCDataChannel.close(p_id);
+ IDHandler.remove(p_id);
+ },
+
+ godot_js_rtc_datachannel_connect__sig: 'viiiiii',
+ godot_js_rtc_datachannel_connect: function (p_id, p_ref, p_on_open, p_on_message, p_on_error, p_on_close) {
+ const onopen = GodotRuntime.get_func(p_on_open).bind(null, p_ref);
+ const onmessage = GodotRuntime.get_func(p_on_message).bind(null, p_ref);
+ const onerror = GodotRuntime.get_func(p_on_error).bind(null, p_ref);
+ const onclose = GodotRuntime.get_func(p_on_close).bind(null, p_ref);
+ GodotRTCDataChannel.connect(p_id, onopen, onmessage, onerror, onclose);
+ },
+
+ godot_js_rtc_datachannel_close__sig: 'vi',
+ godot_js_rtc_datachannel_close: function (p_id) {
+ const ref = IDHandler.get(p_id);
+ if (!ref) {
+ return;
+ }
+ GodotRTCDataChannel.close(p_id);
+ },
+};
+
+autoAddDeps(GodotRTCDataChannel, '$GodotRTCDataChannel');
+mergeInto(LibraryManager.library, GodotRTCDataChannel);
+
+const GodotRTCPeerConnection = {
+ $GodotRTCPeerConnection__deps: ['$IDHandler', '$GodotRuntime', '$GodotRTCDataChannel'],
+ $GodotRTCPeerConnection: {
+ onstatechange: function (p_id, p_conn, callback, event) {
+ const ref = IDHandler.get(p_id);
+ if (!ref) {
+ return;
+ }
+ let state;
+ switch (p_conn.iceConnectionState) {
+ case 'new':
+ state = 0;
+ break;
+ case 'checking':
+ state = 1;
+ break;
+ case 'connected':
+ case 'completed':
+ state = 2;
+ break;
+ case 'disconnected':
+ state = 3;
+ break;
+ case 'failed':
+ state = 4;
+ break;
+ case 'closed':
+ default:
+ state = 5;
+ break;
+ }
+ callback(state);
+ },
+
+ onicecandidate: function (p_id, callback, event) {
+ const ref = IDHandler.get(p_id);
+ if (!ref || !event.candidate) {
+ return;
+ }
+
+ const c = event.candidate;
+ const candidate_str = GodotRuntime.allocString(c.candidate);
+ const mid_str = GodotRuntime.allocString(c.sdpMid);
+ callback(mid_str, c.sdpMLineIndex, candidate_str);
+ GodotRuntime.free(candidate_str);
+ GodotRuntime.free(mid_str);
+ },
+
+ ondatachannel: function (p_id, callback, event) {
+ const ref = IDHandler.get(p_id);
+ if (!ref) {
+ return;
+ }
+
+ const cid = IDHandler.add(event.channel);
+ callback(cid);
+ },
+
+ onsession: function (p_id, callback, session) {
+ const ref = IDHandler.get(p_id);
+ if (!ref) {
+ return;
+ }
+ const type_str = GodotRuntime.allocString(session.type);
+ const sdp_str = GodotRuntime.allocString(session.sdp);
+ callback(type_str, sdp_str);
+ GodotRuntime.free(type_str);
+ GodotRuntime.free(sdp_str);
+ },
+
+ onerror: function (p_id, callback, error) {
+ const ref = IDHandler.get(p_id);
+ if (!ref) {
+ return;
+ }
+ GodotRuntime.error(error);
+ callback();
+ },
+ },
+
+ godot_js_rtc_pc_create__sig: 'iiiiii',
+ godot_js_rtc_pc_create: function (p_config, p_ref, p_on_state_change, p_on_candidate, p_on_datachannel) {
+ const onstatechange = GodotRuntime.get_func(p_on_state_change).bind(null, p_ref);
+ const oncandidate = GodotRuntime.get_func(p_on_candidate).bind(null, p_ref);
+ const ondatachannel = GodotRuntime.get_func(p_on_datachannel).bind(null, p_ref);
+
+ const config = JSON.parse(GodotRuntime.parseString(p_config));
+ let conn = null;
+ try {
+ conn = new RTCPeerConnection(config);
+ } catch (e) {
+ GodotRuntime.error(e);
+ return 0;
+ }
+
+ const base = GodotRTCPeerConnection;
+ const id = IDHandler.add(conn);
+ conn.oniceconnectionstatechange = base.onstatechange.bind(null, id, conn, onstatechange);
+ conn.onicecandidate = base.onicecandidate.bind(null, id, oncandidate);
+ conn.ondatachannel = base.ondatachannel.bind(null, id, ondatachannel);
+ return id;
+ },
+
+ godot_js_rtc_pc_close__sig: 'vi',
+ godot_js_rtc_pc_close: function (p_id) {
+ const ref = IDHandler.get(p_id);
+ if (!ref) {
+ return;
+ }
+ ref.close();
+ },
+
+ godot_js_rtc_pc_destroy__sig: 'vi',
+ godot_js_rtc_pc_destroy: function (p_id) {
+ const ref = IDHandler.get(p_id);
+ if (!ref) {
+ return;
+ }
+ ref.oniceconnectionstatechange = null;
+ ref.onicecandidate = null;
+ ref.ondatachannel = null;
+ IDHandler.remove(p_id);
+ },
+
+ godot_js_rtc_pc_offer_create__sig: 'viiii',
+ godot_js_rtc_pc_offer_create: function (p_id, p_obj, p_on_session, p_on_error) {
+ const ref = IDHandler.get(p_id);
+ if (!ref) {
+ return;
+ }
+ const onsession = GodotRuntime.get_func(p_on_session).bind(null, p_obj);
+ const onerror = GodotRuntime.get_func(p_on_error).bind(null, p_obj);
+ ref.createOffer().then(function (session) {
+ GodotRTCPeerConnection.onsession(p_id, onsession, session);
+ }).catch(function (error) {
+ GodotRTCPeerConnection.onerror(p_id, onerror, error);
+ });
+ },
+
+ godot_js_rtc_pc_local_description_set__sig: 'viiiii',
+ godot_js_rtc_pc_local_description_set: function (p_id, p_type, p_sdp, p_obj, p_on_error) {
+ const ref = IDHandler.get(p_id);
+ if (!ref) {
+ return;
+ }
+ const type = GodotRuntime.parseString(p_type);
+ const sdp = GodotRuntime.parseString(p_sdp);
+ const onerror = GodotRuntime.get_func(p_on_error).bind(null, p_obj);
+ ref.setLocalDescription({
+ 'sdp': sdp,
+ 'type': type,
+ }).catch(function (error) {
+ GodotRTCPeerConnection.onerror(p_id, onerror, error);
+ });
+ },
+
+ godot_js_rtc_pc_remote_description_set__sig: 'viiiiii',
+ godot_js_rtc_pc_remote_description_set: function (p_id, p_type, p_sdp, p_obj, p_session_created, p_on_error) {
+ const ref = IDHandler.get(p_id);
+ if (!ref) {
+ return;
+ }
+ const type = GodotRuntime.parseString(p_type);
+ const sdp = GodotRuntime.parseString(p_sdp);
+ const onerror = GodotRuntime.get_func(p_on_error).bind(null, p_obj);
+ const onsession = GodotRuntime.get_func(p_session_created).bind(null, p_obj);
+ ref.setRemoteDescription({
+ 'sdp': sdp,
+ 'type': type,
+ }).then(function () {
+ if (type !== 'offer') {
+ return Promise.resolve();
+ }
+ return ref.createAnswer().then(function (session) {
+ GodotRTCPeerConnection.onsession(p_id, onsession, session);
+ });
+ }).catch(function (error) {
+ GodotRTCPeerConnection.onerror(p_id, onerror, error);
+ });
+ },
+
+ godot_js_rtc_pc_ice_candidate_add__sig: 'viiii',
+ godot_js_rtc_pc_ice_candidate_add: function (p_id, p_mid_name, p_mline_idx, p_sdp) {
+ const ref = IDHandler.get(p_id);
+ if (!ref) {
+ return;
+ }
+ const sdpMidName = GodotRuntime.parseString(p_mid_name);
+ const sdpName = GodotRuntime.parseString(p_sdp);
+ ref.addIceCandidate(new RTCIceCandidate({
+ 'candidate': sdpName,
+ 'sdpMid': sdpMidName,
+ 'sdpMlineIndex': p_mline_idx,
+ }));
+ },
+
+ godot_js_rtc_pc_datachannel_create__deps: ['$GodotRTCDataChannel'],
+ godot_js_rtc_pc_datachannel_create__sig: 'iiii',
+ godot_js_rtc_pc_datachannel_create: function (p_id, p_label, p_config) {
+ try {
+ const ref = IDHandler.get(p_id);
+ if (!ref) {
+ return 0;
+ }
+
+ const label = GodotRuntime.parseString(p_label);
+ const config = JSON.parse(GodotRuntime.parseString(p_config));
+
+ const channel = ref.createDataChannel(label, config);
+ return IDHandler.add(channel);
+ } catch (e) {
+ GodotRuntime.error(e);
+ return 0;
+ }
+ },
+};
+
+autoAddDeps(GodotRTCPeerConnection, '$GodotRTCPeerConnection');
+mergeInto(LibraryManager.library, GodotRTCPeerConnection);
diff --git a/modules/webrtc/register_types.cpp b/modules/webrtc/register_types.cpp
index 5b296b1ac6..ecfaed9089 100644
--- a/modules/webrtc/register_types.cpp
+++ b/modules/webrtc/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,7 +29,7 @@
/*************************************************************************/
#include "register_types.h"
-#include "core/project_settings.h"
+#include "core/config/project_settings.h"
#include "webrtc_data_channel.h"
#include "webrtc_peer_connection.h"
diff --git a/modules/webrtc/register_types.h b/modules/webrtc/register_types.h
index 8f5b9e8452..710ee88a28 100644
--- a/modules/webrtc/register_types.h
+++ b/modules/webrtc/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/webrtc/webrtc_data_channel.cpp b/modules/webrtc/webrtc_data_channel.cpp
index 7566532982..004112f992 100644
--- a/modules/webrtc/webrtc_data_channel.cpp
+++ b/modules/webrtc/webrtc_data_channel.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,7 +29,7 @@
/*************************************************************************/
#include "webrtc_data_channel.h"
-#include "core/project_settings.h"
+#include "core/config/project_settings.h"
void WebRTCDataChannel::_bind_methods() {
ClassDB::bind_method(D_METHOD("poll"), &WebRTCDataChannel::poll);
diff --git a/modules/webrtc/webrtc_data_channel.h b/modules/webrtc/webrtc_data_channel.h
index 1407f1e3bd..20affc513f 100644
--- a/modules/webrtc/webrtc_data_channel.h
+++ b/modules/webrtc/webrtc_data_channel.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/webrtc/webrtc_data_channel_gdnative.cpp b/modules/webrtc/webrtc_data_channel_gdnative.cpp
index 67ad2c07ce..d4cf464c7c 100644
--- a/modules/webrtc/webrtc_data_channel_gdnative.cpp
+++ b/modules/webrtc/webrtc_data_channel_gdnative.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/webrtc/webrtc_data_channel_gdnative.h b/modules/webrtc/webrtc_data_channel_gdnative.h
index 03396d207d..7e02a32046 100644
--- a/modules/webrtc/webrtc_data_channel_gdnative.h
+++ b/modules/webrtc/webrtc_data_channel_gdnative.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/webrtc/webrtc_data_channel_js.cpp b/modules/webrtc/webrtc_data_channel_js.cpp
index 2c648ba9f9..9f2b084cb1 100644
--- a/modules/webrtc/webrtc_data_channel_js.cpp
+++ b/modules/webrtc/webrtc_data_channel_js.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,65 +34,58 @@
#include "emscripten.h"
extern "C" {
-EMSCRIPTEN_KEEPALIVE void _emrtc_on_ch_error(void *obj) {
- WebRTCDataChannelJS *peer = static_cast<WebRTCDataChannelJS *>(obj);
- peer->_on_error();
-}
+typedef void (*RTCChOnOpen)(void *p_obj);
+typedef void (*RTCChOnMessage)(void *p_obj, const uint8_t *p_buffer, int p_size, int p_is_string);
+typedef void (*RTCChOnClose)(void *p_obj);
+typedef void (*RTCChOnError)(void *p_obj);
-EMSCRIPTEN_KEEPALIVE void _emrtc_on_ch_open(void *obj) {
- WebRTCDataChannelJS *peer = static_cast<WebRTCDataChannelJS *>(obj);
- peer->_on_open();
+extern int godot_js_rtc_datachannel_ready_state_get(int p_id);
+extern int godot_js_rtc_datachannel_send(int p_id, const uint8_t *p_buffer, int p_length, int p_raw);
+extern int godot_js_rtc_datachannel_is_ordered(int p_id);
+extern int godot_js_rtc_datachannel_id_get(int p_id);
+extern int godot_js_rtc_datachannel_max_packet_lifetime_get(int p_id);
+extern int godot_js_rtc_datachannel_max_retransmits_get(int p_id);
+extern int godot_js_rtc_datachannel_is_negotiated(int p_id);
+extern char *godot_js_rtc_datachannel_label_get(int p_id); // Must free the returned string.
+extern char *godot_js_rtc_datachannel_protocol_get(int p_id); // Must free the returned string.
+extern void godot_js_rtc_datachannel_destroy(int p_id);
+extern void godot_js_rtc_datachannel_connect(int p_id, void *p_obj, RTCChOnOpen p_on_open, RTCChOnMessage p_on_message, RTCChOnError p_on_error, RTCChOnClose p_on_close);
+extern void godot_js_rtc_datachannel_close(int p_id);
}
-EMSCRIPTEN_KEEPALIVE void _emrtc_on_ch_close(void *obj) {
- WebRTCDataChannelJS *peer = static_cast<WebRTCDataChannelJS *>(obj);
- peer->_on_close();
+void WebRTCDataChannelJS::_on_open(void *p_obj) {
+ WebRTCDataChannelJS *peer = static_cast<WebRTCDataChannelJS *>(p_obj);
+ peer->in_buffer.resize(peer->_in_buffer_shift);
}
-EMSCRIPTEN_KEEPALIVE void _emrtc_on_ch_message(void *obj, uint8_t *p_data, uint32_t p_size, bool p_is_string) {
- WebRTCDataChannelJS *peer = static_cast<WebRTCDataChannelJS *>(obj);
- peer->_on_message(p_data, p_size, p_is_string);
-}
+void WebRTCDataChannelJS::_on_close(void *p_obj) {
+ WebRTCDataChannelJS *peer = static_cast<WebRTCDataChannelJS *>(p_obj);
+ peer->close();
}
-void WebRTCDataChannelJS::_on_open() {
- in_buffer.resize(_in_buffer_shift);
+void WebRTCDataChannelJS::_on_error(void *p_obj) {
+ WebRTCDataChannelJS *peer = static_cast<WebRTCDataChannelJS *>(p_obj);
+ peer->close();
}
-void WebRTCDataChannelJS::_on_close() {
- close();
-}
+void WebRTCDataChannelJS::_on_message(void *p_obj, const uint8_t *p_data, int p_size, int p_is_string) {
+ WebRTCDataChannelJS *peer = static_cast<WebRTCDataChannelJS *>(p_obj);
+ RingBuffer<uint8_t> &in_buffer = peer->in_buffer;
-void WebRTCDataChannelJS::_on_error() {
- close();
-}
-
-void WebRTCDataChannelJS::_on_message(uint8_t *p_data, uint32_t p_size, bool p_is_string) {
ERR_FAIL_COND_MSG(in_buffer.space_left() < (int)(p_size + 5), "Buffer full! Dropping data.");
uint8_t is_string = p_is_string ? 1 : 0;
in_buffer.write((uint8_t *)&p_size, 4);
in_buffer.write((uint8_t *)&is_string, 1);
in_buffer.write(p_data, p_size);
- queue_count++;
+ peer->queue_count++;
}
void WebRTCDataChannelJS::close() {
in_buffer.resize(0);
queue_count = 0;
_was_string = false;
- /* clang-format off */
- EM_ASM({
- var dict = Module.IDHandler.get($0);
- if (!dict) return;
- var channel = dict["channel"];
- channel.onopen = null;
- channel.onclose = null;
- channel.onerror = null;
- channel.onmessage = null;
- channel.close();
- }, _js_id);
- /* clang-format on */
+ godot_js_rtc_datachannel_close(_js_id);
}
Error WebRTCDataChannelJS::poll() {
@@ -100,24 +93,7 @@ Error WebRTCDataChannelJS::poll() {
}
WebRTCDataChannelJS::ChannelState WebRTCDataChannelJS::get_ready_state() const {
- /* clang-format off */
- return (ChannelState) EM_ASM_INT({
- var dict = Module.IDHandler.get($0);
- if (!dict) return 3; // CLOSED
- var channel = dict["channel"];
- switch(channel.readyState) {
- case "connecting":
- return 0;
- case "open":
- return 1;
- case "closing":
- return 2;
- case "closed":
- return 3;
- }
- return 3; // CLOSED
- }, _js_id);
- /* clang-format on */
+ return (ChannelState)godot_js_rtc_datachannel_ready_state_get(_js_id);
}
int WebRTCDataChannelJS::get_available_packet_count() const {
@@ -157,27 +133,7 @@ Error WebRTCDataChannelJS::put_packet(const uint8_t *p_buffer, int p_buffer_size
ERR_FAIL_COND_V(get_ready_state() != STATE_OPEN, ERR_UNCONFIGURED);
int is_bin = _write_mode == WebRTCDataChannel::WRITE_MODE_BINARY ? 1 : 0;
-
- /* clang-format off */
- EM_ASM({
- var dict = Module.IDHandler.get($0);
- var channel = dict["channel"];
- var bytes_array = new Uint8Array($2);
- var i = 0;
-
- for(i=0; i<$2; i++) {
- bytes_array[i] = getValue($1+i, 'i8');
- }
-
- if ($3) {
- channel.send(bytes_array.buffer);
- } else {
- var string = new TextDecoder("utf-8").decode(bytes_array);
- channel.send(string);
- }
- }, _js_id, p_buffer, p_buffer_size, is_bin);
- /* clang-format on */
-
+ godot_js_rtc_datachannel_send(_js_id, p_buffer, p_buffer_size, is_bin);
return OK;
}
@@ -201,46 +157,20 @@ String WebRTCDataChannelJS::get_label() const {
return _label;
}
-/* clang-format off */
-#define _JS_GET(PROP, DEF) \
-EM_ASM_INT({ \
- var dict = Module.IDHandler.get($0); \
- if (!dict || !dict["channel"]) { \
- return DEF; \
- } \
- var out = dict["channel"].PROP; \
- return out === null ? DEF : out; \
-}, _js_id)
-/* clang-format on */
-
bool WebRTCDataChannelJS::is_ordered() const {
- return _JS_GET(ordered, true);
+ return godot_js_rtc_datachannel_is_ordered(_js_id);
}
int WebRTCDataChannelJS::get_id() const {
- return _JS_GET(id, 65535);
+ return godot_js_rtc_datachannel_id_get(_js_id);
}
int WebRTCDataChannelJS::get_max_packet_life_time() const {
- // Can't use macro, webkit workaround.
- /* clang-format off */
- return EM_ASM_INT({
- var dict = Module.IDHandler.get($0);
- if (!dict || !dict["channel"]) {
- return 65535;
- }
- if (dict["channel"].maxRetransmitTime !== undefined) {
- // Guess someone didn't appreciate the standardization process.
- return dict["channel"].maxRetransmitTime;
- }
- var out = dict["channel"].maxPacketLifeTime;
- return out === null ? 65535 : out;
- }, _js_id);
- /* clang-format on */
+ return godot_js_rtc_datachannel_max_packet_lifetime_get(_js_id);
}
int WebRTCDataChannelJS::get_max_retransmits() const {
- return _JS_GET(maxRetransmits, 65535);
+ return godot_js_rtc_datachannel_max_retransmits_get(_js_id);
}
String WebRTCDataChannelJS::get_protocol() const {
@@ -248,7 +178,7 @@ String WebRTCDataChannelJS::get_protocol() const {
}
bool WebRTCDataChannelJS::is_negotiated() const {
- return _JS_GET(negotiated, false);
+ return godot_js_rtc_datachannel_is_negotiated(_js_id);
}
WebRTCDataChannelJS::WebRTCDataChannelJS() {
@@ -264,101 +194,22 @@ WebRTCDataChannelJS::WebRTCDataChannelJS(int js_id) {
_write_mode = WRITE_MODE_BINARY;
_js_id = js_id;
- /* clang-format off */
- EM_ASM({
- var c_ptr = $0;
- var dict = Module.IDHandler.get($1);
- if (!dict) return;
- var channel = dict["channel"];
- dict["ptr"] = c_ptr;
-
- channel.binaryType = "arraybuffer";
- channel.onopen = function (evt) {
- ccall("_emrtc_on_ch_open",
- "void",
- ["number"],
- [c_ptr]
- );
- };
- channel.onclose = function (evt) {
- ccall("_emrtc_on_ch_close",
- "void",
- ["number"],
- [c_ptr]
- );
- };
- channel.onerror = function (evt) {
- ccall("_emrtc_on_ch_error",
- "void",
- ["number"],
- [c_ptr]
- );
- };
- channel.onmessage = function(event) {
- var buffer;
- var is_string = 0;
- if (event.data instanceof ArrayBuffer) {
- buffer = new Uint8Array(event.data);
- } else if (event.data instanceof Blob) {
- console.error("Blob type not supported");
- return;
- } else if (typeof event.data === "string") {
- is_string = 1;
- var enc = new TextEncoder("utf-8");
- buffer = new Uint8Array(enc.encode(event.data));
- } else {
- console.error("Unknown message type");
- return;
- }
- var len = buffer.length*buffer.BYTES_PER_ELEMENT;
- var out = _malloc(len);
- HEAPU8.set(buffer, out);
- ccall("_emrtc_on_ch_message",
- "void",
- ["number", "number", "number", "number"],
- [c_ptr, out, len, is_string]
- );
- _free(out);
- }
-
- }, this, js_id);
+ godot_js_rtc_datachannel_connect(js_id, this, &_on_open, &_on_message, &_on_error, &_on_close);
// Parse label
- char *str;
- str = (char *)EM_ASM_INT({
- var dict = Module.IDHandler.get($0);
- if (!dict || !dict["channel"]) return 0;
- var str = dict["channel"].label;
- var len = lengthBytesUTF8(str)+1;
- var ptr = _malloc(str);
- stringToUTF8(str, ptr, len+1);
- return ptr;
- }, js_id);
- if(str != nullptr) {
- _label.parse_utf8(str);
- EM_ASM({ _free($0) }, str);
+ char *label = godot_js_rtc_datachannel_label_get(js_id);
+ if (label) {
+ _label.parse_utf8(label);
+ free(label);
}
- str = (char *)EM_ASM_INT({
- var dict = Module.IDHandler.get($0);
- if (!dict || !dict["channel"]) return 0;
- var str = dict["channel"].protocol;
- var len = lengthBytesUTF8(str)+1;
- var ptr = _malloc(str);
- stringToUTF8(str, ptr, len+1);
- return ptr;
- }, js_id);
- if(str != nullptr) {
- _protocol.parse_utf8(str);
- EM_ASM({ _free($0) }, str);
+ char *protocol = godot_js_rtc_datachannel_protocol_get(js_id);
+ if (protocol) {
+ _protocol.parse_utf8(protocol);
+ free(protocol);
}
- /* clang-format on */
}
WebRTCDataChannelJS::~WebRTCDataChannelJS() {
close();
- /* clang-format off */
- EM_ASM({
- Module.IDHandler.remove($0);
- }, _js_id);
- /* clang-format on */
-};
+ godot_js_rtc_datachannel_destroy(_js_id);
+}
#endif
diff --git a/modules/webrtc/webrtc_data_channel_js.h b/modules/webrtc/webrtc_data_channel_js.h
index 7545910e66..8c56b62303 100644
--- a/modules/webrtc/webrtc_data_channel_js.h
+++ b/modules/webrtc/webrtc_data_channel_js.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -54,12 +54,12 @@ private:
int queue_count;
uint8_t packet_buffer[PACKET_BUFFER_SIZE];
-public:
- void _on_open();
- void _on_close();
- void _on_error();
- void _on_message(uint8_t *p_data, uint32_t p_size, bool p_is_string);
+ static void _on_open(void *p_obj);
+ static void _on_close(void *p_obj);
+ static void _on_error(void *p_obj);
+ static void _on_message(void *p_obj, const uint8_t *p_data, int p_size, int p_is_string);
+public:
virtual void set_write_mode(WriteMode mode) override;
virtual WriteMode get_write_mode() const override;
virtual bool was_string_packet() const override;
diff --git a/modules/webrtc/webrtc_multiplayer.cpp b/modules/webrtc/webrtc_multiplayer.cpp
index e0c0cad68c..741cad5640 100644
--- a/modules/webrtc/webrtc_multiplayer.cpp
+++ b/modules/webrtc/webrtc_multiplayer.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/webrtc/webrtc_multiplayer.h b/modules/webrtc/webrtc_multiplayer.h
index fb37bd7722..6b4ae6fcc8 100644
--- a/modules/webrtc/webrtc_multiplayer.h
+++ b/modules/webrtc/webrtc_multiplayer.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/webrtc/webrtc_peer_connection.cpp b/modules/webrtc/webrtc_peer_connection.cpp
index 670924bca2..3e2938bf7d 100644
--- a/modules/webrtc/webrtc_peer_connection.cpp
+++ b/modules/webrtc/webrtc_peer_connection.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/webrtc/webrtc_peer_connection.h b/modules/webrtc/webrtc_peer_connection.h
index 7366c3d0e8..ae75864489 100644
--- a/modules/webrtc/webrtc_peer_connection.h
+++ b/modules/webrtc/webrtc_peer_connection.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/webrtc/webrtc_peer_connection_gdnative.cpp b/modules/webrtc/webrtc_peer_connection_gdnative.cpp
index aaa45d3a54..dcf78dfb73 100644
--- a/modules/webrtc/webrtc_peer_connection_gdnative.cpp
+++ b/modules/webrtc/webrtc_peer_connection_gdnative.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/webrtc/webrtc_peer_connection_gdnative.h b/modules/webrtc/webrtc_peer_connection_gdnative.h
index 846b65c466..578af0202f 100644
--- a/modules/webrtc/webrtc_peer_connection_gdnative.h
+++ b/modules/webrtc/webrtc_peer_connection_gdnative.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/webrtc/webrtc_peer_connection_js.cpp b/modules/webrtc/webrtc_peer_connection_js.cpp
index 593c3a5162..8879f7d6ec 100644
--- a/modules/webrtc/webrtc_peer_connection_js.cpp
+++ b/modules/webrtc/webrtc_peer_connection_js.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -37,116 +37,32 @@
#include "core/io/json.h"
#include "emscripten.h"
-extern "C" {
-EMSCRIPTEN_KEEPALIVE void _emrtc_on_ice_candidate(void *obj, char *p_MidName, int p_MlineIndexName, char *p_sdpName) {
- WebRTCPeerConnectionJS *peer = static_cast<WebRTCPeerConnectionJS *>(obj);
- peer->emit_signal("ice_candidate_created", String(p_MidName), p_MlineIndexName, String(p_sdpName));
+void WebRTCPeerConnectionJS::_on_ice_candidate(void *p_obj, const char *p_mid_name, int p_mline_idx, const char *p_candidate) {
+ WebRTCPeerConnectionJS *peer = static_cast<WebRTCPeerConnectionJS *>(p_obj);
+ peer->emit_signal("ice_candidate_created", String(p_mid_name), p_mline_idx, String(p_candidate));
}
-EMSCRIPTEN_KEEPALIVE void _emrtc_session_description_created(void *obj, char *p_type, char *p_offer) {
- WebRTCPeerConnectionJS *peer = static_cast<WebRTCPeerConnectionJS *>(obj);
- peer->emit_signal("session_description_created", String(p_type), String(p_offer));
+void WebRTCPeerConnectionJS::_on_session_created(void *p_obj, const char *p_type, const char *p_session) {
+ WebRTCPeerConnectionJS *peer = static_cast<WebRTCPeerConnectionJS *>(p_obj);
+ peer->emit_signal("session_description_created", String(p_type), String(p_session));
}
-EMSCRIPTEN_KEEPALIVE void _emrtc_on_connection_state_changed(void *obj) {
- WebRTCPeerConnectionJS *peer = static_cast<WebRTCPeerConnectionJS *>(obj);
- peer->_on_connection_state_changed();
+void WebRTCPeerConnectionJS::_on_connection_state_changed(void *p_obj, int p_state) {
+ WebRTCPeerConnectionJS *peer = static_cast<WebRTCPeerConnectionJS *>(p_obj);
+ peer->_conn_state = (ConnectionState)p_state;
}
-EMSCRIPTEN_KEEPALIVE void _emrtc_on_error() {
+void WebRTCPeerConnectionJS::_on_error(void *p_obj) {
ERR_PRINT("RTCPeerConnection error!");
}
-EMSCRIPTEN_KEEPALIVE void _emrtc_emit_channel(void *obj, int p_id) {
- WebRTCPeerConnectionJS *peer = static_cast<WebRTCPeerConnectionJS *>(obj);
+void WebRTCPeerConnectionJS::_on_data_channel(void *p_obj, int p_id) {
+ WebRTCPeerConnectionJS *peer = static_cast<WebRTCPeerConnectionJS *>(p_obj);
peer->emit_signal("data_channel_received", Ref<WebRTCDataChannelJS>(new WebRTCDataChannelJS(p_id)));
}
-}
-
-void _emrtc_create_pc(int p_id, const Dictionary &p_config) {
- String config = JSON::print(p_config);
- /* clang-format off */
- EM_ASM({
- var dict = Module.IDHandler.get($0);
- var c_ptr = dict["ptr"];
- var config = JSON.parse(UTF8ToString($1));
- // Setup local connaction
- var conn = null;
- try {
- conn = new RTCPeerConnection(config);
- } catch (e) {
- console.log(e);
- return;
- }
- conn.oniceconnectionstatechange = function(event) {
- if (!Module.IDHandler.get($0)) return;
- ccall("_emrtc_on_connection_state_changed", "void", ["number"], [c_ptr]);
- };
- conn.onicecandidate = function(event) {
- if (!Module.IDHandler.get($0)) return;
- if (!event.candidate) return;
-
- var c = event.candidate;
- // should emit on ice candidate
- ccall("_emrtc_on_ice_candidate",
- "void",
- ["number", "string", "number", "string"],
- [c_ptr, c.sdpMid, c.sdpMLineIndex, c.candidate]
- );
- };
- conn.ondatachannel = function (evt) {
- var dict = Module.IDHandler.get($0);
- if (!dict) {
- return;
- }
- var id = Module.IDHandler.add({"channel": evt.channel, "ptr": null});
- ccall("_emrtc_emit_channel",
- "void",
- ["number", "number"],
- [c_ptr, id]
- );
- };
- dict["conn"] = conn;
- }, p_id, config.utf8().get_data());
- /* clang-format on */
-}
-
-void WebRTCPeerConnectionJS::_on_connection_state_changed() {
- /* clang-format off */
- _conn_state = (ConnectionState)EM_ASM_INT({
- var dict = Module.IDHandler.get($0);
- if (!dict) return 5; // CLOSED
- var conn = dict["conn"];
- switch(conn.iceConnectionState) {
- case "new":
- return 0;
- case "checking":
- return 1;
- case "connected":
- case "completed":
- return 2;
- case "disconnected":
- return 3;
- case "failed":
- return 4;
- case "closed":
- return 5;
- }
- return 5; // CLOSED
- }, _js_id);
- /* clang-format on */
-}
void WebRTCPeerConnectionJS::close() {
- /* clang-format off */
- EM_ASM({
- var dict = Module.IDHandler.get($0);
- if (!dict) return;
- if (dict["conn"]) {
- dict["conn"].close();
- }
- }, _js_id);
- /* clang-format on */
+ godot_js_rtc_pc_close(_js_id);
_conn_state = STATE_CLOSED;
}
@@ -154,46 +70,12 @@ Error WebRTCPeerConnectionJS::create_offer() {
ERR_FAIL_COND_V(_conn_state != STATE_NEW, FAILED);
_conn_state = STATE_CONNECTING;
- /* clang-format off */
- EM_ASM({
- var dict = Module.IDHandler.get($0);
- var conn = dict["conn"];
- var c_ptr = dict["ptr"];
- var onError = function(error) {
- console.error(error);
- ccall("_emrtc_on_error", "void", [], []);
- };
- var onCreated = function(offer) {
- ccall("_emrtc_session_description_created",
- "void",
- ["number", "string", "string"],
- [c_ptr, offer.type, offer.sdp]
- );
- };
- conn.createOffer().then(onCreated).catch(onError);
- }, _js_id);
- /* clang-format on */
+ godot_js_rtc_pc_offer_create(_js_id, this, &_on_session_created, &_on_error);
return OK;
}
Error WebRTCPeerConnectionJS::set_local_description(String type, String sdp) {
- /* clang-format off */
- EM_ASM({
- var dict = Module.IDHandler.get($0);
- var conn = dict["conn"];
- var c_ptr = dict["ptr"];
- var type = UTF8ToString($1);
- var sdp = UTF8ToString($2);
- var onError = function(error) {
- console.error(error);
- ccall("_emrtc_on_error", "void", [], []);
- };
- conn.setLocalDescription({
- "sdp": sdp,
- "type": type
- }).catch(onError);
- }, _js_id, type.utf8().get_data(), sdp.utf8().get_data());
- /* clang-format on */
+ godot_js_rtc_pc_local_description_set(_js_id, type.utf8().get_data(), sdp.utf8().get_data(), this, &_on_error);
return OK;
}
@@ -202,83 +84,32 @@ Error WebRTCPeerConnectionJS::set_remote_description(String type, String sdp) {
ERR_FAIL_COND_V(_conn_state != STATE_NEW, FAILED);
_conn_state = STATE_CONNECTING;
}
- /* clang-format off */
- EM_ASM({
- var dict = Module.IDHandler.get($0);
- var conn = dict["conn"];
- var c_ptr = dict["ptr"];
- var type = UTF8ToString($1);
- var sdp = UTF8ToString($2);
-
- var onError = function(error) {
- console.error(error);
- ccall("_emrtc_on_error", "void", [], []);
- };
- var onCreated = function(offer) {
- ccall("_emrtc_session_description_created",
- "void",
- ["number", "string", "string"],
- [c_ptr, offer.type, offer.sdp]
- );
- };
- var onSet = function() {
- if (type != "offer") {
- return;
- }
- conn.createAnswer().then(onCreated);
- };
- conn.setRemoteDescription({
- "sdp": sdp,
- "type": type
- }).then(onSet).catch(onError);
- }, _js_id, type.utf8().get_data(), sdp.utf8().get_data());
- /* clang-format on */
+ godot_js_rtc_pc_remote_description_set(_js_id, type.utf8().get_data(), sdp.utf8().get_data(), this, &_on_session_created, &_on_error);
return OK;
}
Error WebRTCPeerConnectionJS::add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName) {
- /* clang-format off */
- EM_ASM({
- var dict = Module.IDHandler.get($0);
- var conn = dict["conn"];
- var c_ptr = dict["ptr"];
- var sdpMidName = UTF8ToString($1);
- var sdpMlineIndexName = UTF8ToString($2);
- var sdpName = UTF8ToString($3);
- conn.addIceCandidate(new RTCIceCandidate({
- "candidate": sdpName,
- "sdpMid": sdpMidName,
- "sdpMlineIndex": sdpMlineIndexName
- }));
- }, _js_id, sdpMidName.utf8().get_data(), sdpMlineIndexName, sdpName.utf8().get_data());
- /* clang-format on */
+ godot_js_rtc_pc_ice_candidate_add(_js_id, sdpMidName.utf8().get_data(), sdpMlineIndexName, sdpName.utf8().get_data());
return OK;
}
Error WebRTCPeerConnectionJS::initialize(Dictionary p_config) {
- _emrtc_create_pc(_js_id, p_config);
- return OK;
+ if (_js_id) {
+ godot_js_rtc_pc_destroy(_js_id);
+ _js_id = 0;
+ }
+ _conn_state = STATE_NEW;
+
+ String config = JSON::print(p_config);
+ _js_id = godot_js_rtc_pc_create(config.utf8().get_data(), this, &_on_connection_state_changed, &_on_ice_candidate, &_on_data_channel);
+ return _js_id ? OK : FAILED;
}
Ref<WebRTCDataChannel> WebRTCPeerConnectionJS::create_data_channel(String p_channel, Dictionary p_channel_config) {
+ ERR_FAIL_COND_V(_conn_state != STATE_NEW, nullptr);
+
String config = JSON::print(p_channel_config);
- /* clang-format off */
- int id = EM_ASM_INT({
- try {
- var dict = Module.IDHandler.get($0);
- if (!dict) return 0;
- var label = UTF8ToString($1);
- var config = JSON.parse(UTF8ToString($2));
- var conn = dict["conn"];
- return Module.IDHandler.add({
- "channel": conn.createDataChannel(label, config),
- "ptr": null
- })
- } catch (e) {
- return 0;
- }
- }, _js_id, p_channel.utf8().get_data(), config.utf8().get_data());
- /* clang-format on */
+ int id = godot_js_rtc_pc_datachannel_create(_js_id, p_channel.utf8().get_data(), config.utf8().get_data());
ERR_FAIL_COND_V(id == 0, nullptr);
return memnew(WebRTCDataChannelJS(id));
}
@@ -293,22 +124,17 @@ WebRTCPeerConnection::ConnectionState WebRTCPeerConnectionJS::get_connection_sta
WebRTCPeerConnectionJS::WebRTCPeerConnectionJS() {
_conn_state = STATE_NEW;
+ _js_id = 0;
- /* clang-format off */
- _js_id = EM_ASM_INT({
- return Module.IDHandler.add({"conn": null, "ptr": $0});
- }, this);
- /* clang-format on */
Dictionary config;
- _emrtc_create_pc(_js_id, config);
+ initialize(config);
}
WebRTCPeerConnectionJS::~WebRTCPeerConnectionJS() {
close();
- /* clang-format off */
- EM_ASM({
- Module.IDHandler.remove($0);
- }, _js_id);
- /* clang-format on */
+ if (_js_id) {
+ godot_js_rtc_pc_destroy(_js_id);
+ _js_id = 0;
+ }
};
#endif
diff --git a/modules/webrtc/webrtc_peer_connection_js.h b/modules/webrtc/webrtc_peer_connection_js.h
index cdaf3068e3..0272e67f6f 100644
--- a/modules/webrtc/webrtc_peer_connection_js.h
+++ b/modules/webrtc/webrtc_peer_connection_js.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,16 +35,37 @@
#include "webrtc_peer_connection.h"
+extern "C" {
+typedef void (*RTCOnIceConnectionStateChange)(void *p_obj, int p_state);
+typedef void (*RTCOnIceCandidate)(void *p_obj, const char *p_mid, int p_mline_idx, const char *p_candidate);
+typedef void (*RTCOnDataChannel)(void *p_obj, int p_id);
+typedef void (*RTCOnSession)(void *p_obj, const char *p_type, const char *p_sdp);
+typedef void (*RTCOnError)(void *p_obj);
+extern int godot_js_rtc_pc_create(const char *p_config, void *p_obj, RTCOnIceConnectionStateChange p_on_state_change, RTCOnIceCandidate p_on_candidate, RTCOnDataChannel p_on_datachannel);
+extern void godot_js_rtc_pc_close(int p_id);
+extern void godot_js_rtc_pc_destroy(int p_id);
+extern void godot_js_rtc_pc_offer_create(int p_id, void *p_obj, RTCOnSession p_on_session, RTCOnError p_on_error);
+extern void godot_js_rtc_pc_local_description_set(int p_id, const char *p_type, const char *p_sdp, void *p_obj, RTCOnError p_on_error);
+extern void godot_js_rtc_pc_remote_description_set(int p_id, const char *p_type, const char *p_sdp, void *p_obj, RTCOnSession p_on_session, RTCOnError p_on_error);
+extern void godot_js_rtc_pc_ice_candidate_add(int p_id, const char *p_mid_name, int p_mline_idx, const char *p_sdo);
+extern int godot_js_rtc_pc_datachannel_create(int p_id, const char *p_label, const char *p_config);
+}
+
class WebRTCPeerConnectionJS : public WebRTCPeerConnection {
private:
int _js_id;
ConnectionState _conn_state;
+ static void _on_connection_state_changed(void *p_obj, int p_state);
+ static void _on_ice_candidate(void *p_obj, const char *p_mid_name, int p_mline_idx, const char *p_candidate);
+ static void _on_data_channel(void *p_obj, int p_channel);
+ static void _on_session_created(void *p_obj, const char *p_type, const char *p_session);
+ static void _on_error(void *p_obj);
+
public:
static WebRTCPeerConnection *_create() { return memnew(WebRTCPeerConnectionJS); }
static void make_default() { WebRTCPeerConnection::_create = WebRTCPeerConnectionJS::_create; }
- void _on_connection_state_changed();
virtual ConnectionState get_connection_state() const;
virtual Error initialize(Dictionary configuration = Dictionary());
diff --git a/modules/websocket/SCsub b/modules/websocket/SCsub
index af60055855..4c022c43cf 100644
--- a/modules/websocket/SCsub
+++ b/modules/websocket/SCsub
@@ -3,28 +3,46 @@
Import("env")
Import("env_modules")
-# Thirdparty source files
-
env_ws = env_modules.Clone()
-if env["builtin_wslay"] and not env["platform"] == "javascript": # already builtin for javascript
- wslay_dir = "#thirdparty/wslay/"
- wslay_sources = [
+thirdparty_obj = []
+
+if env["platform"] == "javascript":
+ # Our JavaScript/C++ interface.
+ env.AddJSLibraries(["library_godot_websocket.js"])
+
+elif env["builtin_wslay"]:
+ # Thirdparty source files
+ thirdparty_dir = "#thirdparty/wslay/"
+ thirdparty_sources = [
"wslay_net.c",
"wslay_event.c",
"wslay_queue.c",
"wslay_stack.c",
"wslay_frame.c",
]
- wslay_sources = [wslay_dir + s for s in wslay_sources]
- env_ws.Prepend(CPPPATH=[wslay_dir + "includes/"])
+ thirdparty_sources = [thirdparty_dir + s for s in thirdparty_sources]
+
+ env_ws.Prepend(CPPPATH=[thirdparty_dir + "includes/"])
env_ws.Append(CPPDEFINES=["HAVE_CONFIG_H"])
+
if env["platform"] == "windows" or env["platform"] == "uwp":
env_ws.Append(CPPDEFINES=["HAVE_WINSOCK2_H"])
else:
env_ws.Append(CPPDEFINES=["HAVE_NETINET_IN_H"])
- env_wslay = env_ws.Clone()
- env_wslay.disable_warnings()
- env_wslay.add_source_files(env.modules_sources, wslay_sources)
-env_ws.add_source_files(env.modules_sources, "*.cpp")
+ env_thirdparty = env_ws.Clone()
+ env_thirdparty.disable_warnings()
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
+
+# Godot source files
+
+module_obj = []
+
+env_ws.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/websocket/editor_debugger_server_websocket.cpp b/modules/websocket/editor_debugger_server_websocket.cpp
index 95ea7ceafa..b02d212c42 100644
--- a/modules/websocket/editor_debugger_server_websocket.cpp
+++ b/modules/websocket/editor_debugger_server_websocket.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,7 +30,7 @@
#include "editor_debugger_server_websocket.h"
-#include "core/project_settings.h"
+#include "core/config/project_settings.h"
#include "editor/editor_settings.h"
#include "modules/websocket/remote_debugger_peer_websocket.h"
diff --git a/modules/websocket/editor_debugger_server_websocket.h b/modules/websocket/editor_debugger_server_websocket.h
index 861f389aab..2f73b98c3d 100644
--- a/modules/websocket/editor_debugger_server_websocket.h
+++ b/modules/websocket/editor_debugger_server_websocket.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/websocket/emws_client.cpp b/modules/websocket/emws_client.cpp
index 7c31449709..aec01a1eea 100644
--- a/modules/websocket/emws_client.cpp
+++ b/modules/websocket/emws_client.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,18 +31,17 @@
#ifdef JAVASCRIPT_ENABLED
#include "emws_client.h"
+#include "core/config/project_settings.h"
#include "core/io/ip.h"
-#include "core/project_settings.h"
#include "emscripten.h"
-extern "C" {
-EMSCRIPTEN_KEEPALIVE void _esws_on_connect(void *obj, char *proto) {
+void EMWSClient::_esws_on_connect(void *obj, char *proto) {
EMWSClient *client = static_cast<EMWSClient *>(obj);
client->_is_connecting = false;
client->_on_connect(String(proto));
}
-EMSCRIPTEN_KEEPALIVE void _esws_on_message(void *obj, uint8_t *p_data, int p_data_size, int p_is_string) {
+void EMWSClient::_esws_on_message(void *obj, const uint8_t *p_data, int p_data_size, int p_is_string) {
EMWSClient *client = static_cast<EMWSClient *>(obj);
Error err = static_cast<EMWSPeer *>(*client->get_peer(1))->read_msg(p_data, p_data_size, p_is_string == 1);
@@ -50,21 +49,26 @@ EMSCRIPTEN_KEEPALIVE void _esws_on_message(void *obj, uint8_t *p_data, int p_dat
client->_on_peer_packet();
}
-EMSCRIPTEN_KEEPALIVE void _esws_on_error(void *obj) {
+void EMWSClient::_esws_on_error(void *obj) {
EMWSClient *client = static_cast<EMWSClient *>(obj);
client->_is_connecting = false;
client->_on_error();
}
-EMSCRIPTEN_KEEPALIVE void _esws_on_close(void *obj, int code, char *reason, int was_clean) {
+void EMWSClient::_esws_on_close(void *obj, int code, const char *reason, int was_clean) {
EMWSClient *client = static_cast<EMWSClient *>(obj);
client->_on_close_request(code, String(reason));
client->_is_connecting = false;
+ client->disconnect_from_host();
client->_on_disconnect(was_clean != 0);
}
-}
Error EMWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const Vector<String> p_protocols, const Vector<String> p_custom_headers) {
+ if (_js_id) {
+ godot_js_websocket_destroy(_js_id);
+ _js_id = 0;
+ }
+
String proto_string;
for (int i = 0; i < p_protocols.size(); i++) {
if (i != 0)
@@ -84,106 +88,17 @@ Error EMWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port,
}
}
str += p_host + ":" + itos(p_port) + p_path;
-
_is_connecting = true;
- /* clang-format off */
- int peer_sock = EM_ASM_INT({
- var proto_str = UTF8ToString($2);
- var socket = null;
- try {
- if (proto_str) {
- socket = new WebSocket(UTF8ToString($1), proto_str.split(","));
- } else {
- socket = new WebSocket(UTF8ToString($1));
- }
- } catch (e) {
- return -1;
- }
- var c_ptr = Module.IDHandler.get($0);
- socket.binaryType = "arraybuffer";
-
- // Connection opened
- socket.addEventListener("open", function (event) {
- if (!Module.IDHandler.has($0))
- return; // Godot Object is gone!
- ccall("_esws_on_connect",
- "void",
- ["number", "string"],
- [c_ptr, socket.protocol]
- );
- });
-
- // Listen for messages
- socket.addEventListener("message", function (event) {
- if (!Module.IDHandler.has($0))
- return; // Godot Object is gone!
- var buffer;
- var is_string = 0;
- if (event.data instanceof ArrayBuffer) {
-
- buffer = new Uint8Array(event.data);
-
- } else if (event.data instanceof Blob) {
-
- alert("Blob type not supported");
- return;
-
- } else if (typeof event.data === "string") {
-
- is_string = 1;
- var enc = new TextEncoder("utf-8");
- buffer = new Uint8Array(enc.encode(event.data));
-
- } else {
-
- alert("Unknown message type");
- return;
-
- }
- var len = buffer.length*buffer.BYTES_PER_ELEMENT;
- var out = _malloc(len);
- HEAPU8.set(buffer, out);
- ccall("_esws_on_message",
- "void",
- ["number", "number", "number", "number"],
- [c_ptr, out, len, is_string]
- );
- _free(out);
- });
-
- socket.addEventListener("error", function (event) {
- if (!Module.IDHandler.has($0))
- return; // Godot Object is gone!
- ccall("_esws_on_error",
- "void",
- ["number"],
- [c_ptr]
- );
- });
-
- socket.addEventListener("close", function (event) {
- if (!Module.IDHandler.has($0))
- return; // Godot Object is gone!
- var was_clean = 0;
- if (event.wasClean)
- was_clean = 1;
- ccall("_esws_on_close",
- "void",
- ["number", "number", "string", "number"],
- [c_ptr, event.code, event.reason, was_clean]
- );
- });
-
- return Module.IDHandler.add(socket);
- }, _js_id, str.utf8().get_data(), proto_string.utf8().get_data());
- /* clang-format on */
- if (peer_sock == -1)
+
+ _js_id = godot_js_websocket_create(this, str.utf8().get_data(), proto_string.utf8().get_data(), &_esws_on_connect, &_esws_on_message, &_esws_on_error, &_esws_on_close);
+ if (!_js_id) {
return FAILED;
+ }
- static_cast<Ref<EMWSPeer>>(_peer)->set_sock(peer_sock, _in_buf_size, _in_pkt_size);
+ static_cast<Ref<EMWSPeer>>(_peer)->set_sock(_js_id, _in_buf_size, _in_pkt_size);
return OK;
-};
+}
void EMWSClient::poll() {
}
@@ -200,19 +115,19 @@ NetworkedMultiplayerPeer::ConnectionStatus EMWSClient::get_connection_status() c
}
return CONNECTION_DISCONNECTED;
-};
+}
void EMWSClient::disconnect_from_host(int p_code, String p_reason) {
_peer->close(p_code, p_reason);
-};
+}
IP_Address EMWSClient::get_connected_host() const {
ERR_FAIL_V_MSG(IP_Address(), "Not supported in HTML5 export.");
-};
+}
uint16_t EMWSClient::get_connected_port() const {
ERR_FAIL_V_MSG(0, "Not supported in HTML5 export.");
-};
+}
int EMWSClient::get_max_packet_size() const {
return (1 << _in_buf_size) - PROTO_SIZE;
@@ -227,24 +142,17 @@ Error EMWSClient::set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffe
EMWSClient::EMWSClient() {
_in_buf_size = DEF_BUF_SHIFT;
_in_pkt_size = DEF_PKT_SHIFT;
-
_is_connecting = false;
_peer = Ref<EMWSPeer>(memnew(EMWSPeer));
- /* clang-format off */
- _js_id = EM_ASM_INT({
- return Module.IDHandler.add($0);
- }, this);
- /* clang-format on */
-};
+ _js_id = 0;
+}
EMWSClient::~EMWSClient() {
disconnect_from_host();
_peer = Ref<EMWSPeer>();
- /* clang-format off */
- EM_ASM({
- Module.IDHandler.remove($0);
- }, _js_id);
- /* clang-format on */
-};
+ if (_js_id) {
+ godot_js_websocket_destroy(_js_id);
+ }
+}
#endif // JAVASCRIPT_ENABLED
diff --git a/modules/websocket/emws_client.h b/modules/websocket/emws_client.h
index ab8a0612bb..fdf7a231d2 100644
--- a/modules/websocket/emws_client.h
+++ b/modules/websocket/emws_client.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,7 +33,7 @@
#ifdef JAVASCRIPT_ENABLED
-#include "core/error_list.h"
+#include "core/error/error_list.h"
#include "emws_peer.h"
#include "websocket_client.h"
@@ -41,13 +41,17 @@ class EMWSClient : public WebSocketClient {
GDCIIMPL(EMWSClient, WebSocketClient);
private:
+ int _js_id;
+ bool _is_connecting;
int _in_buf_size;
int _in_pkt_size;
- int _js_id;
-public:
- bool _is_connecting;
+ static void _esws_on_connect(void *obj, char *proto);
+ static void _esws_on_message(void *obj, const uint8_t *p_data, int p_data_size, int p_is_string);
+ static void _esws_on_error(void *obj);
+ 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;
diff --git a/modules/websocket/emws_peer.cpp b/modules/websocket/emws_peer.cpp
index 749f45451a..496c1edc04 100644
--- a/modules/websocket/emws_peer.cpp
+++ b/modules/websocket/emws_peer.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -47,38 +47,14 @@ EMWSPeer::WriteMode EMWSPeer::get_write_mode() const {
return write_mode;
}
-Error EMWSPeer::read_msg(uint8_t *p_data, uint32_t p_size, bool p_is_string) {
+Error EMWSPeer::read_msg(const uint8_t *p_data, uint32_t p_size, bool p_is_string) {
uint8_t is_string = p_is_string ? 1 : 0;
return _in_buffer.write_packet(p_data, p_size, &is_string);
}
Error EMWSPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
int is_bin = write_mode == WebSocketPeer::WRITE_MODE_BINARY ? 1 : 0;
-
- /* clang-format off */
- EM_ASM({
- var sock = Module.IDHandler.get($0);
- var bytes_array = new Uint8Array($2);
- var i = 0;
-
- for(i=0; i<$2; i++) {
- bytes_array[i] = getValue($1+i, 'i8');
- }
-
- try {
- if ($3) {
- sock.send(bytes_array.buffer);
- } else {
- var string = new TextDecoder("utf-8").decode(bytes_array);
- sock.send(string);
- }
- } catch (e) {
- return 1;
- }
- return 0;
- }, peer_sock, p_buffer, p_buffer_size, is_bin);
- /* clang-format on */
-
+ godot_js_websocket_send(peer_sock, p_buffer, p_buffer_size, is_bin);
return OK;
};
@@ -110,15 +86,7 @@ bool EMWSPeer::is_connected_to_host() const {
void EMWSPeer::close(int p_code, String p_reason) {
if (peer_sock != -1) {
- /* clang-format off */
- EM_ASM({
- var sock = Module.IDHandler.get($0);
- var code = $1;
- var reason = UTF8ToString($2);
- sock.close(code, reason);
- Module.IDHandler.remove($0);
- }, peer_sock, p_code, p_reason.utf8().get_data());
- /* clang-format on */
+ godot_js_websocket_close(peer_sock, p_code, p_reason.utf8().get_data());
}
_is_string = 0;
_in_buffer.clear();
diff --git a/modules/websocket/emws_peer.h b/modules/websocket/emws_peer.h
index 9c00f2d58b..07f61b62a0 100644
--- a/modules/websocket/emws_peer.h
+++ b/modules/websocket/emws_peer.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,13 +33,25 @@
#ifdef JAVASCRIPT_ENABLED
-#include "core/error_list.h"
+#include "core/error/error_list.h"
#include "core/io/packet_peer.h"
-#include "core/ring_buffer.h"
+#include "core/templates/ring_buffer.h"
#include "emscripten.h"
#include "packet_buffer.h"
#include "websocket_peer.h"
+extern "C" {
+typedef void (*WSOnOpen)(void *p_ref, char *p_protocol);
+typedef void (*WSOnMessage)(void *p_ref, const uint8_t *p_buf, int p_buf_len, int p_is_string);
+typedef void (*WSOnClose)(void *p_ref, int p_code, const char *p_reason, int p_is_clean);
+typedef void (*WSOnError)(void *p_ref);
+
+extern int godot_js_websocket_create(void *p_ref, const char *p_url, const char *p_proto, WSOnOpen p_on_open, WSOnMessage p_on_message, WSOnError p_on_error, WSOnClose p_on_close);
+extern int godot_js_websocket_send(int p_id, const uint8_t *p_buf, int p_buf_len, int p_raw);
+extern void godot_js_websocket_close(int p_id, int p_code, const char *p_reason);
+extern void godot_js_websocket_destroy(int p_id);
+}
+
class EMWSPeer : public WebSocketPeer {
GDCIIMPL(EMWSPeer, WebSocketPeer);
@@ -52,7 +64,7 @@ private:
uint8_t _is_string;
public:
- Error read_msg(uint8_t *p_data, uint32_t p_size, bool p_is_string);
+ 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);
virtual int get_available_packet_count() const;
virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size);
diff --git a/modules/websocket/emws_server.cpp b/modules/websocket/emws_server.cpp
index 9d43283d3e..a35d84f372 100644
--- a/modules/websocket/emws_server.cpp
+++ b/modules/websocket/emws_server.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/websocket/emws_server.h b/modules/websocket/emws_server.h
index bb6f35a711..4179b20ffe 100644
--- a/modules/websocket/emws_server.h
+++ b/modules/websocket/emws_server.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,7 +33,7 @@
#ifdef JAVASCRIPT_ENABLED
-#include "core/reference.h"
+#include "core/object/reference.h"
#include "emws_peer.h"
#include "websocket_server.h"
diff --git a/modules/websocket/library_godot_websocket.js b/modules/websocket/library_godot_websocket.js
new file mode 100644
index 0000000000..b182d1ecde
--- /dev/null
+++ b/modules/websocket/library_godot_websocket.js
@@ -0,0 +1,188 @@
+/*************************************************************************/
+/* library_godot_websocket.js */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+const GodotWebSocket = {
+ // Our socket implementation that forwards events to C++.
+ $GodotWebSocket__deps: ['$IDHandler', '$GodotRuntime'],
+ $GodotWebSocket: {
+ // Connection opened, report selected protocol
+ _onopen: function (p_id, callback, event) {
+ const ref = IDHandler.get(p_id);
+ if (!ref) {
+ return; // Godot object is gone.
+ }
+ const c_str = GodotRuntime.allocString(ref.protocol);
+ callback(c_str);
+ GodotRuntime.free(c_str);
+ },
+
+ // Message received, report content and type (UTF8 vs binary)
+ _onmessage: function (p_id, callback, event) {
+ const ref = IDHandler.get(p_id);
+ if (!ref) {
+ return; // Godot object is gone.
+ }
+ let buffer;
+ let is_string = 0;
+ if (event.data instanceof ArrayBuffer) {
+ buffer = new Uint8Array(event.data);
+ } else if (event.data instanceof Blob) {
+ GodotRuntime.error('Blob type not supported');
+ return;
+ } else if (typeof event.data === 'string') {
+ is_string = 1;
+ const enc = new TextEncoder('utf-8');
+ buffer = new Uint8Array(enc.encode(event.data));
+ } else {
+ GodotRuntime.error('Unknown message type');
+ return;
+ }
+ const len = buffer.length * buffer.BYTES_PER_ELEMENT;
+ const out = GodotRuntime.malloc(len);
+ HEAPU8.set(buffer, out);
+ callback(out, len, is_string);
+ GodotRuntime.free(out);
+ },
+
+ // An error happened, 'onclose' will be called after this.
+ _onerror: function (p_id, callback, event) {
+ const ref = IDHandler.get(p_id);
+ if (!ref) {
+ return; // Godot object is gone.
+ }
+ callback();
+ },
+
+ // Connection is closed, this is always fired. Report close code, reason, and clean status.
+ _onclose: function (p_id, callback, event) {
+ const ref = IDHandler.get(p_id);
+ if (!ref) {
+ return; // Godot object is gone.
+ }
+ const c_str = GodotRuntime.allocString(event.reason);
+ callback(event.code, c_str, event.wasClean ? 1 : 0);
+ GodotRuntime.free(c_str);
+ },
+
+ // Send a message
+ send: function (p_id, p_data) {
+ const ref = IDHandler.get(p_id);
+ if (!ref || ref.readyState !== ref.OPEN) {
+ return 1; // Godot object is gone or socket is not in a ready state.
+ }
+ ref.send(p_data);
+ return 0;
+ },
+
+ create: function (socket, p_on_open, p_on_message, p_on_error, p_on_close) {
+ const id = IDHandler.add(socket);
+ socket.onopen = GodotWebSocket._onopen.bind(null, id, p_on_open);
+ socket.onmessage = GodotWebSocket._onmessage.bind(null, id, p_on_message);
+ socket.onerror = GodotWebSocket._onerror.bind(null, id, p_on_error);
+ socket.onclose = GodotWebSocket._onclose.bind(null, id, p_on_close);
+ return id;
+ },
+
+ // Closes the JavaScript WebSocket (if not already closing) associated to a given C++ object.
+ close: function (p_id, p_code, p_reason) {
+ const ref = IDHandler.get(p_id);
+ if (ref && ref.readyState < ref.CLOSING) {
+ const code = p_code;
+ const reason = GodotRuntime.parseString(p_reason);
+ ref.close(code, reason);
+ }
+ },
+
+ // Deletes the reference to a C++ object (closing any connected socket if necessary).
+ destroy: function (p_id) {
+ const ref = IDHandler.get(p_id);
+ if (!ref) {
+ return;
+ }
+ GodotWebSocket.close(p_id, 1001, '');
+ IDHandler.remove(p_id);
+ ref.onopen = null;
+ ref.onmessage = null;
+ ref.onerror = null;
+ ref.onclose = null;
+ },
+ },
+
+ godot_js_websocket_create__sig: 'iiiiiiii',
+ godot_js_websocket_create: function (p_ref, p_url, p_proto, p_on_open, p_on_message, p_on_error, p_on_close) {
+ const on_open = GodotRuntime.get_func(p_on_open).bind(null, p_ref);
+ const on_message = GodotRuntime.get_func(p_on_message).bind(null, p_ref);
+ const on_error = GodotRuntime.get_func(p_on_error).bind(null, p_ref);
+ const on_close = GodotRuntime.get_func(p_on_close).bind(null, p_ref);
+ const url = GodotRuntime.parseString(p_url);
+ const protos = GodotRuntime.parseString(p_proto);
+ let socket = null;
+ try {
+ if (protos) {
+ socket = new WebSocket(url, protos.split(','));
+ } else {
+ socket = new WebSocket(url);
+ }
+ } catch (e) {
+ return 0;
+ }
+ socket.binaryType = 'arraybuffer';
+ return GodotWebSocket.create(socket, on_open, on_message, on_error, on_close);
+ },
+
+ godot_js_websocket_send__sig: 'iiiii',
+ godot_js_websocket_send: function (p_id, p_buf, p_buf_len, p_raw) {
+ const bytes_array = new Uint8Array(p_buf_len);
+ let i = 0;
+ for (i = 0; i < p_buf_len; i++) {
+ bytes_array[i] = GodotRuntime.getHeapValue(p_buf + i, 'i8');
+ }
+ let out = bytes_array.buffer;
+ if (!p_raw) {
+ out = new TextDecoder('utf-8').decode(bytes_array);
+ }
+ return GodotWebSocket.send(p_id, out);
+ },
+
+ godot_js_websocket_close__sig: 'viii',
+ godot_js_websocket_close: function (p_id, p_code, p_reason) {
+ const code = p_code;
+ const reason = GodotRuntime.parseString(p_reason);
+ GodotWebSocket.close(p_id, code, reason);
+ },
+
+ godot_js_websocket_destroy__sig: 'vi',
+ godot_js_websocket_destroy: function (p_id) {
+ GodotWebSocket.destroy(p_id);
+ },
+};
+
+autoAddDeps(GodotWebSocket, '$GodotWebSocket');
+mergeInto(LibraryManager.library, GodotWebSocket);
diff --git a/modules/websocket/packet_buffer.h b/modules/websocket/packet_buffer.h
index 9973efe297..ed756363cf 100644
--- a/modules/websocket/packet_buffer.h
+++ b/modules/websocket/packet_buffer.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,7 +32,7 @@
#define PACKET_BUFFER_H
#include "core/os/copymem.h"
-#include "core/ring_buffer.h"
+#include "core/templates/ring_buffer.h"
template <class T>
class PacketBuffer {
diff --git a/modules/websocket/register_types.cpp b/modules/websocket/register_types.cpp
index bc50de414e..5a02509c4a 100644
--- a/modules/websocket/register_types.cpp
+++ b/modules/websocket/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,8 +29,8 @@
/*************************************************************************/
#include "register_types.h"
-#include "core/error_macros.h"
-#include "core/project_settings.h"
+#include "core/config/project_settings.h"
+#include "core/error/error_macros.h"
#ifdef JAVASCRIPT_ENABLED
#include "emscripten.h"
#include "emws_client.h"
diff --git a/modules/websocket/register_types.h b/modules/websocket/register_types.h
index bb7be57ab3..3884db67b7 100644
--- a/modules/websocket/register_types.h
+++ b/modules/websocket/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/websocket/remote_debugger_peer_websocket.cpp b/modules/websocket/remote_debugger_peer_websocket.cpp
index a67a959e31..c9591cc564 100644
--- a/modules/websocket/remote_debugger_peer_websocket.cpp
+++ b/modules/websocket/remote_debugger_peer_websocket.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,7 +30,7 @@
#include "remote_debugger_peer_websocket.h"
-#include "core/project_settings.h"
+#include "core/config/project_settings.h"
Error RemoteDebuggerPeerWebSocket::connect_to_host(const String &p_uri) {
Vector<String> protocols;
diff --git a/modules/websocket/remote_debugger_peer_websocket.h b/modules/websocket/remote_debugger_peer_websocket.h
index bb03e5e892..03c60fb480 100644
--- a/modules/websocket/remote_debugger_peer_websocket.h
+++ b/modules/websocket/remote_debugger_peer_websocket.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/websocket/websocket_client.cpp b/modules/websocket/websocket_client.cpp
index 8feaa9af5a..eb0252e6d1 100644
--- a/modules/websocket/websocket_client.cpp
+++ b/modules/websocket/websocket_client.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/websocket/websocket_client.h b/modules/websocket/websocket_client.h
index 1053be22e3..78b77b89cd 100644
--- a/modules/websocket/websocket_client.h
+++ b/modules/websocket/websocket_client.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,7 +32,7 @@
#define WEBSOCKET_CLIENT_H
#include "core/crypto/crypto.h"
-#include "core/error_list.h"
+#include "core/error/error_list.h"
#include "websocket_multiplayer_peer.h"
#include "websocket_peer.h"
diff --git a/modules/websocket/websocket_macros.h b/modules/websocket/websocket_macros.h
index cf4545b435..d04909c97d 100644
--- a/modules/websocket/websocket_macros.h
+++ b/modules/websocket/websocket_macros.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/websocket/websocket_multiplayer_peer.cpp b/modules/websocket/websocket_multiplayer_peer.cpp
index fa2fe891a5..f94642475c 100644
--- a/modules/websocket/websocket_multiplayer_peer.cpp
+++ b/modules/websocket/websocket_multiplayer_peer.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/websocket/websocket_multiplayer_peer.h b/modules/websocket/websocket_multiplayer_peer.h
index af26aef21e..e593163b7c 100644
--- a/modules/websocket/websocket_multiplayer_peer.h
+++ b/modules/websocket/websocket_multiplayer_peer.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,9 +31,9 @@
#ifndef WEBSOCKET_MULTIPLAYER_PEER_H
#define WEBSOCKET_MULTIPLAYER_PEER_H
-#include "core/error_list.h"
+#include "core/error/error_list.h"
#include "core/io/networked_multiplayer_peer.h"
-#include "core/list.h"
+#include "core/templates/list.h"
#include "websocket_peer.h"
class WebSocketMultiplayerPeer : public NetworkedMultiplayerPeer {
diff --git a/modules/websocket/websocket_peer.cpp b/modules/websocket/websocket_peer.cpp
index 30a5972330..e77fdcfed2 100644
--- a/modules/websocket/websocket_peer.cpp
+++ b/modules/websocket/websocket_peer.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/websocket/websocket_peer.h b/modules/websocket/websocket_peer.h
index a61943b615..2ba83637f9 100644
--- a/modules/websocket/websocket_peer.h
+++ b/modules/websocket/websocket_peer.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,7 +31,7 @@
#ifndef WEBSOCKETPEER_H
#define WEBSOCKETPEER_H
-#include "core/error_list.h"
+#include "core/error/error_list.h"
#include "core/io/packet_peer.h"
#include "websocket_macros.h"
diff --git a/modules/websocket/websocket_server.cpp b/modules/websocket/websocket_server.cpp
index b20b925dec..f57e8d959c 100644
--- a/modules/websocket/websocket_server.cpp
+++ b/modules/websocket/websocket_server.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/websocket/websocket_server.h b/modules/websocket/websocket_server.h
index 064ad4f179..3fbd5e3b95 100644
--- a/modules/websocket/websocket_server.h
+++ b/modules/websocket/websocket_server.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,7 +32,7 @@
#define WEBSOCKET_H
#include "core/crypto/crypto.h"
-#include "core/reference.h"
+#include "core/object/reference.h"
#include "websocket_multiplayer_peer.h"
#include "websocket_peer.h"
diff --git a/modules/websocket/wsl_client.cpp b/modules/websocket/wsl_client.cpp
index 7d16c2e99f..3e2f48e9b3 100644
--- a/modules/websocket/wsl_client.cpp
+++ b/modules/websocket/wsl_client.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,8 +31,8 @@
#ifndef JAVASCRIPT_ENABLED
#include "wsl_client.h"
+#include "core/config/project_settings.h"
#include "core/io/ip.h"
-#include "core/project_settings.h"
void WSLClient::_do_handshake() {
if (_requested < _request.size() - 1) {
diff --git a/modules/websocket/wsl_client.h b/modules/websocket/wsl_client.h
index 8355a5a737..8712b57f2c 100644
--- a/modules/websocket/wsl_client.h
+++ b/modules/websocket/wsl_client.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,7 +33,7 @@
#ifndef JAVASCRIPT_ENABLED
-#include "core/error_list.h"
+#include "core/error/error_list.h"
#include "core/io/stream_peer_ssl.h"
#include "core/io/stream_peer_tcp.h"
#include "websocket_client.h"
diff --git a/modules/websocket/wsl_peer.cpp b/modules/websocket/wsl_peer.cpp
index bf1ba43f8a..9d016e1139 100644
--- a/modules/websocket/wsl_peer.cpp
+++ b/modules/websocket/wsl_peer.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/websocket/wsl_peer.h b/modules/websocket/wsl_peer.h
index fe4abfb64c..01efa4b21e 100644
--- a/modules/websocket/wsl_peer.h
+++ b/modules/websocket/wsl_peer.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,10 +33,10 @@
#ifndef JAVASCRIPT_ENABLED
-#include "core/error_list.h"
+#include "core/error/error_list.h"
#include "core/io/packet_peer.h"
#include "core/io/stream_peer_tcp.h"
-#include "core/ring_buffer.h"
+#include "core/templates/ring_buffer.h"
#include "packet_buffer.h"
#include "websocket_peer.h"
#include "wslay/wslay.h"
diff --git a/modules/websocket/wsl_server.cpp b/modules/websocket/wsl_server.cpp
index da7bfc70c0..9df076bf3f 100644
--- a/modules/websocket/wsl_server.cpp
+++ b/modules/websocket/wsl_server.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,8 +31,8 @@
#ifndef JAVASCRIPT_ENABLED
#include "wsl_server.h"
+#include "core/config/project_settings.h"
#include "core/os/os.h"
-#include "core/project_settings.h"
WSLServer::PendingPeer::PendingPeer() {
use_ssl = false;
diff --git a/modules/websocket/wsl_server.h b/modules/websocket/wsl_server.h
index f86de02797..8b2d4d3a04 100644
--- a/modules/websocket/wsl_server.h
+++ b/modules/websocket/wsl_server.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/webxr/SCsub b/modules/webxr/SCsub
new file mode 100644
index 0000000000..0a96af0811
--- /dev/null
+++ b/modules/webxr/SCsub
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+Import("env")
+Import("env_modules")
+
+if env["platform"] == "javascript":
+ env.AddJSLibraries(["native/library_godot_webxr.js"])
+ env.AddJSExterns(["native/webxr.externs.js"])
+
+env_webxr = env_modules.Clone()
+env_webxr.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/webxr/config.py b/modules/webxr/config.py
new file mode 100644
index 0000000000..9efebed4e6
--- /dev/null
+++ b/modules/webxr/config.py
@@ -0,0 +1,14 @@
+def can_build(env, platform):
+ return True
+
+
+def configure(env):
+ pass
+
+
+def get_doc_classes():
+ return ["WebXRInterface"]
+
+
+def get_doc_path():
+ return "doc_classes"
diff --git a/modules/webxr/doc_classes/WebXRInterface.xml b/modules/webxr/doc_classes/WebXRInterface.xml
new file mode 100644
index 0000000000..2407d44496
--- /dev/null
+++ b/modules/webxr/doc_classes/WebXRInterface.xml
@@ -0,0 +1,257 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="WebXRInterface" inherits="XRInterface" version="4.0">
+ <brief_description>
+ AR/VR interface using WebXR.
+ </brief_description>
+ <description>
+ WebXR is an open standard that allows creating VR and AR applications that run in the web browser.
+ As such, this interface is only available when running in an HTML5 export.
+ WebXR supports a wide range of devices, from the very capable (like Valve Index, HTC Vive, Oculus Rift and Quest) down to the much less capable (like Google Cardboard, Oculus Go, GearVR, or plain smartphones).
+ Since WebXR is based on Javascript, it makes extensive use of callbacks, which means that [WebXRInterface] is forced to use signals, where other AR/VR interfaces would instead use functions that return a result immediately. This makes [WebXRInterface] quite a bit more complicated to intialize than other AR/VR interfaces.
+ Here's the minimum code required to start an immersive VR session:
+ [codeblock]
+ extends Node3D
+
+ var webxr_interface
+ var vr_supported = false
+
+ func _ready():
+ # We assume this node has a button as a child.
+ # This button is for the user to consent to entering immersive VR mode.
+ $Button.connect("pressed", self, "_on_Button_pressed")
+
+ webxr_interface = XRServer.find_interface("WebXR")
+ if webxr_interface:
+ # WebXR uses a lot of asynchronous callbacks, so we connect to various
+ # signals in order to receive them.
+ webxr_interface.connect("session_supported", self, "_webxr_session_supported")
+ webxr_interface.connect("session_started", self, "_webxr_session_started")
+ webxr_interface.connect("session_ended", self, "_webxr_session_ended")
+ webxr_interface.connect("session_failed", self, "_webxr_session_failed")
+
+ # This returns immediately - our _webxr_session_supported() method
+ # (which we connected to the "session_supported" signal above) will
+ # be called sometime later to let us know if it's supported or not.
+ webxr_interface.is_session_supported("immersive-vr")
+
+ func _webxr_session_supported(session_mode, supported):
+ if session_mode == 'immersive-vr':
+ vr_supported = supported
+
+ func _on_Button_pressed():
+ if not vr_supported:
+ OS.alert("Your browser doesn't support VR")
+ return
+
+ # We want an immersive VR session, as opposed to AR ('immersive-ar') or a
+ # simple 3DoF viewer ('viewer').
+ webxr_interface.session_mode = 'immersive-vr'
+ # 'bounded-floor' is room scale, 'local-floor' is a standing or sitting
+ # experience (it puts you 1.6m above the ground if you have 3DoF headset),
+ # whereas as 'local' puts you down at the XROrigin.
+ # This list means it'll first try to request 'bounded-floor', then
+ # fallback on 'local-floor' and ultimately 'local', if nothing else is
+ # supported.
+ webxr_interface.requested_reference_space_types = 'bounded-floor, local-floor, local'
+ # In order to use 'local-floor' or 'bounded-floor' we must also
+ # mark the features as required or optional.
+ webxr_interface.required_features = 'local-floor'
+ webxr_interface.optional_features = 'bounded-floor'
+
+ # This will return false if we're unable to even request the session,
+ # however, it can still fail asynchronously later in the process, so we
+ # only know if it's really succeeded or failed when our
+ # _webxr_session_started() or _webxr_session_failed() methods are called.
+ if not webxr_interface.initialize():
+ OS.alert("Failed to initialize")
+ return
+
+ func _webxr_session_started():
+ $Button.visible = false
+ # This tells Godot to start rendering to the headset.
+ get_viewport().xr = true
+ # This will be the reference space type you ultimately got, out of the
+ # types that you requested above. This is useful if you want the game to
+ # work a little differently in 'bounded-floor' versus 'local-floor'.
+ print ("Reference space type: " + webxr_interface.reference_space_type)
+
+ func _webxr_session_ended():
+ $Button.visible = true
+ # If the user exits immersive mode, then we tell Godot to render to the web
+ # page again.
+ get_viewport().xr = false
+
+ func _webxr_session_failed(message):
+ OS.alert("Failed to initialize: " + message)
+ [/codeblock]
+ There are several ways to handle "controller" input:
+ - Using [XRController3D] nodes and their [signal XRController3D.button_pressed] and [signal XRController3D.button_released] signals. This is how controllers are typically handled in AR/VR apps in Godot, however, this will only work with advanced VR controllers like the Oculus Touch or Index controllers, for example. The buttons codes are defined by [url=https://immersive-web.github.io/webxr-gamepads-module/#xr-standard-gamepad-mapping]Section 3.3 of the WebXR Gamepads Module[/url].
+ - Using [method Node._unhandled_input] and [InputEventJoypadButton] or [InputEventJoypadMotion]. This works the same as normal joypads, except the [member InputEvent.device] starts at 100, so the left controller is 100 and the right controller is 101, and the button codes are also defined by [url=https://immersive-web.github.io/webxr-gamepads-module/#xr-standard-gamepad-mapping]Section 3.3 of the WebXR Gamepads Module[/url].
+ - Using the [signal select], [signal squeeze] and related signals. This method will work for both advanced VR controllers, and non-traditional "controllers" like a tap on the screen, a spoken voice command or a button press on the device itself. The [code]controller_id[/code] passed to these signals is the same id as used in [member XRController3D.controller_id].
+ You can use one or all of these methods to allow your game or app to support a wider or narrower set of devices and input methods, or to allow more advanced interations with more advanced devices.
+ </description>
+ <tutorials>
+ <link title="How to make a VR game for WebXR with Godot">https://www.snopekgames.com/blog/2020/how-make-vr-game-webxr-godot</link>
+ </tutorials>
+ <methods>
+ <method name="get_controller" qualifiers="const">
+ <return type="XRPositionalTracker">
+ </return>
+ <argument index="0" name="controller_id" type="int">
+ </argument>
+ <description>
+ Gets an [XRPositionalTracker] for the given [code]controller_id[/code].
+ In the context of WebXR, a "controller" can be an advanced VR controller like the Oculus Touch or Index controllers, or even a tap on the screen, a spoken voice command or a button press on the device itself. When a non-traditional controller is used, interpret the position and orientation of the [XRPositionalTracker] as a ray pointing at the object the user wishes to interact with.
+ Use this method to get information about the controller that triggered one of these signals:
+ - [signal selectstart]
+ - [signal select]
+ - [signal selectend]
+ - [signal squeezestart]
+ - [signal squeeze]
+ - [signal squeezestart]
+ </description>
+ </method>
+ <method name="is_session_supported">
+ <return type="void">
+ </return>
+ <argument index="0" name="session_mode" type="String">
+ </argument>
+ <description>
+ Checks if the given [code]session_mode[/code] is supported by the user's browser.
+ Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRSessionMode]WebXR's XRSessionMode[/url], including: [code]"immersive-vr"[/code], [code]"immersive-ar"[/code], and [code]"inline"[/code].
+ This method returns nothing, instead it emits the [signal session_supported] signal with the result.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="bounds_geometry" type="PackedVector3Array" setter="" getter="get_bounds_geometry">
+ The vertices of a polygon which defines the boundaries of the user's play area.
+ This will only be available if [member reference_space_type] is [code]"bounded-floor"[/code] and only on certain browsers and devices that support it.
+ The [signal reference_space_reset] signal may indicate when this changes.
+ </member>
+ <member name="optional_features" type="String" setter="set_optional_features" getter="get_optional_features">
+ A comma-seperated list of optional features used by [method XRInterface.initialize] when setting up the WebXR session.
+ If a user's browser or device doesn't support one of the given features, initialization will continue, but you won't be able to use the requested feature.
+ This doesn't have any effect on the interface when already initialized.
+ Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpaceType]WebXR's XRReferenceSpaceType[/url]. If you want to use a particular reference space type, it must be listed in either [member required_features] or [member optional_features].
+ </member>
+ <member name="reference_space_type" type="String" setter="" getter="get_reference_space_type">
+ The reference space type (from the list of requested types set in the [member requested_reference_space_types] property), that was ultimately used by [method XRInterface.initialize] when setting up the WebXR session.
+ Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpaceType]WebXR's XRReferenceSpaceType[/url]. If you want to use a particular reference space type, it must be listed in either [member required_features] or [member optional_features].
+ </member>
+ <member name="requested_reference_space_types" type="String" setter="set_requested_reference_space_types" getter="get_requested_reference_space_types">
+ A comma-seperated list of reference space types used by [method XRInterface.initialize] when setting up the WebXR session.
+ The reference space types are requested in order, and the first on supported by the users device or browser will be used. The [member reference_space_type] property contains the reference space type that was ultimately used.
+ This doesn't have any effect on the interface when already initialized.
+ Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpaceType]WebXR's XRReferenceSpaceType[/url]. If you want to use a particular reference space type, it must be listed in either [member required_features] or [member optional_features].
+ </member>
+ <member name="required_features" type="String" setter="set_required_features" getter="get_required_features">
+ A comma-seperated list of required features used by [method XRInterface.initialize] when setting up the WebXR session.
+ If a user's browser or device doesn't support one of the given features, initialization will fail and [signal session_failed] will be emitted.
+ This doesn't have any effect on the interface when already initialized.
+ Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpaceType]WebXR's XRReferenceSpaceType[/url]. If you want to use a particular reference space type, it must be listed in either [member required_features] or [member optional_features].
+ </member>
+ <member name="session_mode" type="String" setter="set_session_mode" getter="get_session_mode">
+ The session mode used by [method XRInterface.initialize] when setting up the WebXR session.
+ This doesn't have any effect on the interface when already initialized.
+ Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRSessionMode]WebXR's XRSessionMode[/url], including: [code]"immersive-vr"[/code], [code]"immersive-ar"[/code], and [code]"inline"[/code].
+ </member>
+ <member name="visibility_state" type="String" setter="" getter="get_visibility_state">
+ Indicates if the WebXR session's imagery is visible to the user.
+ Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRVisibilityState]WebXR's XRVisibilityState[/url], including [code]"hidden"[/code], [code]"visible"[/code], and [code]"visible-blurred"[/code].
+ </member>
+ </members>
+ <signals>
+ <signal name="reference_space_reset">
+ <description>
+ Emitted to indicate that the reference space has been reset or reconfigured.
+ When (or whether) this is emitted depends on the user's browser or device, but may include when the user has changed the dimensions of their play space (which you may be able to access via [member bounds_geometry]) or pressed/held a button to recenter their position.
+ See [url=https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpace/reset_event]WebXR's XRReferenceSpace reset event[/url] for more information.
+ </description>
+ </signal>
+ <signal name="select">
+ <argument index="0" name="controller_id" type="int">
+ </argument>
+ <description>
+ Emitted after one of the "controllers" has finished its "primary action".
+ Use [method get_controller] to get more information about the controller.
+ </description>
+ </signal>
+ <signal name="selectend">
+ <argument index="0" name="controller_id" type="int">
+ </argument>
+ <description>
+ Emitted when one of the "controllers" has finished its "primary action".
+ Use [method get_controller] to get more information about the controller.
+ </description>
+ </signal>
+ <signal name="selectstart">
+ <argument index="0" name="controller_id" type="int">
+ </argument>
+ <description>
+ Emitted when one of the "controllers" has started its "primary action".
+ Use [method get_controller] to get more information about the controller.
+ </description>
+ </signal>
+ <signal name="session_ended">
+ <description>
+ Emitted when the user ends the WebXR session (which can be done using UI from the browser or device).
+ At this point, you should do [code]get_viewport().xr = false[/code] to instruct Godot to resume rendering to the screen.
+ </description>
+ </signal>
+ <signal name="session_failed">
+ <argument index="0" name="message" type="String">
+ </argument>
+ <description>
+ Emitted by [method XRInterface.initialize] if the session fails to start.
+ [code]message[/code] may optionally contain an error message from WebXR, or an empty string if no message is available.
+ </description>
+ </signal>
+ <signal name="session_started">
+ <description>
+ Emitted by [method XRInterface.initialize] if the session is successfully started.
+ At this point, it's safe to do [code]get_viewport().xr = true[/code] to instruct Godot to start rendering to the AR/VR device.
+ </description>
+ </signal>
+ <signal name="session_supported">
+ <argument index="0" name="session_mode" type="String">
+ </argument>
+ <argument index="1" name="supported" type="bool">
+ </argument>
+ <description>
+ Emitted by [method is_session_supported] to indicate if the given [code]session_mode[/code] is supported or not.
+ </description>
+ </signal>
+ <signal name="squeeze">
+ <argument index="0" name="controller_id" type="int">
+ </argument>
+ <description>
+ Emitted after one of the "controllers" has finished its "primary squeeze action".
+ Use [method get_controller] to get more information about the controller.
+ </description>
+ </signal>
+ <signal name="squeezeend">
+ <argument index="0" name="controller_id" type="int">
+ </argument>
+ <description>
+ Emitted when one of the "controllers" has finished its "primary squeeze action".
+ Use [method get_controller] to get more information about the controller.
+ </description>
+ </signal>
+ <signal name="squeezestart">
+ <argument index="0" name="controller_id" type="int">
+ </argument>
+ <description>
+ Emitted when one of the "controllers" has started its "primary squeeze action".
+ Use [method get_controller] to get more information about the controller.
+ </description>
+ </signal>
+ <signal name="visibility_state_changed">
+ <description>
+ Emitted when [member visibility_state] has changed.
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ </constants>
+</class>
diff --git a/modules/webxr/godot_webxr.h b/modules/webxr/godot_webxr.h
new file mode 100644
index 0000000000..41a690f473
--- /dev/null
+++ b/modules/webxr/godot_webxr.h
@@ -0,0 +1,85 @@
+/*************************************************************************/
+/* godot_webxr.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GODOT_WEBXR_H
+#define GODOT_WEBXR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "stddef.h"
+
+typedef void (*GodotWebXRSupportedCallback)(char *p_session_mode, int p_supported);
+typedef void (*GodotWebXRStartedCallback)(char *p_reference_space_type);
+typedef void (*GodotWebXREndedCallback)();
+typedef void (*GodotWebXRFailedCallback)(char *p_message);
+typedef void (*GodotWebXRControllerCallback)();
+typedef void (*GodotWebXRInputEventCallback)(char *p_signal_name, int p_controller_id);
+typedef void (*GodotWebXRSimpleEventCallback)(char *p_signal_name);
+
+extern int godot_webxr_is_supported();
+extern void godot_webxr_is_session_supported(const char *p_session_mode, GodotWebXRSupportedCallback p_callback);
+
+extern void godot_webxr_initialize(
+ const char *p_session_mode,
+ const char *p_required_features,
+ const char *p_optional_features,
+ const char *p_requested_reference_space_types,
+ GodotWebXRStartedCallback p_on_session_started,
+ GodotWebXREndedCallback p_on_session_ended,
+ GodotWebXRFailedCallback p_on_session_failed,
+ GodotWebXRControllerCallback p_on_controller_changed,
+ GodotWebXRInputEventCallback p_on_input_event,
+ GodotWebXRSimpleEventCallback p_on_simple_event);
+extern void godot_webxr_uninitialize();
+
+extern int godot_webxr_get_view_count();
+extern int *godot_webxr_get_render_targetsize();
+extern float *godot_webxr_get_transform_for_eye(int p_eye);
+extern float *godot_webxr_get_projection_for_eye(int p_eye);
+extern int godot_webxr_get_external_texture_for_eye(int p_eye);
+extern void godot_webxr_commit_for_eye(int p_eye);
+
+extern void godot_webxr_sample_controller_data();
+extern int godot_webxr_get_controller_count();
+extern int godot_webxr_is_controller_connected(int p_controller);
+extern float *godot_webxr_get_controller_transform(int p_controller);
+extern int *godot_webxr_get_controller_buttons(int p_controller);
+extern int *godot_webxr_get_controller_axes(int p_controller);
+
+extern char *godot_webxr_get_visibility_state();
+extern int *godot_webxr_get_bounds_geometry();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GODOT_WEBXR_H */
diff --git a/modules/webxr/native/library_godot_webxr.js b/modules/webxr/native/library_godot_webxr.js
new file mode 100644
index 0000000000..8e9ef8a73c
--- /dev/null
+++ b/modules/webxr/native/library_godot_webxr.js
@@ -0,0 +1,672 @@
+/*************************************************************************/
+/* library_godot_webxr.js */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+const GodotWebXR = {
+ $GodotWebXR__deps: ['$Browser', '$GL', '$GodotRuntime'],
+ $GodotWebXR: {
+ gl: null,
+
+ texture_ids: [null, null],
+ textures: [null, null],
+
+ session: null,
+ space: null,
+ frame: null,
+ pose: null,
+
+ // Monkey-patch the requestAnimationFrame() used by Emscripten for the main
+ // loop, so that we can swap it out for XRSession.requestAnimationFrame()
+ // when an XR session is started.
+ orig_requestAnimationFrame: null,
+ requestAnimationFrame: (callback) => {
+ if (GodotWebXR.session && GodotWebXR.space) {
+ const onFrame = function (time, frame) {
+ GodotWebXR.frame = frame;
+ GodotWebXR.pose = frame.getViewerPose(GodotWebXR.space);
+ callback(time);
+ GodotWebXR.frame = null;
+ GodotWebXR.pose = null;
+ };
+ GodotWebXR.session.requestAnimationFrame(onFrame);
+ } else {
+ GodotWebXR.orig_requestAnimationFrame(callback);
+ }
+ },
+ monkeyPatchRequestAnimationFrame: (enable) => {
+ if (GodotWebXR.orig_requestAnimationFrame === null) {
+ GodotWebXR.orig_requestAnimationFrame = Browser.requestAnimationFrame;
+ }
+ Browser.requestAnimationFrame = enable
+ ? GodotWebXR.requestAnimationFrame : GodotWebXR.orig_requestAnimationFrame;
+ },
+ pauseResumeMainLoop: () => {
+ // Once both GodotWebXR.session and GodotWebXR.space are set or
+ // unset, our monkey-patched requestAnimationFrame() should be
+ // enabled or disabled. When using the WebXR API Emulator, this
+ // gets picked up automatically, however, in the Oculus Browser
+ // on the Quest, we need to pause and resume the main loop.
+ Browser.pauseAsyncCallbacks();
+ Browser.mainLoop.pause();
+ window.setTimeout(function () {
+ Browser.resumeAsyncCallbacks();
+ Browser.mainLoop.resume();
+ }, 0);
+ },
+
+ // Some custom WebGL code for blitting our eye textures to the
+ // framebuffer we get from WebXR.
+ shaderProgram: null,
+ programInfo: null,
+ buffer: null,
+ // Vertex shader source.
+ vsSource: `
+ const vec2 scale = vec2(0.5, 0.5);
+ attribute vec4 aVertexPosition;
+
+ varying highp vec2 vTextureCoord;
+
+ void main () {
+ gl_Position = aVertexPosition;
+ vTextureCoord = aVertexPosition.xy * scale + scale;
+ }
+ `,
+ // Fragment shader source.
+ fsSource: `
+ varying highp vec2 vTextureCoord;
+
+ uniform sampler2D uSampler;
+
+ void main() {
+ gl_FragColor = texture2D(uSampler, vTextureCoord);
+ }
+ `,
+
+ initShaderProgram: (gl, vsSource, fsSource) => {
+ const vertexShader = GodotWebXR.loadShader(gl, gl.VERTEX_SHADER, vsSource);
+ const fragmentShader = GodotWebXR.loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
+
+ const shaderProgram = gl.createProgram();
+ gl.attachShader(shaderProgram, vertexShader);
+ gl.attachShader(shaderProgram, fragmentShader);
+ gl.linkProgram(shaderProgram);
+
+ if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
+ GodotRuntime.error(`Unable to initialize the shader program: ${gl.getProgramInfoLog(shaderProgram)}`);
+ return null;
+ }
+
+ return shaderProgram;
+ },
+ loadShader: (gl, type, source) => {
+ const shader = gl.createShader(type);
+ gl.shaderSource(shader, source);
+ gl.compileShader(shader);
+
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
+ GodotRuntime.error(`An error occurred compiling the shader: ${gl.getShaderInfoLog(shader)}`);
+ gl.deleteShader(shader);
+ return null;
+ }
+
+ return shader;
+ },
+ initBuffer: (gl) => {
+ const positionBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+ const positions = [
+ -1.0, -1.0,
+ 1.0, -1.0,
+ -1.0, 1.0,
+ 1.0, 1.0,
+ ];
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
+ return positionBuffer;
+ },
+ blitTexture: (gl, texture) => {
+ if (GodotWebXR.shaderProgram === null) {
+ GodotWebXR.shaderProgram = GodotWebXR.initShaderProgram(gl, GodotWebXR.vsSource, GodotWebXR.fsSource);
+ GodotWebXR.programInfo = {
+ program: GodotWebXR.shaderProgram,
+ attribLocations: {
+ vertexPosition: gl.getAttribLocation(GodotWebXR.shaderProgram, 'aVertexPosition'),
+ },
+ uniformLocations: {
+ uSampler: gl.getUniformLocation(GodotWebXR.shaderProgram, 'uSampler'),
+ },
+ };
+ GodotWebXR.buffer = GodotWebXR.initBuffer(gl);
+ }
+
+ const orig_program = gl.getParameter(gl.CURRENT_PROGRAM);
+ gl.useProgram(GodotWebXR.shaderProgram);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, GodotWebXR.buffer);
+ gl.vertexAttribPointer(GodotWebXR.programInfo.attribLocations.vertexPosition, 2, gl.FLOAT, false, 0, 0);
+ gl.enableVertexAttribArray(GodotWebXR.programInfo.attribLocations.vertexPosition);
+
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.uniform1i(GodotWebXR.programInfo.uniformLocations.uSampler, 0);
+
+ gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
+
+ // Restore state.
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ gl.disableVertexAttribArray(GodotWebXR.programInfo.attribLocations.vertexPosition);
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
+ gl.useProgram(orig_program);
+ },
+
+ // Holds the controllers list between function calls.
+ controllers: [],
+
+ // Updates controllers array, where the left hand (or sole tracker) is
+ // the first element, and the right hand is the second element, and any
+ // others placed at the 3rd position and up.
+ sampleControllers: () => {
+ if (!GodotWebXR.session || !GodotWebXR.frame) {
+ return;
+ }
+
+ let other_index = 2;
+ const controllers = [];
+ GodotWebXR.session.inputSources.forEach((input_source) => {
+ if (input_source.targetRayMode === 'tracked-pointer') {
+ if (input_source.handedness === 'right') {
+ controllers[1] = input_source;
+ } else if (input_source.handedness === 'left' || !controllers[0]) {
+ controllers[0] = input_source;
+ }
+ } else {
+ controllers[other_index++] = input_source;
+ }
+ });
+ GodotWebXR.controllers = controllers;
+ },
+
+ getControllerId: (input_source) => GodotWebXR.controllers.indexOf(input_source),
+ },
+
+ godot_webxr_is_supported__proxy: 'sync',
+ godot_webxr_is_supported__sig: 'i',
+ godot_webxr_is_supported: function () {
+ return !!navigator.xr;
+ },
+
+ godot_webxr_is_session_supported__proxy: 'sync',
+ godot_webxr_is_session_supported__sig: 'vii',
+ godot_webxr_is_session_supported: function (p_session_mode, p_callback) {
+ const session_mode = GodotRuntime.parseString(p_session_mode);
+ const cb = GodotRuntime.get_func(p_callback);
+ if (navigator.xr) {
+ navigator.xr.isSessionSupported(session_mode).then(function (supported) {
+ const c_str = GodotRuntime.allocString(session_mode);
+ cb(c_str, supported ? 1 : 0);
+ GodotRuntime.free(c_str);
+ });
+ } else {
+ const c_str = GodotRuntime.allocString(session_mode);
+ cb(c_str, 0);
+ GodotRuntime.free(c_str);
+ }
+ },
+
+ godot_webxr_initialize__deps: ['emscripten_webgl_get_current_context'],
+ godot_webxr_initialize__proxy: 'sync',
+ godot_webxr_initialize__sig: 'viiiiiiiiii',
+ godot_webxr_initialize: function (p_session_mode, p_required_features, p_optional_features, p_requested_reference_spaces, p_on_session_started, p_on_session_ended, p_on_session_failed, p_on_controller_changed, p_on_input_event, p_on_simple_event) {
+ GodotWebXR.monkeyPatchRequestAnimationFrame(true);
+
+ const session_mode = GodotRuntime.parseString(p_session_mode);
+ const required_features = GodotRuntime.parseString(p_required_features).split(',').map((s) => s.trim()).filter((s) => s !== '');
+ const optional_features = GodotRuntime.parseString(p_optional_features).split(',').map((s) => s.trim()).filter((s) => s !== '');
+ const requested_reference_space_types = GodotRuntime.parseString(p_requested_reference_spaces).split(',').map((s) => s.trim());
+ const onstarted = GodotRuntime.get_func(p_on_session_started);
+ const onended = GodotRuntime.get_func(p_on_session_ended);
+ const onfailed = GodotRuntime.get_func(p_on_session_failed);
+ const oncontroller = GodotRuntime.get_func(p_on_controller_changed);
+ const oninputevent = GodotRuntime.get_func(p_on_input_event);
+ const onsimpleevent = GodotRuntime.get_func(p_on_simple_event);
+
+ const session_init = {};
+ if (required_features.length > 0) {
+ session_init['requiredFeatures'] = required_features;
+ }
+ if (optional_features.length > 0) {
+ session_init['optionalFeatures'] = optional_features;
+ }
+
+ navigator.xr.requestSession(session_mode, session_init).then(function (session) {
+ GodotWebXR.session = session;
+
+ session.addEventListener('end', function (evt) {
+ onended();
+ });
+
+ session.addEventListener('inputsourceschange', function (evt) {
+ let controller_changed = false;
+ [evt.added, evt.removed].forEach((lst) => {
+ lst.forEach((input_source) => {
+ if (input_source.targetRayMode === 'tracked-pointer') {
+ controller_changed = true;
+ }
+ });
+ });
+ if (controller_changed) {
+ oncontroller();
+ }
+ });
+
+ ['selectstart', 'select', 'selectend', 'squeezestart', 'squeeze', 'squeezeend'].forEach((input_event) => {
+ session.addEventListener(input_event, function (evt) {
+ const c_str = GodotRuntime.allocString(input_event);
+ oninputevent(c_str, GodotWebXR.getControllerId(evt.inputSource));
+ GodotRuntime.free(c_str);
+ });
+ });
+
+ session.addEventListener('visibilitychange', function (evt) {
+ const c_str = GodotRuntime.allocString('visibility_state_changed');
+ onsimpleevent(c_str);
+ GodotRuntime.free(c_str);
+ });
+
+ const gl_context_handle = _emscripten_webgl_get_current_context(); // eslint-disable-line no-undef
+ const gl = GL.getContext(gl_context_handle).GLctx;
+ GodotWebXR.gl = gl;
+
+ gl.makeXRCompatible().then(function () {
+ session.updateRenderState({
+ baseLayer: new XRWebGLLayer(session, gl),
+ });
+
+ function onReferenceSpaceSuccess(reference_space, reference_space_type) {
+ GodotWebXR.space = reference_space;
+
+ // Using reference_space.addEventListener() crashes when
+ // using the polyfill with the WebXR Emulator extension,
+ // so we set the event property instead.
+ reference_space.onreset = function (evt) {
+ const c_str = GodotRuntime.allocString('reference_space_reset');
+ onsimpleevent(c_str);
+ GodotRuntime.free(c_str);
+ };
+
+ // Now that both GodotWebXR.session and GodotWebXR.space are
+ // set, we need to pause and resume the main loop for the XR
+ // main loop to kick in.
+ GodotWebXR.pauseResumeMainLoop();
+
+ // Call in setTimeout() so that errors in the onstarted()
+ // callback don't bubble up here and cause Godot to try the
+ // next reference space.
+ window.setTimeout(function () {
+ const c_str = GodotRuntime.allocString(reference_space_type);
+ onstarted(c_str);
+ GodotRuntime.free(c_str);
+ }, 0);
+ }
+
+ function requestReferenceSpace() {
+ const reference_space_type = requested_reference_space_types.shift();
+ session.requestReferenceSpace(reference_space_type)
+ .then((refSpace) => {
+ onReferenceSpaceSuccess(refSpace, reference_space_type);
+ })
+ .catch(() => {
+ if (requested_reference_space_types.length === 0) {
+ const c_str = GodotRuntime.allocString('Unable to get any of the requested reference space types');
+ onfailed(c_str);
+ GodotRuntime.free(c_str);
+ } else {
+ requestReferenceSpace();
+ }
+ });
+ }
+
+ requestReferenceSpace();
+ }).catch(function (error) {
+ const c_str = GodotRuntime.allocString(`Unable to make WebGL context compatible with WebXR: ${error}`);
+ onfailed(c_str);
+ GodotRuntime.free(c_str);
+ });
+ }).catch(function (error) {
+ const c_str = GodotRuntime.allocString(`Unable to start session: ${error}`);
+ onfailed(c_str);
+ GodotRuntime.free(c_str);
+ });
+ },
+
+ godot_webxr_uninitialize__proxy: 'sync',
+ godot_webxr_uninitialize__sig: 'v',
+ godot_webxr_uninitialize: function () {
+ if (GodotWebXR.session) {
+ GodotWebXR.session.end()
+ // Prevent exception when session has already ended.
+ .catch((e) => { });
+ }
+
+ // Clean-up the textures we allocated for each view.
+ const gl = GodotWebXR.gl;
+ for (let i = 0; i < GodotWebXR.textures.length; i++) {
+ const texture = GodotWebXR.textures[i];
+ if (texture !== null) {
+ gl.deleteTexture(texture);
+ }
+ GodotWebXR.textures[i] = null;
+
+ const texture_id = GodotWebXR.texture_ids[i];
+ if (texture_id !== null) {
+ GL.textures[texture_id] = null;
+ }
+ GodotWebXR.texture_ids[i] = null;
+ }
+
+ GodotWebXR.session = null;
+ GodotWebXR.space = null;
+ GodotWebXR.frame = null;
+ GodotWebXR.pose = null;
+
+ // Disable the monkey-patched window.requestAnimationFrame() and
+ // pause/restart the main loop to activate it on all platforms.
+ GodotWebXR.monkeyPatchRequestAnimationFrame(false);
+ GodotWebXR.pauseResumeMainLoop();
+ },
+
+ godot_webxr_get_view_count__proxy: 'sync',
+ godot_webxr_get_view_count__sig: 'i',
+ godot_webxr_get_view_count: function () {
+ if (!GodotWebXR.session || !GodotWebXR.pose) {
+ return 0;
+ }
+ return GodotWebXR.pose.views.length;
+ },
+
+ godot_webxr_get_render_targetsize__proxy: 'sync',
+ godot_webxr_get_render_targetsize__sig: 'i',
+ godot_webxr_get_render_targetsize: function () {
+ if (!GodotWebXR.session || !GodotWebXR.pose) {
+ return 0;
+ }
+
+ const glLayer = GodotWebXR.session.renderState.baseLayer;
+ const view = GodotWebXR.pose.views[0];
+ const viewport = glLayer.getViewport(view);
+
+ const buf = GodotRuntime.malloc(2 * 4);
+ GodotRuntime.setHeapValue(buf + 0, viewport.width, 'i32');
+ GodotRuntime.setHeapValue(buf + 4, viewport.height, 'i32');
+ return buf;
+ },
+
+ godot_webxr_get_transform_for_eye__proxy: 'sync',
+ godot_webxr_get_transform_for_eye__sig: 'ii',
+ godot_webxr_get_transform_for_eye: function (p_eye) {
+ if (!GodotWebXR.session || !GodotWebXR.pose) {
+ return 0;
+ }
+
+ const views = GodotWebXR.pose.views;
+ let matrix;
+ if (p_eye === 0) {
+ matrix = GodotWebXR.pose.transform.matrix;
+ } else {
+ matrix = views[p_eye - 1].transform.matrix;
+ }
+ const buf = GodotRuntime.malloc(16 * 4);
+ for (let i = 0; i < 16; i++) {
+ GodotRuntime.setHeapValue(buf + (i * 4), matrix[i], 'float');
+ }
+ return buf;
+ },
+
+ godot_webxr_get_projection_for_eye__proxy: 'sync',
+ godot_webxr_get_projection_for_eye__sig: 'ii',
+ godot_webxr_get_projection_for_eye: function (p_eye) {
+ if (!GodotWebXR.session || !GodotWebXR.pose) {
+ return 0;
+ }
+
+ const view_index = (p_eye === 2 /* ARVRInterface::EYE_RIGHT */) ? 1 : 0;
+ const matrix = GodotWebXR.pose.views[view_index].projectionMatrix;
+ const buf = GodotRuntime.malloc(16 * 4);
+ for (let i = 0; i < 16; i++) {
+ GodotRuntime.setHeapValue(buf + (i * 4), matrix[i], 'float');
+ }
+ return buf;
+ },
+
+ godot_webxr_get_external_texture_for_eye__proxy: 'sync',
+ godot_webxr_get_external_texture_for_eye__sig: 'ii',
+ godot_webxr_get_external_texture_for_eye: function (p_eye) {
+ if (!GodotWebXR.session) {
+ return 0;
+ }
+
+ const view_index = (p_eye === 2 /* ARVRInterface::EYE_RIGHT */) ? 1 : 0;
+ if (GodotWebXR.texture_ids[view_index]) {
+ return GodotWebXR.texture_ids[view_index];
+ }
+
+ // Check pose separately and after returning the cached texture id,
+ // because we won't get a pose in some cases if we lose tracking, and
+ // we don't want to return 0 just because tracking was lost.
+ if (!GodotWebXR.pose) {
+ return 0;
+ }
+
+ const glLayer = GodotWebXR.session.renderState.baseLayer;
+ const view = GodotWebXR.pose.views[view_index];
+ const viewport = glLayer.getViewport(view);
+ const gl = GodotWebXR.gl;
+
+ const texture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, viewport.width, viewport.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+
+ const texture_id = GL.getNewId(GL.textures);
+ GL.textures[texture_id] = texture;
+ GodotWebXR.textures[view_index] = texture;
+ GodotWebXR.texture_ids[view_index] = texture_id;
+ return texture_id;
+ },
+
+ godot_webxr_commit_for_eye__proxy: 'sync',
+ godot_webxr_commit_for_eye__sig: 'vi',
+ godot_webxr_commit_for_eye: function (p_eye) {
+ if (!GodotWebXR.session || !GodotWebXR.pose) {
+ return;
+ }
+
+ const view_index = (p_eye === 2 /* ARVRInterface::EYE_RIGHT */) ? 1 : 0;
+ const glLayer = GodotWebXR.session.renderState.baseLayer;
+ const view = GodotWebXR.pose.views[view_index];
+ const viewport = glLayer.getViewport(view);
+ const gl = GodotWebXR.gl;
+
+ const orig_framebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);
+ const orig_viewport = gl.getParameter(gl.VIEWPORT);
+
+ // Bind to WebXR's framebuffer.
+ gl.bindFramebuffer(gl.FRAMEBUFFER, glLayer.framebuffer);
+ gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
+
+ GodotWebXR.blitTexture(gl, GodotWebXR.textures[view_index]);
+
+ // Restore state.
+ gl.bindFramebuffer(gl.FRAMEBUFFER, orig_framebuffer);
+ gl.viewport(orig_viewport[0], orig_viewport[1], orig_viewport[2], orig_viewport[3]);
+ },
+
+ godot_webxr_sample_controller_data__proxy: 'sync',
+ godot_webxr_sample_controller_data__sig: 'v',
+ godot_webxr_sample_controller_data: function () {
+ GodotWebXR.sampleControllers();
+ },
+
+ godot_webxr_get_controller_count__proxy: 'sync',
+ godot_webxr_get_controller_count__sig: 'i',
+ godot_webxr_get_controller_count: function () {
+ if (!GodotWebXR.session || !GodotWebXR.frame) {
+ return 0;
+ }
+ return GodotWebXR.controllers.length;
+ },
+
+ godot_webxr_is_controller_connected__proxy: 'sync',
+ godot_webxr_is_controller_connected__sig: 'ii',
+ godot_webxr_is_controller_connected: function (p_controller) {
+ if (!GodotWebXR.session || !GodotWebXR.frame) {
+ return false;
+ }
+ return !!GodotWebXR.controllers[p_controller];
+ },
+
+ godot_webxr_get_controller_transform__proxy: 'sync',
+ godot_webxr_get_controller_transform__sig: 'ii',
+ godot_webxr_get_controller_transform: function (p_controller) {
+ if (!GodotWebXR.session || !GodotWebXR.frame) {
+ return 0;
+ }
+
+ const controller = GodotWebXR.controllers[p_controller];
+ if (!controller) {
+ return 0;
+ }
+
+ const frame = GodotWebXR.frame;
+ const space = GodotWebXR.space;
+
+ const pose = frame.getPose(controller.targetRaySpace, space);
+ if (!pose) {
+ // This can mean that the controller lost tracking.
+ return 0;
+ }
+ const matrix = pose.transform.matrix;
+
+ const buf = GodotRuntime.malloc(16 * 4);
+ for (let i = 0; i < 16; i++) {
+ GodotRuntime.setHeapValue(buf + (i * 4), matrix[i], 'float');
+ }
+ return buf;
+ },
+
+ godot_webxr_get_controller_buttons__proxy: 'sync',
+ godot_webxr_get_controller_buttons__sig: 'ii',
+ godot_webxr_get_controller_buttons: function (p_controller) {
+ if (GodotWebXR.controllers.length === 0) {
+ return 0;
+ }
+
+ const controller = GodotWebXR.controllers[p_controller];
+ if (!controller || !controller.gamepad) {
+ return 0;
+ }
+
+ const button_count = controller.gamepad.buttons.length;
+
+ const buf = GodotRuntime.malloc((button_count + 1) * 4);
+ GodotRuntime.setHeapValue(buf, button_count, 'i32');
+ for (let i = 0; i < button_count; i++) {
+ GodotRuntime.setHeapValue(buf + 4 + (i * 4), controller.gamepad.buttons[i].value, 'float');
+ }
+ return buf;
+ },
+
+ godot_webxr_get_controller_axes__proxy: 'sync',
+ godot_webxr_get_controller_axes__sig: 'ii',
+ godot_webxr_get_controller_axes: function (p_controller) {
+ if (GodotWebXR.controllers.length === 0) {
+ return 0;
+ }
+
+ const controller = GodotWebXR.controllers[p_controller];
+ if (!controller || !controller.gamepad) {
+ return 0;
+ }
+
+ const axes_count = controller.gamepad.axes.length;
+
+ const buf = GodotRuntime.malloc((axes_count + 1) * 4);
+ GodotRuntime.setHeapValue(buf, axes_count, 'i32');
+ for (let i = 0; i < axes_count; i++) {
+ let value = controller.gamepad.axes[i];
+ if (i === 1 || i === 3) {
+ // Invert the Y-axis on thumbsticks and trackpads, in order to
+ // match OpenXR and other XR platform SDKs.
+ value *= -1.0;
+ }
+ GodotRuntime.setHeapValue(buf + 4 + (i * 4), value, 'float');
+ }
+ return buf;
+ },
+
+ godot_webxr_get_visibility_state__proxy: 'sync',
+ godot_webxr_get_visibility_state__sig: 'i',
+ godot_webxr_get_visibility_state: function () {
+ if (!GodotWebXR.session || !GodotWebXR.session.visibilityState) {
+ return 0;
+ }
+
+ return GodotRuntime.allocString(GodotWebXR.session.visibilityState);
+ },
+
+ godot_webxr_get_bounds_geometry__proxy: 'sync',
+ godot_webxr_get_bounds_geometry__sig: 'i',
+ godot_webxr_get_bounds_geometry: function () {
+ if (!GodotWebXR.space || !GodotWebXR.space.boundsGeometry) {
+ return 0;
+ }
+
+ const point_count = GodotWebXR.space.boundsGeometry.length;
+ if (point_count === 0) {
+ return 0;
+ }
+
+ const buf = GodotRuntime.malloc(((point_count * 3) + 1) * 4);
+ GodotRuntime.setHeapValue(buf, point_count, 'i32');
+ for (let i = 0; i < point_count; i++) {
+ const point = GodotWebXR.space.boundsGeometry[i];
+ GodotRuntime.setHeapValue(buf + ((i * 3) + 1) * 4, point.x, 'float');
+ GodotRuntime.setHeapValue(buf + ((i * 3) + 2) * 4, point.y, 'float');
+ GodotRuntime.setHeapValue(buf + ((i * 3) + 3) * 4, point.z, 'float');
+ }
+
+ return buf;
+ },
+};
+
+autoAddDeps(GodotWebXR, '$GodotWebXR');
+mergeInto(LibraryManager.library, GodotWebXR);
diff --git a/modules/webxr/native/webxr.externs.js b/modules/webxr/native/webxr.externs.js
new file mode 100644
index 0000000000..03dc05bc83
--- /dev/null
+++ b/modules/webxr/native/webxr.externs.js
@@ -0,0 +1,499 @@
+/**
+ * @type {XR}
+ */
+Navigator.prototype.xr;
+
+/**
+ * @constructor
+ */
+function XRSessionInit() {};
+
+/**
+ * @type {Array<string>}
+ */
+XRSessionInit.prototype.requiredFeatures;
+
+/**
+ * @type {Array<string>}
+ */
+XRSessionInit.prototype.optionalFeatures;
+
+/**
+ * @constructor
+ */
+function XR() {}
+
+/**
+ * @type {?function (Event)}
+ */
+XR.prototype.ondevicechanged;
+
+/**
+ * @param {string} mode
+ *
+ * @return {!Promise<boolean>}
+ */
+XR.prototype.isSessionSupported = function(mode) {}
+
+/**
+ * @param {string} mode
+ * @param {XRSessionInit} options
+ *
+ * @return {!Promise<XRSession>}
+ */
+XR.prototype.requestSession = function(mode, options) {}
+
+/**
+ * @constructor
+ */
+function XRSession() {}
+
+/**
+ * @type {XRRenderState}
+ */
+XRSession.prototype.renderState;
+
+/**
+ * @type {Array<XRInputSource>}
+ */
+XRSession.prototype.inputSources;
+
+/**
+ * @type {string}
+ */
+XRSession.prototype.visibilityState;
+
+/**
+ * @type {?function (Event)}
+ */
+XRSession.prototype.onend;
+
+/**
+ * @type {?function (XRInputSourcesChangeEvent)}
+ */
+XRSession.prototype.oninputsourceschange;
+
+/**
+ * @type {?function (XRInputSourceEvent)}
+ */
+XRSession.prototype.onselectstart;
+
+/**
+ * @type {?function (XRInputSourceEvent)}
+ */
+XRSession.prototype.onselect;
+
+/**
+ * @type {?function (XRInputSourceEvent)}
+ */
+XRSession.prototype.onselectend;
+
+/**
+ * @type {?function (XRInputSourceEvent)}
+ */
+XRSession.prototype.onsqueezestart;
+
+/**
+ * @type {?function (XRInputSourceEvent)}
+ */
+XRSession.prototype.onsqueeze;
+
+/**
+ * @type {?function (XRInputSourceEvent)}
+ */
+XRSession.prototype.onsqueezeend;
+
+/**
+ * @type {?function (Event)}
+ */
+XRSession.prototype.onvisibilitychange;
+
+/**
+ * @param {XRRenderStateInit} state
+ * @return {void}
+ */
+XRSession.prototype.updateRenderState = function (state) {};
+
+/**
+ * @param {XRFrameRequestCallback} callback
+ * @return {number}
+ */
+XRSession.prototype.requestAnimationFrame = function (callback) {};
+
+/**
+ * @param {number} handle
+ * @return {void}
+ */
+XRSession.prototype.cancelAnimationFrame = function (handle) {};
+
+/**
+ * @return {Promise<void>}
+ */
+XRSession.prototype.end = function () {};
+
+/**
+ * @param {string} referenceSpaceType
+ * @return {Promise<XRReferenceSpace>}
+ */
+XRSession.prototype.requestReferenceSpace = function (referenceSpaceType) {};
+
+/**
+ * @typedef {function(number, XRFrame): undefined}
+ */
+var XRFrameRequestCallback;
+
+/**
+ * @constructor
+ */
+function XRRenderStateInit() {}
+
+/**
+ * @type {number}
+ */
+XRRenderStateInit.prototype.depthNear;
+
+/**
+ * @type {number}
+ */
+XRRenderStateInit.prototype.depthFar;
+
+/**
+ * @type {number}
+ */
+XRRenderStateInit.prototype.inlineVerticalFieldOfView;
+
+/**
+ * @type {?XRWebGLLayer}
+ */
+XRRenderStateInit.prototype.baseLayer;
+
+/**
+ * @constructor
+ */
+function XRRenderState() {};
+
+/**
+ * @type {number}
+ */
+XRRenderState.prototype.depthNear;
+
+/**
+ * @type {number}
+ */
+XRRenderState.prototype.depthFar;
+
+/**
+ * @type {?number}
+ */
+XRRenderState.prototype.inlineVerticalFieldOfView;
+
+/**
+ * @type {?XRWebGLLayer}
+ */
+XRRenderState.prototype.baseLayer;
+
+/**
+ * @constructor
+ */
+function XRFrame() {}
+
+/**
+ * @type {XRSession}
+ */
+XRFrame.prototype.session;
+
+/**
+ * @param {XRReferenceSpace} referenceSpace
+ * @return {?XRViewerPose}
+ */
+XRFrame.prototype.getViewerPose = function (referenceSpace) {};
+
+/**
+ *
+ * @param {XRSpace} space
+ * @param {XRSpace} baseSpace
+ * @return {XRPose}
+ */
+XRFrame.prototype.getPose = function (space, baseSpace) {};
+
+/**
+ * @constructor
+ */
+function XRReferenceSpace() {};
+
+/**
+ * @type {Array<DOMPointReadOnly>}
+ */
+XRReferenceSpace.prototype.boundsGeometry;
+
+/**
+ * @param {XRRigidTransform} originOffset
+ * @return {XRReferenceSpace}
+ */
+XRReferenceSpace.prototype.getOffsetReferenceSpace = function(originOffset) {};
+
+/**
+ * @type {?function (Event)}
+ */
+XRReferenceSpace.prototype.onreset;
+
+/**
+ * @constructor
+ */
+function XRRigidTransform() {};
+
+/**
+ * @type {DOMPointReadOnly}
+ */
+XRRigidTransform.prototype.position;
+
+/**
+ * @type {DOMPointReadOnly}
+ */
+XRRigidTransform.prototype.orientation;
+
+/**
+ * @type {Float32Array}
+ */
+XRRigidTransform.prototype.matrix;
+
+/**
+ * @type {XRRigidTransform}
+ */
+XRRigidTransform.prototype.inverse;
+
+/**
+ * @constructor
+ */
+function XRView() {}
+
+/**
+ * @type {string}
+ */
+XRView.prototype.eye;
+
+/**
+ * @type {Float32Array}
+ */
+XRView.prototype.projectionMatrix;
+
+/**
+ * @type {XRRigidTransform}
+ */
+XRView.prototype.transform;
+
+/**
+ * @constructor
+ */
+function XRViewerPose() {}
+
+/**
+ * @type {Array<XRView>}
+ */
+XRViewerPose.prototype.views;
+
+/**
+ * @constructor
+ */
+function XRViewport() {}
+
+/**
+ * @type {number}
+ */
+XRViewport.prototype.x;
+
+/**
+ * @type {number}
+ */
+XRViewport.prototype.y;
+
+/**
+ * @type {number}
+ */
+XRViewport.prototype.width;
+
+/**
+ * @type {number}
+ */
+XRViewport.prototype.height;
+
+/**
+ * @constructor
+ */
+function XRWebGLLayerInit() {};
+
+/**
+ * @type {boolean}
+ */
+XRWebGLLayerInit.prototype.antialias;
+
+/**
+ * @type {boolean}
+ */
+XRWebGLLayerInit.prototype.depth;
+
+/**
+ * @type {boolean}
+ */
+XRWebGLLayerInit.prototype.stencil;
+
+/**
+ * @type {boolean}
+ */
+XRWebGLLayerInit.prototype.alpha;
+
+/**
+ * @type {boolean}
+ */
+XRWebGLLayerInit.prototype.ignoreDepthValues;
+
+/**
+ * @type {boolean}
+ */
+XRWebGLLayerInit.prototype.ignoreDepthValues;
+
+/**
+ * @type {number}
+ */
+XRWebGLLayerInit.prototype.framebufferScaleFactor;
+
+/**
+ * @constructor
+ *
+ * @param {XRSession} session
+ * @param {WebGLRenderContext|WebGL2RenderingContext} ctx
+ * @param {?XRWebGLLayerInit} options
+ */
+function XRWebGLLayer(session, ctx, options) {}
+
+/**
+ * @type {boolean}
+ */
+XRWebGLLayer.prototype.antialias;
+
+/**
+ * @type {boolean}
+ */
+XRWebGLLayer.prototype.ignoreDepthValues;
+
+/**
+ * @type {number}
+ */
+XRWebGLLayer.prototype.framebufferWidth;
+
+/**
+ * @type {number}
+ */
+XRWebGLLayer.prototype.framebufferHeight;
+
+/**
+ * @type {WebGLFramebuffer}
+ */
+XRWebGLLayer.prototype.framebuffer;
+
+/**
+ * @param {XRView} view
+ * @return {?XRViewport}
+ */
+XRWebGLLayer.prototype.getViewport = function(view) {};
+
+/**
+ * @param {XRSession} session
+ * @return {number}
+ */
+XRWebGLLayer.prototype.getNativeFramebufferScaleFactor = function (session) {};
+
+/**
+ * @constructor
+ */
+function WebGLRenderingContextBase() {};
+
+/**
+ * @return {Promise<void>}
+ */
+WebGLRenderingContextBase.prototype.makeXRCompatible = function () {};
+
+/**
+ * @constructor
+ */
+function XRInputSourcesChangeEvent() {};
+
+/**
+ * @type {Array<XRInputSource>}
+ */
+XRInputSourcesChangeEvent.prototype.added;
+
+/**
+ * @type {Array<XRInputSource>}
+ */
+XRInputSourcesChangeEvent.prototype.removed;
+
+/**
+ * @constructor
+ */
+function XRInputSourceEvent() {};
+
+/**
+ * @type {XRFrame}
+ */
+XRInputSourceEvent.prototype.frame;
+
+/**
+ * @type {XRInputSource}
+ */
+XRInputSourceEvent.prototype.inputSource;
+
+/**
+ * @constructor
+ */
+function XRInputSource() {};
+
+/**
+ * @type {Gamepad}
+ */
+XRInputSource.prototype.gamepad;
+
+/**
+ * @type {XRSpace}
+ */
+XRInputSource.prototype.gripSpace;
+
+/**
+ * @type {string}
+ */
+XRInputSource.prototype.handedness;
+
+/**
+ * @type {string}
+ */
+XRInputSource.prototype.profiles;
+
+/**
+ * @type {string}
+ */
+XRInputSource.prototype.targetRayMode;
+
+/**
+ * @type {XRSpace}
+ */
+XRInputSource.prototype.targetRaySpace;
+
+/**
+ * @constructor
+ */
+function XRSpace() {};
+
+/**
+ * @constructor
+ */
+function XRPose() {};
+
+/**
+ * @type {XRRigidTransform}
+ */
+XRPose.prototype.transform;
+
+/**
+ * @type {boolean}
+ */
+XRPose.prototype.emulatedPosition;
diff --git a/modules/webxr/register_types.cpp b/modules/webxr/register_types.cpp
new file mode 100644
index 0000000000..8baf7e05b8
--- /dev/null
+++ b/modules/webxr/register_types.cpp
@@ -0,0 +1,47 @@
+/*************************************************************************/
+/* register_types.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "register_types.h"
+
+#include "webxr_interface.h"
+#include "webxr_interface_js.h"
+
+void register_webxr_types() {
+ ClassDB::register_virtual_class<WebXRInterface>();
+
+#ifdef JAVASCRIPT_ENABLED
+ Ref<WebXRInterfaceJS> webxr;
+ webxr.instance();
+ XRServer::get_singleton()->add_interface(webxr);
+#endif
+}
+
+void unregister_webxr_types() {
+}
diff --git a/modules/assimp/register_types.h b/modules/webxr/register_types.h
index f399a7acc6..f0c5a4bd79 100644
--- a/modules/assimp/register_types.h
+++ b/modules/webxr/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -28,10 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef ASSIMP_REGISTER_TYPES_H
-#define ASSIMP_REGISTER_TYPES_H
+#ifndef WEBXR_REGISTER_TYPES_H
+#define WEBXR_REGISTER_TYPES_H
-void register_assimp_types();
-void unregister_assimp_types();
+void register_webxr_types();
+void unregister_webxr_types();
-#endif // ASSIMP_REGISTER_TYPES_H
+#endif // WEBXR_REGISTER_TYPES_H
diff --git a/modules/webxr/webxr_interface.cpp b/modules/webxr/webxr_interface.cpp
new file mode 100644
index 0000000000..3e8e75bf0e
--- /dev/null
+++ b/modules/webxr/webxr_interface.cpp
@@ -0,0 +1,71 @@
+/*************************************************************************/
+/* webxr_interface.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "webxr_interface.h"
+#include <stdlib.h>
+
+void WebXRInterface::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("is_session_supported", "session_mode"), &WebXRInterface::is_session_supported);
+ ClassDB::bind_method(D_METHOD("set_session_mode", "session_mode"), &WebXRInterface::set_session_mode);
+ ClassDB::bind_method(D_METHOD("get_session_mode"), &WebXRInterface::get_session_mode);
+ ClassDB::bind_method(D_METHOD("set_required_features", "required_features"), &WebXRInterface::set_required_features);
+ ClassDB::bind_method(D_METHOD("get_required_features"), &WebXRInterface::get_required_features);
+ ClassDB::bind_method(D_METHOD("set_optional_features", "optional_features"), &WebXRInterface::set_optional_features);
+ ClassDB::bind_method(D_METHOD("get_optional_features"), &WebXRInterface::get_optional_features);
+ ClassDB::bind_method(D_METHOD("get_reference_space_type"), &WebXRInterface::get_reference_space_type);
+ ClassDB::bind_method(D_METHOD("set_requested_reference_space_types", "requested_reference_space_types"), &WebXRInterface::set_requested_reference_space_types);
+ ClassDB::bind_method(D_METHOD("get_requested_reference_space_types"), &WebXRInterface::get_requested_reference_space_types);
+ ClassDB::bind_method(D_METHOD("get_controller", "controller_id"), &WebXRInterface::get_controller);
+ ClassDB::bind_method(D_METHOD("get_visibility_state"), &WebXRInterface::get_visibility_state);
+ ClassDB::bind_method(D_METHOD("get_bounds_geometry"), &WebXRInterface::get_bounds_geometry);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "session_mode", PROPERTY_HINT_NONE), "set_session_mode", "get_session_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "required_features", PROPERTY_HINT_NONE), "set_required_features", "get_required_features");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "optional_features", PROPERTY_HINT_NONE), "set_optional_features", "get_optional_features");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "requested_reference_space_types", PROPERTY_HINT_NONE), "set_requested_reference_space_types", "get_requested_reference_space_types");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "reference_space_type", PROPERTY_HINT_NONE), "", "get_reference_space_type");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "visibility_state", PROPERTY_HINT_NONE), "", "get_visibility_state");
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "bounds_geometry", PROPERTY_HINT_NONE), "", "get_bounds_geometry");
+
+ ADD_SIGNAL(MethodInfo("session_supported", PropertyInfo(Variant::STRING, "session_mode"), PropertyInfo(Variant::BOOL, "supported")));
+ ADD_SIGNAL(MethodInfo("session_started"));
+ ADD_SIGNAL(MethodInfo("session_ended"));
+ ADD_SIGNAL(MethodInfo("session_failed", PropertyInfo(Variant::STRING, "message")));
+
+ ADD_SIGNAL(MethodInfo("selectstart", PropertyInfo(Variant::INT, "controller_id")));
+ ADD_SIGNAL(MethodInfo("select", PropertyInfo(Variant::INT, "controller_id")));
+ ADD_SIGNAL(MethodInfo("selectend", PropertyInfo(Variant::INT, "controller_id")));
+ ADD_SIGNAL(MethodInfo("squeezestart", PropertyInfo(Variant::INT, "controller_id")));
+ ADD_SIGNAL(MethodInfo("squeeze", PropertyInfo(Variant::INT, "controller_id")));
+ ADD_SIGNAL(MethodInfo("squeezeend", PropertyInfo(Variant::INT, "controller_id")));
+
+ ADD_SIGNAL(MethodInfo("visibility_state_changed"));
+ ADD_SIGNAL(MethodInfo("reference_space_reset"));
+}
diff --git a/modules/webxr/webxr_interface.h b/modules/webxr/webxr_interface.h
new file mode 100644
index 0000000000..c5b2dc8d73
--- /dev/null
+++ b/modules/webxr/webxr_interface.h
@@ -0,0 +1,65 @@
+/*************************************************************************/
+/* webxr_interface.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef WEBXR_INTERFACE_H
+#define WEBXR_INTERFACE_H
+
+#include "servers/xr/xr_interface.h"
+#include "servers/xr/xr_positional_tracker.h"
+
+/**
+ @author David Snopek <david.snopek@snopekgames.com>
+
+ The WebXR interface is a VR/AR interface that can be used on the web.
+*/
+
+class WebXRInterface : public XRInterface {
+ GDCLASS(WebXRInterface, XRInterface);
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual void is_session_supported(const String &p_session_mode) = 0;
+ virtual void set_session_mode(String p_session_mode) = 0;
+ virtual String get_session_mode() const = 0;
+ virtual void set_required_features(String p_required_features) = 0;
+ virtual String get_required_features() const = 0;
+ virtual void set_optional_features(String p_optional_features) = 0;
+ virtual String get_optional_features() const = 0;
+ virtual void set_requested_reference_space_types(String p_requested_reference_space_types) = 0;
+ virtual String get_requested_reference_space_types() const = 0;
+ virtual String get_reference_space_type() const = 0;
+ virtual XRPositionalTracker *get_controller(int p_controller_id) const = 0;
+ virtual String get_visibility_state() const = 0;
+ virtual PackedVector3Array get_bounds_geometry() const = 0;
+};
+
+#endif // WEBXR_INTERFACE_H
diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp
new file mode 100644
index 0000000000..74789fc98e
--- /dev/null
+++ b/modules/webxr/webxr_interface_js.cpp
@@ -0,0 +1,460 @@
+/*************************************************************************/
+/* webxr_interface_js.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifdef JAVASCRIPT_ENABLED
+
+#include "webxr_interface_js.h"
+#include "core/input/input.h"
+#include "core/os/os.h"
+#include "emscripten.h"
+#include "godot_webxr.h"
+#include <stdlib.h>
+
+void _emwebxr_on_session_supported(char *p_session_mode, int p_supported) {
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
+
+ Ref<XRInterface> interface = xr_server->find_interface("WebXR");
+ ERR_FAIL_COND(interface.is_null());
+
+ String session_mode = String(p_session_mode);
+ interface->emit_signal("session_supported", session_mode, p_supported ? true : false);
+}
+
+void _emwebxr_on_session_started(char *p_reference_space_type) {
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
+
+ Ref<XRInterface> interface = xr_server->find_interface("WebXR");
+ 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);
+ interface->emit_signal("session_started");
+}
+
+void _emwebxr_on_session_ended() {
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
+
+ Ref<XRInterface> interface = xr_server->find_interface("WebXR");
+ ERR_FAIL_COND(interface.is_null());
+
+ interface->uninitialize();
+ interface->emit_signal("session_ended");
+}
+
+void _emwebxr_on_session_failed(char *p_message) {
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
+
+ Ref<XRInterface> interface = xr_server->find_interface("WebXR");
+ ERR_FAIL_COND(interface.is_null());
+
+ interface->uninitialize();
+
+ String message = String(p_message);
+ interface->emit_signal("session_failed", message);
+}
+
+void _emwebxr_on_controller_changed() {
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
+
+ Ref<XRInterface> interface = xr_server->find_interface("WebXR");
+ ERR_FAIL_COND(interface.is_null());
+
+ ((WebXRInterfaceJS *)interface.ptr())->_on_controller_changed();
+}
+
+extern "C" EMSCRIPTEN_KEEPALIVE void _emwebxr_on_input_event(char *p_signal_name, int p_input_source) {
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
+
+ Ref<XRInterface> interface = xr_server->find_interface("WebXR");
+ ERR_FAIL_COND(interface.is_null());
+
+ StringName signal_name = StringName(p_signal_name);
+ interface->emit_signal(signal_name, p_input_source + 1);
+}
+
+extern "C" EMSCRIPTEN_KEEPALIVE void _emwebxr_on_simple_event(char *p_signal_name) {
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
+
+ Ref<XRInterface> interface = xr_server->find_interface("WebXR");
+ ERR_FAIL_COND(interface.is_null());
+
+ StringName signal_name = StringName(p_signal_name);
+ interface->emit_signal(signal_name);
+}
+
+void WebXRInterfaceJS::is_session_supported(const String &p_session_mode) {
+ godot_webxr_is_session_supported(p_session_mode.utf8().get_data(), &_emwebxr_on_session_supported);
+}
+
+void WebXRInterfaceJS::set_session_mode(String p_session_mode) {
+ session_mode = p_session_mode;
+}
+
+String WebXRInterfaceJS::get_session_mode() const {
+ return session_mode;
+}
+
+void WebXRInterfaceJS::set_required_features(String p_required_features) {
+ required_features = p_required_features;
+}
+
+String WebXRInterfaceJS::get_required_features() const {
+ return required_features;
+}
+
+void WebXRInterfaceJS::set_optional_features(String p_optional_features) {
+ optional_features = p_optional_features;
+}
+
+String WebXRInterfaceJS::get_optional_features() const {
+ return optional_features;
+}
+
+void WebXRInterfaceJS::set_requested_reference_space_types(String p_requested_reference_space_types) {
+ requested_reference_space_types = p_requested_reference_space_types;
+}
+
+String WebXRInterfaceJS::get_requested_reference_space_types() const {
+ return requested_reference_space_types;
+}
+
+void WebXRInterfaceJS::_set_reference_space_type(String p_reference_space_type) {
+ reference_space_type = p_reference_space_type;
+}
+
+String WebXRInterfaceJS::get_reference_space_type() const {
+ return reference_space_type;
+}
+
+XRPositionalTracker *WebXRInterfaceJS::get_controller(int p_controller_id) const {
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL_V(xr_server, nullptr);
+
+ return xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
+}
+
+String WebXRInterfaceJS::get_visibility_state() const {
+ char *c_str = godot_webxr_get_visibility_state();
+ if (c_str) {
+ String visibility_state = String(c_str);
+ free(c_str);
+
+ return visibility_state;
+ }
+ return String();
+}
+
+PackedVector3Array WebXRInterfaceJS::get_bounds_geometry() const {
+ PackedVector3Array ret;
+
+ int *js_bounds = godot_webxr_get_bounds_geometry();
+ if (js_bounds) {
+ ret.resize(js_bounds[0]);
+ for (int i = 0; i < js_bounds[0]; i++) {
+ float *js_vector3 = ((float *)js_bounds) + (i * 3) + 1;
+ ret.set(i, Vector3(js_vector3[0], js_vector3[1], js_vector3[2]));
+ }
+ free(js_bounds);
+ }
+
+ return ret;
+}
+
+StringName WebXRInterfaceJS::get_name() const {
+ return "WebXR";
+};
+
+int WebXRInterfaceJS::get_capabilities() const {
+ return XRInterface::XR_STEREO | XRInterface::XR_MONO;
+};
+
+bool WebXRInterfaceJS::is_stereo() {
+ return godot_webxr_get_view_count() == 2;
+};
+
+bool WebXRInterfaceJS::is_initialized() const {
+ return (initialized);
+};
+
+bool WebXRInterfaceJS::initialize() {
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL_V(xr_server, false);
+
+ if (!initialized) {
+ if (!godot_webxr_is_supported()) {
+ return false;
+ }
+
+ if (requested_reference_space_types.size() == 0) {
+ return false;
+ }
+
+ // make this our primary interface
+ xr_server->set_primary_interface(this);
+
+ // Clear render_targetsize to make sure it gets reset to the new size.
+ // Clearing in uninitialize() doesn't work because a frame can still be
+ // rendered after it's called, which will fill render_targetsize again.
+ render_targetsize.width = 0;
+ render_targetsize.height = 0;
+
+ initialized = true;
+
+ godot_webxr_initialize(
+ session_mode.utf8().get_data(),
+ required_features.utf8().get_data(),
+ optional_features.utf8().get_data(),
+ requested_reference_space_types.utf8().get_data(),
+ &_emwebxr_on_session_started,
+ &_emwebxr_on_session_ended,
+ &_emwebxr_on_session_failed,
+ &_emwebxr_on_controller_changed,
+ &_emwebxr_on_input_event,
+ &_emwebxr_on_simple_event);
+ };
+
+ return true;
+};
+
+void WebXRInterfaceJS::uninitialize() {
+ if (initialized) {
+ XRServer *xr_server = XRServer::get_singleton();
+ if (xr_server != NULL) {
+ // no longer our primary interface
+ xr_server->clear_primary_interface_if(this);
+ }
+
+ godot_webxr_uninitialize();
+
+ reference_space_type = "";
+ initialized = false;
+ };
+};
+
+Transform WebXRInterfaceJS::_js_matrix_to_transform(float *p_js_matrix) {
+ Transform 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.origin.x = p_js_matrix[12];
+ transform.origin.y = p_js_matrix[13];
+ transform.origin.z = p_js_matrix[14];
+
+ return transform;
+}
+
+Size2 WebXRInterfaceJS::get_render_targetsize() {
+ if (render_targetsize.width != 0 && render_targetsize.height != 0) {
+ return render_targetsize;
+ }
+
+ int *js_size = godot_webxr_get_render_targetsize();
+ if (!initialized || js_size == nullptr) {
+ // As a temporary default (until WebXR is fully initialized), use half the window size.
+ Size2 temp = DisplayServer::get_singleton()->window_get_size();
+ temp.width /= 2.0;
+ return temp;
+ }
+
+ render_targetsize.width = js_size[0];
+ render_targetsize.height = js_size[1];
+
+ free(js_size);
+
+ return render_targetsize;
+};
+
+Transform WebXRInterfaceJS::get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) {
+ Transform transform_for_eye;
+
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL_V(xr_server, transform_for_eye);
+
+ float *js_matrix = godot_webxr_get_transform_for_eye(p_eye);
+ if (!initialized || js_matrix == nullptr) {
+ transform_for_eye = p_cam_transform;
+ return transform_for_eye;
+ }
+
+ transform_for_eye = _js_matrix_to_transform(js_matrix);
+ free(js_matrix);
+
+ return p_cam_transform * xr_server->get_reference_frame() * transform_for_eye;
+};
+
+CameraMatrix WebXRInterfaceJS::get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) {
+ CameraMatrix eye;
+
+ float *js_matrix = godot_webxr_get_projection_for_eye(p_eye);
+ if (!initialized || js_matrix == nullptr) {
+ return eye;
+ }
+
+ int k = 0;
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ eye.matrix[i][j] = js_matrix[k++];
+ }
+ }
+
+ free(js_matrix);
+
+ // Copied from godot_oculus_mobile's ovr_mobile_session.cpp
+ eye.matrix[2][2] = -(p_z_far + p_z_near) / (p_z_far - p_z_near);
+ eye.matrix[3][2] = -(2.0f * p_z_far * p_z_near) / (p_z_far - p_z_near);
+
+ return eye;
+}
+
+unsigned int WebXRInterfaceJS::get_external_texture_for_eye(XRInterface::Eyes p_eye) {
+ if (!initialized) {
+ return 0;
+ }
+ return godot_webxr_get_external_texture_for_eye(p_eye);
+}
+
+void WebXRInterfaceJS::commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) {
+ if (!initialized) {
+ return;
+ }
+ godot_webxr_commit_for_eye(p_eye);
+};
+
+void WebXRInterfaceJS::process() {
+ if (initialized) {
+ godot_webxr_sample_controller_data();
+
+ int controller_count = godot_webxr_get_controller_count();
+ if (controller_count == 0) {
+ return;
+ }
+
+ for (int i = 0; i < controller_count; i++) {
+ _update_tracker(i);
+ }
+ };
+};
+
+void WebXRInterfaceJS::_update_tracker(int p_controller_id) {
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
+
+ XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id + 1);
+ if (godot_webxr_is_controller_connected(p_controller_id)) {
+ if (tracker == nullptr) {
+ tracker = memnew(XRPositionalTracker);
+ tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER);
+ // Controller id's 0 and 1 are always the left and right hands.
+ if (p_controller_id < 2) {
+ tracker->set_tracker_name(p_controller_id == 0 ? "Left" : "Right");
+ tracker->set_tracker_hand(p_controller_id == 0 ? XRPositionalTracker::TRACKER_HAND_LEFT : XRPositionalTracker::TRACKER_HAND_RIGHT);
+ }
+ // Use the ids we're giving to our "virtual" gamepads.
+ tracker->set_joy_id(p_controller_id + 100);
+ xr_server->add_tracker(tracker);
+ }
+
+ Input *input = Input::get_singleton();
+
+ float *tracker_matrix = godot_webxr_get_controller_transform(p_controller_id);
+ if (tracker_matrix) {
+ Transform transform = _js_matrix_to_transform(tracker_matrix);
+ tracker->set_position(transform.origin);
+ tracker->set_orientation(transform.basis);
+ free(tracker_matrix);
+ }
+
+ int *buttons = godot_webxr_get_controller_buttons(p_controller_id);
+ if (buttons) {
+ for (int i = 0; i < buttons[0]; i++) {
+ input->joy_button(p_controller_id + 100, i, *((float *)buttons + (i + 1)));
+ }
+ free(buttons);
+ }
+
+ int *axes = godot_webxr_get_controller_axes(p_controller_id);
+ if (axes) {
+ for (int i = 0; i < axes[0]; i++) {
+ Input::JoyAxis joy_axis;
+ joy_axis.min = -1;
+ joy_axis.value = *((float *)axes + (i + 1));
+ input->joy_axis(p_controller_id + 100, i, joy_axis);
+ }
+ free(axes);
+ }
+ } else if (tracker) {
+ xr_server->remove_tracker(tracker);
+ }
+}
+
+void WebXRInterfaceJS::_on_controller_changed() {
+ // Register "virtual" gamepads with Godot for the ones we get from WebXR.
+ godot_webxr_sample_controller_data();
+ for (int i = 0; i < 2; i++) {
+ bool controller_connected = godot_webxr_is_controller_connected(i);
+ if (controllers_state[i] != controller_connected) {
+ Input::get_singleton()->joy_connection_changed(i + 100, controller_connected, i == 0 ? "Left" : "Right", "");
+ controllers_state[i] = controller_connected;
+ }
+ }
+}
+
+void WebXRInterfaceJS::notification(int p_what) {
+ // Nothing to do here.
+}
+
+WebXRInterfaceJS::WebXRInterfaceJS() {
+ initialized = false;
+ session_mode = "inline";
+ requested_reference_space_types = "local";
+};
+
+WebXRInterfaceJS::~WebXRInterfaceJS() {
+ // and make sure we cleanup if we haven't already
+ if (initialized) {
+ uninitialize();
+ };
+};
+
+#endif // JAVASCRIPT_ENABLED
diff --git a/modules/arkit/arkit_interface.h b/modules/webxr/webxr_interface_js.h
index 29e09411ff..49299b252f 100644
--- a/modules/arkit/arkit_interface.h
+++ b/modules/webxr/webxr_interface_js.h
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* arkit_interface.h */
+/* webxr_interface_js.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -28,85 +28,52 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef ARKIT_INTERFACE_H
-#define ARKIT_INTERFACE_H
+#ifndef WEBXR_INTERFACE_JS_H
+#define WEBXR_INTERFACE_JS_H
-#include "servers/camera/camera_feed.h"
-#include "servers/xr/xr_interface.h"
-#include "servers/xr/xr_positional_tracker.h"
+#ifdef JAVASCRIPT_ENABLED
+
+#include "webxr_interface.h"
/**
- @author Bastiaan Olij <mux213@gmail.com>
+ @author David Snopek <david.snopek@snopekgames.com>
- ARKit interface between iPhone and Godot
+ The WebXR interface is a VR/AR interface that can be used on the web.
*/
-// forward declaration for some needed objects
-class ARKitShader;
-
-#ifdef __OBJC__
-
-typedef ARAnchor GodotARAnchor;
-
-#else
-
-typedef void GodotARAnchor;
-#endif
-
-class ARKitInterface : public XRInterface {
- GDCLASS(ARKitInterface, XRInterface);
+class WebXRInterfaceJS : public WebXRInterface {
+ GDCLASS(WebXRInterfaceJS, WebXRInterface);
private:
bool initialized;
- bool session_was_started;
- bool plane_detection_is_enabled;
- bool light_estimation_is_enabled;
- real_t ambient_intensity;
- real_t ambient_color_temperature;
-
- Transform transform;
- CameraMatrix projection;
- float eye_height, z_near, z_far;
-
- Ref<CameraFeed> feed;
- size_t image_width[2];
- size_t image_height[2];
- Vector<uint8_t> img_data[2];
-
- struct anchor_map {
- XRPositionalTracker *tracker;
- unsigned char uuid[16];
- };
-
- ///@TODO should use memory map object from Godot?
- unsigned int num_anchors;
- unsigned int max_anchors;
- anchor_map *anchors;
- XRPositionalTracker *get_anchor_for_uuid(const unsigned char *p_uuid);
- void remove_anchor_for_uuid(const unsigned char *p_uuid);
- void remove_all_anchors();
-
-protected:
- static void _bind_methods();
-public:
- void start_session();
- void stop_session();
+ String session_mode;
+ String required_features;
+ String optional_features;
+ String requested_reference_space_types;
+ String reference_space_type;
- bool get_anchor_detection_is_enabled() const override;
- void set_anchor_detection_is_enabled(bool p_enable) override;
- virtual int get_camera_feed_id() override;
+ bool controllers_state[2];
+ Size2 render_targetsize;
- bool get_light_estimation_is_enabled() const;
- void set_light_estimation_is_enabled(bool p_enable);
+ Transform _js_matrix_to_transform(float *p_js_matrix);
+ void _update_tracker(int p_controller_id);
- real_t get_ambient_intensity() const;
- real_t get_ambient_color_temperature() const;
-
- /* while Godot has its own raycast logic this takes ARKits camera into account and hits on any ARAnchor */
- Array raycast(Vector2 p_screen_coord);
-
- virtual void notification(int p_what) override;
+public:
+ virtual void is_session_supported(const String &p_session_mode) override;
+ virtual void set_session_mode(String p_session_mode) override;
+ virtual String get_session_mode() const override;
+ virtual void set_required_features(String p_required_features) override;
+ virtual String get_required_features() const override;
+ virtual void set_optional_features(String p_optional_features) override;
+ virtual String get_optional_features() const override;
+ virtual void set_requested_reference_space_types(String p_requested_reference_space_types) override;
+ virtual String get_requested_reference_space_types() const override;
+ void _set_reference_space_type(String p_reference_space_type);
+ virtual String get_reference_space_type() const override;
+ virtual XRPositionalTracker *get_controller(int p_controller_id) const override;
+ virtual String get_visibility_state() const override;
+ virtual PackedVector3Array get_bounds_geometry() const override;
virtual StringName get_name() const override;
virtual int get_capabilities() const override;
@@ -119,16 +86,18 @@ public:
virtual bool is_stereo() override;
virtual Transform get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) override;
virtual CameraMatrix get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) override;
+ virtual unsigned int get_external_texture_for_eye(XRInterface::Eyes p_eye) override;
virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) override;
virtual void process() override;
+ virtual void notification(int p_what) override;
- // called by delegate (void * because C++ and Obj-C don't always mix, should really change all platform/iphone/*.cpp files to .mm)
- void _add_or_update_anchor(GodotARAnchor *p_anchor);
- void _remove_anchor(GodotARAnchor *p_anchor);
+ void _on_controller_changed();
- ARKitInterface();
- ~ARKitInterface();
+ WebXRInterfaceJS();
+ ~WebXRInterfaceJS();
};
-#endif /* !ARKIT_INTERFACE_H */
+#endif // JAVASCRIPT_ENABLED
+
+#endif // WEBXR_INTERFACE_JS_H
diff --git a/modules/xatlas_unwrap/SCsub b/modules/xatlas_unwrap/SCsub
index c659349d05..aa6bdaea33 100644
--- a/modules/xatlas_unwrap/SCsub
+++ b/modules/xatlas_unwrap/SCsub
@@ -6,6 +6,9 @@ Import("env_modules")
env_xatlas_unwrap = env_modules.Clone()
# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_xatlas"]:
thirdparty_dir = "#thirdparty/xatlas/"
thirdparty_sources = [
@@ -17,7 +20,16 @@ if env["builtin_xatlas"]:
env_thirdparty = env_xatlas_unwrap.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
+
# Godot source files
-env_xatlas_unwrap.add_source_files(env.modules_sources, "*.cpp")
+
+module_obj = []
+
+env_xatlas_unwrap.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/xatlas_unwrap/register_types.cpp b/modules/xatlas_unwrap/register_types.cpp
index 6242009f67..9f6e7efb27 100644
--- a/modules/xatlas_unwrap/register_types.cpp
+++ b/modules/xatlas_unwrap/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,7 +30,7 @@
#include "register_types.h"
-#include "core/error_macros.h"
+#include "core/error/error_macros.h"
#include "core/crypto/crypto_core.h"
@@ -141,11 +141,11 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
xatlas::Atlas *atlas = xatlas::Create();
printf("Adding mesh..\n");
- xatlas::AddMeshError::Enum err = xatlas::AddMesh(atlas, input_mesh, 1);
- ERR_FAIL_COND_V_MSG(err != xatlas::AddMeshError::Enum::Success, false, xatlas::StringForEnum(err));
+ xatlas::AddMeshError err = xatlas::AddMesh(atlas, input_mesh, 1);
+ ERR_FAIL_COND_V_MSG(err != xatlas::AddMeshError::Success, false, xatlas::StringForEnum(err));
printf("Generate..\n");
- xatlas::Generate(atlas, chart_options, xatlas::ParameterizeOptions(), pack_options);
+ xatlas::Generate(atlas, chart_options, pack_options);
*r_size_hint_x = atlas->width;
*r_size_hint_y = atlas->height;
diff --git a/modules/xatlas_unwrap/register_types.h b/modules/xatlas_unwrap/register_types.h
index fe924bab96..2ad729f172 100644
--- a/modules/xatlas_unwrap/register_types.h
+++ b/modules/xatlas_unwrap/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */